From 57e32fed732a413d4445cc130e55304f3cd8d890 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Sun, 5 Apr 2026 23:52:55 +0700 Subject: [PATCH] refactor: implement null-safe operator for safer property access across various models and pages --- app/Filament/Pages/Auth/Login.php | 6 ++--- .../Information/CourseSchedule/Index.php | 14 +++++----- .../Actions/EditStudyGroupAction.php | 4 +-- .../Pages/Learning/StudyGroup/Index.php | 14 +++++----- app/Filament/Pages/Profile.php | 8 +++--- app/Filament/Pages/System/ManageSettings.php | 2 +- .../Assignments/Actions/SubmitAction.php | 2 +- .../Assignments/Pages/EditAssignment.php | 6 ++--- .../Assignments/Pages/ListAssignments.php | 16 ++++++------ .../Pages/SubmissionDetailPage.php | 26 +++++++++---------- .../Pages/SubmitAssignmentPage.php | 22 ++++++++-------- .../Attendances/Pages/ManageAttendances.php | 18 ++++++------- .../Actions/CopyAttendanceLinkAction.php | 2 +- .../Actions/GenerateSessionsAction.php | 2 +- .../Actions/ShareAttendanceAction.php | 4 +-- .../Actions/ViewAssignmentsAction.php | 4 +-- .../Actions/ViewAttendanceAction.php | 2 +- .../Pages/ListCourseSessions.php | 10 +++---- .../Pages/ManageClassSessions.php | 12 ++++----- .../Materials/Tables/MaterialTable.php | 2 +- .../Controllers/ShareAttendanceController.php | 2 +- app/Http/Middleware/DynamicFilamentTheme.php | 10 +++---- app/Models/Assignment.php | 2 +- app/Models/AssignmentPin.php | 2 +- app/Models/AssignmentSubmission.php | 2 +- app/Models/AssignmentTarget.php | 2 +- app/Models/Attendance.php | 2 +- app/Models/Changelog.php | 4 +-- app/Models/ClassSession.php | 2 +- app/Models/Course.php | 2 +- app/Models/CourseSchedule.php | 2 +- app/Models/Material.php | 2 +- app/Models/Student.php | 2 +- app/Models/StudyGroup.php | 2 +- app/Models/StudyGroupMember.php | 2 +- app/Models/User.php | 2 +- app/Models/UserSetting.php | 2 +- 37 files changed, 110 insertions(+), 110 deletions(-) diff --git a/app/Filament/Pages/Auth/Login.php b/app/Filament/Pages/Auth/Login.php index 135dd92..41ec354 100644 --- a/app/Filament/Pages/Auth/Login.php +++ b/app/Filament/Pages/Auth/Login.php @@ -75,7 +75,7 @@ public function authenticate(): ?LoginResponse return null; } - $data = $this->form->getState(); + $data = $this->form?->getState(); $authGuard = Filament::auth(); @@ -105,7 +105,7 @@ public function authenticate(): ?LoginResponse filled($this->userUndertakingMultiFactorAuthentication) && (decrypt($this->userUndertakingMultiFactorAuthentication) === $user->getAuthIdentifier()) ) { - $this->multiFactorChallengeForm->validate(); + $this->multiFactorChallengeForm?->validate(); } else { foreach (Filament::getMultiFactorAuthenticationProviders() as $multiFactorAuthenticationProvider) { if (! $multiFactorAuthenticationProvider->isEnabled($user)) { @@ -122,7 +122,7 @@ public function authenticate(): ?LoginResponse } if (filled($this->userUndertakingMultiFactorAuthentication)) { - $this->multiFactorChallengeForm->fill(); + $this->multiFactorChallengeForm?->fill(); return null; } diff --git a/app/Filament/Pages/Information/CourseSchedule/Index.php b/app/Filament/Pages/Information/CourseSchedule/Index.php index 0c9cd13..febe1c6 100644 --- a/app/Filament/Pages/Information/CourseSchedule/Index.php +++ b/app/Filament/Pages/Information/CourseSchedule/Index.php @@ -71,7 +71,7 @@ public static function getPagePermission(): string public function mount(): void { - $this->form->fill(); + $this->form?->fill(); } public function form(Schema $schema): Schema @@ -132,15 +132,15 @@ public function getSchedules(): Collection ->map(function ($daySchedules) { return $daySchedules->map(fn ($schedule) => (object) [ 'id' => $schedule->id, - 'course_code' => $schedule->course->code ?? 'MATKUL', - 'course_name' => $schedule->course->name ?? 'Mata Kuliah Tidak Diketahui', - 'lecturer' => $schedule->course->lecturer ?? 'Dosen Belum Ditentukan', - 'semester' => $schedule->course->semester, - 'credit' => $schedule->course->credit ?? '-', + 'course_code' => $schedule->course?->code ?? 'MATKUL', + 'course_name' => $schedule->course?->name ?? 'Mata Kuliah Tidak Diketahui', + 'lecturer' => $schedule->course?->lecturer ?? 'Dosen Belum Ditentukan', + 'semester' => $schedule->course?->semester, + 'credit' => $schedule->course?->credit ?? '-', 'room' => $schedule->room, 'mode_label' => $schedule->mode?->getLabel(), 'mode_color' => $schedule->mode?->getColor(), - 'time_range' => $schedule->start_time->format('H:i').' – '.$schedule->end_time->format('H:i'), + 'time_range' => $schedule->start_time?->format('H:i').' – '.$schedule->end_time?->format('H:i'), ]); }); } diff --git a/app/Filament/Pages/Learning/StudyGroup/Actions/EditStudyGroupAction.php b/app/Filament/Pages/Learning/StudyGroup/Actions/EditStudyGroupAction.php index d11dec6..d390008 100644 --- a/app/Filament/Pages/Learning/StudyGroup/Actions/EditStudyGroupAction.php +++ b/app/Filament/Pages/Learning/StudyGroup/Actions/EditStudyGroupAction.php @@ -33,8 +33,8 @@ protected function setUp(): void return [ 'name' => $record->name, 'leader_id' => $record->leader_id, - 'course_id' => $record->courses->pluck('id')->toArray(), - 'students' => $record->students->pluck('id')->toArray(), + 'course_id' => $record->courses?->pluck('id')->toArray(), + 'students' => $record->students?->pluck('id')->toArray(), ]; }) ->after(function (StudyGroup $record, array $data) { diff --git a/app/Filament/Pages/Learning/StudyGroup/Index.php b/app/Filament/Pages/Learning/StudyGroup/Index.php index 08cd7e2..7012316 100644 --- a/app/Filament/Pages/Learning/StudyGroup/Index.php +++ b/app/Filament/Pages/Learning/StudyGroup/Index.php @@ -81,7 +81,7 @@ public function emptyDescription(): string public function mount(): void { - $this->form->fill([ + $this->form?->fill([ 'course_id' => $this->course_id, ]); } @@ -141,20 +141,20 @@ public function studyGroups(): Collection $studentId = auth()->user()?->student?->id; return $query->orderBy('name', 'asc')->get()->map(function ($record) use ($studentId) { - $isMyGroup = ($studentId && ($record->leader_id === $studentId || $record->students->contains($studentId))); + $isMyGroup = ($studentId && ($record->leader_id === $studentId || $record->students?->contains($studentId))); return (object) [ 'id' => $record->id, 'name' => $record->name, 'is_my_group' => $isMyGroup, 'leader_avatar' => $record->leader?->user?->facehash_avatar_url, - 'leader_name' => $record->leader->full_name ?? 'Belum Ditentukan', + 'leader_name' => $record->leader?->full_name ?? 'Belum Ditentukan', 'is_leader' => $studentId && $record->leader_id === $studentId, - 'courses' => $record->courses->map(fn ($c) => (object) [ + 'courses' => $record->courses?->map(fn ($c) => (object) [ 'name' => $c->name, ]), - 'students_count' => $record->students->count(), - 'students' => $record->students->map(fn ($s) => (object) [ + 'students_count' => $record->students?->count() ?? 0, + 'students' => $record->students?->map(fn ($s) => (object) [ 'id' => $s->id, 'full_name' => $s->full_name, 'is_me' => $studentId && $s->id === $studentId, @@ -177,7 +177,7 @@ public function isMyGroup(StudyGroup $record): bool return false; } - return $record->leader_id === $studentId || $record->students->contains($studentId); + return $record->leader_id === $studentId || $record->students?->contains($studentId); } public function studyGroupFormSchema(): array diff --git a/app/Filament/Pages/Profile.php b/app/Filament/Pages/Profile.php index 0c3b524..ed24a0a 100644 --- a/app/Filament/Pages/Profile.php +++ b/app/Filament/Pages/Profile.php @@ -243,7 +243,7 @@ public function save(): void $this->callHook('beforeValidate'); - $data = $this->form->getState(); + $data = $this->form?->getState(); $this->callHook('afterValidate'); @@ -311,13 +311,13 @@ protected function handleRecordUpdate(Model $record, array $data): Model /** @var User $record */ if ($studentData && $record->student()->exists()) { - $record->student->update($studentData); + $record->student?->update($studentData); } elseif ($studentData) { $record->student()->create($studentData); } if ($settingsData && $record->settings()->exists()) { - $record->settings->update($settingsData); + $record->settings?->update($settingsData); } elseif ($settingsData) { $record->settings()->create($settingsData); } @@ -330,7 +330,7 @@ protected function afterSave(): void SystemNotification::send('profile_updated') ->send(); - if (filled($this->form->getState()['password'] ?? null)) { + if (filled($this->form?->getState()['password'] ?? null)) { filament()->auth()->logout(); session()->invalidate(); session()->regenerateToken(); diff --git a/app/Filament/Pages/System/ManageSettings.php b/app/Filament/Pages/System/ManageSettings.php index 052ca7e..68b78e4 100644 --- a/app/Filament/Pages/System/ManageSettings.php +++ b/app/Filament/Pages/System/ManageSettings.php @@ -92,7 +92,7 @@ protected function afterSave(): void $student = Student::find($kosmaId); if ($student?->user) { - $student->user->assignRole(RoleEnum::Kosma); + $student->user?->assignRole(RoleEnum::Kosma); } } } diff --git a/app/Filament/Resources/Learning/Assignments/Actions/SubmitAction.php b/app/Filament/Resources/Learning/Assignments/Actions/SubmitAction.php index e28d05d..3d9cd27 100644 --- a/app/Filament/Resources/Learning/Assignments/Actions/SubmitAction.php +++ b/app/Filament/Resources/Learning/Assignments/Actions/SubmitAction.php @@ -30,7 +30,7 @@ protected function setUp(): void if ($record->type === AssignmentType::Group) { return $record->studyGroups() - ->where('leader_id', auth()->user()->student->id) + ->where('leader_id', auth()->user()?->student?->id) ->exists(); } diff --git a/app/Filament/Resources/Learning/Assignments/Pages/EditAssignment.php b/app/Filament/Resources/Learning/Assignments/Pages/EditAssignment.php index 6f14598..c9fbc6b 100644 --- a/app/Filament/Resources/Learning/Assignments/Pages/EditAssignment.php +++ b/app/Filament/Resources/Learning/Assignments/Pages/EditAssignment.php @@ -41,17 +41,17 @@ protected function getSavedNotification(): ?Notification protected function mutateFormDataBeforeFill(array $data): array { - $data['student_ids'] = $this->record->assignmentTargets() + $data['student_ids'] = $this->record?->assignmentTargets() ->whereNotNull('student_id') ->pluck('student_id') ->toArray(); - $data['study_group_ids'] = $this->record->assignmentTargets() + $data['study_group_ids'] = $this->record?->assignmentTargets() ->whereNotNull('study_group_id') ->pluck('study_group_id') ->toArray(); - $media = $this->record->getMedia('assignments')->last(); + $media = $this->record?->getMedia('assignments')->last(); $relativePath = $media ? $media->getPathRelativeToRoot() : null; $data['pdf'] = $relativePath ? [$relativePath] : []; diff --git a/app/Filament/Resources/Learning/Assignments/Pages/ListAssignments.php b/app/Filament/Resources/Learning/Assignments/Pages/ListAssignments.php index e4da2dc..76d4474 100644 --- a/app/Filament/Resources/Learning/Assignments/Pages/ListAssignments.php +++ b/app/Filament/Resources/Learning/Assignments/Pages/ListAssignments.php @@ -46,7 +46,7 @@ public static function getPagePermission(): string public function mount(): void { - $this->form->fill([ + $this->form?->fill([ 'search' => $this->search, 'course_id' => $this->course_id, ]); @@ -221,7 +221,7 @@ public function assignments(): Collection private function getAssignmentPriority($assignment): int { - $isSubmitted = $assignment->assignmentSubmissions->isNotEmpty(); + $isSubmitted = $assignment->assignmentSubmissions?->isNotEmpty(); $isOverdue = now()->isAfter($assignment->due_date); if (! $isOverdue) { @@ -244,14 +244,14 @@ public function assignmentCards() $pinnedIds = $this->pinnedIds; return $this->assignments()->map(function ($assignment) use ($studentProfile, $pinnedIds) { - $submission = $assignment->assignmentSubmissions->first(); + $submission = $assignment->assignmentSubmissions?->first(); $isSubmitted = $submission !== null; $isGroup = $assignment->type === AssignmentType::Group; $isLeader = false; if ($isGroup) { - $userGroup = $assignment->studyGroups->first(function ($g) use ($studentProfile) { - return $g->leader_id === $studentProfile->id || $g->students->contains($studentProfile->id); + $userGroup = $assignment->studyGroups?->first(function ($g) use ($studentProfile) { + return $g->leader_id === $studentProfile->id || $g->students?->contains($studentProfile->id); }); $isLeader = $userGroup && $userGroup->leader_id === $studentProfile->id; } @@ -263,7 +263,7 @@ public function assignmentCards() $canSubmitActual = $canSubmit && $canSubmitByRole; $isUrgent = ! $isSubmitted && $canSubmitActual && now()->diffInHours($assignment->due_date) <= 48; - $isNew = $assignment->created_at->diffInDays(now()) <= 3; + $isNew = $assignment->created_at?->diffInDays(now()) <= 3; $isPinned = in_array($assignment->id, $pinnedIds); $statusLabel = SystemNotification::getByKey('labels.assignment_status.not_submitted'); @@ -288,8 +288,8 @@ public function assignmentCards() 'id' => $assignment->id, 'title' => $assignment->title, 'course_name' => $assignment->course?->name ?? '-', - 'due_date_formatted' => $assignment->due_date->translatedFormat('l, d F Y H:i'), - 'submitted_at_formatted' => ($isSubmitted && $submission->submitted_at) ? $submission->submitted_at->translatedFormat('l, d F Y H:i') : null, + 'due_date_formatted' => $assignment->due_date?->translatedFormat('l, d F Y H:i'), + 'submitted_at_formatted' => ($isSubmitted && $submission->submitted_at) ? $submission->submitted_at?->translatedFormat('l, d F Y H:i') : null, 'is_submitted' => $isSubmitted, 'is_group' => $isGroup, 'is_leader' => $isLeader, diff --git a/app/Filament/Resources/Learning/Assignments/Pages/SubmissionDetailPage.php b/app/Filament/Resources/Learning/Assignments/Pages/SubmissionDetailPage.php index 1f9db13..11403e0 100644 --- a/app/Filament/Resources/Learning/Assignments/Pages/SubmissionDetailPage.php +++ b/app/Filament/Resources/Learning/Assignments/Pages/SubmissionDetailPage.php @@ -30,7 +30,7 @@ public function statCards(): array { return [ [ - 'label' => $this->record->type === AssignmentType::Individual ? 'Total Mahasiswa' : 'Total Kelompok', + 'label' => $this->record?->type === AssignmentType::Individual ? 'Total Mahasiswa' : 'Total Kelompok', 'value' => $this->totalCount, 'icon' => 'heroicon-o-user-group', 'color_classes' => 'bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-900', @@ -65,11 +65,11 @@ public function progressColorClass(): string #[Computed] public function submissionSummary(): Collection { - $assignment = $this->record->load(['students', 'studyGroups', 'course']); + $assignment = $this->record?->load(['students', 'studyGroups', 'course']); $isIndividual = $assignment->type === AssignmentType::Individual; if ($isIndividual) { - $targets = $assignment->students->keyBy('id'); + $targets = $assignment->students?->keyBy('id') ?? collect(); $submissions = AssignmentSubmission::with('student') ->where('assignment_id', $assignment->id) @@ -87,7 +87,7 @@ public function submissionSummary(): Collection 'secondary_info' => $student->student_number, 'submission_id' => $submission?->id, 'submitted' => $isSubmitted, - 'submitted_at_formatted' => $isSubmitted ? $submission->submitted_at?->translatedFormat('l, d F Y H:i') : '-', + 'submitted_at_formatted' => $isSubmitted ? $submission?->submitted_at?->translatedFormat('l, d F Y H:i') : '-', 'has_file' => $isSubmitted && $submission->hasMedia('submission'), 'status_classes' => Arr::toCssClasses([ 'inline-flex items-center gap-1 rounded-full px-2.5 py-0.5 text-xs font-medium', @@ -98,7 +98,7 @@ public function submissionSummary(): Collection ]; })->sortBy('secondary_info')->values(); } else { - $targets = $assignment->studyGroups->keyBy('id'); + $targets = $assignment->studyGroups?->keyBy('id') ?? collect(); $submissions = AssignmentSubmission::with(['studyGroup', 'student']) ->where('assignment_id', $assignment->id) @@ -113,7 +113,7 @@ public function submissionSummary(): Collection 'id' => $group->id, 'is_individual' => false, 'primary_name' => $group->name, - 'secondary_info' => $isSubmitted ? $submission->student->full_name : '-', + 'secondary_info' => $isSubmitted ? $submission?->student?->full_name : '-', 'submission_id' => $submission?->id, 'submitted' => $isSubmitted, 'submitted_at_formatted' => $isSubmitted ? $submission->submitted_at?->translatedFormat('l, d F Y H:i') : '-', @@ -132,13 +132,13 @@ public function submissionSummary(): Collection #[Computed] public function totalCount(): int { - return $this->submissionSummary->count(); + return $this->submissionSummary?->count(); } #[Computed] public function doneCount(): int { - return $this->submissionSummary->where('submitted', true)->count(); + return $this->submissionSummary?->where('submitted', true)->count(); } #[Computed] @@ -152,17 +152,17 @@ public function percentage(): int #[Computed] public function isOverdue(): bool { - return now()->isAfter($this->record->due_date); + return now()->isAfter($this->record?->due_date); } #[Computed] public function assignmentSummary(): array { return [ - 'title' => $this->record->title, - 'course' => $this->record->course?->name ?? '-', - 'due_date' => $this->record->due_date?->translatedFormat('l, d F Y H:i'), - 'type' => $this->record->type->value, + 'title' => $this->record?->title, + 'course' => $this->record?->course?->name ?? '-', + 'due_date' => $this->record?->due_date?->translatedFormat('l, d F Y H:i'), + 'type' => $this->record?->type->value, 'is_overdue' => $this->isOverdue, ]; } diff --git a/app/Filament/Resources/Learning/Assignments/Pages/SubmitAssignmentPage.php b/app/Filament/Resources/Learning/Assignments/Pages/SubmitAssignmentPage.php index 2289bb5..6fe3b4c 100644 --- a/app/Filament/Resources/Learning/Assignments/Pages/SubmitAssignmentPage.php +++ b/app/Filament/Resources/Learning/Assignments/Pages/SubmitAssignmentPage.php @@ -42,7 +42,7 @@ public function mount(Assignment $record): void { $this->record = $record; - $this->form->fill([ + $this->form?->fill([ 'is_resubmit' => $this->isResubmit, ]); } @@ -59,7 +59,7 @@ public function statusCards(): array return [ [ 'label' => 'Batas Waktu', - 'value' => $this->record->due_date?->translatedFormat('l, d F Y H:i'), + 'value' => $this->record?->due_date?->translatedFormat('l, d F Y H:i'), 'icon' => 'heroicon-o-clock', 'is_danger' => $this->isOverdue, 'badge' => $this->isOverdue ? '(Terlewat)' : null, @@ -98,7 +98,7 @@ public function currentGroup(): ?StudyGroup { $student = $this->student; - return $this->record->studyGroups() + return $this->record?->studyGroups() ->where(fn ($q) => $q->where('leader_id', $student->id)->orWhereHas('students', fn ($sq) => $sq->whereKey($student->id))) ->first(); } @@ -108,18 +108,18 @@ public function existingSubmission(): ?AssignmentSubmission { $student = $this->student; - if ($this->record->type === AssignmentType::Group) { + if ($this->record?->type === AssignmentType::Group) { $group = $this->currentGroup; if (! $group) { return null; } - return AssignmentSubmission::where('assignment_id', $this->record->id) + return AssignmentSubmission::where('assignment_id', $this->record?->id) ->where('study_group_id', $group->id) ->first(); } - return AssignmentSubmission::where('assignment_id', $this->record->id) + return AssignmentSubmission::where('assignment_id', $this->record?->id) ->where('student_id', $student->id) ->first(); } @@ -133,19 +133,19 @@ public function isResubmit(): bool #[Computed] public function isOverdue(): bool { - return now()->isAfter($this->record->due_date); + return now()->isAfter($this->record?->due_date); } #[Computed] public function canSubmit(): bool { - if ($this->record->type === AssignmentType::Individual) { + if ($this->record?->type === AssignmentType::Individual) { return true; } $group = $this->currentGroup; - return $group && $group->leader_id === $this->student->id; + return $group && $group->leader_id === $this->student?->id; } #[Computed] @@ -251,7 +251,7 @@ public function submit(): void } $existingSubmission = $this->existingSubmission; - $state = $this->form->getState(); + $state = $this->form?->getState(); if (! $existingSubmission && empty($state['file'])) { SystemNotification::send('submission_file_missing', type: 'warning') @@ -300,7 +300,7 @@ public function submit(): void ->send(); } - $this->form->fill([ + $this->form?->fill([ 'is_resubmit' => $this->isResubmit, ]); unset($this->existingSubmission, $this->isResubmit); diff --git a/app/Filament/Resources/Learning/Attendances/Pages/ManageAttendances.php b/app/Filament/Resources/Learning/Attendances/Pages/ManageAttendances.php index 872a342..1b0fa7e 100644 --- a/app/Filament/Resources/Learning/Attendances/Pages/ManageAttendances.php +++ b/app/Filament/Resources/Learning/Attendances/Pages/ManageAttendances.php @@ -95,7 +95,7 @@ public function scheduleCards() { return $this->getSchedules() ->map(function ($schedule) { - $attendance = $schedule->attendances->first(); + $attendance = $schedule->attendances?->first(); $isAttended = $attendance !== null; $now = now(); @@ -118,15 +118,15 @@ public function scheduleCards() return (object) [ 'id' => $schedule->id, - 'course_name' => $schedule->course->name, - 'lecturer_name' => $schedule->course->lecturer ?? 'Belum Ditentukan', - 'time_range' => $schedule->start_time->format('H:i').' - '.$schedule->end_time->format('H:i'), + 'course_name' => $schedule->course?->name, + 'lecturer_name' => $schedule->course?->lecturer ?? 'Belum Ditentukan', + 'time_range' => $schedule->start_time?->format('H:i').' - '.$schedule->end_time?->format('H:i'), 'is_attended' => $isAttended, 'can_attend' => $canAttend && ! $isAttended, 'status_label' => $statusLabel, 'status_color' => $statusColor, 'status_icon' => $statusIcon, - 'attended_at' => $isAttended ? $attendance->attended_at->format('H:i') : null, + 'attended_at' => $isAttended ? $attendance?->attended_at?->format('H:i') : null, // Pre-calculated classes 'card_classes' => Arr::toCssClasses([ 'fi-card flex flex-col justify-between rounded-xl border transition duration-200 group relative', @@ -204,14 +204,14 @@ public function attend(int $sessionId): void // Find schedule for compatibility $schedule = CourseSchedule::where('course_id', $session->course_id) - ->where('day_of_week', $session->date->dayOfWeekIso) + ->where('day_of_week', $session->date?->dayOfWeekIso) ->first(); Attendance::create([ 'student_id' => $student->id, 'class_session_id' => $sessionId, 'course_schedule_id' => $schedule?->id, - 'date' => $session->date->toDateString(), + 'date' => $session->date?->toDateString(), 'attended_at' => now(), ]); @@ -232,7 +232,7 @@ public function table(Table $table): Table ->label('Tanggal') ->date('l, d F Y') ->sortable() - ->description(fn (Attendance $record): string => $record->attended_at->format('H:i').' ') + ->description(fn (Attendance $record): string => $record->attended_at?->format('H:i').' ') ->color('gray'), TextColumn::make('courseSchedule.course.name') @@ -240,7 +240,7 @@ public function table(Table $table): Table ->searchable() ->sortable() ->wrap() - ->description(fn (Attendance $record): string => $record->courseSchedule->course->lecturer ?? 'Belum Ditentukan'), + ->description(fn (Attendance $record): string => $record->courseSchedule?->course?->lecturer ?? 'Belum Ditentukan'), ]) ->defaultSort('date', 'desc') ->filters([ diff --git a/app/Filament/Resources/Learning/ClassSessions/Actions/CopyAttendanceLinkAction.php b/app/Filament/Resources/Learning/ClassSessions/Actions/CopyAttendanceLinkAction.php index 2a451e1..fb8d42f 100644 --- a/app/Filament/Resources/Learning/ClassSessions/Actions/CopyAttendanceLinkAction.php +++ b/app/Filament/Resources/Learning/ClassSessions/Actions/CopyAttendanceLinkAction.php @@ -24,7 +24,7 @@ protected function setUp(): void ->action(function (array $arguments, $livewire) { $course = $livewire->course; $session = ClassSession::find($arguments['session'] ?? null); - $date = $session ? $session->date->toDateString() : null; + $date = $session ? $session->date?->toDateString() : null; $url = URL::temporarySignedRoute('share.attendance', now()->addHour(), ['course' => $course->id, 'date' => $date]); diff --git a/app/Filament/Resources/Learning/ClassSessions/Actions/GenerateSessionsAction.php b/app/Filament/Resources/Learning/ClassSessions/Actions/GenerateSessionsAction.php index 3506a66..bccef6e 100644 --- a/app/Filament/Resources/Learning/ClassSessions/Actions/GenerateSessionsAction.php +++ b/app/Filament/Resources/Learning/ClassSessions/Actions/GenerateSessionsAction.php @@ -28,7 +28,7 @@ protected function setUp(): void ->modalHeading('Generate Sesi Pembelajaran') ->modalDescription('Sistem akan men-generate atau memperbarui sesi secara otomatis berdasarkan jadwal mata kuliah ini.') ->schema(function ($livewire) { - $lastSession = $livewire->course->classSessions()->latest('session_number')->first(); + $lastSession = $livewire->course?->classSessions()->latest('session_number')->first(); $lastNumber = $lastSession?->session_number ?? 0; $nextNumber = $lastNumber + 1; $lastDate = $lastSession?->date ? Carbon::parse($lastSession->date) : now(); diff --git a/app/Filament/Resources/Learning/ClassSessions/Actions/ShareAttendanceAction.php b/app/Filament/Resources/Learning/ClassSessions/Actions/ShareAttendanceAction.php index 5073598..314939b 100644 --- a/app/Filament/Resources/Learning/ClassSessions/Actions/ShareAttendanceAction.php +++ b/app/Filament/Resources/Learning/ClassSessions/Actions/ShareAttendanceAction.php @@ -34,11 +34,11 @@ protected function setUp(): void ->action(function (array $arguments, $livewire) { $course = $livewire->course; $session = ClassSession::find($arguments['session'] ?? null); - $date = $session ? $session->date->toDateString() : null; + $date = $session ? $session->date?->toDateString() : null; $url = URL::temporarySignedRoute('share.attendance', now()->addHour(), ['course' => $course->id, 'date' => $date]); - $text = "*Info Kelas {$course->name}*\nSesi ke-".($session->session_number ?? '-').' ('.($session->date->translatedFormat('d M Y') ?? '').")\n\nSilakan cek detail/rekap kehadiran melalui tautan ini:\n\n{$url}"; + $text = "*Info Kelas {$course->name}*\nSesi ke-".($session->session_number ?? '-').' ('.($session->date?->translatedFormat('d M Y') ?? '').")\n\nSilakan cek detail/rekap kehadiran melalui tautan ini:\n\n{$url}"; $escapedText = json_encode($text); diff --git a/app/Filament/Resources/Learning/ClassSessions/Actions/ViewAssignmentsAction.php b/app/Filament/Resources/Learning/ClassSessions/Actions/ViewAssignmentsAction.php index 302622c..1010353 100644 --- a/app/Filament/Resources/Learning/ClassSessions/Actions/ViewAssignmentsAction.php +++ b/app/Filament/Resources/Learning/ClassSessions/Actions/ViewAssignmentsAction.php @@ -37,7 +37,7 @@ protected function setUp(): void return ['assignment' => null]; } - $assignment = $session->assignments->first(); + $assignment = $session->assignments?->first(); if (! $assignment) { return ['assignment' => null]; @@ -48,7 +48,7 @@ protected function setUp(): void ->orderBy('full_name') ->get(); - $submissionMap = $assignment->assignmentSubmissions->keyBy('student_id'); + $submissionMap = $assignment->assignmentSubmissions?->keyBy('student_id'); $data = (object) [ 'id' => $assignment->id, diff --git a/app/Filament/Resources/Learning/ClassSessions/Actions/ViewAttendanceAction.php b/app/Filament/Resources/Learning/ClassSessions/Actions/ViewAttendanceAction.php index 6a33013..da593d5 100644 --- a/app/Filament/Resources/Learning/ClassSessions/Actions/ViewAttendanceAction.php +++ b/app/Filament/Resources/Learning/ClassSessions/Actions/ViewAttendanceAction.php @@ -40,7 +40,7 @@ protected function setUp(): void ->orderBy('full_name') ->get(); - $attendanceMap = $session->attendances->keyBy('student_id'); + $attendanceMap = $session->attendances?->keyBy('student_id'); $students = $activeStudents->map(fn ($student) => (object) [ 'student' => $student, diff --git a/app/Filament/Resources/Learning/ClassSessions/Pages/ListCourseSessions.php b/app/Filament/Resources/Learning/ClassSessions/Pages/ListCourseSessions.php index 3fcc534..4ad186d 100644 --- a/app/Filament/Resources/Learning/ClassSessions/Pages/ListCourseSessions.php +++ b/app/Filament/Resources/Learning/ClassSessions/Pages/ListCourseSessions.php @@ -46,15 +46,15 @@ public function sessions(): Collection ->whereHas('user', fn ($q) => $q->active()) ->count(); - return $this->course->classSessions() + return $this->course?->classSessions() ->withCount(['attendances', 'materials', 'assignments']) ->orderByDesc('session_number') ->get() ->map(fn ($session) => (object) [ 'id' => $session->id, 'session_number' => $session->session_number, - 'date_formatted' => $session->date->translatedFormat('l, d F Y'), - 'time_range' => $session->start_time->format('H:i').' - '.$session->end_time->format('H:i'), + 'date_formatted' => $session->date?->translatedFormat('l, d F Y'), + 'time_range' => $session->start_time?->format('H:i').' - '.$session->end_time?->format('H:i'), 'attendances_count' => $session->attendances_count, 'total_students' => $totalActiveStudents, 'attendance_percentage' => $totalActiveStudents > 0 ? round(($session->attendances_count / $totalActiveStudents) * 100) : 0, @@ -71,12 +71,12 @@ public function form(Schema $schema): Schema #[Computed] public function description(): string { - return 'Data sesi pembelajaran untuk mata kuliah '.$this->course->name; + return 'Data sesi pembelajaran untuk mata kuliah '.$this->course?->name; } public function getTitle(): string { - return 'Sesi Kelas - '.$this->course->name; + return 'Sesi Kelas - '.$this->course?->name; } protected function getHeaderActions(): array diff --git a/app/Filament/Resources/Learning/ClassSessions/Pages/ManageClassSessions.php b/app/Filament/Resources/Learning/ClassSessions/Pages/ManageClassSessions.php index bcef960..d4b2b45 100644 --- a/app/Filament/Resources/Learning/ClassSessions/Pages/ManageClassSessions.php +++ b/app/Filament/Resources/Learning/ClassSessions/Pages/ManageClassSessions.php @@ -32,7 +32,7 @@ class ManageClassSessions extends Page implements HasActions, HasForms public function mount(): void { - $this->form->fill(); + $this->form?->fill(); } #[Computed] @@ -76,10 +76,10 @@ public function todaySessions(): Collection 'id' => $session->id, 'is_pending' => false, 'session_number' => $session->session_number, - 'course_name' => $session->course->name, - 'course_code' => $session->course->code, - 'lecturer' => $session->course->lecturer ?? '-', - 'time_range' => $session->start_time->format('H:i').' - '.$session->end_time->format('H:i'), + 'course_name' => $session->course?->name, + 'course_code' => $session->course?->code, + 'lecturer' => $session->course?->lecturer ?? '-', + 'time_range' => $session->start_time?->format('H:i').' - '.$session->end_time?->format('H:i'), 'attendances_count' => $session->attendances_count, 'total_students' => $totalActiveStudents, 'attendance_percentage' => $percentage, @@ -124,7 +124,7 @@ public function courses(): Collection 'name' => $course->name, 'code' => $course->code, 'lecturer' => $course->lecturer ?? 'Dosen Belum Ditentukan', - 'sessions_count' => $course->classSessions->count(), + 'sessions_count' => $course->classSessions?->count(), 'total_students' => $totalActiveStudents, 'url' => ClassSessionResource::getUrl('course', ['course' => $course]), ]; diff --git a/app/Filament/Resources/Learning/Materials/Tables/MaterialTable.php b/app/Filament/Resources/Learning/Materials/Tables/MaterialTable.php index b8642fe..0a40baa 100644 --- a/app/Filament/Resources/Learning/Materials/Tables/MaterialTable.php +++ b/app/Filament/Resources/Learning/Materials/Tables/MaterialTable.php @@ -36,7 +36,7 @@ public static function configure(Table $table): Table ->label('Mata Kuliah') ->searchable() ->sortable() - ->description(fn (Material $record) => $record->classSession?->session_number ? "Sesi Ke-{$record->classSession->session_number}" : ''), + ->description(fn (Material $record) => $record->classSession?->session_number ? "Sesi Ke-{$record->classSession?->session_number}" : ''), TextColumn::make('title') ->label('Judul') diff --git a/app/Http/Controllers/ShareAttendanceController.php b/app/Http/Controllers/ShareAttendanceController.php index 6ef37f3..4c9b7d9 100644 --- a/app/Http/Controllers/ShareAttendanceController.php +++ b/app/Http/Controllers/ShareAttendanceController.php @@ -23,7 +23,7 @@ public function show(Request $request, Course $course): View ->latest('date') ->first(); - $defaultDate = $latestAttendance ? $latestAttendance->date->toDateString() : now()->toDateString(); + $defaultDate = $latestAttendance ? $latestAttendance->date?->toDateString() : now()->toDateString(); $date = $request->query('date', $defaultDate); $attendances = Attendance::with('student') diff --git a/app/Http/Middleware/DynamicFilamentTheme.php b/app/Http/Middleware/DynamicFilamentTheme.php index 24db0fb..311de39 100644 --- a/app/Http/Middleware/DynamicFilamentTheme.php +++ b/app/Http/Middleware/DynamicFilamentTheme.php @@ -28,7 +28,7 @@ public function handle(Request $request, Closure $next): Response if ($user && $user->settings) { // Register Colors FilamentColor::register([ - 'primary' => match ($user->settings->primary_color) { + 'primary' => match ($user->settings?->primary_color) { 'blue' => Color::Blue, 'sky' => Color::Sky, 'cyan' => Color::Cyan, @@ -48,12 +48,12 @@ public function handle(Request $request, Closure $next): Response // Register Top Navigation $panel = Filament::getCurrentOrDefaultPanel(); if ($panel && method_exists($panel, 'topNavigation')) { - $panel->topNavigation((bool) $user->settings->top_navigation); + $panel->topNavigation((bool) $user->settings?->top_navigation); } // Register Font & UI Styles - $font = $user->settings->font ?? 'Inter'; - $radius = match ($user->settings->border_radius ?? 'md') { + $font = $user->settings?->font ?? 'Inter'; + $radius = match ($user->settings?->border_radius ?? 'md') { 'none' => '0px', 'md' => '0.375rem', 'lg' => '0.5rem', @@ -61,7 +61,7 @@ public function handle(Request $request, Closure $next): Response '2xl' => '1rem', default => '0.5rem', }; - $maxWidth = match ($user->settings->content_width ?? 'full') { + $maxWidth = match ($user->settings?->content_width ?? 'full') { 'centered' => '80rem', default => 'none', }; diff --git a/app/Models/Assignment.php b/app/Models/Assignment.php index 586e9cc..f70cd79 100644 --- a/app/Models/Assignment.php +++ b/app/Models/Assignment.php @@ -42,7 +42,7 @@ protected function formattedDueDate(): Attribute protected function formattedCreatedAt(): Attribute { - return Attribute::get(fn () => $this->created_at->translatedFormat('l, d M Y H:i')); + return Attribute::get(fn () => $this->created_at?->translatedFormat('l, d M Y H:i')); } protected function formattedUpdatedAt(): Attribute diff --git a/app/Models/AssignmentPin.php b/app/Models/AssignmentPin.php index 248fd6a..19c710f 100644 --- a/app/Models/AssignmentPin.php +++ b/app/Models/AssignmentPin.php @@ -16,7 +16,7 @@ class AssignmentPin extends Model protected function formattedCreatedAt(): Attribute { - return Attribute::get(fn () => $this->created_at->translatedFormat('l, d M Y H:i')); + return Attribute::get(fn () => $this->created_at?->translatedFormat('l, d M Y H:i')); } protected function formattedUpdatedAt(): Attribute diff --git a/app/Models/AssignmentSubmission.php b/app/Models/AssignmentSubmission.php index 4183b03..2f1e56a 100644 --- a/app/Models/AssignmentSubmission.php +++ b/app/Models/AssignmentSubmission.php @@ -37,7 +37,7 @@ protected function formattedSubmittedAt(): Attribute protected function formattedCreatedAt(): Attribute { - return Attribute::get(fn () => $this->created_at->translatedFormat('l, d M Y H:i')); + return Attribute::get(fn () => $this->created_at?->translatedFormat('l, d M Y H:i')); } protected function formattedUpdatedAt(): Attribute diff --git a/app/Models/AssignmentTarget.php b/app/Models/AssignmentTarget.php index 4d9d21d..b49192a 100644 --- a/app/Models/AssignmentTarget.php +++ b/app/Models/AssignmentTarget.php @@ -21,7 +21,7 @@ class AssignmentTarget extends Model protected function formattedCreatedAt(): Attribute { - return Attribute::get(fn () => $this->created_at->translatedFormat('l, d M Y H:i')); + return Attribute::get(fn () => $this->created_at?->translatedFormat('l, d M Y H:i')); } protected function formattedUpdatedAt(): Attribute diff --git a/app/Models/Attendance.php b/app/Models/Attendance.php index 282dc67..ce7b42d 100644 --- a/app/Models/Attendance.php +++ b/app/Models/Attendance.php @@ -41,7 +41,7 @@ protected function formattedAttendedAt(): Attribute protected function formattedCreatedAt(): Attribute { - return Attribute::get(fn () => $this->created_at->translatedFormat('l, d M Y H:i')); + return Attribute::get(fn () => $this->created_at?->translatedFormat('l, d M Y H:i')); } protected function formattedUpdatedAt(): Attribute diff --git a/app/Models/Changelog.php b/app/Models/Changelog.php index 63d56a7..abe60d6 100644 --- a/app/Models/Changelog.php +++ b/app/Models/Changelog.php @@ -42,12 +42,12 @@ protected function formattedVersion(): Attribute protected function formattedReleaseDate(): Attribute { - return Attribute::get(fn () => $this->release_date->translatedFormat('l, d M Y')); + return Attribute::get(fn () => $this->release_date?->translatedFormat('l, d M Y')); } protected function formattedCreatedAt(): Attribute { - return Attribute::get(fn () => $this->created_at->translatedFormat('l, d M Y H:i')); + return Attribute::get(fn () => $this->created_at?->translatedFormat('l, d M Y H:i')); } protected function formattedUpdatedAt(): Attribute diff --git a/app/Models/ClassSession.php b/app/Models/ClassSession.php index 88af5fe..6750f15 100644 --- a/app/Models/ClassSession.php +++ b/app/Models/ClassSession.php @@ -50,7 +50,7 @@ protected function formattedEndTime(): Attribute protected function formattedCreatedAt(): Attribute { - return Attribute::get(fn () => $this->created_at->translatedFormat('l, d M Y H:i')); + return Attribute::get(fn () => $this->created_at?->translatedFormat('l, d M Y H:i')); } protected function formattedUpdatedAt(): Attribute diff --git a/app/Models/Course.php b/app/Models/Course.php index 08c1186..35a83d4 100644 --- a/app/Models/Course.php +++ b/app/Models/Course.php @@ -23,7 +23,7 @@ class Course extends Model protected function formattedCreatedAt(): Attribute { - return Attribute::get(fn () => $this->created_at->translatedFormat('l, d M Y H:i')); + return Attribute::get(fn () => $this->created_at?->translatedFormat('l, d M Y H:i')); } protected function formattedUpdatedAt(): Attribute diff --git a/app/Models/CourseSchedule.php b/app/Models/CourseSchedule.php index 182b275..ba4fdc8 100644 --- a/app/Models/CourseSchedule.php +++ b/app/Models/CourseSchedule.php @@ -43,7 +43,7 @@ protected function formattedEndTime(): Attribute protected function formattedCreatedAt(): Attribute { - return Attribute::get(fn () => $this->created_at->translatedFormat('l, d M Y H:i')); + return Attribute::get(fn () => $this->created_at?->translatedFormat('l, d M Y H:i')); } protected function formattedUpdatedAt(): Attribute diff --git a/app/Models/Material.php b/app/Models/Material.php index 63d2d44..fdd64b3 100644 --- a/app/Models/Material.php +++ b/app/Models/Material.php @@ -24,7 +24,7 @@ class Material extends Model implements HasMedia protected function formattedCreatedAt(): Attribute { - return Attribute::get(fn () => $this->created_at->translatedFormat('l, d M Y H:i')); + return Attribute::get(fn () => $this->created_at?->translatedFormat('l, d M Y H:i')); } protected function formattedUpdatedAt(): Attribute diff --git a/app/Models/Student.php b/app/Models/Student.php index 94e816e..f581f45 100644 --- a/app/Models/Student.php +++ b/app/Models/Student.php @@ -56,7 +56,7 @@ protected function formattedDateOfBirth(): Attribute protected function formattedCreatedAt(): Attribute { - return Attribute::get(fn () => $this->created_at->translatedFormat('l, d M Y H:i')); + return Attribute::get(fn () => $this->created_at?->translatedFormat('l, d M Y H:i')); } protected function formattedUpdatedAt(): Attribute diff --git a/app/Models/StudyGroup.php b/app/Models/StudyGroup.php index d0632e5..0735ddb 100644 --- a/app/Models/StudyGroup.php +++ b/app/Models/StudyGroup.php @@ -24,7 +24,7 @@ class StudyGroup extends Model protected function formattedCreatedAt(): Attribute { - return Attribute::get(fn () => $this->created_at->translatedFormat('l, d M Y H:i')); + return Attribute::get(fn () => $this->created_at?->translatedFormat('l, d M Y H:i')); } protected function formattedUpdatedAt(): Attribute diff --git a/app/Models/StudyGroupMember.php b/app/Models/StudyGroupMember.php index 47d655f..6cbc38f 100644 --- a/app/Models/StudyGroupMember.php +++ b/app/Models/StudyGroupMember.php @@ -21,7 +21,7 @@ class StudyGroupMember extends Model protected function formattedCreatedAt(): Attribute { - return Attribute::get(fn () => $this->created_at->translatedFormat('l, d M Y H:i')); + return Attribute::get(fn () => $this->created_at?->translatedFormat('l, d M Y H:i')); } protected function formattedUpdatedAt(): Attribute diff --git a/app/Models/User.php b/app/Models/User.php index bceb993..2394af9 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -68,7 +68,7 @@ protected function name(): Attribute protected function formattedCreatedAt(): Attribute { - return Attribute::get(fn () => $this->created_at->translatedFormat('l, d M Y H:i')); + return Attribute::get(fn () => $this->created_at?->translatedFormat('l, d M Y H:i')); } protected function formattedUpdatedAt(): Attribute diff --git a/app/Models/UserSetting.php b/app/Models/UserSetting.php index afe19b6..b426de9 100644 --- a/app/Models/UserSetting.php +++ b/app/Models/UserSetting.php @@ -27,7 +27,7 @@ protected function casts(): array protected function formattedCreatedAt(): Attribute { - return Attribute::get(fn () => $this->created_at->translatedFormat('l, d M Y H:i')); + return Attribute::get(fn () => $this->created_at?->translatedFormat('l, d M Y H:i')); } protected function formattedUpdatedAt(): Attribute