From 6d58190e28f704317690aa311b2d457e2cd136ab Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Sun, 29 Mar 2026 22:51:29 +0700 Subject: [PATCH] refactor: update course schedule and study group views for improved structure and functionality, including renaming views and enhancing data presentation --- .../Information/CourseSchedule/Index.php | 45 +++-- .../Pages/Learning/StudyGroup/Index.php | 43 +++-- .../Assignments/Pages/ListAssignments.php | 30 +++- .../Pages/SubmissionDetailPage.php | 36 +++- .../Pages/SubmitAssignmentPage.php | 13 +- .../Attendances/Pages/ManageAttendances.php | 51 ++++-- .../Pages/ListCourseSessions.php | 27 ++- .../Pages/ManageClassSessions.php | 79 ++++++--- .../course-schedule/index.blade.php | 121 +++++++++++++ .../information/course-schedules.blade.php | 136 --------------- .../learning/class-session/index.blade.php | 61 ++----- .../learning/study-group/index.blade.php | 157 +++++++++++++++++ .../pages/learning/study-groups.blade.php | 162 ------------------ ...-assignments.blade.php => index.blade.php} | 39 +---- .../{pages => }/submission-detail.blade.php | 36 ++-- .../{pages => }/submit-assignment.blade.php | 15 +- ...-attendances.blade.php => index.blade.php} | 52 +----- ...rse-sessions.blade.php => index.blade.php} | 17 +- .../manage-class-sessions.blade.php | 103 ----------- 19 files changed, 582 insertions(+), 641 deletions(-) create mode 100644 resources/views/filament/pages/information/course-schedule/index.blade.php delete mode 100644 resources/views/filament/pages/information/course-schedules.blade.php create mode 100644 resources/views/filament/pages/learning/study-group/index.blade.php delete mode 100644 resources/views/filament/pages/learning/study-groups.blade.php rename resources/views/filament/resources/learning/assignments/{pages/list-assignments.blade.php => index.blade.php} (70%) rename resources/views/filament/resources/learning/assignments/{pages => }/submission-detail.blade.php (78%) rename resources/views/filament/resources/learning/assignments/{pages => }/submit-assignment.blade.php (91%) rename resources/views/filament/resources/learning/attendances/{pages/list-attendances.blade.php => index.blade.php} (63%) rename resources/views/filament/resources/learning/class-sessions/{pages/list-course-sessions.blade.php => index.blade.php} (84%) delete mode 100644 resources/views/filament/resources/learning/class-sessions/manage-class-sessions.blade.php diff --git a/app/Filament/Pages/Information/CourseSchedule/Index.php b/app/Filament/Pages/Information/CourseSchedule/Index.php index 5e04376..d248c4f 100644 --- a/app/Filament/Pages/Information/CourseSchedule/Index.php +++ b/app/Filament/Pages/Information/CourseSchedule/Index.php @@ -23,6 +23,7 @@ use Filament\Schemas\Schema; use Filament\Support\Icons\Heroicon; use Illuminate\Support\Collection; +use Livewire\Attributes\Computed; use UnitEnum; class Index extends Page implements HasActions, HasForms @@ -43,7 +44,7 @@ class Index extends Page implements HasActions, HasForms protected static ?string $slug = 'information/course-schedules'; - protected string $view = 'filament.pages.information.course-schedules'; + protected string $view = 'filament.pages.information.course-schedule.index'; public ?string $search = ''; @@ -111,23 +112,39 @@ public function getSchedules(): Collection ['day_of_week', 'asc'], ['start_time', 'asc'], ]) - ->groupBy('day_of_week'); + ->groupBy('day_of_week') + ->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 ?? '-', + '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'), + ]); + }); } - protected function getViewData(): array + #[Computed] + public function schedulesGrouped(): Collection { - return [ - 'schedules' => $this->getSchedules(), - 'days' => [ - 1 => 'Senin', - 2 => 'Selasa', - 3 => 'Rabu', - 4 => 'Kamis', - 5 => 'Jumat', - 6 => 'Sabtu', - 7 => 'Minggu', - ], + $days = [ + 1 => 'Senin', + 2 => 'Selasa', + 3 => 'Rabu', + 4 => 'Kamis', + 5 => 'Jumat', + 6 => 'Sabtu', + 7 => 'Minggu', ]; + + return $this->getSchedules()->mapWithKeys(function ($schedules, $day) use ($days) { + return [$days[$day] ?? 'Lainnya' => $schedules]; + }); } public function scheduleFormSchema(): array diff --git a/app/Filament/Pages/Learning/StudyGroup/Index.php b/app/Filament/Pages/Learning/StudyGroup/Index.php index 2b5caa3..a53341d 100644 --- a/app/Filament/Pages/Learning/StudyGroup/Index.php +++ b/app/Filament/Pages/Learning/StudyGroup/Index.php @@ -24,7 +24,9 @@ use Filament\Schemas\Schema; use Filament\Support\Icons\Heroicon; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Support\Arr; use Illuminate\Support\Collection; +use Livewire\Attributes\Computed; use UnitEnum; class Index extends Page implements HasActions, HasForms @@ -48,7 +50,7 @@ public static function getPagePermission(): string return 'View:StudyGroup'; } - protected string $view = 'filament.pages.learning.study-groups'; + protected string $view = 'filament.pages.learning.study-group.index'; public ?int $course_id = null; @@ -101,7 +103,8 @@ public function deleteStudyGroupAction(): Action ->visible(fn () => auth()->user()->can('Delete:StudyGroup')); } - public function getStudyGroups(): Collection + #[Computed] + public function studyGroups(): Collection { $query = StudyGroup::with(['leader', 'students', 'courses']) ->whereHas('courses', fn ($q) => $q->where('courses.semester', app(GeneralSettings::class)->current_semester)); @@ -110,15 +113,35 @@ public function getStudyGroups(): Collection $query->whereHas('courses', fn ($q) => $q->where('courses.id', $this->course_id)); } - return $query->latest()->get(); - } + $studentId = auth()->user()?->student?->id; - protected function getViewData(): array - { - return [ - 'groups' => $this->getStudyGroups(), - 'studentId' => auth()->user()?->student?->id, - ]; + return $query->latest()->get()->map(function ($record) use ($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', + 'is_leader' => $studentId && $record->leader_id === $studentId, + 'courses' => $record->courses->map(fn ($c) => (object) [ + 'name' => $c->name, + ]), + 'students_count' => $record->students->count(), + 'students' => $record->students->map(fn ($s) => (object) [ + 'id' => $s->id, + 'full_name' => $s->full_name, + 'is_me' => $studentId && $s->id === $studentId, + ]), + // Pre-calculated classes + 'card_classes' => Arr::toCssClasses([ + 'fi-card flex flex-col justify-between rounded-xl border transition duration-200 group relative', + 'bg-white dark:bg-gray-900 border-gray-200 dark:border-gray-700 shadow-sm hover:shadow-md' => ! $isMyGroup, + 'bg-primary-50/30 dark:bg-primary-900/10 border-primary-500 shadow-md ring-1 ring-primary-500' => $isMyGroup, + ]), + ]; + }); } public function isMyGroup(StudyGroup $record): bool diff --git a/app/Filament/Resources/Learning/Assignments/Pages/ListAssignments.php b/app/Filament/Resources/Learning/Assignments/Pages/ListAssignments.php index 7b41a37..eb01deb 100644 --- a/app/Filament/Resources/Learning/Assignments/Pages/ListAssignments.php +++ b/app/Filament/Resources/Learning/Assignments/Pages/ListAssignments.php @@ -14,13 +14,14 @@ use Filament\Actions\Action; use Filament\Resources\Pages\Page; use Illuminate\Database\Eloquent\Collection; +use Illuminate\Support\Arr; use Livewire\Attributes\Computed; class ListAssignments extends Page { protected static string $resource = AssignmentResource::class; - protected string $view = 'filament.resources.learning.assignments.pages.list-assignments'; + protected string $view = 'filament.resources.learning.assignments.index'; protected static ?string $title = 'Tugas'; @@ -139,8 +140,33 @@ public function assignmentCards() 'is_new' => $isNew, 'is_pinned' => $isPinned, 'status_label' => $statusLabel, - 'status_color' => $statusColor, 'status_icon' => $statusIcon, + // Pre-calculated classes + 'card_classes' => Arr::toCssClasses([ + 'group flex w-full rounded-xl border transition-all overflow-hidden relative', + 'border-primary-300 dark:border-primary-700 bg-primary-50/30 dark:bg-primary-900/10 shadow-sm' => $isPinned, + 'border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800' => ! $isPinned && $canSubmitActual, + 'border-gray-100 dark:border-gray-800 bg-gray-50 dark:bg-gray-800/40 opacity-80' => ! $canSubmitActual, + ]), + 'icon_wrapper_classes' => Arr::toCssClasses([ + 'flex h-11 w-11 shrink-0 items-center justify-center rounded-lg', + 'bg-success-50 dark:bg-success-900/20 text-success-600 dark:text-success-400' => $isSubmitted, + 'bg-danger-50 dark:bg-danger-900/20 text-danger-600 dark:text-danger-400' => ! $isSubmitted && $isOverdue, + 'bg-warning-50 dark:bg-warning-900/20 text-warning-600 dark:text-warning-400' => ! $isSubmitted && ! $isOverdue, + ]), + 'status_badge_classes' => Arr::toCssClasses([ + 'inline-flex items-center gap-1 rounded-full px-2.5 py-0.5 text-xs font-medium', + 'bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400' => $statusColor === 'amber', + 'bg-success-100 text-success-700 dark:bg-success-900/30 dark:text-success-400' => $statusColor === 'success', + 'bg-danger-100 text-danger-700 dark:bg-danger-900/30 dark:text-danger-400' => $statusColor === 'danger', + 'bg-warning-100 text-warning-700 dark:bg-warning-900/30 dark:text-warning-400' => $statusColor === 'warning', + 'bg-gray-100 text-gray-500 dark:bg-gray-800 dark:text-gray-400' => $statusColor === 'gray', + ]), + 'indicator_icon_classes' => Arr::toCssClasses([ + 'h-5 w-5 opacity-20', + 'text-primary-500' => $isLeader, + 'text-gray-400' => ! $isLeader, + ]), ]; }); } diff --git a/app/Filament/Resources/Learning/Assignments/Pages/SubmissionDetailPage.php b/app/Filament/Resources/Learning/Assignments/Pages/SubmissionDetailPage.php index 146cdc5..60ba18b 100644 --- a/app/Filament/Resources/Learning/Assignments/Pages/SubmissionDetailPage.php +++ b/app/Filament/Resources/Learning/Assignments/Pages/SubmissionDetailPage.php @@ -10,6 +10,7 @@ use Filament\Actions\Action; use Filament\Resources\Pages\Page; use Filament\Support\Enums\Width; +use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Joaopaulolndev\FilamentPdfViewer\Infolists\Components\PdfViewerEntry; use Livewire\Attributes\Computed; @@ -18,7 +19,7 @@ class SubmissionDetailPage extends Page { protected static string $resource = AssignmentResource::class; - protected string $view = 'filament.resources.learning.assignments.pages.submission-detail'; + protected string $view = 'filament.resources.learning.assignments.submission-detail'; protected static ?string $title = 'Detail Rekap Pengumpulan'; @@ -32,29 +33,35 @@ public function statCards(): array 'label' => $this->record->type === AssignmentType::Individual ? 'Total Mahasiswa' : 'Total Kelompok', 'value' => $this->totalCount, 'icon' => 'heroicon-o-user-group', - 'color' => 'bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-900', + 'color_classes' => 'bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-900', ], [ 'label' => 'Sudah Kumpul', 'value' => $this->doneCount, 'icon' => 'heroicon-o-check-circle', - 'color' => 'bg-success-100 dark:bg-success-900/30 text-success-700 dark:text-success-400', + 'color_classes' => 'bg-success-100 dark:bg-success-900/30 text-success-700 dark:text-success-400', ], [ 'label' => 'Belum Kumpul', 'value' => $this->totalCount - $this->doneCount, 'icon' => 'heroicon-o-x-circle', - 'color' => 'bg-danger-100 dark:bg-danger-900/30 text-danger-700 dark:text-danger-400', + 'color_classes' => 'bg-danger-100 dark:bg-danger-900/30 text-danger-700 dark:text-danger-400', ], [ 'label' => 'Persentase', 'value' => $this->percentage.'%', 'icon' => 'heroicon-o-chart-bar', - 'color' => 'bg-primary-100 dark:bg-primary-900/30 text-primary-700 dark:text-primary-400', + 'color_classes' => 'bg-primary-100 dark:bg-primary-900/30 text-primary-700 dark:text-primary-400', ], ]; } + #[Computed] + public function progressColorClass(): string + { + return $this->percentage === 100 ? 'bg-success-500' : ($this->percentage > 0 ? 'bg-warning-500' : 'bg-gray-300'); + } + #[Computed] public function submissionSummary(): Collection { @@ -78,10 +85,16 @@ public function submissionSummary(): Collection 'is_individual' => true, 'primary_name' => $student->full_name, 'secondary_info' => $student->student_number, - 'submission' => $submission, + 'submission_id' => $submission?->id, 'submitted' => $isSubmitted, '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', + 'bg-success-100 text-success-700 dark:bg-success-900/30 dark:text-success-400' => $isSubmitted, + 'bg-danger-100 text-danger-700 dark:bg-danger-900/30 dark:text-danger-400' => ! $isSubmitted, + ]), + 'status_label' => $isSubmitted ? '✓ Terkumpul' : 'Belum', ]; })->sortBy('secondary_info')->values(); } else { @@ -101,10 +114,16 @@ public function submissionSummary(): Collection 'is_individual' => false, 'primary_name' => $group->name, 'secondary_info' => $isSubmitted ? $submission->student->full_name : '-', - 'submission' => $submission, + 'submission_id' => $submission?->id, 'submitted' => $isSubmitted, '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', + 'bg-success-100 text-success-700 dark:bg-success-900/30 dark:text-success-400' => $isSubmitted, + 'bg-danger-100 text-danger-700 dark:bg-danger-900/30 dark:text-danger-400' => ! $isSubmitted, + ]), + 'status_label' => $isSubmitted ? '✓ Terkumpul' : 'Belum', ]; })->sortBy('primary_name')->values(); } @@ -136,7 +155,8 @@ public function isOverdue(): bool return now()->isAfter($this->record->due_date); } - public function getAssignmentInfo(): array + #[Computed] + public function assignmentSummary(): array { return [ 'title' => $this->record->title, diff --git a/app/Filament/Resources/Learning/Assignments/Pages/SubmitAssignmentPage.php b/app/Filament/Resources/Learning/Assignments/Pages/SubmitAssignmentPage.php index 2864b39..ef5c792 100644 --- a/app/Filament/Resources/Learning/Assignments/Pages/SubmitAssignmentPage.php +++ b/app/Filament/Resources/Learning/Assignments/Pages/SubmitAssignmentPage.php @@ -11,6 +11,7 @@ use App\Models\Student; use App\Models\StudyGroup; use Filament\Resources\Pages\Page; +use Illuminate\Support\Arr; use Livewire\Attributes\Computed; use Livewire\WithFileUploads; @@ -20,7 +21,7 @@ class SubmitAssignmentPage extends Page protected static string $resource = AssignmentResource::class; - protected string $view = 'filament.resources.learning.assignments.pages.submit-assignment'; + protected string $view = 'filament.resources.learning.assignments.submit-assignment'; protected static ?string $title = 'Kumpulkan Tugas'; @@ -38,6 +39,11 @@ public function statusCards(): array 'icon' => 'heroicon-o-clock', 'is_danger' => $this->isOverdue, 'badge' => $this->isOverdue ? '(Terlewat)' : null, + 'icon_classes' => Arr::toCssClasses([ + 'flex h-9 w-9 shrink-0 items-center justify-center rounded-lg', + 'bg-danger-50 dark:bg-danger-900/20 text-danger-600' => $this->isOverdue, + 'bg-warning-50 dark:bg-warning-900/20 text-warning-600' => ! $this->isOverdue, + ]), ], [ 'label' => 'Status Pengumpulan', @@ -45,6 +51,11 @@ public function statusCards(): array 'icon' => $this->isOverdue ? 'heroicon-o-lock-closed' : 'heroicon-o-check-circle', 'is_danger' => $this->isOverdue, 'is_success' => ! $this->isOverdue, + 'icon_classes' => Arr::toCssClasses([ + 'flex h-9 w-9 shrink-0 items-center justify-center rounded-lg', + 'bg-danger-50 dark:bg-danger-900/20 text-danger-600' => $this->isOverdue, + 'bg-success-50 dark:bg-success-900/20 text-success-600' => ! $this->isOverdue, + ]), ], ]; } diff --git a/app/Filament/Resources/Learning/Attendances/Pages/ManageAttendances.php b/app/Filament/Resources/Learning/Attendances/Pages/ManageAttendances.php index 8cc7925..f8c4f91 100644 --- a/app/Filament/Resources/Learning/Attendances/Pages/ManageAttendances.php +++ b/app/Filament/Resources/Learning/Attendances/Pages/ManageAttendances.php @@ -20,6 +20,8 @@ use Filament\Tables\Filters\SelectFilter; use Filament\Tables\Table; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Support\Arr; +use Livewire\Attributes\Computed; class ManageAttendances extends Page implements HasForms, HasTable { @@ -31,7 +33,7 @@ class ManageAttendances extends Page implements HasForms, HasTable protected static ?string $navigationLabel = 'Presensi'; - protected string $view = 'filament.resources.learning.attendances.pages.list-attendances'; + protected string $view = 'filament.resources.learning.attendances.index'; public function getSchedules() { @@ -59,7 +61,8 @@ public function getSchedules() ->get(); } - public function getScheduleCards() + #[Computed] + public function scheduleCards() { return $this->getSchedules() ->map(function ($schedule) { @@ -68,7 +71,6 @@ public function getScheduleCards() $now = now(); $startTime = now()->setTimeFrom($schedule->start_time); - $canAttend = $now->greaterThanOrEqualTo($startTime); $statusLabel = 'Belum Presensi'; @@ -96,17 +98,46 @@ public function getScheduleCards() 'status_color' => $statusColor, 'status_icon' => $statusIcon, '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', + 'bg-white dark:bg-gray-900 border-gray-200 dark:border-gray-700 shadow-sm hover:shadow-md' => ! $isAttended, + 'bg-primary-50/30 dark:bg-primary-900/10 border-primary-500 shadow-md ring-1 ring-primary-500' => $isAttended, + ]), + 'title_classes' => Arr::toCssClasses([ + 'text-lg font-bold leading-tight flex items-center gap-2 transition-colors', + 'text-gray-950 dark:text-white group-hover:text-primary-600 dark:group-hover:text-primary-400' => ! $isAttended, + 'text-primary-900 dark:text-primary-100' => $isAttended, + ]), + 'lecturer_wrapper_classes' => Arr::toCssClasses([ + 'flex items-center gap-1.5', + 'text-gray-500 dark:text-gray-400' => ! $isAttended, + 'text-primary-600 dark:text-primary-400' => $isAttended, + ]), + 'icon_wrapper_classes' => Arr::toCssClasses([ + 'w-8 h-8 rounded-full flex items-center justify-center mr-3 shrink-0 border', + 'bg-primary-100 dark:bg-primary-900/40 border-primary-200 dark:border-primary-800' => ! $isAttended, + 'bg-white dark:bg-primary-800 border-primary-300 dark:border-primary-600' => $isAttended, + ]), + 'time_label_classes' => Arr::toCssClasses([ + 'truncate font-medium', + 'text-gray-100 dark:text-gray-200' => ! $isAttended, + 'text-primary-900 dark:text-primary-50' => $isAttended, + ]), + 'status_badge_classes' => Arr::toCssClasses([ + 'text-[10px] font-bold px-1.5 py-0.5 rounded ring-1 ring-inset', + 'bg-success-50 dark:bg-success-500/10 text-success-600 dark:text-success-400 ring-success-600/20' => $isAttended, + 'bg-warning-50 dark:bg-warning-500/10 text-warning-600 dark:text-warning-400 ring-warning-600/20' => ! $isAttended && $canAttend && ! $isAttended, + 'bg-gray-50 dark:bg-gray-500/10 text-gray-600 dark:text-gray-400 ring-gray-600/20' => ! $isAttended && ! $canAttend, + ]), + 'footer_classes' => Arr::toCssClasses([ + 'flex items-center justify-end gap-2 p-4 pt-0 rounded-b-xl', + 'bg-primary-100/30 dark:bg-primary-900/10 pt-4' => $isAttended || ($canAttend && ! $isAttended), + ]), ]; }); } - protected function getViewData(): array - { - return [ - 'scheduleCards' => $this->getScheduleCards(), - ]; - } - public function attend(int $scheduleId): void { /** @var User $user */ diff --git a/app/Filament/Resources/Learning/ClassSessions/Pages/ListCourseSessions.php b/app/Filament/Resources/Learning/ClassSessions/Pages/ListCourseSessions.php index ae2c0da..ed2ca53 100644 --- a/app/Filament/Resources/Learning/ClassSessions/Pages/ListCourseSessions.php +++ b/app/Filament/Resources/Learning/ClassSessions/Pages/ListCourseSessions.php @@ -16,6 +16,7 @@ use Filament\Resources\Pages\Page; use Filament\Support\Enums\Width; use Illuminate\Support\Collection; +use Livewire\Attributes\Computed; class ListCourseSessions extends Page implements HasActions, HasForms { @@ -23,7 +24,7 @@ class ListCourseSessions extends Page implements HasActions, HasForms protected static string $resource = ClassSessionResource::class; - protected string $view = 'filament.resources.learning.class-sessions.pages.list-course-sessions'; + protected string $view = 'filament.resources.learning.class-sessions.index'; public $courseId; @@ -32,19 +33,35 @@ public function mount($courseId): void $this->courseId = $courseId; } - public function getCourse(): Course + #[Computed] + public function course(): Course { return Course::findOrFail($this->courseId); } - public function getSessions(): Collection + #[Computed] + public function sessions(): Collection { - return $this->getCourse()->classSessions()->orderBy('session_number', 'asc')->get(); + return $this->course->classSessions() + ->orderBy('session_number', 'asc') + ->get() + ->map(fn ($session) => (object) [ + 'id' => $session->id, + 'session_number' => $session->session_number, + 'date_formatted' => $session->date->format('l, d F Y'), + 'time_range' => $session->start_time->format('H:i').' - '.$session->end_time->format('H:i'), + ]); + } + + #[Computed] + public function description(): string + { + return 'Data sesi pembelajaran untuk mata kuliah '.$this->course->name; } public function getTitle(): string { - return 'Sesi Kelas - '.$this->getCourse()->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 68356a0..ed82db6 100644 --- a/app/Filament/Resources/Learning/ClassSessions/Pages/ManageClassSessions.php +++ b/app/Filament/Resources/Learning/ClassSessions/Pages/ManageClassSessions.php @@ -2,13 +2,11 @@ namespace App\Filament\Resources\Learning\ClassSessions\Pages; -use App\Filament\Actions\Cheerful\DeleteAction; use App\Filament\Resources\Learning\ClassSessions\ClassSessionResource; use App\Models\ClassSession; use App\Models\Course; use App\Models\CourseSchedule; use App\Settings\GeneralSettings; -use Filament\Actions\Action; use Filament\Actions\Concerns\InteractsWithActions; use Filament\Actions\Contracts\HasActions; use Filament\Forms\Components\TextInput; @@ -16,7 +14,9 @@ use Filament\Forms\Contracts\HasForms; use Filament\Resources\Pages\Page; use Filament\Schemas\Schema; +use Illuminate\Support\Arr; use Illuminate\Support\Collection; +use Livewire\Attributes\Computed; class ManageClassSessions extends Page implements HasActions, HasForms { @@ -35,6 +35,12 @@ public function mount(): void $this->form->fill(); } + #[Computed] + public function todayDate(): string + { + return now()->translatedFormat('l, d F Y'); + } + public function form(Schema $schema): Schema { return $schema @@ -51,18 +57,8 @@ public function form(Schema $schema): Schema ]); } - protected function getHeaderActions(): array - { - return []; - } - - public function deleteSessionAction(): Action - { - return DeleteAction::make('deleteSession') - ->record(fn (array $arguments) => ClassSession::find($arguments['session'])); - } - - public function getTodaySessions(): Collection + #[Computed] + public function todaySessions(): Collection { $dayOfWeek = now()->dayOfWeekIso; // 1 (Mon) - 7 (Sun) @@ -80,21 +76,52 @@ public function getTodaySessions(): Collection return $schedules->map(function ($schedule) { $session = $schedule->course->classSessions->first(); + $isPending = ! $session; + $sessionNumber = $session?->session_number ?? (ClassSession::where('course_id', $schedule->course_id)->max('session_number') ?? 0) + 1; return (object) [ 'id' => $session?->id, - 'course' => $schedule->course, - 'session_number' => $session?->session_number ?? (ClassSession::where('course_id', $schedule->course_id)->max('session_number') ?? 0) + 1, - 'start_time' => $schedule->start_time, - 'end_time' => $schedule->end_time, - 'title' => $session?->title, - 'is_pending' => ! $session, + 'is_pending' => $isPending, + 'session_number' => $sessionNumber, + 'course_name' => $schedule->course->name, + 'course_code' => $schedule->course->code, + 'lecturer' => $schedule->course->lecturer ?? '-', + 'time_range' => $schedule->start_time->format('H:i').' - '.$schedule->end_time->format('H:i'), 'attendances_count' => $session?->attendances_count ?? 0, + 'url' => $isPending ? null : ClassSessionResource::getUrl('course', ['courseId' => $schedule->course->id]), + + // Pre-calculated classes + 'card_classes' => Arr::toCssClasses([ + 'group flex w-full rounded-xl border overflow-hidden relative transition-all hover:shadow-md', + 'border-primary-300 dark:border-primary-700 bg-primary-50/30 dark:bg-primary-900/10 shadow-sm' => ! $isPending, + 'border-gray-300 dark:border-gray-700 bg-gray-50/30 dark:bg-gray-800/10 border-dashed' => $isPending, + ]), + 'session_badge_classes' => Arr::toCssClasses([ + 'flex h-12 w-12 shrink-0 flex-col items-center justify-center rounded-lg font-bold border', + 'bg-primary-100 dark:bg-primary-800 text-primary-700 dark:text-primary-300 border-primary-200 dark:border-primary-700' => ! $isPending, + 'bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 border-gray-200 dark:border-gray-700' => $isPending, + ]), + 'title_classes' => Arr::toCssClasses([ + 'font-bold transition-colors', + 'text-gray-900 dark:text-white group-hover:text-primary-600' => ! $isPending, + 'text-gray-500 dark:text-gray-400' => $isPending, + ]), + 'status_badge_classes' => Arr::toCssClasses([ + 'flex items-center gap-1.5 rounded-full px-3 py-1 text-[11px] font-bold shadow-sm', + 'bg-primary-500 text-white animate-pulse' => ! $isPending, + 'bg-gray-500 text-white opacity-60' => $isPending, + ]), + 'attendance_section_classes' => Arr::toCssClasses([ + 'flex flex-col items-center justify-center border-l p-2 bg-white/30 dark:bg-black/10 transition-colors', + 'border-primary-200 dark:border-primary-800 group-hover:bg-primary-500/5' => ! $isPending, + 'border-gray-200 dark:border-gray-800' => $isPending, + ]), ]; }); } - public function getCourses(): Collection + #[Computed] + public function courses(): Collection { $query = Course::query() ->where('semester', app(GeneralSettings::class)->current_semester) @@ -109,6 +136,14 @@ public function getCourses(): Collection } return $query->get() - ->sortBy('name'); + ->sortBy('name') + ->map(fn ($course) => (object) [ + 'id' => $course->id, + 'name' => $course->name, + 'code' => $course->code, + 'lecturer' => $course->lecturer ?? 'Dosen Belum Ditentukan', + 'sessions_count' => $course->classSessions->count(), + 'url' => ClassSessionResource::getUrl('course', ['courseId' => $course->id]), + ]); } } diff --git a/resources/views/filament/pages/information/course-schedule/index.blade.php b/resources/views/filament/pages/information/course-schedule/index.blade.php new file mode 100644 index 0000000..22c4171 --- /dev/null +++ b/resources/views/filament/pages/information/course-schedule/index.blade.php @@ -0,0 +1,121 @@ + + +
+
+ + +
+ Geser ke samping untuk melihat hari lainnya. +
+
+
+ +
+
+ {{ $this->form }} +
+
+ + @if ($this->schedulesGrouped->isNotEmpty()) +
+
+ + @foreach ($this->schedulesGrouped as $dayName => $daySchedules) +
+ +
+ +

+ {{ $dayName }} +

+
+ +
+ @foreach ($daySchedules as $schedule) +
+ +
+
+
+ + {{ $schedule->course_code }} + + + @if ($schedule->mode_label) + + {{ $schedule->mode_label }} + + @endif +
+ + @if ($schedule->room) + + + {{ $schedule->room }} + + @endif +
+ +

+ {{ $schedule->course_name }} +

+ +
+ + {{ $schedule->lecturer }} +
+ +
+ @if ($schedule->semester) + + + Semester {{ $schedule->semester }} + + @endif +
+ +
+
+ + {{ $schedule->time_range }} +
+ + + {{ $schedule->credit }} SKS + +
+ + @canAny(['Update:CourseSchedule', 'Delete:CourseSchedule']) +
+ {{ $this->editScheduleAction(['schedule' => $schedule->id]) }} + + {{ $this->deleteScheduleAction(['schedule' => $schedule->id]) }} +
+ @endcanAny +
+
+ @endforeach +
+
+ @endforeach + +
+
+ @else + + + @endif +
+
diff --git a/resources/views/filament/pages/information/course-schedules.blade.php b/resources/views/filament/pages/information/course-schedules.blade.php deleted file mode 100644 index dbca8af..0000000 --- a/resources/views/filament/pages/information/course-schedules.blade.php +++ /dev/null @@ -1,136 +0,0 @@ - - -
-
- - -
- Geser ke samping untuk melihat hari lainnya. -
-
-
- -
-
- {{ $this->form }} -
-
- - @if ($schedules->isNotEmpty()) -
-
- - @foreach ($days as $dayNumber => $dayName) - @php - $daySchedules = $schedules->get($dayNumber); - @endphp - - @if ($daySchedules && $daySchedules->count() > 0) -
- -
- -

- {{ $dayName }} -

-
- -
- @foreach ($daySchedules as $schedule) -
- -
-
-
- - {{ $schedule->course->code ?? 'MATKUL' }} - - - @if ($schedule->mode) - @php - $color = $schedule->mode->getColor(); - @endphp - - {{ $schedule->mode->getLabel() }} - - @endif -
- - @if ($schedule->room) - - - {{ $schedule->room }} - - @endif -
- -

- {{ $schedule->course->name ?? 'Mata Kuliah Tidak Diketahui' }} -

- -
- - - {{ $schedule->course->lecturer ?? 'Dosen Belum Ditentukan' }} - -
- -
- @if ($schedule->course?->semester) - - - Semester {{ $schedule->course->semester }} - - @endif -
- -
-
- - {{ $schedule->start_time->format('H:i') }} - - {{ $schedule->end_time->format('H:i') }} -
- - - {{ $schedule->course->credit ?? '-' }} SKS - -
- - @canAny(['Update:CourseSchedule', 'Delete:CourseSchedule']) -
- {{ ($this->editScheduleAction)(['schedule' => $schedule->id]) }} - - {{ ($this->deleteScheduleAction)(['schedule' => $schedule->id]) }} -
- @endcanAny -
-
- @endforeach -
-
- @endif - @endforeach - -
-
- @endif - - @if ($schedules->isEmpty()) - - - @endif -
-
diff --git a/resources/views/filament/pages/learning/class-session/index.blade.php b/resources/views/filament/pages/learning/class-session/index.blade.php index a679f1d..be10951 100644 --- a/resources/views/filament/pages/learning/class-session/index.blade.php +++ b/resources/views/filament/pages/learning/class-session/index.blade.php @@ -9,38 +9,24 @@ - @if ($this->getTodaySessions()->isNotEmpty()) + @if ($this->todaySessions->isNotEmpty()) Sesi Hari Ini - Sesi yang dijadwalkan pada {{ now()->translatedFormat('l, d F Y') }} + Sesi yang dijadwalkan pada {{ $this->today_date }}
- @foreach ($this->getTodaySessions() as $session) - @php - $cardClass = \Illuminate\Support\Arr::toCssClasses([ - 'group flex w-full rounded-xl border overflow-hidden relative transition-all hover:shadow-md', - 'border-primary-300 dark:border-primary-700 bg-primary-50/30 dark:bg-primary-900/10 shadow-sm' => !$session->is_pending, - 'border-gray-300 dark:border-gray-700 bg-gray-50/30 dark:bg-gray-800/10 border-dashed' => $session->is_pending, - ]); - @endphp - + @foreach ($this->todaySessions as $session) @if ($session->is_pending) -
+
@else - + @endif
-
!$session->is_pending, - 'bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 border-gray-200 dark:border-gray-700' => - $session->is_pending, - ])> +
Sesi #{{ $session->session_number }}
@@ -48,25 +34,16 @@ class="{{ $cardClass }}">
-

!$session->is_pending, - 'text-gray-500 dark:text-gray-400' => $session->is_pending, - ])> - {{ $session->course->name }} +

+ {{ $session->course_name }}

- {{ $session->course->code }} • {{ $session->course->lecturer ?? '-' }} + {{ $session->course_code }} • {{ $session->lecturer }}

-
!$session->is_pending, - 'bg-gray-500 text-white opacity-60' => $session->is_pending, - ])> +
- {{ $session->start_time->format('H:i') }} - - {{ $session->end_time->format('H:i') }} + {{ $session->time_range }}
@if ($session->is_pending)
attendance_section_classes }}"> @if ($session->is_pending)
@@ -119,10 +92,10 @@ class="mt-2 flex items-center gap-1.5 text-[10px] text-gray-400 dark:text-gray-5 Pilih mata kuliah untuk melihat dan mengelola semua riwayat sesi. - @if ($this->getCourses()->isNotEmpty()) + @if ($this->courses->isNotEmpty())
- @foreach ($this->getCourses() as $course) - courses as $course) +
@@ -134,7 +107,7 @@ class="inline-flex items-center rounded-md bg-primary-50 dark:bg-primary-500/10
- {{ $course->classSessions->count() }} Sesi + {{ $course->sessions_count }} Sesi @@ -148,7 +121,7 @@ class="text-base font-bold text-gray-950 dark:text-white leading-tight group-hov
- {{ $course->lecturer ?? 'Dosen Belum Ditentukan' }} + {{ $course->lecturer }}
diff --git a/resources/views/filament/pages/learning/study-group/index.blade.php b/resources/views/filament/pages/learning/study-group/index.blade.php new file mode 100644 index 0000000..4edb685 --- /dev/null +++ b/resources/views/filament/pages/learning/study-group/index.blade.php @@ -0,0 +1,157 @@ + + +
+
+ {{ $this->form }} +
+
+ + @if ($this->studyGroups->isNotEmpty()) +
+ @foreach ($this->studyGroups as $record) +
+
+ + @if ($record->is_my_group) +
+ + + Kelompok Saya + +
+ @endif + +
+
+ @forelse ($record->courses as $course) + !$record->is_my_group, + 'bg-white dark:bg-primary-800/40 text-primary-700 dark:text-primary-200 ring-primary-500/30' => $record->is_my_group, + ])> + {{ $course->name }} + + @empty + + Tanpa Mata Kuliah + + @endforelse +
+ +
+

!$record->is_my_group, + 'text-primary-900 dark:text-primary-100' => $record->is_my_group, + ])> + !$record->is_my_group, + 'text-primary-500' => $record->is_my_group, + ]) /> + {{ $record->name }} +

+
+
+
+
!$record->is_my_group, + 'bg-white dark:bg-primary-800 border-primary-300 dark:border-primary-600' => $record->is_my_group, + ])> + @if ($record->leader_avatar) + User avatar + @else + !$record->is_my_group, + 'text-primary-700 dark:text-primary-200' => $record->is_my_group, + ]) /> + @endif +
+
+ Ketua + Kelompok + !$record->is_my_group, + 'text-primary-900 dark:text-primary-50' => $record->is_my_group, + ])> + {{ $record->leader_name }} + @if ($record->is_leader) + (Anda) + @endif + +
+
+ +
!$record->is_my_group, + 'border-primary-200 dark:border-primary-800' => $record->is_my_group, + ])> +
+ Anggota + Kelompok + + {{ $record->students_count }} orang + +
+
+ @forelse ($record->students as $student) + + !$student->is_me, + 'bg-primary-600 text-white dark:text-gray-900 ring-primary-700 font-bold shadow-sm' => + $student->is_me, + ])> + {{ $student->full_name }} + @if ($student->is_me) + (Anda) + @endif + + @empty + Belum ada anggota + @endforelse +
+
+
+
+ + @canAny(['Update:StudyGroup', 'Delete:StudyGroup']) +
$record->is_my_group, + ])> +
!$record->is_my_group, + 'border-primary-200 dark:border-primary-800' => $record->is_my_group, + ])> + {{ $this->editStudyGroupAction(['studyGroup' => $record->id]) }} + + {{ $this->deleteStudyGroupAction(['studyGroup' => $record->id]) }} +
+
+ @endcanAny +
+
+ @endforeach +
+ @endif + + @if ($this->studyGroups->isEmpty()) + + + @endif +
+
diff --git a/resources/views/filament/pages/learning/study-groups.blade.php b/resources/views/filament/pages/learning/study-groups.blade.php deleted file mode 100644 index c50fc1d..0000000 --- a/resources/views/filament/pages/learning/study-groups.blade.php +++ /dev/null @@ -1,162 +0,0 @@ - - -
-
- {{ $this->form }} -
-
- - @if ($groups->isNotEmpty()) -
- @foreach ($groups as $record) - @php $isMyGroup = $this->isMyGroup($record); @endphp -
-
!$isMyGroup, - 'bg-primary-50/30 dark:bg-primary-900/10 border-primary-500 shadow-md ring-1 ring-primary-500' => $isMyGroup, - ])> - - @if ($isMyGroup) -
- - - Kelompok Saya - -
- @endif - -
-
- @forelse ($record->courses as $course) - !$isMyGroup, - 'bg-white dark:bg-primary-800/40 text-primary-700 dark:text-primary-200 ring-primary-500/30' => $isMyGroup, - ])> - {{ $course->name }} - - @empty - - Tanpa Mata Kuliah - - @endforelse -
- -
-

!$isMyGroup, - 'text-primary-900 dark:text-primary-100' => $isMyGroup, - ])> - !$isMyGroup, - 'text-primary-500' => $isMyGroup, - ]) /> - {{ $record->name }} -

-
-
-
-
!$isMyGroup, - 'bg-white dark:bg-primary-800 border-primary-300 dark:border-primary-600' => $isMyGroup, - ])> - @if ($record->leader) - User avatar - @else - !$isMyGroup, - 'text-primary-700 dark:text-primary-200' => $isMyGroup, - ]) /> - @endif -
-
- Ketua - Kelompok - !$isMyGroup, - 'text-primary-900 dark:text-primary-50' => $isMyGroup, - ])> - {{ $record->leader->full_name ?? 'Belum Ditentukan' }} - @if ($studentId && $record->leader_id === $studentId) - (Anda) - @endif - -
-
- -
!$isMyGroup, - 'border-primary-200 dark:border-primary-800' => $isMyGroup, - ])> -
- Anggota - Kelompok - - {{ $record->students->count() }} orang - -
-
- @forelse ($record->students as $student) - - $student->id !== $studentId, - 'bg-primary-600 text-white dark:text-gray-900 ring-primary-700 font-bold shadow-sm' => - $student->id === $studentId, - ])> - {{ $student->full_name }} - @if ($student->id === $studentId) - (Anda) - @endif - - @empty - Belum ada anggota - @endforelse -
-
-
-
- - @canAny(['Update:StudyGroup', 'Delete:StudyGroup']) -
$isMyGroup, - ])> -
!$isMyGroup, - 'border-primary-200 dark:border-primary-800' => $isMyGroup, - ])> - {{ ($this->editStudyGroupAction)(['studyGroup' => $record->id]) }} - - {{ ($this->deleteStudyGroupAction)(['studyGroup' => $record->id]) }} -
-
- @endcanAny -
-
- @endforeach -
- @endif - - @if ($groups->isEmpty()) - - - @endif -
-
diff --git a/resources/views/filament/resources/learning/assignments/pages/list-assignments.blade.php b/resources/views/filament/resources/learning/assignments/index.blade.php similarity index 70% rename from resources/views/filament/resources/learning/assignments/pages/list-assignments.blade.php rename to resources/views/filament/resources/learning/assignments/index.blade.php index 3ce1c8a..d6d96d6 100644 --- a/resources/views/filament/resources/learning/assignments/pages/list-assignments.blade.php +++ b/resources/views/filament/resources/learning/assignments/index.blade.php @@ -10,26 +10,11 @@ @else
@foreach ($this->assignmentCards as $card) -
- $card->is_pinned, - 'border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800' => - !$card->is_pinned && $card->can_submit_actual, - 'border-gray-100 dark:border-gray-800 bg-gray-50 dark:bg-gray-800/40 opacity-80' => !$card->can_submit_actual, - ])> +
-
- $card->is_submitted, - 'bg-danger-50 dark:bg-danger-900/20 text-danger-600 dark:text-danger-400' => - !$card->is_submitted && $card->is_overdue, - 'bg-warning-50 dark:bg-warning-900/20 text-warning-600 dark:text-warning-400' => - !$card->is_submitted && !$card->is_overdue, - ])> +
@@ -64,19 +49,7 @@ class="inline-flex items-center gap-1 rounded-full bg-blue-100 text-blue-700 dar @endif - - $card->status_color === 'amber', - 'bg-success-100 text-success-700 dark:bg-success-900/30 dark:text-success-400' => - $card->status_color === 'success', - 'bg-danger-100 text-danger-700 dark:bg-danger-900/30 dark:text-danger-400' => - $card->status_color === 'danger', - 'bg-warning-100 text-warning-700 dark:bg-warning-900/30 dark:text-warning-400' => - $card->status_color === 'warning', - 'bg-gray-100 text-gray-500 dark:bg-gray-800 dark:text-gray-400' => - $card->status_color === 'gray', - ])> + @if ($card->status_icon) @endif @@ -132,11 +105,7 @@ class="flex flex-col items-center justify-center border-l border-gray-100 dark:b
$card->is_leader, - 'text-gray-400' => !$card->is_leader, - ]) + class="{{ $card->indicator_icon_classes }}" title="{{ $card->is_leader ? 'Anda adalah Ketua Kelompok' : 'Anda adalah Anggota Kelompok' }}" />
@endif diff --git a/resources/views/filament/resources/learning/assignments/pages/submission-detail.blade.php b/resources/views/filament/resources/learning/assignments/submission-detail.blade.php similarity index 78% rename from resources/views/filament/resources/learning/assignments/pages/submission-detail.blade.php rename to resources/views/filament/resources/learning/assignments/submission-detail.blade.php index a351456..f46228c 100644 --- a/resources/views/filament/resources/learning/assignments/pages/submission-detail.blade.php +++ b/resources/views/filament/resources/learning/assignments/submission-detail.blade.php @@ -5,7 +5,7 @@
-
+
@@ -22,23 +22,19 @@
-
- @php - $info = $this->getAssignmentInfo(); - @endphp - - {{ $info['title'] }} + {{ $this->assignmentSummary['title'] }} - {{ $info['course'] }} + {{ $this->assignmentSummary['course'] }}  ·  - Batas: {{ $info['due_date'] }} + Batas: {{ $this->assignmentSummary['due_date'] }}  ·  - Tipe: {{ $info['type'] }} - @if ($info['is_overdue']) + Tipe: {{ $this->assignmentSummary['type'] }} + @if ($this->assignmentSummary['is_overdue']) Terlewat @endif @@ -84,17 +80,9 @@ - @if ($item->submitted) - - ✓ Terkumpul - - @else - - Belum - - @endif + + {{ $item->status_label }} + @@ -104,7 +92,7 @@ class="inline-flex items-center rounded-full bg-danger-100 text-danger-700 dark: @if ($item->has_file)