diff --git a/app/Filament/Widgets/MyAssignmentCompletionChart.php b/app/Filament/Widgets/MyAssignmentCompletionChart.php new file mode 100644 index 0000000..0e86952 --- /dev/null +++ b/app/Filament/Widgets/MyAssignmentCompletionChart.php @@ -0,0 +1,74 @@ +user()?->student !== null; + } + + protected function getData(): array + { + $studentId = auth()->user()?->student?->id; + + $baseQuery = Assignment::query() + ->whereHas('assignmentTargets', function (Builder $query) use ($studentId) { + $query->where('student_id', $studentId) + ->orWhereIn('study_group_id', function ($q) use ($studentId) { + $q->select('study_group_id')->from('study_group_members')->where('student_id', $studentId); + }) + ->orWhereIn('study_group_id', function ($q) use ($studentId) { + $q->select('id')->from('study_groups')->where('leader_id', $studentId); + }); + }); + + $submittedCount = (clone $baseQuery)->whereHas('assignmentSubmissions', function (Builder $query) use ($studentId) { + $query->where('student_id', $studentId) + ->orWhereIn('study_group_id', function ($q) use ($studentId) { + $q->select('study_group_id')->from('study_group_members')->where('student_id', $studentId); + }) + ->orWhereIn('study_group_id', function ($q) use ($studentId) { + $q->select('id')->from('study_groups')->where('leader_id', $studentId); + }); + })->count(); + + $totalCount = $baseQuery->count(); + + $notSubmittedCount = $totalCount - $submittedCount; + + return [ + 'datasets' => [ + [ + 'label' => 'Tugas', + 'data' => [$submittedCount, $notSubmittedCount], + 'backgroundColor' => [ + 'rgba(59, 130, 246, 0.8)', // Blue 500 + 'rgba(245, 158, 11, 0.8)', // Amber 500 + ], + 'borderColor' => [ + 'rgba(59, 130, 246, 1)', + 'rgba(245, 158, 11, 1)', + ], + ], + ], + 'labels' => ['Sudah Dikerjakan', 'Belum Dikerjakan'], + ]; + } + + protected function getType(): string + { + return 'doughnut'; + } +} diff --git a/app/Filament/Widgets/MyAttendanceRatioChart.php b/app/Filament/Widgets/MyAttendanceRatioChart.php new file mode 100644 index 0000000..9e4b083 --- /dev/null +++ b/app/Filament/Widgets/MyAttendanceRatioChart.php @@ -0,0 +1,57 @@ +user()?->student !== null; + } + + protected function getData(): array + { + $studentId = auth()->user()?->student?->id; + + $presentCount = Attendance::where('student_id', $studentId) + ->whereNotNull('attended_at') + ->count(); + + $absentCount = Attendance::where('student_id', $studentId) + ->whereNull('attended_at') + ->where('date', '<=', today()) + ->count(); + + return [ + 'datasets' => [ + [ + 'label' => 'Presensi', + 'data' => [$presentCount, $absentCount], + 'backgroundColor' => [ + 'rgba(16, 185, 129, 0.8)', // Emerald 500 + 'rgba(244, 63, 94, 0.8)', // Rose 500 + ], + 'borderColor' => [ + 'rgba(16, 185, 129, 1)', + 'rgba(244, 63, 94, 1)', + ], + ], + ], + 'labels' => ['Hadir', 'Tidak / Belum Hadir'], + ]; + } + + protected function getType(): string + { + return 'doughnut'; + } +} diff --git a/app/Filament/Widgets/MyPendingAssignmentsTable.php b/app/Filament/Widgets/MyPendingAssignmentsTable.php new file mode 100644 index 0000000..b8900f9 --- /dev/null +++ b/app/Filament/Widgets/MyPendingAssignmentsTable.php @@ -0,0 +1,95 @@ +user()?->student !== null; + } + + public function table(Table $table): Table + { + $studentId = auth()->user()?->student?->id; + + return $table + ->query( + Assignment::query() + ->whereHas('assignmentTargets', function (Builder $query) use ($studentId) { + $query->where('student_id', $studentId) + ->orWhereIn('study_group_id', function ($q) use ($studentId) { + $q->select('study_group_id') + ->from('study_group_members') + ->where('student_id', $studentId); + }) + ->orWhereIn('study_group_id', function ($q) use ($studentId) { + $q->select('id') + ->from('study_groups') + ->where('leader_id', $studentId); + }); + }) + ->whereDoesntHave('assignmentSubmissions', function (Builder $query) use ($studentId) { + $query->where('student_id', $studentId) + ->orWhereIn('study_group_id', function ($q) use ($studentId) { + $q->select('study_group_id') + ->from('study_group_members') + ->where('student_id', $studentId); + }) + ->orWhereIn('study_group_id', function ($q) use ($studentId) { + $q->select('id') + ->from('study_groups') + ->where('leader_id', $studentId); + }); + }) + ->where('due_date', '>=', now()) + ->orderBy('due_date', 'asc') + ) + ->columns([ + TextColumn::make('title') + ->label('Judul Tugas') + ->searchable() + ->sortable() + ->wrap(), + + TextColumn::make('course.name') + ->label('Mata Kuliah') + ->searchable() + ->sortable() + ->wrap(), + + TextColumn::make('type') + ->label('Jenis') + ->badge(), + + TextColumn::make('due_date') + ->label('Tenggat Waktu') + ->dateTime('d M Y H:i') + ->sortable() + ->color(fn (Assignment $record) => $record->due_date < now()->addDays(2) ? 'danger' : 'warning'), + ]) + ->recordActions([ + Action::make('kerjakan') + ->label('Lihat Detail & Kerjakan') + ->url(fn (Assignment $record): string => '/admin/learning/assignments/'.$record->id.'/submit') + ->icon('heroicon-m-arrow-top-right-on-square') + ->button() + ->color('primary'), + ]) + ->emptyStateHeading('Tidak Ada Tugas') + ->emptyStateDescription('Semua tugas telah diselesaikan atau tidak ada tugas mendatang.'); + } +} diff --git a/app/Filament/Widgets/StatsOverview.php b/app/Filament/Widgets/StatsOverview.php new file mode 100644 index 0000000..1361cf7 --- /dev/null +++ b/app/Filament/Widgets/StatsOverview.php @@ -0,0 +1,84 @@ +user()?->student !== null; + } + + protected function getStats(): array + { + $studentId = auth()->user()?->student?->id; + + if (! $studentId) { + return []; + } + + $presentCount = Attendance::where('student_id', $studentId) + ->whereNotNull('attended_at') + ->count(); + $totalSessions = Attendance::where('student_id', $studentId)->count(); + $attendanceRate = $totalSessions > 0 ? round(($presentCount / $totalSessions) * 100) : 0; + + $baseAssignmentQuery = Assignment::query() + ->whereHas('assignmentTargets', function (Builder $query) use ($studentId) { + $query->where('student_id', $studentId) + ->orWhereIn('study_group_id', function ($q) use ($studentId) { + $q->select('study_group_id')->from('study_group_members')->where('student_id', $studentId); + }) + ->orWhereIn('study_group_id', function ($q) use ($studentId) { + $q->select('id')->from('study_groups')->where('leader_id', $studentId); + }); + }); + + $completedAssignments = (clone $baseAssignmentQuery)->whereHas('assignmentSubmissions', function (Builder $query) use ($studentId) { + $query->where('student_id', $studentId) + ->orWhereIn('study_group_id', function ($q) use ($studentId) { + $q->select('study_group_id')->from('study_group_members')->where('student_id', $studentId); + }) + ->orWhereIn('study_group_id', function ($q) use ($studentId) { + $q->select('id')->from('study_groups')->where('leader_id', $studentId); + }); + })->count(); + + $pendingAssignments = (clone $baseAssignmentQuery)->whereDoesntHave('assignmentSubmissions', function (Builder $query) use ($studentId) { + $query->where('student_id', $studentId) + ->orWhereIn('study_group_id', function ($q) use ($studentId) { + $q->select('study_group_id')->from('study_group_members')->where('student_id', $studentId); + }) + ->orWhereIn('study_group_id', function ($q) use ($studentId) { + $q->select('id')->from('study_groups')->where('leader_id', $studentId); + }); + }) + ->where('due_date', '>=', now()) + ->count(); + + return [ + Stat::make('Kehadiran', $presentCount.' / '.$totalSessions.' Sesi') + ->description($attendanceRate.'% Tingkat Kehadiran') + ->descriptionIcon('heroicon-m-check-circle') + ->color($attendanceRate >= 75 ? 'success' : 'danger'), + + Stat::make('Tugas Selesai', $completedAssignments.' Tugas') + ->description('Telah dikumpulkan') + ->descriptionIcon('heroicon-m-clipboard-document-check') + ->color('success'), + + Stat::make('Tugas Mendatang', $pendingAssignments.' Tugas') + ->description('Belum dikerjakan') + ->descriptionIcon($pendingAssignments > 0 ? 'heroicon-m-exclamation-circle' : 'heroicon-m-face-smile') + ->color($pendingAssignments > 0 ? 'warning' : 'gray'), + ]; + } +} diff --git a/app/Providers/Filament/AdminPanelProvider.php b/app/Providers/Filament/AdminPanelProvider.php index df80535..c5743c8 100644 --- a/app/Providers/Filament/AdminPanelProvider.php +++ b/app/Providers/Filament/AdminPanelProvider.php @@ -15,7 +15,6 @@ use Filament\Panel; use Filament\PanelProvider; use Filament\Support\Colors\Color; -use Filament\Widgets\AccountWidget; use Hammadzafar05\MobileBottomNav\MobileBottomNav; use Hammadzafar05\MobileBottomNav\MobileBottomNavItem; use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse; @@ -27,7 +26,6 @@ use Saade\Facehash\Enums\Variant; use Saade\FilamentFacehash\FacehashPlugin; use Saade\FilamentFacehash\FacehashProvider; -use SalmanAlmajali\JokesWidget\JokesWidget; class AdminPanelProvider extends PanelProvider { @@ -49,10 +47,7 @@ public function panel(Panel $panel): Panel Dashboard::class, ]) ->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\Filament\Widgets') - ->widgets([ - AccountWidget::class, - JokesWidget::class, - ]) + ->widgets([]) ->middleware([ EncryptCookies::class, AddQueuedCookiesToResponse::class,