refactor: implement null-safe operator for safer property access across various models and pages
This commit is contained in:
parent
b583e8b49c
commit
57e32fed73
@ -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;
|
||||
}
|
||||
|
||||
@ -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'),
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
@ -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] : [];
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
];
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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([
|
||||
|
||||
@ -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]);
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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]),
|
||||
];
|
||||
|
||||
@ -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')
|
||||
|
||||
@ -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')
|
||||
|
||||
@ -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',
|
||||
};
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user