refactor: implement null-safe operator for safer property access across various models and pages

This commit is contained in:
Yoga Pangestu 2026-04-05 23:52:55 +07:00
parent b583e8b49c
commit 57e32fed73
37 changed files with 110 additions and 110 deletions

View File

@ -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;
}

View File

@ -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'),
]);
});
}

View File

@ -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) {

View File

@ -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

View File

@ -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();

View File

@ -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);
}
}
}

View File

@ -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();
}

View File

@ -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] : [];

View File

@ -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,

View File

@ -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,
];
}

View File

@ -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);

View File

@ -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([

View File

@ -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]);

View File

@ -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();

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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

View File

@ -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]),
];

View File

@ -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')

View File

@ -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')

View File

@ -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',
};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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