diff --git a/app/Http/Controllers/Admin/ProjectController.php b/app/Http/Controllers/Admin/ProjectController.php new file mode 100644 index 0000000..fa4dd0e --- /dev/null +++ b/app/Http/Controllers/Admin/ProjectController.php @@ -0,0 +1,302 @@ +all(), [ + 'title' => 'required', + 'section' => 'required|numeric', + 'course_id' => 'required' + ]); + + if ($validator->fails()) { + return redirect()->back()->withErrors($validator)->withInput(); + } + + $data['title'] = $request->title; + $data['course_id'] = $request->course_id; + $data['section_id'] = $request->section; + $data['description'] = $request->description; + $data['attachment'] = $request->attachment; + $data['summary'] = $request->summary; + + + Lesson::where('id', $id)->update($data); + + Session::flash('success', get_phrase('Project has been updated.')); + return redirect()->back(); + } + + public function store(Request $request) + { + $maxSort = Lesson::where('section_id', $request->section) + ->max('sort'); + + $data['user_id'] = auth()->user()->id; + $data['sort'] = $maxSort + 1; + $data['title'] = $request->title; + $data['course_id'] = $request->course_id; + $data['section_id'] = $request->section; + $data['attachment'] = $request->attachment; + $data['description'] = $request->description; + $data['summary'] = $request->summary; + $data['lesson_type'] = 'project'; + $data['status'] = 1; + + Lesson::insert($data); + + Session::flash('success', get_phrase('Project has been created.')); + return redirect()->back(); + } + + public function getSubmissions($id) + { + $participants = ProjectSubmission::join('users', 'project_submissions.user_id', '=', 'users.id') + ->where('project_submissions.lesson_id', $id) + ->where('project_submissions.status', 0) + ->select('users.name', 'users.id') + ->distinct() + ->get(); + + return view('admin.project.grading.index', ['participants' => $participants, 'lesson_id' => $id]); + } + + public function getPreview(Request $request) + { + // Validasi input + $request->validate([ + 'lesson_id' => 'required|integer', + 'user_id' => 'required|integer' + ]); + + // Cari submission terbaru + $submission = ProjectSubmission::where('lesson_id', $request->lesson_id) + ->where('user_id', $request->user_id) + ->latest() + ->first(); + // dd($submission); // <-- INI HARUS DIHAPUS ATAU DI-KOMEN + + // Tentukan label komentar + $commentLabel = (!empty($submission) && !empty($submission->comment)) + ? "Revisi Sebelumnya" + : "Masukkan Revisi Anda"; + + // Return view preview + return view('admin.project.grading.preview', compact('submission', 'commentLabel')); + } + + public function getParticipantSubmission(Request $request) + { + $submissions = ProjectSubmission::where('lesson_id', $request->quizId) + ->where('user_id', $request->participant) + ->orderBy('created_at', 'desc') + ->get(); + + $html = ''; + + if($submissions->count() > 0){ + foreach ($submissions as $submission) { + $date = date('d M Y, H:i', strtotime($submission->created_at)); + + $statusLabel = ''; + if($submission->status == 1) $statusLabel = ' (Lulus)'; + elseif($submission->status == 2) $statusLabel = ' (Revisi)'; + else $statusLabel = ' (Pending)'; + + $html .= ''; + } + } else { + $html .= ''; + } + + return response()->json($html); + } + + public function updateSubmission(Request $request, $id) + { + $request->validate([ + 'status' => 'required|in:1,2', + 'comment' => 'required_if:status,2', // Wajib isi jika status 2 (Revisi) + ]); + + // Menggunakan Model findOrFail + $submission = ProjectSubmission::findOrFail($id); + + $submission->status = $request->status; + $submission->reviewed_by = auth()->id(); + $submission->reviewed_at = now(); + + if ($request->status == 1) { + // Jika Diterima (1), Comment jadi NULL (sesuai request) + $submission->comment = null; + } else { + // Jika Perlu Perbaikan (2), Simpan Comment + $submission->comment = $request->comment; + } + + $submission->save(); + + // **LOGIKA WATCH HISTORY - DIPERBAIKI berdasarkan referensi** + + $lesson = Lesson::findOrFail($submission->lesson_id); + + $student_id = $submission->user_id; + $course_id = $lesson->course_id; + $lesson_id = $submission->lesson_id; + + // Ambil semua lesson ID untuk course ini + $total_lesson = Lesson::where('course_id', $course_id) + ->pluck('id') + ->map(function($id) { + return (int)$id; + }) + ->toArray(); + + // Cari watch_history untuk student ini + $watch_history = Watch_history::where('course_id', $course_id) + ->where('student_id', $student_id) + ->first(); + + // **LOGIKA UTAMA berdasarkan referensi set_watch_history** + if ($watch_history) { + // Parse data lama dengan handling yang robust + $completed_lessons = []; + + if (!empty($watch_history->completed_lesson)) { + $decoded = json_decode($watch_history->completed_lesson, true); + + if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) { + // Konversi semua nilai ke integer + $completed_lessons = array_map('intval', $decoded); + } else { + // Fallback jika format tidak valid + $completed_lesson_data = trim($watch_history->completed_lesson, '[]"\' '); + if (!empty($completed_lesson_data)) { + $completed_lessons = array_map('intval', explode(',', $completed_lesson_data)); + } + } + } + + // Hapus duplikat dan sortir + $completed_lessons = array_unique($completed_lessons); + sort($completed_lessons); + + // **HANYA tambahkan lesson jika project DITERIMA (status 1)** + if ($request->status == 1 && !in_array($lesson_id, $completed_lessons)) { + $completed_lessons[] = $lesson_id; + sort($completed_lessons); + } + + // Hitung completion dengan benar (seperti referensi) + $completed_in_course = array_intersect($completed_lessons, $total_lesson); + $is_completed = count($total_lesson) > 0 && + count($completed_in_course) >= count($total_lesson); + + $data = [ + 'course_id' => $course_id, + 'student_id' => $student_id, + 'watching_lesson_id' => $lesson_id, + 'completed_lesson' => json_encode($completed_lessons, JSON_NUMERIC_CHECK), // Gunakan JSON_NUMERIC_CHECK + 'completed_date' => $is_completed ? date('Y-m-d H:i:s') : null, // Format MySQL datetime + ]; + + // **FIX: Update dengan student_id yang benar (bukan auth user)** + Watch_history::where('course_id', $course_id) + ->where('student_id', $student_id) + ->update($data); + + // Log untuk debugging + \Log::info('Project submission watch history updated:', [ + 'project_submission_id' => $id, + 'student_id' => $student_id, + 'course_id' => $course_id, + 'lesson_id' => $lesson_id, + 'completed_lessons' => $completed_lessons, + 'is_completed' => $is_completed, + 'total_lessons_in_course' => count($total_lesson) + ]); + + } else { + // **Jika tidak ada watch_history, buat baru** + // Hanya buat jika project DITERIMA (status 1) + if ($request->status == 1) { + $completed_lessons = [$lesson_id]; + + // Hitung completion untuk data baru + $is_completed = count($total_lesson) == 1 && in_array($lesson_id, $total_lesson); + + $data = [ + 'course_id' => $course_id, + 'student_id' => $student_id, + 'watching_lesson_id' => $lesson_id, + 'completed_lesson' => json_encode($completed_lessons, JSON_NUMERIC_CHECK), + 'completed_date' => $is_completed ? date('Y-m-d H:i:s') : null, + 'created_at' => now(), + 'updated_at' => now(), + ]; + + Watch_history::create($data); + + \Log::info('New watch history created from project submission:', [ + 'project_submission_id' => $id, + 'student_id' => $student_id, + 'course_id' => $course_id, + 'lesson_id' => $lesson_id + ]); + } + } + + // **LOGIKA SERTIFIKAT - dengan progress yang benar** + $completed_lessons = $completed_lessons ?? []; + $completed_in_course = array_intersect($completed_lessons, $total_lesson); + $completed_count = count($completed_in_course); + $total_count = count($total_lesson); + + $progress_percentage = 0; + if ($total_count > 0) { + $progress_percentage = ($completed_count / $total_count) * 100; + } + + // Jika progress 100% dan status project diterima, buat sertifikat + if ($progress_percentage >= 100 && $request->status == 1) { + $certificateExists = Certificate::where('user_id', $student_id) + ->where('course_id', $course_id) + ->exists(); + + if (!$certificateExists) { + // Cek jika method generateIdentifier ada + if (method_exists($this, 'generateIdentifier')) { + $identifier = $this->generateIdentifier(12); + } else { + // Fallback ke random string + $identifier = \Illuminate\Support\Str::random(12); + } + + Certificate::create([ + 'user_id' => $student_id, + 'course_id' => $course_id, + 'identifier' => $identifier, + ]); + + \Log::info('Certificate created after project submission:', [ + 'student_id' => $student_id, + 'course_id' => $course_id, + 'project_submission_id' => $id + ]); + } + } + + return redirect()->back()->with('success', get_phrase('Project graded successfully')); + } +} diff --git a/app/Http/Controllers/Admin/QuizController.php b/app/Http/Controllers/Admin/QuizController.php index c34e379..bc5d50c 100644 --- a/app/Http/Controllers/Admin/QuizController.php +++ b/app/Http/Controllers/Admin/QuizController.php @@ -56,6 +56,10 @@ class QuizController extends Controller return redirect()->back(); } + $maxSort = Lesson::where('section_id', $request->section) + ->max('sort'); + $data['user_id'] = auth()->user()->id; + $data['sort'] = $maxSort + 1; $data['title'] = $request->title; $data['course_id'] = $request->course_id; $data['section_id'] = $request->section; diff --git a/app/Http/Controllers/SettingController.php b/app/Http/Controllers/SettingController.php index 9131de7..3c821b7 100644 --- a/app/Http/Controllers/SettingController.php +++ b/app/Http/Controllers/SettingController.php @@ -657,11 +657,41 @@ class SettingController extends Controller return redirect(route('admin.certificate.settings'))->with('success', get_phrase('Certificate template has been updated')); } + function certificate_update_template_details(Request $request) + { + $request->validate(['certificate_template_details' => 'required|image']); + + $row = Setting::where('type', 'certificate_template_details'); + + if ($row->count() > 0) { + remove_file(get_settings('certificate_template_details')); + $path = FileUploader::upload($request->certificate_template_details, 'uploads/certificate-template-details', 1000); + Setting::where('type', 'certificate_template_details')->update(['description' => $path]); + } else { + $path = FileUploader::upload($request->certificate_template_details, 'uploads/certificate-template-details', 1000); + Setting::insert(['type' => 'certificate_template_details', 'description' => $path]); + } + + $certificate_builder_content = get_settings('certificate_builder_content'); + if ($certificate_builder_content) { + // Use regular expression to replace the image source + $modifiedHtml = preg_replace('/(]+src=")([^"]+)(")/', '$1' . get_image($path) . '$3', $certificate_builder_content); + Setting::where('type', 'certificate_builder_content')->update(['description' => $modifiedHtml]); + } + + return redirect(route('admin.certificate.settings'))->with('success', get_phrase('Certificate template has been updated')); + } + function certificate_builder() { return view('admin.certificate.builder'); } + function certificate_builder_details() + { + return view('admin.certificate.builder_details'); + } + function certificate_builder_update(Request $request) { $request->validate(['certificate_builder_content' => 'required']); @@ -677,6 +707,20 @@ class SettingController extends Controller return route('admin.certificate.settings'); } + function certificate_builder_details_update(Request $request) + { + $request->validate(['certificate_builder_content_details' => 'required']); + + $row = Setting::where('type', 'certificate_builder_content_details'); + if ($row->count() > 0) { + Setting::where('type', 'certificate_builder_content_details')->update(['description' => $request->certificate_builder_content_details]); + } else { + Setting::insert(['type' => 'certificate_builder_content_details', 'description' => $request->certificate_builder_content_details]); + } + Session::flash('success', get_phrase('Certificate builder template has been updated')); + return route('admin.certificate.settings'); + } + //User Review Add public function user_review_add() { diff --git a/app/Http/Controllers/instructor/ProjectController.php b/app/Http/Controllers/instructor/ProjectController.php index 42db41d..b841fe7 100644 --- a/app/Http/Controllers/instructor/ProjectController.php +++ b/app/Http/Controllers/instructor/ProjectController.php @@ -14,39 +14,32 @@ class ProjectController extends Controller { public function update(Request $request, $id) { - $request->validate([ - 'status' => 'required|in:1,2', - 'comment' => 'required_if:status,2', + $validator = Validator::make($request->all(), [ + 'title' => 'required', + 'section' => 'required|numeric', + 'course_id' => 'required' ]); - $submission = ProjectSubmission::findOrFail($id); - - $submission->status = $request->status; - $submission->reviewed_by = auth()->id(); - $submission->reviewed_at = now(); - - if ($request->status == 1) { - $submission->comment = null; - } else { - $submission->comment = $request->comment; + if ($validator->fails()) { + return redirect()->back()->withErrors($validator)->withInput(); } - $submission->save(); + $data['title'] = $request->title; + $data['course_id'] = $request->course_id; + $data['section_id'] = $request->section; + $data['description'] = $request->description; + $data['attachment'] = $request->attachment; + $data['summary'] = $request->summary; - return redirect()->back()->with('success', get_phrase('Project graded successfully')); + + Lesson::where('id', $id)->update($data); + + Session::flash('success', get_phrase('Project has been updated.')); + return redirect()->back(); } public function store(Request $request) { - $title = Lesson::join('sections', 'lessons.section_id', 'sections.id') - ->join('courses', 'sections.course_id', 'courses.id') - ->where('courses.user_id', auth()->user()->id) - ->where('lessons.title', $request->title) - ->first(); - if ($title) { - Session::flash('error', get_phrase('Title has been taken.')); - return redirect()->back(); - } $maxSort = Lesson::where('section_id', $request->section) ->max('sort'); @@ -56,8 +49,8 @@ class ProjectController extends Controller $data['title'] = $request->title; $data['course_id'] = $request->course_id; $data['section_id'] = $request->section; - $data['description'] = $request->description; $data['attachment'] = $request->attachment; + $data['description'] = $request->description; $data['summary'] = $request->summary; $data['lesson_type'] = 'project'; $data['status'] = 1; @@ -68,10 +61,11 @@ class ProjectController extends Controller return redirect()->back(); } - public function getIndex($id) + public function getSubmissions($id) { $participants = ProjectSubmission::join('users', 'project_submissions.user_id', '=', 'users.id') ->where('project_submissions.lesson_id', $id) + ->where('project_submissions.status', 0) ->select('users.name', 'users.id') ->distinct() ->get(); diff --git a/resources/views/admin/certificate/builder_details.blade.php b/resources/views/admin/certificate/builder_details.blade.php new file mode 100644 index 0000000..d6f9049 --- /dev/null +++ b/resources/views/admin/certificate/builder_details.blade.php @@ -0,0 +1,849 @@ + + + + + {{ get_phrase('Certificate') }} + + + + {{-- FlatIcons --}} + + + + + + + + + {{-- Font Awesome untuk ikon tambahan --}} + + + + + + + + + + + + + + + + +
+ {{-- Common style for page builder start --}} + + {{-- Common style for page builder END --}} + + @if (get_settings('certificate_builder_content_details')) + @php + $htmlContent = get_settings('certificate_builder_content_details'); + $newSrc = get_image(get_settings('certificate_template_details')); + $certificate_builder_content_details = preg_replace('/(]*class=["\']certificate-template["\'][^>]*src=["\'])([^"\']*)(["\'])/i', '${1}' . $newSrc . '${3}', $htmlContent); + @endphp + {!! $certificate_builder_content_details !!} + @else +
+ +
+ @endif +
+ + + + + \ No newline at end of file diff --git a/resources/views/admin/certificate/index.blade.php b/resources/views/admin/certificate/index.blade.php index 50709fd..420bc2b 100644 --- a/resources/views/admin/certificate/index.blade.php +++ b/resources/views/admin/certificate/index.blade.php @@ -32,7 +32,7 @@
-

{{ get_phrase('Certificate template') }}

+

{{ get_phrase('Certificate Template Main') }}

@php $htmlContent = get_settings('certificate_builder_content'); @@ -47,7 +47,7 @@
-

{{ get_phrase('Certificate template') }}

+

{{ get_phrase('Certificate Template Main') }}

@csrf @@ -55,7 +55,7 @@
- +
@@ -66,6 +66,44 @@
+ +
+
+
+

{{ get_phrase('Certificate Template Details') }}

+
+ @php + $htmlContent = get_settings('certificate_builder_content_details'); + // Use regex to update the src attribute of the tag with the class 'certificate-template'. + $newSrc = get_image(get_settings('certificate_template_details')); + $certificate_builder_content = preg_replace('/(]*class=["\']certificate-template["\'][^>]*src=["\'])([^"\']*)(["\'])/i', '${1}' . $newSrc . '${3}', $htmlContent); + @endphp + {!! $certificate_builder_content !!} + {{ get_phrase('Build your certificate') }} +
+
+
+
+
+

{{ get_phrase('Certificate Template Details') }}

+
+ + @csrf +
+ +
+
+ + +
+
+ +
+ +
+
+
+
@endsection @push('js') diff --git a/resources/views/admin/course/curriculum.blade.php b/resources/views/admin/course/curriculum.blade.php index 43f5714..ef5d0a6 100644 --- a/resources/views/admin/course/curriculum.blade.php +++ b/resources/views/admin/course/curriculum.blade.php @@ -10,6 +10,8 @@ {{ get_phrase('Add quiz') }} {{ get_phrase('Sort Section') }} + + {{ get_phrase('Add project') }} @endif
@@ -57,7 +59,7 @@
@if ($lesson->lesson_type == 'quiz') - + @@ -67,9 +69,20 @@ + @elseif ($lesson->lesson_type == 'project') + + + + + + @endif - @if ($lesson->lesson_type != 'quiz') + @if ($lesson->lesson_type != 'quiz' && $lesson->lesson_type != 'project') diff --git a/resources/views/admin/project/create.blade.php b/resources/views/admin/project/create.blade.php new file mode 100644 index 0000000..32ce5b5 --- /dev/null +++ b/resources/views/admin/project/create.blade.php @@ -0,0 +1,50 @@ +
@csrf + + +
+ + +
+ +
+
+ + +
+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+
+ +@include('admin.init') diff --git a/resources/views/admin/project/edit.blade.php b/resources/views/admin/project/edit.blade.php new file mode 100644 index 0000000..1dad468 --- /dev/null +++ b/resources/views/admin/project/edit.blade.php @@ -0,0 +1,63 @@ +@php + $project = App\Models\Lesson::join('sections', 'lessons.section_id', 'sections.id') + ->join('courses', 'sections.course_id', 'courses.id') + ->select('lessons.*', 'courses.id as course_id') + ->where('lessons.id', $id) + ->first(); +@endphp + +
@csrf + + {{-- FIX: Pass the course_id back to the controller --}} + + +
+ + +
+ +
+
+ + +
+
+ +
+ + +
+ +
+ + {{-- Ensure your Controller handles $request->attachment --}} + +
+ +
+ + +
+ +
+ +
+
+ +@include('admin.init') diff --git a/resources/views/admin/project/grading/index.blade.php b/resources/views/admin/project/grading/index.blade.php new file mode 100644 index 0000000..012cf9c --- /dev/null +++ b/resources/views/admin/project/grading/index.blade.php @@ -0,0 +1,121 @@ +{{-- Container Utama --}} +
+ + {{-- KOLOM KIRI: LIST SISWA --}} +
+
+
{{ get_phrase('Student List') }}
+
+ +
+ @if($participants->isEmpty()) +
+ {{ get_phrase('No participants found.') }} +
+ @else + @foreach ($participants as $participant) + + +
+
+ {{ strtoupper(substr($participant->name, 0, 1)) }} +
+ +
+
{{ $participant->name }}
+ {{ get_phrase('Click to grade') }} +
+ +
+
+ @endforeach + @endif +
+
+ + {{-- KOLOM KANAN: AREA PREVIEW & GRADING --}} +
+ {{-- ID ini penting: target AJAX --}} +
+ + {{-- State Awal (Belum Klik) --}} +
+
+ +
+
{{ get_phrase('Select a student to start grading') }}
+
+ +
+
+
+ + \ No newline at end of file diff --git a/resources/views/admin/project/grading/preview.blade.php b/resources/views/admin/project/grading/preview.blade.php new file mode 100644 index 0000000..bdb24d6 --- /dev/null +++ b/resources/views/admin/project/grading/preview.blade.php @@ -0,0 +1,182 @@ +{{-- HAPUS
jika ada, gunakan div biasa --}} +
+ + {{-- KONDISI 1: Belum Submit --}} + @if(!$submission) +
+
+ +
+
{{ get_phrase('Not Submitted') }}
+

{{ get_phrase('This student has not submitted the project yet.') }}

+
+ + {{-- KONDISI 2: Sudah Submit --}} + @else +
+ {{-- Header Status --}} +
+
+
{{ get_phrase('Project Submission') }}
+ + + {{ date('d M Y, H:i', strtotime($submission->created_at)) }} + +
+
+ @if($submission->status == 1) + {{ get_phrase('Accepted') }} + @elseif($submission->status == 2) + {{ get_phrase('Revision Needed') }} + @else + {{ get_phrase('Pending Review') }} + @endif +
+
+ + {{-- Link Project --}} +
+ + +
+ + {{-- Form Grading --}} +
+
+
+ @csrf +
{{ get_phrase('Grading') }}
+ +
+
+ status == 1 ? 'checked' : '' }} onchange="toggleComment(this)"> + + + status == 2 ? 'checked' : '' }} onchange="toggleComment(this)"> + +
+
+ + {{-- Area Komentar dengan WYSIWYG Editor --}} +
+
+ + + {{-- Textarea untuk Summernote --}} + +
+
+ + +
+
+
+
+ @endif +
+ +{{-- Tambahkan CSS Summernote --}} + + +{{-- Tambahkan Script Summernote --}} + + + \ No newline at end of file diff --git a/resources/views/course_player/project/index.blade.php b/resources/views/course_player/project/index.blade.php index d83d871..3807f57 100644 --- a/resources/views/course_player/project/index.blade.php +++ b/resources/views/course_player/project/index.blade.php @@ -8,21 +8,10 @@ @endphp diff --git a/resources/views/course_player/side_bar.blade.php b/resources/views/course_player/side_bar.blade.php index 7d25c4d..24f187b 100644 --- a/resources/views/course_player/side_bar.blade.php +++ b/resources/views/course_player/side_bar.blade.php @@ -98,7 +98,7 @@

{{ $lesson->lesson_type }}

- @if (in_array($type, ['google_drive', 'video-url', 'quiz'])) + @if (in_array($type, ['google_drive', 'video-url', 'quiz', 'project'])) {{ $lesson->title }} diff --git a/resources/views/curriculum/certificate/download.blade.php b/resources/views/curriculum/certificate/download.blade.php index 9dd65fb..7fb8dac 100644 --- a/resources/views/curriculum/certificate/download.blade.php +++ b/resources/views/curriculum/certificate/download.blade.php @@ -26,7 +26,7 @@ display: none !important; } - .certificate-layout-module { + .certificate-layout-module { left: unset !important; top: unset !important; margin-left: auto !important; @@ -38,6 +38,11 @@ height: 100%; } + .certificate-page { + width: 1123px; + height: 794px; + } + .download-wrapper { position: fixed; bottom: 20px; @@ -123,201 +128,220 @@ } + @php + $bulan_indonesia = [ + 1 => 'Januari', 2 => 'Februari', 3 => 'Maret', 4 => 'April', + 5 => 'Mei', 6 => 'Juni', 7 => 'Juli', 8 => 'Agustus', + 9 => 'September', 10 => 'Oktober', 11 => 'November', 12 => 'Desember' + ]; + + $completion_date = $certificate->created_at; + $timestamp = strtotime($completion_date); + $hari = date('j', $timestamp); + $bulan_angka = (int)date('n', $timestamp); + $tahun = date('Y', $timestamp); + + $course_completion_date = $hari . ' ' . $bulan_indonesia[$bulan_angka] . ' ' . $tahun; + $course_duration = $certificate->course->total_duration(); + $student_name = $certificate->user->name; + $course_title = $certificate->course->title; + $number_of_lesson = $certificate->course->lessons->count(); + $qr_code = $qrcode; + $certificate_id = $certificate->identifier; + $certificate_download_date = date('d M Y'); + $course_level = ucfirst($certificate->course->level); + $course_language = ucfirst($certificate->course->language); - {{-- Downloadable canvas --}} -
- @php - $bulan_indonesia = [ - 1 => 'Januari', - 2 => 'Februari', - 3 => 'Maret', - 4 => 'April', - 5 => 'Mei', - 6 => 'Juni', - 7 => 'Juli', - 8 => 'Agustus', - 9 => 'September', - 10 => 'Oktober', - 11 => 'November', - 12 => 'Desember' - ]; - - // Jika date_formatter() mengembalikan tanggal string - $completion_date = $certificate->created_at; // Ambil timestamp asli - - // Konversi ke format Indonesia - $timestamp = strtotime($completion_date); // atau $completion_date jika sudah timestamp - $hari = date('j', $timestamp); // tanggal tanpa nol - $bulan_angka = (int)date('n', $timestamp); // bulan angka - $tahun = date('Y', $timestamp); - - $course_completion_date = $hari . ' ' . $bulan_indonesia[$bulan_angka] . ' ' . $tahun; - $course_duration = $certificate->course->total_duration(); - $student_name = $certificate->user->name; - $course_title = $certificate->course->title; - $number_of_lesson = $certificate->course->lessons->count(); - $qr_code = $qrcode; - $certificate_id = $certificate->identifier; - $certificate_download_date = date('d M Y'); - $course_level = ucfirst($certificate->course->level); - $course_language = ucfirst($certificate->course->language); - $instructor_name = ''; - - foreach ($certificate->course->instructors() as $instructor) { - $instructor_name .= '

' . $instructor->name . '

'; - } - - $certificate_builder_content = get_settings('certificate_builder_content'); - $certificate_builder_content = str_replace('{course_duration}', $course_duration, $certificate_builder_content); - $certificate_builder_content = str_replace('{instructor_name}', $instructor_name, $certificate_builder_content); - $certificate_builder_content = str_replace('{student_name}', $student_name, $certificate_builder_content); - $certificate_builder_content = str_replace('{course_title}', $course_title, $certificate_builder_content); - $certificate_builder_content = str_replace('{number_of_lesson}', $number_of_lesson, $certificate_builder_content); - $certificate_builder_content = str_replace('{qr_code}', $qr_code, $certificate_builder_content); - $certificate_builder_content = str_replace('{course_completion_date}', $course_completion_date, $certificate_builder_content); - $certificate_builder_content = str_replace('{certificate_id}', $certificate_id, $certificate_builder_content); - $certificate_builder_content = str_replace('{certificate_download_date}', $certificate_download_date, $certificate_builder_content); - $certificate_builder_content = str_replace('{course_level}', $course_level, $certificate_builder_content); - $certificate_builder_content = str_replace('{course_language}', $course_language, $certificate_builder_content); - - // Use regex to update the src attribute of the tag with the class 'certificate-template'. - $newSrc = get_image(get_settings('certificate_template')); - $certificate_builder_content = preg_replace('/(]*class=["\']certificate-template["\'][^>]*src=["\'])([^"\']*)(["\'])/i', '${1}' . $newSrc . '${3}', $certificate_builder_content); - @endphp - - {!! $certificate_builder_content !!} -
- {{-- Downloadable canvas end--}} - - - {{-- Preview certificate --}} -
-
- {!! $certificate_builder_content !!} -
-
- {{-- Preview certificate end--}} - - -
- - - - + const canvas = await html2canvas(pageElement, { + allowTaint: true, + useCORS: true, + scale: 2, // cukup tajam, jangan kebesaran + backgroundColor: '#ffffff' + }); + + const imgData = canvas.toDataURL("image/png"); + + if (i > 0) pdf.addPage(); + + // 🔥 FULL PAGE – TANPA WHITESPACE + pdf.addImage( + imgData, + 'PNG', + 0, + 0, + pageWidth, + pageHeight, + undefined, + 'FAST' + ); + } + + const courseTitle = {!! json_encode($course_title) !!}; + const fileName = `Grownesesa Certificate - ${courseTitle}.pdf`; + pdf.save(fileName); + } + + + diff --git a/resources/views/instructor/project/create.blade.php b/resources/views/instructor/project/create.blade.php index 27adebb..1d57e40 100644 --- a/resources/views/instructor/project/create.blade.php +++ b/resources/views/instructor/project/create.blade.php @@ -15,7 +15,7 @@ {{ get_phrase('Section') }} * - @foreach (App\Models\Section::where('course_id', $id)->get() as $section) @@ -37,9 +37,9 @@
- - +
diff --git a/resources/views/instructor/project/edit.blade.php b/resources/views/instructor/project/edit.blade.php index 5af7d24..2d5c1f5 100644 --- a/resources/views/instructor/project/edit.blade.php +++ b/resources/views/instructor/project/edit.blade.php @@ -7,6 +7,10 @@ @endphp
@csrf + + {{-- FIX: Pass the course_id back to the controller --}} + +
- @foreach (App\Models\Section::where('course_id', $project->course_id)->get() as $section)
-@include('instructor.init') +@include('instructor.init') \ No newline at end of file diff --git a/routes/admin.php b/routes/admin.php index 02d844f..f1c23ec 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -10,6 +10,7 @@ use App\Http\Controllers\Admin\MessageController; use App\Http\Controllers\Admin\OfflinePaymentController; use App\Http\Controllers\Admin\OpenAiController; use App\Http\Controllers\Admin\PageBuilderController; +use App\Http\Controllers\Admin\ProjectController; use App\Http\Controllers\Admin\QuestionController; use App\Http\Controllers\Admin\QuizController; use App\Http\Controllers\Admin\TeamTrainingController; @@ -256,8 +257,11 @@ Route::name('admin.')->prefix('admin')->middleware('admin')->group(function () { // Certificate settings Route::get('certificate_settings', 'certificate')->name('certificate.settings'); Route::post('certificate/update/template', 'certificate_update_template')->name('certificate.update.template'); + Route::post('certificate/update/template/details', 'certificate_update_template_details')->name('certificate.update.template.details'); Route::get('certificate/builder', 'certificate_builder')->name('certificate.builder'); Route::post('certificate/builder/update', 'certificate_builder_update')->name('certificate.certificate.builder.update'); + Route::get('certificate/builder_details', 'certificate_builder_details')->name('certificate.builder_details'); + Route::post('certificate/builder/update/details', 'certificate_builder_details_update')->name('certificate.builder.details.update'); // Admin User Review Add Route::get('user/review', 'user_review_add')->name('review.create'); @@ -356,6 +360,16 @@ Route::name('admin.')->prefix('admin')->middleware('admin')->group(function () { Route::get('quiz/result/preview', 'result_preview')->name('quiz.result.preview'); }); + // course project + Route::controller(ProjectController::class)->group(function () { + Route::post('course/project/store', 'store')->name('course.project.store'); + Route::post('course/project/update/{id}', 'update')->name('course.project.update'); + Route::get('/project/grading/preview', 'getPreview')->name('project.grading.preview'); + Route::get('/project/grading/{id}', 'getSubmissions')->name('project.grading.index'); + Route::get('/project/participant/submission', 'getParticipantSubmission')->name('project.participant.submission'); + Route::post('/project/grading/update/{id}', 'updateSubmission')->name('project.grading.update'); + }); + // question route Route::controller(QuestionController::class)->group(function () { Route::post('course/question/store', 'store')->name('course.question.store'); diff --git a/routes/instructor.php b/routes/instructor.php index 9d7986c..421f01b 100644 --- a/routes/instructor.php +++ b/routes/instructor.php @@ -82,7 +82,7 @@ Route::name('instructor.')->prefix('instructor')->middleware(['instructor'])->gr Route::post('course/project/store', 'store')->name('course.project.store'); Route::post('course/project/update/{id}', 'update')->name('course.project.update'); Route::get('/project/grading/preview', 'getPreview')->name('project.grading.preview'); - Route::get('/project/grading/{id}', 'getIndex')->name('project.grading.index'); + Route::get('/project/grading/{id}', 'getSubmissions')->name('project.grading.index'); Route::get('/project/participant/submission', 'getParticipantSubmission')->name('project.participant.submission'); Route::post('/project/grading/update/{id}', 'updateSubmission')->name('project.grading.update'); });