From f0e68416286ae337d2f5984266f0450cd96fc7ac Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Sun, 29 Mar 2026 20:40:54 +0700 Subject: [PATCH] refactor: Remove legacy attendance management pages and integrate class session management functionality, including new models, migrations, and views for class sessions and attendance tracking. --- .../Pages/Manage/Attendance/Detail.php | 122 ---------- .../Pages/Manage/Attendance/Index.php | 65 ----- .../ClassSessions/ClassSessionResource.php | 226 ++++++++++++++++++ .../Pages/ListCourseSessions.php | 83 +++++++ .../Pages/ManageClassSessions.php | 159 ++++++++++++ .../AttendanceRelationManager.php | 90 +++++++ app/Models/Assignment.php | 6 + app/Models/Attendance.php | 5 + app/Models/ClassSession.php | 49 ++++ app/Models/Course.php | 5 + app/Models/Material.php | 5 + ...25_0245099_create_class_sessions_table.php | 35 +++ ..._02_25_024510_create_assignments_table.php | 1 + ..._03_11_133639_create_attendances_table.php | 8 +- ...26_10_25_024508_create_materials_table.php | 1 + .../learning/class-session/index.blade.php | 139 +++++++++++ .../pages/manage/attendance/detail.blade.php | 145 ----------- .../pages/manage/attendance/index.blade.php | 102 -------- .../manage-class-sessions.blade.php | 103 ++++++++ .../pages/list-course-sessions.blade.php | 58 +++++ routes/web.php | 2 +- 21 files changed, 971 insertions(+), 438 deletions(-) delete mode 100644 app/Filament/Pages/Manage/Attendance/Detail.php delete mode 100644 app/Filament/Pages/Manage/Attendance/Index.php create mode 100644 app/Filament/Resources/Learning/ClassSessions/ClassSessionResource.php create mode 100644 app/Filament/Resources/Learning/ClassSessions/Pages/ListCourseSessions.php create mode 100644 app/Filament/Resources/Learning/ClassSessions/Pages/ManageClassSessions.php create mode 100644 app/Filament/Resources/Learning/ClassSessions/RelationManagers/AttendanceRelationManager.php create mode 100644 app/Models/ClassSession.php create mode 100644 database/migrations/2026_02_25_0245099_create_class_sessions_table.php create mode 100644 resources/views/filament/pages/learning/class-session/index.blade.php delete mode 100644 resources/views/filament/pages/manage/attendance/detail.blade.php delete mode 100644 resources/views/filament/pages/manage/attendance/index.blade.php create mode 100644 resources/views/filament/resources/learning/class-sessions/manage-class-sessions.blade.php create mode 100644 resources/views/filament/resources/learning/class-sessions/pages/list-course-sessions.blade.php diff --git a/app/Filament/Pages/Manage/Attendance/Detail.php b/app/Filament/Pages/Manage/Attendance/Detail.php deleted file mode 100644 index d326557..0000000 --- a/app/Filament/Pages/Manage/Attendance/Detail.php +++ /dev/null @@ -1,122 +0,0 @@ -course = $course; - } - - public function getHeaderActions(): array - { - return [ - BackAction::make() - ->url(Index::getUrl()), - ]; - } - - protected function getViewData(): array - { - return [ - 'selectedCourse' => $this->course, - 'meetingHistory' => $this->getMeetingHistory(), - 'activeMeetingStats' => $this->getActiveMeetingStats(), - ]; - } - - private function getMeetingHistory(): Collection - { - return Attendance::query() - ->whereHas('courseSchedule', function ($q) { - $q->where('course_id', $this->course->id); - }) - ->select('date') - ->distinct() - ->orderBy('date', 'desc') - ->get() - ->map(function ($att) { - $attendedCount = Attendance::whereHas('courseSchedule', function ($q) { - $q->where('course_id', $this->course->id); - }) - ->whereDate('date', $att->date) - ->count(); - - $totalStudents = Student::count(); - - return (object) [ - 'date' => [ - 'month' => $att->date->translatedFormat('M'), - 'day' => $att->date->translatedFormat('d'), - ], - 'formatted_date' => $att->date->translatedFormat('l, d F Y'), - 'attended_count' => $attendedCount, - 'total_students' => $totalStudents, - 'share_url' => route('share.attendance', [ - 'token' => $this->course->sharing_token, - 'date' => $att->date->toDateString(), - ]), - ]; - }); - } - - private function getActiveMeetingStats(): ?object - { - $today = now()->dayOfWeekIso; - $nowTime = now()->format('H:i'); - - $activeSchedule = CourseSchedule::where('course_id', $this->course->id) - ->where('day_of_week', $today) - ->where('start_time', '<=', $nowTime) - ->where('end_time', '>=', $nowTime) - ->first(); - - if (! $activeSchedule) { - return null; - } - - $attendedIds = Attendance::where('course_schedule_id', $activeSchedule->id) - ->whereDate('date', now()->toDateString()) - ->pluck('student_id') - ->toArray(); - - $totalStudents = Student::count(); - - $absentStudents = Student::whereNotIn('id', $attendedIds)->get(); - - return (object) [ - 'time_range' => $activeSchedule->start_time->format('H:i').' - '.$activeSchedule->end_time->format('H:i'), - 'attended_count' => count($attendedIds), - 'total_students' => $totalStudents, - 'absent_students' => $absentStudents, - 'percentage' => round((count($attendedIds) / $totalStudents) * 100), - ]; - } -} diff --git a/app/Filament/Pages/Manage/Attendance/Index.php b/app/Filament/Pages/Manage/Attendance/Index.php deleted file mode 100644 index e5bb2dd..0000000 --- a/app/Filament/Pages/Manage/Attendance/Index.php +++ /dev/null @@ -1,65 +0,0 @@ - $this->getCourses(), - ]; - } - - private function getCourses(): Collection - { - $semester = app(GeneralSettings::class)->current_semester; - $today = now()->dayOfWeekIso; - - return Course::query() - ->where('semester', $semester) - ->with(['lecturer', 'courseSchedules']) - ->get() - ->map(function ($course) use ($today) { - $isOngoing = $course->courseSchedules->contains(function ($schedule) use ($today) { - return $schedule->day_of_week == $today; - }); - - $course->lecturer_name = $course->lecturer?->full_name; - $course->is_ongoing = $isOngoing; - $course->detail_url = Detail::getUrl(['course' => $course]); - - return $course; - }); - } -} diff --git a/app/Filament/Resources/Learning/ClassSessions/ClassSessionResource.php b/app/Filament/Resources/Learning/ClassSessions/ClassSessionResource.php new file mode 100644 index 0000000..a6d902a --- /dev/null +++ b/app/Filament/Resources/Learning/ClassSessions/ClassSessionResource.php @@ -0,0 +1,226 @@ +components([ + Grid::make(2) + ->schema([ + Select::make('course_id') + ->label('Mata Kuliah') + ->placeholder('Pilih Mata Kuliah') + ->options(function () { + return Course::query() + ->where('semester', app(GeneralSettings::class)->current_semester) + ->pluck('name', 'id') + ->toArray(); + }) + ->searchable() + ->required() + ->preload() + ->live() + ->afterStateUpdated(function ($state, $set) { + if (! $state) { + return; + } + + $schedule = \App\Models\CourseSchedule::where('course_id', $state)->first(); + + if ($schedule) { + $set('start_time', $schedule->start_time?->format('H:i')); + $set('end_time', $schedule->end_time?->format('H:i')); + } + + // Ambil pertemuan terakhir + 1 + $lastSession = \App\Models\ClassSession::where('course_id', $state)->max('session_number'); + $set('session_number', ($lastSession ?? 0) + 1); + }) + ->columnSpanFull(), + + TextInput::make('session_number') + ->label('Pertemuan Ke-') + ->placeholder('1') + ->numeric() + ->required() + ->minValue(1) + ->maxValue(16) + ->autocomplete(false), + + DatePicker::make('date') + ->label('Tanggal') + ->placeholder('Pilih Tanggal') + ->required() + ->native(false) + ->displayFormat('l, d F Y') + ->default(now()->toDateString()), + + TimePicker::make('start_time') + ->label('Waktu Mulai') + ->placeholder('08:00') + ->native(false) + ->displayFormat('H:i') + ->seconds(false) + ->required(), + + TimePicker::make('end_time') + ->label('Waktu Selesai') + ->placeholder('10:00') + ->native(false) + ->displayFormat('H:i') + ->seconds(false) + ->required(), + ]) + ->columnSpanFull(), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + TextColumn::make('session_number') + ->label('Pertemuan Ke-') + ->sortable() + ->badge(), + + TextColumn::make('course.name') + ->label('Mata Kuliah') + ->searchable() + ->sortable() + ->wrap() + ->description(fn (ClassSession $record) => $record->course->code), + + TextColumn::make('date') + ->label('Tanggal') + ->date('l, d F Y') + ->sortable() + ->description(fn (ClassSession $record) => $record->start_time->format('H:i').' - '.$record->end_time->format('H:i').' WIB'), + + TextColumn::make('attendances_count') + ->counts('attendances') + ->label('Presensi') + ->badge() + ->color('success'), + + TextColumn::make('materials_count') + ->counts('materials') + ->label('Materi') + ->badge() + ->color('warning'), + + TextColumn::make('assignments_count') + ->counts('assignments') + ->label('Tugas') + ->badge() + ->color('info'), + + ...TimestampColumns::make(), + ]) + ->filters([ + TrashedFilter::make() + ->native(false) + ->visible(fn () => auth()->user()->hasRole(RoleEnum::Developer)), + ]) + ->recordActions([ + EditAction::make() + ->modalWidth(Width::TwoExtraLarge), + + DeleteAction::make(), + + ForceDeleteAction::make(), + + RestoreAction::make(), + ]) + ->toolbarActions([ + BulkActionGroup::make([ + ...DefaultBulkActions::make('Sesi Kelas'), + ]), + ]) + ->emptyStateIcon(Heroicon::OutlinedPresentationChartBar) + ->emptyStateDescription('Setelah Anda membuat data pertama, maka akan muncul disini.') + ->defaultSort('created_at', 'desc') + ->deferFilters(false) + ->paginated([25, 50, 100, 'all']) + ->defaultPaginationPageOption(25); + } + + public static function getRelations(): array + { + return [ + AttendanceRelationManager::class, + ]; + } + + public static function getPages(): array + { + return [ + 'index' => ManageClassSessions::route('/'), + 'course' => ListCourseSessions::route('/course/{courseId}'), + ]; + } + + public static function getEloquentQuery(): Builder + { + return parent::getEloquentQuery() + ->whereHas('course', function (Builder $query) { + $query->where('semester', app(GeneralSettings::class)->current_semester); + }); + } + + public static function getRecordRouteBindingEloquentQuery(): Builder + { + return parent::getRecordRouteBindingEloquentQuery() + ->withoutGlobalScopes([ + SoftDeletingScope::class, + ]); + } +} diff --git a/app/Filament/Resources/Learning/ClassSessions/Pages/ListCourseSessions.php b/app/Filament/Resources/Learning/ClassSessions/Pages/ListCourseSessions.php new file mode 100644 index 0000000..ae2c0da --- /dev/null +++ b/app/Filament/Resources/Learning/ClassSessions/Pages/ListCourseSessions.php @@ -0,0 +1,83 @@ +courseId = $courseId; + } + + public function getCourse(): Course + { + return Course::findOrFail($this->courseId); + } + + public function getSessions(): Collection + { + return $this->getCourse()->classSessions()->orderBy('session_number', 'asc')->get(); + } + + public function getTitle(): string + { + return 'Sesi Kelas - '.$this->getCourse()->name; + } + + protected function getHeaderActions(): array + { + return [ + CreateAction::make() + ->label('Tambah Sesi') + ->modalHeading('Tambah Sesi') + ->modalSubmitActionLabel('Simpan') + ->modalCancelActionLabel('Batal') + ->mutateFormDataUsing(function (array $data): array { + $data['course_id'] = $this->courseId; + + return $data; + }) + ->extraModalFooterActions(fn (CreateAction $action): array => [ + $action->makeModalSubmitAction('createAnother', arguments: ['another' => true]) + ->label('Simpan dan Tambah Lagi'), + ]) + ->modalWidth(Width::TwoExtraLarge), + ]; + } + + public function editSessionAction(): Action + { + return EditAction::make('editSession') + ->record(fn (array $arguments) => ClassSession::find($arguments['session'])) + ->modalWidth(Width::TwoExtraLarge); + } + + public function deleteSessionAction(): Action + { + return DeleteAction::make('deleteSession') + ->record(fn (array $arguments) => ClassSession::find($arguments['session'])); + } +} diff --git a/app/Filament/Resources/Learning/ClassSessions/Pages/ManageClassSessions.php b/app/Filament/Resources/Learning/ClassSessions/Pages/ManageClassSessions.php new file mode 100644 index 0000000..5d38e3f --- /dev/null +++ b/app/Filament/Resources/Learning/ClassSessions/Pages/ManageClassSessions.php @@ -0,0 +1,159 @@ +form->fill(); + } + + public function form(Schema $schema): Schema + { + return $schema + ->schema([ + TextInput::make('search') + ->label('Cari') + ->placeholder('Cari Mata Kuliah atau Dosen...') + ->autocomplete(false) + ->live(debounce: 500) + ->afterStateUpdated(fn ($state) => $this->search = $state), + ]) + ->columns([ + 'sm' => 1, + ]); + } + + protected function getHeaderActions(): array + { + return []; + } + + public function editSessionAction(): Action + { + return EditAction::make('editSession') + ->record(fn (array $arguments) => ClassSession::find($arguments['session'])) + ->modalWidth(Width::TwoExtraLarge); + } + + public function deleteSessionAction(): Action + { + return DeleteAction::make('deleteSession') + ->record(fn (array $arguments) => ClassSession::find($arguments['session'])); + } + + public function generateTodaySessionAction(): Action + { + return Action::make('generateTodaySession') + ->label('Generate Sesi') + ->icon('heroicon-o-sparkles') + ->color('primary') + ->requiresConfirmation() + ->modalHeading('Generate Sesi Hari Ini?') + ->modalDescription('Sistem akan membuat sesi baru secara otomatis berdasarkan jadwal aktif.') + ->modalSubmitActionLabel('Generate Sekarang') + ->action(function (array $arguments) { + $courseId = $arguments['course']; + $schedule = CourseSchedule::where('course_id', $courseId)->first(); + + if (! $schedule) { + \Filament\Notifications\Notification::make() + ->title('Jadwal Tidak Ditemukan') + ->danger() + ->send(); + + return; + } + + $lastSession = ClassSession::where('course_id', $courseId)->max('session_number'); + + ClassSession::create([ + 'course_id' => $courseId, + 'session_number' => ($lastSession ?? 0) + 1, + 'date' => now()->toDateString(), + 'start_time' => $schedule->start_time, + 'end_time' => $schedule->end_time, + ]); + + \Filament\Notifications\Notification::make() + ->title('Sesi Berhasil Digenerate') + ->success() + ->send(); + }); + } + + public function getTodaySessions(): Collection + { + $dayOfWeek = now()->dayOfWeekIso; // 1 (Mon) - 7 (Sun) + + $schedules = CourseSchedule::query() + ->where('day_of_week', $dayOfWeek) + ->whereHas('course', function ($query) { + $query->where('semester', app(GeneralSettings::class)->current_semester); + }) + ->with(['course.lecturer', 'course.classSessions' => fn ($q) => $q->whereDate('date', now())]) + ->orderBy('start_time', 'asc') + ->get(); + + return $schedules->map(function ($schedule) { + $session = $schedule->course->classSessions->first(); + + 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, + ]; + }); + } + + public function getCourses(): Collection + { + $query = Course::query() + ->where('semester', app(GeneralSettings::class)->current_semester) + ->with(['classSessions' => fn ($q) => $q->orderBy('session_number', 'asc'), 'lecturer']); + + if ($this->search) { + $query->where(function ($q) { + $q->where('name', 'like', "%{$this->search}%") + ->orWhere('code', 'like', "%{$this->search}%") + ->orWhereHas('lecturer', fn ($sq) => $sq->where('full_name', 'like', "%{$this->search}%")); + }); + } + + return $query->get() + ->sortBy('name'); + } +} diff --git a/app/Filament/Resources/Learning/ClassSessions/RelationManagers/AttendanceRelationManager.php b/app/Filament/Resources/Learning/ClassSessions/RelationManagers/AttendanceRelationManager.php new file mode 100644 index 0000000..e5f432d --- /dev/null +++ b/app/Filament/Resources/Learning/ClassSessions/RelationManagers/AttendanceRelationManager.php @@ -0,0 +1,90 @@ +components([ + Select::make('student_id') + ->label('Mahasiswa') + ->placeholder('Pilih Mahasiswa') + ->relationship('student', 'full_name') + ->searchable() + ->required() + ->preload() + ->helperText('Pilih mahasiswa yang hadir pada pertemuan ini.'), + + DateTimePicker::make('attended_at') + ->label('Waktu Presensi') + ->default(now()) + ->native(false) + ->helperText('Tanggal dan jam mahasiswa melakukan presensi.'), + ]) + ->columns(1); + } + + public function table(Table $table): Table + { + return $table + ->recordTitleAttribute('student.full_name') + ->columns([ + Tables\Columns\TextColumn::make('student.student_number') + ->label('NIM') + ->copyable() + ->searchable() + ->sortable() + ->color('gray'), + + Tables\Columns\TextColumn::make('student.full_name') + ->label('Nama Mahasiswa') + ->searchable() + ->sortable(), + + Tables\Columns\TextColumn::make('attended_at') + ->label('Waktu Presensi') + ->dateTime('l, d F Y H:i') + ->sortable() + ->description(fn ($record) => $record->attended_at->format('H:i').' WIB') + ->color('primary'), + ]) + ->filters([ + // + ]) + ->headerActions([ + CreateAction::make() + ->modalWidth(Width::Large), + ]) + ->actions([ + EditAction::make() + ->modalWidth(Width::Large), + + DeleteAction::make(), + ]) + ->toolbarActions([ + BulkActionGroup::make([ + ...DefaultBulkActions::make('Presensi Mahasiswa'), + ]), + ]) + ->emptyStateDescription('Belum ada data presensi untuk pertemuan ini.'); + } +} diff --git a/app/Models/Assignment.php b/app/Models/Assignment.php index 3f5b5e1..a94d5cb 100644 --- a/app/Models/Assignment.php +++ b/app/Models/Assignment.php @@ -18,6 +18,7 @@ class Assignment extends Model implements HasMedia protected $fillable = [ 'course_id', + 'class_session_id', 'description', 'due_date', 'title', @@ -52,6 +53,11 @@ public function course(): BelongsTo return $this->belongsTo(Course::class); } + public function classSession(): BelongsTo + { + return $this->belongsTo(ClassSession::class); + } + public function students(): BelongsToMany { return $this->belongsToMany( diff --git a/app/Models/Attendance.php b/app/Models/Attendance.php index 2760cbc..4eefa57 100644 --- a/app/Models/Attendance.php +++ b/app/Models/Attendance.php @@ -25,4 +25,9 @@ public function courseSchedule() { return $this->belongsTo(CourseSchedule::class); } + + public function classSession() + { + return $this->belongsTo(ClassSession::class); + } } diff --git a/app/Models/ClassSession.php b/app/Models/ClassSession.php new file mode 100644 index 0000000..44ccde8 --- /dev/null +++ b/app/Models/ClassSession.php @@ -0,0 +1,49 @@ + 'date', + 'session_number' => 'integer', + 'start_time' => 'datetime', + 'end_time' => 'datetime', + ]; + + public function course(): BelongsTo + { + return $this->belongsTo(Course::class); + } + + public function materials(): HasMany + { + return $this->hasMany(Material::class); + } + + public function assignments(): HasMany + { + return $this->hasMany(Assignment::class); + } + + public function attendances(): HasMany + { + return $this->hasMany(Attendance::class); + } +} diff --git a/app/Models/Course.php b/app/Models/Course.php index c558e45..a40e9df 100644 --- a/app/Models/Course.php +++ b/app/Models/Course.php @@ -49,4 +49,9 @@ public function courseSchedules(): HasMany { return $this->hasMany(CourseSchedule::class); } + + public function classSessions(): HasMany + { + return $this->hasMany(ClassSession::class); + } } diff --git a/app/Models/Material.php b/app/Models/Material.php index f9e83af..22d5f6f 100644 --- a/app/Models/Material.php +++ b/app/Models/Material.php @@ -23,4 +23,9 @@ public function course(): BelongsTo { return $this->belongsTo(Course::class); } + + public function classSession(): BelongsTo + { + return $this->belongsTo(ClassSession::class); + } } diff --git a/database/migrations/2026_02_25_0245099_create_class_sessions_table.php b/database/migrations/2026_02_25_0245099_create_class_sessions_table.php new file mode 100644 index 0000000..00cd0ab --- /dev/null +++ b/database/migrations/2026_02_25_0245099_create_class_sessions_table.php @@ -0,0 +1,35 @@ +id(); + $table->foreignId('course_id')->constrained()->cascadeOnDelete(); + $table->unsignedTinyInteger('session_number'); // e.g., 1, 2, ... + $table->date('date'); + $table->time('start_time'); + $table->time('end_time'); + $table->timestamps(); + $table->softDeletes(); + + $table->unique(['course_id', 'session_number'], 'class_sessions_course_session_unique'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('class_sessions'); + } +}; diff --git a/database/migrations/2026_02_25_024510_create_assignments_table.php b/database/migrations/2026_02_25_024510_create_assignments_table.php index 59246be..84da9f0 100644 --- a/database/migrations/2026_02_25_024510_create_assignments_table.php +++ b/database/migrations/2026_02_25_024510_create_assignments_table.php @@ -15,6 +15,7 @@ public function up(): void Schema::create('assignments', function (Blueprint $table) { $table->id(); $table->foreignId('course_id')->constrained()->cascadeOnDelete(); + $table->foreignId('class_session_id')->nullable()->constrained()->nullOnDelete(); $table->string('title', 100); $table->text('description')->nullable(); $table->timestamp('due_date'); diff --git a/database/migrations/2026_03_11_133639_create_attendances_table.php b/database/migrations/2026_03_11_133639_create_attendances_table.php index 0c24b69..cbe149b 100644 --- a/database/migrations/2026_03_11_133639_create_attendances_table.php +++ b/database/migrations/2026_03_11_133639_create_attendances_table.php @@ -14,12 +14,14 @@ public function up(): void Schema::create('attendances', function (Blueprint $table) { $table->id(); $table->foreignId('student_id')->constrained()->cascadeOnDelete(); - $table->foreignId('course_schedule_id')->constrained()->cascadeOnDelete(); - $table->date('date'); + $table->foreignId('class_session_id')->nullable()->constrained()->nullOnDelete(); + $table->foreignId('course_schedule_id')->nullable()->constrained()->cascadeOnDelete(); + $table->date('date')->nullable(); $table->timestamp('attended_at')->nullable(); $table->timestamps(); - $table->unique(['student_id', 'course_schedule_id', 'date']); + $table->unique(['student_id', 'class_session_id']); + $table->index(['student_id', 'course_schedule_id', 'date']); }); } diff --git a/database/migrations/2026_10_25_024508_create_materials_table.php b/database/migrations/2026_10_25_024508_create_materials_table.php index f865953..fe16ecb 100644 --- a/database/migrations/2026_10_25_024508_create_materials_table.php +++ b/database/migrations/2026_10_25_024508_create_materials_table.php @@ -14,6 +14,7 @@ public function up(): void Schema::create('materials', function (Blueprint $table) { $table->id(); $table->foreignId('course_id')->constrained()->cascadeOnDelete(); + $table->foreignId('class_session_id')->nullable()->constrained()->nullOnDelete(); $table->string('title', 100); $table->text('description')->nullable(); $table->timestamp('published_at')->nullable(); diff --git a/resources/views/filament/pages/learning/class-session/index.blade.php b/resources/views/filament/pages/learning/class-session/index.blade.php new file mode 100644 index 0000000..7fadc6d --- /dev/null +++ b/resources/views/filament/pages/learning/class-session/index.blade.php @@ -0,0 +1,139 @@ + + + +
+
+ {{ $this->form }} +
+
+
+ + + @if ($this->getTodaySessions()->isNotEmpty()) + + + Sesi Hari Ini + + + Sesi yang dijadwalkan pada {{ now()->format('l, d F Y') }} + + +
+ @foreach ($this->getTodaySessions() as $session) +
!$session->is_pending, + 'border-gray-300 dark:border-gray-700 bg-gray-50/30 dark:bg-gray-800/10 border-dashed' => $session->is_pending, + ])> +
+
!$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 }} +
+ +
+
+
+

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

+

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

+
+
!$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') }} +
+ @if ($session->is_pending) +
+ + Sesi belum digenerate hari ini +
+ @endif +
+
+ +
!$session->is_pending, + 'border-gray-200 dark:border-gray-800' => $session->is_pending, + ])> + @if ($session->is_pending) + {{ ($this->generateTodaySessionAction)(['course' => $session->course->id]) }} + @else + {{ ($this->editSessionAction)(['session' => $session->id]) }} + @endif +
+
+
+ @endforeach +
+
+ @endif + + + + + Daftar Mata Kuliah Semester Ini + + + Pilih mata kuliah untuk melihat dan mengelola semua riwayat sesi. + + + @if ($this->getCourses()->isNotEmpty()) + + @else + + + @endif + +
diff --git a/resources/views/filament/pages/manage/attendance/detail.blade.php b/resources/views/filament/pages/manage/attendance/detail.blade.php deleted file mode 100644 index 4a11e9d..0000000 --- a/resources/views/filament/pages/manage/attendance/detail.blade.php +++ /dev/null @@ -1,145 +0,0 @@ - -
-
- -
- - Riwayat Pertemuan - Rekapitulasi presensi tiap pertemuan. - -
- @forelse ($meetingHistory as $meeting) -
-
-
- {{ $meeting->date['month'] }} - {{ $meeting->date['day'] }} -
-
-

- {{ $meeting->formatted_date }}

-

- HADIR: {{ $meeting->attended_count }} - / {{ $meeting->total_students }} -

-
-
- - - Salin Link - -
- @empty - - - @endforelse -
-
-
- - -
- @if ($activeMeetingStats) -
-
-
-

- - Monitoring Sesi Ini -

-
- -
-
- WAKTU PERKULIAHAN - {{ $activeMeetingStats->time_range }} -
- -
-
-
- {{ $activeMeetingStats->attended_count }} / - {{ $activeMeetingStats->total_students }} -
- - {{ $activeMeetingStats->percentage }}% - -
-
-
-
-
-
- -
-
- Belum Melakukan Absen - {{ $activeMeetingStats->total_students - $activeMeetingStats->attended_count }} -
-
- @foreach ($activeMeetingStats->absent_students as $absent) -
-
- {{ $absent->full_name }}
-
- {{ $absent->nim }} -
-
- @endforeach -
-
-
-
-
- @else - - - @endif -
-
-
- - -
diff --git a/resources/views/filament/pages/manage/attendance/index.blade.php b/resources/views/filament/pages/manage/attendance/index.blade.php deleted file mode 100644 index 3c06a20..0000000 --- a/resources/views/filament/pages/manage/attendance/index.blade.php +++ /dev/null @@ -1,102 +0,0 @@ - - - diff --git a/resources/views/filament/resources/learning/class-sessions/manage-class-sessions.blade.php b/resources/views/filament/resources/learning/class-sessions/manage-class-sessions.blade.php new file mode 100644 index 0000000..49c12d1 --- /dev/null +++ b/resources/views/filament/resources/learning/class-sessions/manage-class-sessions.blade.php @@ -0,0 +1,103 @@ + + +
+
+ {{ $this->form }} +
+
+ + @if($this->getCourses()->isNotEmpty()) +
+ @foreach($this->getCourses() as $course) +
+ +
+
+ + {{ $course->code }} + + +
+ + {{ $course->classSessions->count() }} Sesi + + +
+
+ +
+

+ {{ $course->name }} +

+
+ + {{ $course->lecturer->full_name ?? 'Dosen Belum Ditentukan' }} +
+
+
+ + +
+ @if($course->classSessions->isNotEmpty()) +
+ @foreach($course->classSessions as $session) +
+
+
+ + #{{ $session->session_number }} + + + {{ $session->date->format('l, d/m/Y') }} + +
+

+ {{ $session->title ?? 'Materi belum diisi' }} +

+
+ + {{ $session->start_time->format('H:i') }} - {{ $session->end_time->format('H:i') }} +
+
+
+ {{ ($this->editSessionAction)(['session' => $session->id]) }} + {{ ($this->deleteSessionAction)(['session' => $session->id]) }} +
+
+ @endforeach +
+ @else +
+ +

+ Belum ada laporan sesi untuk mata kuliah ini. +

+
+ @endif +
+
+ @endforeach +
+ @else + + @endif +
+
diff --git a/resources/views/filament/resources/learning/class-sessions/pages/list-course-sessions.blade.php b/resources/views/filament/resources/learning/class-sessions/pages/list-course-sessions.blade.php new file mode 100644 index 0000000..fb5da0d --- /dev/null +++ b/resources/views/filament/resources/learning/class-sessions/pages/list-course-sessions.blade.php @@ -0,0 +1,58 @@ + +
+ + + +
+

+ {{ $this->getTitle() }} +

+

+ Data sesi pembelajaran untuk mata kuliah {{ $this->getCourse()->name }} +

+
+
+ + + @if ($this->getSessions()->isNotEmpty()) +
+ @foreach ($this->getSessions() as $session) +
+
+
+ Sesi + #{{ $session->session_number }} +
+
+
+
+ + {{ $session->date->format('l, d F Y') }} +
+
+ + {{ $session->start_time->format('H:i') }} - + {{ $session->end_time->format('H:i') }} +
+
+
+
+ +
+ {{ ($this->editSessionAction)(['session' => $session->id]) }} + {{ ($this->deleteSessionAction)(['session' => $session->id]) }} +
+
+ @endforeach +
+ @else + + + @endif +
+
diff --git a/routes/web.php b/routes/web.php index 2420695..2e4f63b 100644 --- a/routes/web.php +++ b/routes/web.php @@ -3,7 +3,7 @@ use Illuminate\Support\Facades\Route; Route::get('/', function () { - return view('welcome'); + return redirect()->route('filament.admin.auth.login'); }); Route::get('/share/presensi/{token}', [\App\Http\Controllers\ShareAttendanceController::class, 'show'])->name('share.attendance');