From 6cd48bf758536a31b0bcb2bb6c57a829cf9c0508 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Mon, 30 Mar 2026 13:26:11 +0700 Subject: [PATCH] feat: implement public assignment sharing functionality with dedicated controller and Filament action --- .../Actions/ShareAssignmentAction.php | 54 ++++ .../Pages/ListCourseSessions.php | 7 + .../Controllers/ShareAssignmentController.php | 68 +++++ .../learning/class-sessions/show.blade.php | 1 + .../views/pages/share-assignment.blade.php | 275 ++++++++++++++++++ .../views/pages/share-attendance.blade.php | 1 - routes/web.php | 2 + 7 files changed, 407 insertions(+), 1 deletion(-) create mode 100644 app/Filament/Resources/Learning/ClassSessions/Actions/ShareAssignmentAction.php create mode 100644 app/Http/Controllers/ShareAssignmentController.php create mode 100644 resources/views/pages/share-assignment.blade.php diff --git a/app/Filament/Resources/Learning/ClassSessions/Actions/ShareAssignmentAction.php b/app/Filament/Resources/Learning/ClassSessions/Actions/ShareAssignmentAction.php new file mode 100644 index 0000000..5d02ca9 --- /dev/null +++ b/app/Filament/Resources/Learning/ClassSessions/Actions/ShareAssignmentAction.php @@ -0,0 +1,54 @@ +label('Bagikan Tugas') + ->icon('heroicon-o-paper-airplane') + ->color('warning') + ->link() + ->action(function (array $arguments, $livewire) { + $course = $livewire->course; + if (empty($course->sharing_token)) { + $course->update(['sharing_token' => Str::random(32)]); + } + + $session = ClassSession::find($arguments['session'] ?? null); + + $url = route('share.assignment', [ + 'token' => $course->sharing_token, + 'session_id' => $session ? $session->id : null, + ]); + + $text = "*Info Tugas Kelas {$course->name}*\nSesi ke-".($session->session_number ?? '-').' ('.($session->date->translatedFormat('d M Y') ?? '').")\n\nSilakan cek status pengumpulan tugas melalui tautan publik berikut:\n\n{$url}"; + + $escapedText = json_encode($text); + + $livewire->js( + << {}); +} +window.open(url, '_blank'); +JS + ); + }); + } +} diff --git a/app/Filament/Resources/Learning/ClassSessions/Pages/ListCourseSessions.php b/app/Filament/Resources/Learning/ClassSessions/Pages/ListCourseSessions.php index 9df7b6f..edbe370 100644 --- a/app/Filament/Resources/Learning/ClassSessions/Pages/ListCourseSessions.php +++ b/app/Filament/Resources/Learning/ClassSessions/Pages/ListCourseSessions.php @@ -7,6 +7,7 @@ use App\Filament\Resources\Learning\ClassSessions\Actions\DeleteSessionAction; use App\Filament\Resources\Learning\ClassSessions\Actions\EditSessionAction; use App\Filament\Resources\Learning\ClassSessions\Actions\GenerateSessionsAction; +use App\Filament\Resources\Learning\ClassSessions\Actions\ShareAssignmentAction; use App\Filament\Resources\Learning\ClassSessions\Actions\ShareAttendanceAction; use App\Filament\Resources\Learning\ClassSessions\Actions\ViewAssignmentDetailAction; use App\Filament\Resources\Learning\ClassSessions\Actions\ViewAssignmentsAction; @@ -144,6 +145,7 @@ protected function getActions(): array { return [ $this->shareAttendanceAction(), + $this->shareAssignmentAction(), $this->viewAttendanceAction(), $this->viewMaterialsAction(), $this->viewAssignmentsAction(), @@ -159,6 +161,11 @@ public function shareAttendanceAction(): Action return ShareAttendanceAction::make(); } + public function shareAssignmentAction(): Action + { + return ShareAssignmentAction::make(); + } + public function viewAttendanceAction(): Action { return ViewAttendanceAction::make(); diff --git a/app/Http/Controllers/ShareAssignmentController.php b/app/Http/Controllers/ShareAssignmentController.php new file mode 100644 index 0000000..63331d8 --- /dev/null +++ b/app/Http/Controllers/ShareAssignmentController.php @@ -0,0 +1,68 @@ +firstOrFail(); + + // Retrieve available assignments for the dropdown (from the whole course) + $availableAssignments = Assignment::where('course_id', $course->id) + ->with('classSession') + ->orderBy('created_at', 'desc') + ->get(); + + // Default: If session_id is provided, try to find an assignment for that session, or fallback to latest assignment. + $assignmentId = $request->query('assignment_id'); + $sessionId = $request->query('session_id'); + + $assignment = null; + if ($assignmentId) { + $assignment = $availableAssignments->firstWhere('id', $assignmentId); + } elseif ($sessionId) { + $assignment = $availableAssignments->firstWhere('class_session_id', $sessionId) ?? $availableAssignments->first(); + } else { + $assignment = $availableAssignments->first(); + } + + $sessionInfo = $assignment ? $assignment->classSession : null; + + // Get submissions and calculate stats + $submissions = collect(); + if ($assignment) { + $submissions = AssignmentSubmission::with(['student', 'media']) + ->where('assignment_id', $assignment->id) + ->get(); + } + + $totalStudents = Student::whereHas('user', fn ($q) => $q->active())->count(); + $submittedCount = $submissions->count(); + $submissionPercentage = $totalStudents > 0 ? round(($submittedCount / $totalStudents) * 100) : 0; + + $formattedDeadline = $assignment && $assignment->due_date + ? Carbon::parse($assignment->due_date)->translatedFormat('l, d F Y H:i') + : '-'; + + return view('pages.share-assignment', compact( + 'course', + 'assignment', + 'availableAssignments', + 'sessionInfo', + 'submissions', + 'totalStudents', + 'submittedCount', + 'submissionPercentage', + 'formattedDeadline' + )); + } +} diff --git a/resources/views/filament/resources/learning/class-sessions/show.blade.php b/resources/views/filament/resources/learning/class-sessions/show.blade.php index 0cfd516..9c22b92 100644 --- a/resources/views/filament/resources/learning/class-sessions/show.blade.php +++ b/resources/views/filament/resources/learning/class-sessions/show.blade.php @@ -55,6 +55,7 @@
{{ ($this->shareAttendanceAction)(['session' => $session->id]) }} + {{ ($this->shareAssignmentAction)(['session' => $session->id]) }} {{ ($this->viewAttendanceAction)(['session' => $session->id]) }} {{ ($this->viewMaterialsAction)(['session' => $session->id]) }} {{ ($this->viewAssignmentsAction)(['session' => $session->id]) }} diff --git a/resources/views/pages/share-assignment.blade.php b/resources/views/pages/share-assignment.blade.php new file mode 100644 index 0000000..ccada65 --- /dev/null +++ b/resources/views/pages/share-assignment.blade.php @@ -0,0 +1,275 @@ + + + + + + + Tugas {{ $course->name }} - {{ config('app.name', 'MyClass') }} + @vite(['resources/css/app.css', 'resources/js/app.js']) + + + + + + +
+
+ +
+ +
+
+
+ + {{ $course->code }} + + + Semester Genap + +
+

{{ $course->name }} +

+

+ + {{ $course->lecturer }} +

+
+
+ + +
+ + +
+
+

Daftar + Pengumpulan

+
+ +
+
+ + + + + + + + + + + @forelse($submissions as $submission) + + + + + + + @empty + + + + @endforelse + +
MahasiswaNomor Induk + Hasil Tugas + + Waktu Pengumpulan
+
+
+ {{ $submission->student->full_name }} +
+
+
+ + {{ $submission->student->student_number }} + + +
+ + @if ($submission->getMedia('submission')->count() > 0) +
+ @foreach ($submission->getMedia('submission') as $media) + + @endforeach +
+ @else + File + tidak ditemukan + @endif +
+
+ @php + $isLate = + $assignment && + $assignment->due_date && + $submission->submitted_at > $assignment->due_date; + @endphp +
+ + {{ $submission->submitted_at ? $submission->submitted_at->format('d M Y H:i') : '-' }} +
+
+
+
+ +
+

+ Tidak ada pengumpulan

+

Belum ada + mahasiswa yang mengumpulkan tugas ini.

+
+
+
+
+
+ + +
+ + +
+

+ Informasi Tugas

+ +
+
+ +
+ +
+
+ +
+ +
+
+ Terkumpul + {{ $submittedCount }}/{{ $totalStudents }} + Orang + +
+
+
+
+ {{ $submissionPercentage }}% +
+
+
+ Batas + Pengumpulan + + {{ $formattedDeadline }} + +
+
+
+
+ +
+
+
+
+ + + + + + + + diff --git a/resources/views/pages/share-attendance.blade.php b/resources/views/pages/share-attendance.blade.php index 7693bcb..82c35ee 100644 --- a/resources/views/pages/share-attendance.blade.php +++ b/resources/views/pages/share-attendance.blade.php @@ -105,7 +105,6 @@ class="font-bold text-gray-950 dark:text-white text-sm">{{ $attendance->student- class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-lg bg-emerald-50 dark:bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 font-bold text-[10px] uppercase tracking-widest"> {{ $attendance->attended_at ? $attendance->attended_at->format('H:i') : '-' }} - WIB diff --git a/routes/web.php b/routes/web.php index 673a976..5247a16 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,5 +1,6 @@ name('share.attendance'); +Route::get('/share/tugas/{token}', [ShareAssignmentController::class, 'show'])->name('share.assignment');