get('search')); $academicYearId = $request->get('academic_year_id'); $departmentId = $request->get('department_id'); $classId = $request->get('class_id'); $documentStatus = (string) $request->get('document_status', 'all'); $sort = (string) $request->get('sort', 'full_name'); $direction = strtolower((string) $request->get('direction', 'asc')) === 'desc' ? 'desc' : 'asc'; $allowedSorts = [ 'full_name' => 'full_name', 'student_number' => 'student_number', 'academic_year' => 'academic_year_id', 'department' => 'department_id', 'class' => 'class_id', 'graduation_date' => 'graduation_date', 'created_at' => 'created_at', ]; if (! array_key_exists($sort, $allowedSorts)) { $sort = 'full_name'; } $documentFields = [ 'skl_file_path', 'ijazah_file_path', 'transcript_file_path', 'ukk_certificate_file_path', 'lsp_certificate_file_path', ]; $graduations = StudentGraduation::query() ->with(['academicYear', 'department', 'classRoom']) ->when($search !== '', function ($query) use ($search) { $query->where(function ($subQuery) use ($search) { $subQuery->where('full_name', 'like', "%{$search}%") ->orWhere('student_number', 'like', "%{$search}%") ->orWhere('nisn', 'like', "%{$search}%"); }); }) ->when($academicYearId, fn ($query) => $query->where('academic_year_id', $academicYearId)) ->when($departmentId, fn ($query) => $query->where('department_id', $departmentId)) ->when($classId, fn ($query) => $query->where('class_id', $classId)) ->when($documentStatus === 'incomplete', function ($query) use ($documentFields) { foreach ($documentFields as $field) { $query->orWhereNull($field); } }) ->when($documentStatus === 'complete', function ($query) use ($documentFields) { foreach ($documentFields as $field) { $query->whereNotNull($field); } }) ->orderBy($allowedSorts[$sort], $direction) ->orderBy('id', $direction) ->paginate(10) ->withQueryString(); $totalGraduations = StudentGraduation::count(); $summary = [ 'total' => $totalGraduations, 'filtered' => $graduations->total(), 'with_skl' => StudentGraduation::query()->whereNotNull('skl_file_path')->count(), 'with_ijazah' => StudentGraduation::query()->whereNotNull('ijazah_file_path')->count(), 'with_transcript' => StudentGraduation::query()->whereNotNull('transcript_file_path')->count(), 'with_ukk_certificate' => StudentGraduation::query()->whereNotNull('ukk_certificate_file_path')->count(), 'with_lsp_certificate' => StudentGraduation::query()->whereNotNull('lsp_certificate_file_path')->count(), 'this_year' => StudentGraduation::query()->whereYear('graduation_date', now()->year)->count(), 'latest_graduation_date' => StudentGraduation::query()->max('graduation_date'), ]; $graduations->getCollection()->transform(function (StudentGraduation $graduation) use ($documentFields) { $availableDocuments = collect($documentFields)->filter(fn ($field) => filled($graduation->{$field}))->count(); $graduation->documents_total = count($documentFields); $graduation->documents_available = $availableDocuments; $graduation->documents_missing = max($graduation->documents_total - $availableDocuments, 0); $graduation->documents_progress_percentage = $graduation->documents_total > 0 ? (int) round(($availableDocuments / $graduation->documents_total) * 100) : 100; return $graduation; }); return view('graduated-students.index', [ 'graduations' => $graduations, 'search' => $search, 'filters' => [ 'academic_year_id' => $academicYearId, 'department_id' => $departmentId, 'class_id' => $classId, 'document_status' => $documentStatus, ], 'academicYears' => AcademicYear::orderBy('name')->pluck('name', 'id'), 'departments' => Department::orderBy('name')->pluck('name', 'id'), 'classes' => SchoolClass::query() ->when($academicYearId, function ($query) use ($academicYearId, $classId) { $query->where('academic_year_id', $academicYearId) ->where(function ($innerQuery) use ($classId) { $innerQuery->where('level', 'XII'); if ($classId) { $innerQuery->orWhere('id', $classId); } }); }, function ($query) use ($classId) { if ($classId) { $query->whereKey($classId); } else { $query->whereRaw('1 = 0'); } }) ->orderBy('name') ->pluck('name', 'id'), 'documentStatusOptions' => [ 'all' => 'Semua Dokumen', 'complete' => 'Dokumen Lengkap', 'incomplete' => 'Dokumen Belum Lengkap', ], 'sort' => $sort, 'direction' => $direction, 'summary' => $summary, ]); } public function show(StudentGraduation $graduatedStudent): View { $graduatedStudent->load(['academicYear', 'department', 'classRoom']); return view('graduated-students.show', [ 'graduation' => $graduatedStudent, ]); } public function update(Request $request, StudentGraduation $graduatedStudent): RedirectResponse { $validated = $request->validate([ 'graduation_date' => ['nullable', 'date'], 'graduation_note' => ['nullable', 'string'], 'skl_file' => ['nullable', 'file', 'mimes:pdf,jpg,jpeg,png', 'max:4096'], 'ijazah_file' => ['nullable', 'file', 'mimes:pdf,jpg,jpeg,png', 'max:4096'], 'transcript_file' => ['nullable', 'file', 'mimes:pdf,jpg,jpeg,png', 'max:4096'], 'ukk_certificate_file' => ['nullable', 'file', 'mimes:pdf,jpg,jpeg,png', 'max:4096'], 'lsp_certificate_file' => ['nullable', 'file', 'mimes:pdf,jpg,jpeg,png', 'max:4096'], ], [ 'skl_file.mimes' => 'File SKL harus berupa PDF, JPG, JPEG, atau PNG.', 'skl_file.max' => 'Ukuran file SKL maksimal 4 MB.', 'ijazah_file.mimes' => 'File ijazah harus berupa PDF, JPG, JPEG, atau PNG.', 'ijazah_file.max' => 'Ukuran file ijazah maksimal 4 MB.', 'transcript_file.mimes' => 'File transkrip nilai harus berupa PDF, JPG, JPEG, atau PNG.', 'transcript_file.max' => 'Ukuran file transkrip nilai maksimal 4 MB.', 'ukk_certificate_file.mimes' => 'File sertifikat UKK harus berupa PDF, JPG, JPEG, atau PNG.', 'ukk_certificate_file.max' => 'Ukuran file sertifikat UKK maksimal 4 MB.', 'lsp_certificate_file.mimes' => 'File sertifikat LSP harus berupa PDF, JPG, JPEG, atau PNG.', 'lsp_certificate_file.max' => 'Ukuran file sertifikat LSP maksimal 4 MB.', ]); $graduatedStudent->graduation_date = $validated['graduation_date'] ?? $graduatedStudent->graduation_date; $graduatedStudent->graduation_note = $validated['graduation_note'] ?? $graduatedStudent->graduation_note; if ($request->hasFile('skl_file')) { if ($graduatedStudent->skl_file_path && Storage::disk('public')->exists($graduatedStudent->skl_file_path)) { Storage::disk('public')->delete($graduatedStudent->skl_file_path); } $file = $request->file('skl_file'); $path = $file->store("student-graduation-documents/{$graduatedStudent->student_id}/skl", 'public'); $graduatedStudent->skl_file_name = $file->getClientOriginalName(); $graduatedStudent->skl_file_path = $path; $graduatedStudent->skl_mime_type = $file->getMimeType(); $graduatedStudent->skl_file_size = $file->getSize(); } if ($request->hasFile('ijazah_file')) { if ($graduatedStudent->ijazah_file_path && Storage::disk('public')->exists($graduatedStudent->ijazah_file_path)) { Storage::disk('public')->delete($graduatedStudent->ijazah_file_path); } $file = $request->file('ijazah_file'); $path = $file->store("student-graduation-documents/{$graduatedStudent->student_id}/ijazah", 'public'); $graduatedStudent->ijazah_file_name = $file->getClientOriginalName(); $graduatedStudent->ijazah_file_path = $path; $graduatedStudent->ijazah_mime_type = $file->getMimeType(); $graduatedStudent->ijazah_file_size = $file->getSize(); } if ($request->hasFile('transcript_file')) { if ($graduatedStudent->transcript_file_path && Storage::disk('public')->exists($graduatedStudent->transcript_file_path)) { Storage::disk('public')->delete($graduatedStudent->transcript_file_path); } $file = $request->file('transcript_file'); $path = $file->store("student-graduation-documents/{$graduatedStudent->student_id}/transcript", 'public'); $graduatedStudent->transcript_file_name = $file->getClientOriginalName(); $graduatedStudent->transcript_file_path = $path; $graduatedStudent->transcript_mime_type = $file->getMimeType(); $graduatedStudent->transcript_file_size = $file->getSize(); } if ($request->hasFile('ukk_certificate_file')) { if ($graduatedStudent->ukk_certificate_file_path && Storage::disk('public')->exists($graduatedStudent->ukk_certificate_file_path)) { Storage::disk('public')->delete($graduatedStudent->ukk_certificate_file_path); } $file = $request->file('ukk_certificate_file'); $path = $file->store("student-graduation-documents/{$graduatedStudent->student_id}/ukk-certificate", 'public'); $graduatedStudent->ukk_certificate_file_name = $file->getClientOriginalName(); $graduatedStudent->ukk_certificate_file_path = $path; $graduatedStudent->ukk_certificate_mime_type = $file->getMimeType(); $graduatedStudent->ukk_certificate_file_size = $file->getSize(); } if ($request->hasFile('lsp_certificate_file')) { if ($graduatedStudent->lsp_certificate_file_path && Storage::disk('public')->exists($graduatedStudent->lsp_certificate_file_path)) { Storage::disk('public')->delete($graduatedStudent->lsp_certificate_file_path); } $file = $request->file('lsp_certificate_file'); $path = $file->store("student-graduation-documents/{$graduatedStudent->student_id}/lsp-certificate", 'public'); $graduatedStudent->lsp_certificate_file_name = $file->getClientOriginalName(); $graduatedStudent->lsp_certificate_file_path = $path; $graduatedStudent->lsp_certificate_mime_type = $file->getMimeType(); $graduatedStudent->lsp_certificate_file_size = $file->getSize(); } $graduatedStudent->save(); Alert::success('Berhasil', 'Arsip siswa lulus berhasil diperbarui.'); return redirect()->route('graduated-students.show', $graduatedStudent)->with('success', 'Arsip siswa lulus berhasil diperbarui.'); } public function previewDocument(StudentGraduation $graduatedStudent, string $document): View { abort_unless(in_array($document, ['skl', 'ijazah', 'transcript', 'ukk-certificate', 'lsp-certificate'], true), 404); $documentConfig = [ 'skl' => ['path' => 'skl_file_path', 'name' => 'skl_file_name', 'mime' => 'skl_mime_type', 'label' => 'SKL'], 'ijazah' => ['path' => 'ijazah_file_path', 'name' => 'ijazah_file_name', 'mime' => 'ijazah_mime_type', 'label' => 'Ijazah'], 'transcript' => ['path' => 'transcript_file_path', 'name' => 'transcript_file_name', 'mime' => 'transcript_mime_type', 'label' => 'Transkrip Nilai'], 'ukk-certificate' => ['path' => 'ukk_certificate_file_path', 'name' => 'ukk_certificate_file_name', 'mime' => 'ukk_certificate_mime_type', 'label' => 'Sertifikat UKK'], 'lsp-certificate' => ['path' => 'lsp_certificate_file_path', 'name' => 'lsp_certificate_file_name', 'mime' => 'lsp_certificate_mime_type', 'label' => 'Sertifikat LSP'], ][$document]; $filePathField = $documentConfig['path']; $fileNameField = $documentConfig['name']; $mimeTypeField = $documentConfig['mime']; abort_unless($graduatedStudent->{$filePathField} && Storage::disk('public')->exists($graduatedStudent->{$filePathField}), 404); $mimeType = $graduatedStudent->{$mimeTypeField} ?: Storage::disk('public')->mimeType($graduatedStudent->{$filePathField}); $fileUrl = asset('storage/' . $graduatedStudent->{$filePathField}); $isImage = Str::startsWith((string) $mimeType, 'image/'); $isPdf = $mimeType === 'application/pdf'; return view('graduated-students.preview-document', [ 'graduation' => $graduatedStudent, 'documentType' => $document, 'documentLabel' => $documentConfig['label'], 'fileName' => $graduatedStudent->{$fileNameField}, 'fileUrl' => $fileUrl, 'mimeType' => $mimeType, 'isImage' => $isImage, 'isPdf' => $isPdf, ]); } }