From 5785ad88fc2afe040851b9ad77462ae3f12185e6 Mon Sep 17 00:00:00 2001 From: RetasyaSalsabila Date: Sun, 19 Apr 2026 22:42:42 +0700 Subject: [PATCH] a lot things added and fixed --- .../Controllers/Admin/ChallengeController.php | 10 +- app/Http/Controllers/Admin/GuruController.php | 53 ++ .../Controllers/Admin/KelasController.php | 46 ++ .../Controllers/Admin/MapelController.php | 61 +- .../Controllers/Admin/SiswaController.php | 59 ++ app/Models/Challenge.php | 4 + app/Providers/AppServiceProvider.php | 11 +- composer.json | 1 + composer.lock | 524 ++++++++++++++- ..._durasi_pengerjaan_to_challenges_table.php | 24 + .../views/admin/challenge/index.blade.php | 635 +++++++++--------- resources/views/admin/guru/index.blade.php | 14 +- resources/views/admin/guru/pdf.blade.php | 62 ++ resources/views/admin/kelas/index.blade.php | 9 +- resources/views/admin/kelas/pdf.blade.php | 52 ++ resources/views/admin/mapel/index.blade.php | 10 +- resources/views/admin/mapel/pdf.blade.php | 56 ++ resources/views/admin/siswa/index.blade.php | 9 +- resources/views/admin/siswa/pdf.blade.php | 56 ++ .../views/siswa/challenge/kerjakan.blade.php | 247 ++++--- .../vendor/pagination/bootstrap-4.blade.php | 46 ++ .../vendor/pagination/bootstrap-5.blade.php | 119 ++++ .../views/vendor/pagination/default.blade.php | 46 ++ .../vendor/pagination/semantic-ui.blade.php | 36 + .../pagination/simple-bootstrap-4.blade.php | 27 + .../pagination/simple-bootstrap-5.blade.php | 29 + .../pagination/simple-default.blade.php | 19 + .../pagination/simple-tailwind.blade.php | 25 + .../vendor/pagination/tailwind.blade.php | 106 +++ routes/web.php | 30 +- 30 files changed, 1939 insertions(+), 487 deletions(-) create mode 100644 database/migrations/2026_04_19_131126_add_durasi_pengerjaan_to_challenges_table.php create mode 100644 resources/views/admin/guru/pdf.blade.php create mode 100644 resources/views/admin/kelas/pdf.blade.php create mode 100644 resources/views/admin/mapel/pdf.blade.php create mode 100644 resources/views/admin/siswa/pdf.blade.php create mode 100644 resources/views/vendor/pagination/bootstrap-4.blade.php create mode 100644 resources/views/vendor/pagination/bootstrap-5.blade.php create mode 100644 resources/views/vendor/pagination/default.blade.php create mode 100644 resources/views/vendor/pagination/semantic-ui.blade.php create mode 100644 resources/views/vendor/pagination/simple-bootstrap-4.blade.php create mode 100644 resources/views/vendor/pagination/simple-bootstrap-5.blade.php create mode 100644 resources/views/vendor/pagination/simple-default.blade.php create mode 100644 resources/views/vendor/pagination/simple-tailwind.blade.php create mode 100644 resources/views/vendor/pagination/tailwind.blade.php diff --git a/app/Http/Controllers/Admin/ChallengeController.php b/app/Http/Controllers/Admin/ChallengeController.php index e710d5c..7d88cc0 100644 --- a/app/Http/Controllers/Admin/ChallengeController.php +++ b/app/Http/Controllers/Admin/ChallengeController.php @@ -38,8 +38,8 @@ public function store(Request $request) 'judul_challenge' => 'required|string|max:200', 'deskripsi' => 'nullable|string', 'exp' => 'required|integer|min:0', - 'id_badge' => 'nullable|exists:badges,id_badge', 'tenggat_waktu' => 'required|date|after:now', + 'durasi_pengerjaan' => 'required|integer|min:1|max:360', 'id_kelas' => 'required|array|min:1', 'id_kelas.*' => 'exists:kelas,id_kelas', // Soal @@ -67,11 +67,14 @@ public function store(Request $request) 'exp' => $request->exp, 'id_badge' => $request->id_badge, 'tenggat_waktu' => $request->tenggat_waktu, + 'durasi_pengerjaan' => $request->durasi_pengerjaan, ]); // Attach ke kelas $challenge->kelas()->sync($request->id_kelas); + $challenge->soal()->delete(); + // Simpan soal foreach ($request->pertanyaan as $i => $pertanyaan) { SoalChallenge::create([ @@ -113,8 +116,8 @@ public function update(Request $request, $id) 'judul_challenge' => 'required|string|max:200', 'deskripsi' => 'nullable|string', 'exp' => 'required|integer|min:0', - 'id_badge' => 'nullable|exists:badges,id_badge', 'tenggat_waktu' => 'required|date', + 'durasi_pengerjaan' => 'required|integer|min:1|max:360', 'id_kelas' => 'required|array|min:1', 'id_kelas.*' => 'exists:kelas,id_kelas', 'pertanyaan' => 'required|array|min:1', @@ -134,6 +137,7 @@ public function update(Request $request, $id) 'exp' => $request->exp, 'id_badge' => $request->id_badge, 'tenggat_waktu' => $request->tenggat_waktu, + 'durasi_pengerjaan' => $request->durasi_pengerjaan, ]); $challenge->kelas()->sync($request->id_kelas); @@ -178,8 +182,8 @@ public function editData($id) 'judul_challenge' => $challenge->judul_challenge, 'deskripsi' => $challenge->deskripsi, 'exp' => $challenge->exp, - 'id_badge' => $challenge->id_badge, 'tenggat_waktu' => $challenge->tenggat_waktu, + 'durasi_pengerjaan' => $challenge->durasi_pengerjaan, 'kelas' => $challenge->kelas->pluck('id_kelas'), 'soal' => $challenge->soal, ]); diff --git a/app/Http/Controllers/Admin/GuruController.php b/app/Http/Controllers/Admin/GuruController.php index f54f282..4f4a375 100644 --- a/app/Http/Controllers/Admin/GuruController.php +++ b/app/Http/Controllers/Admin/GuruController.php @@ -9,6 +9,7 @@ use App\Models\Mengajar; use Illuminate\Http\Request; use Illuminate\Support\Facades\Hash; +use Barryvdh\DomPDF\Facade\Pdf; class GuruController extends Controller { @@ -148,6 +149,58 @@ public function destroy(string $id) ->with('success', 'Data guru berhasil dihapus.'); } + public function downloadPdf(Request $request) +{ + $query = Guru::with('mengajars.mapel', 'mengajars.kelas'); + if ($request->filled('search')) { + $search = $request->search; + $query->where(function($q) use ($search) { + $q->where('nama', 'like', "%$search%") + ->orWhere('nip', 'like', "%$search%"); + }); + } + $gurus = $query->get(); + + $pdf = Pdf::loadView('admin.guru.pdf', compact('gurus')) + ->setPaper('a4', 'landscape'); + + return $pdf->download('daftar-guru-' . date('Ymd') . '.pdf'); +} + +public function downloadExcel(Request $request) +{ + $query = Guru::with('mengajars.mapel', 'mengajars.kelas'); + if ($request->filled('search')) { + $search = $request->search; + $query->where(function($q) use ($search) { + $q->where('nama', 'like', "%$search%") + ->orWhere('nip', 'like', "%$search%"); + }); + } + $gurus = $query->get(); + + $filename = 'daftar-guru-' . date('Ymd') . '.csv'; + $headers = [ + 'Content-Type' => 'text/csv', + 'Content-Disposition' => "attachment; filename=\"$filename\"", + ]; + + $callback = function () use ($gurus) { + $file = fopen('php://output', 'w'); + // BOM agar Excel bisa baca UTF-8 + fprintf($file, chr(0xEF).chr(0xBB).chr(0xBF)); + fputcsv($file, ['No', 'Nama', 'NIP', 'Mata Pelajaran', 'Kelas']); + foreach ($gurus as $i => $guru) { + $mapels = $guru->mengajars->map(fn($m) => optional($m->mapel)->nama_mapel ?? '-')->join(', '); + $kelas = $guru->mengajars->map(fn($m) => (optional($m->kelas)->tingkat . ' ' . optional($m->kelas)->nama_kelas))->join(', '); + fputcsv($file, [$i + 1, $guru->nama, $guru->nip, $mapels, $kelas]); + } + fclose($file); + }; + + return response()->stream($callback, 200, $headers); +} + /** * API: Ambil kelas yang memiliki mapel tertentu (lewat tabel mengajars) * Dipanggil via AJAX saat admin pilih mapel di modal diff --git a/app/Http/Controllers/Admin/KelasController.php b/app/Http/Controllers/Admin/KelasController.php index 764d0af..d2d124a 100644 --- a/app/Http/Controllers/Admin/KelasController.php +++ b/app/Http/Controllers/Admin/KelasController.php @@ -6,6 +6,7 @@ use App\Models\Kelas; use Illuminate\Http\Request; use Illuminate\Validation\Rule; +use Barryvdh\DomPDF\Facade\Pdf; class KelasController extends Controller @@ -88,4 +89,49 @@ public function destroy($id_kelas) return redirect()->route('admin.kelas.index') ->with('success', 'Data kelas berhasil dihapus!'); } + + public function downloadPdf(Request $request) +{ + $query = Kelas::query(); + if ($request->filled('search')) { + $search = $request->search; + $query->where('nama_kelas', 'like', "%$search%") + ->orWhere('id_kelas', 'like', "%$search%"); + } + $kelass = $query->get(); + + $pdf = Pdf::loadView('admin.kelas.pdf', compact('kelass')) + ->setPaper('a4', 'portrait'); + + return $pdf->download('daftar-kelas-' . date('Ymd') . '.pdf'); +} + +public function downloadExcel(Request $request) +{ + $query = Kelas::query(); + if ($request->filled('search')) { + $search = $request->search; + $query->where('nama_kelas', 'like', "%$search%") + ->orWhere('id_kelas', 'like', "%$search%"); + } + $kelass = $query->get(); + + $filename = 'daftar-kelas-' . date('Ymd') . '.csv'; + $headers = [ + 'Content-Type' => 'text/csv', + 'Content-Disposition' => "attachment; filename=\"$filename\"", + ]; + + $callback = function () use ($kelass) { + $file = fopen('php://output', 'w'); + fprintf($file, chr(0xEF).chr(0xBB).chr(0xBF)); + fputcsv($file, ['No', 'ID Kelas', 'Nama Kelas', 'Tingkat']); + foreach ($kelass as $i => $kelas) { + fputcsv($file, [$i + 1, $kelas->id_kelas, $kelas->nama_kelas, $kelas->tingkat]); + } + fclose($file); + }; + + return response()->stream($callback, 200, $headers); +} } diff --git a/app/Http/Controllers/Admin/MapelController.php b/app/Http/Controllers/Admin/MapelController.php index a3e9509..08d957a 100644 --- a/app/Http/Controllers/Admin/MapelController.php +++ b/app/Http/Controllers/Admin/MapelController.php @@ -7,6 +7,7 @@ use App\Models\Kelas; use App\Models\Mengajar; use Illuminate\Http\Request; +use Barryvdh\DomPDF\Facade\Pdf; class MapelController extends Controller { @@ -116,8 +117,6 @@ public function update(Request $request, $id) ->with('success', 'Data mata pelajaran berhasil diupdate!'); } - - public function destroy($id) { @@ -130,4 +129,62 @@ public function destroy($id) return redirect()->route('admin.mapel.index') ->with('success', 'Data mata pelajaran berhasil dihapus!'); } + + public function downloadPdf(Request $request) +{ + $query = Mapel::with('kelas'); + if ($request->filled('search')) { + $query->where(function($q) use ($request) { + $q->where('nama_mapel', 'like', "%$request->search%") + ->orWhere('id_mapel', 'like', "%$request->search%"); + }); + } + if ($request->filled('filter_kelas')) { + $query->whereHas('kelas', function($q) use ($request) { + $q->where('kelas.id_kelas', $request->filter_kelas); + }); + } + $mapels = $query->get(); + + $pdf = Pdf::loadView('admin.mapel.pdf', compact('mapels')) + ->setPaper('a4', 'portrait'); + + return $pdf->download('daftar-mapel-' . date('Ymd') . '.pdf'); +} + +public function downloadExcel(Request $request) +{ + $query = Mapel::with('kelas'); + if ($request->filled('search')) { + $query->where(function($q) use ($request) { + $q->where('nama_mapel', 'like', "%$request->search%") + ->orWhere('id_mapel', 'like', "%$request->search%"); + }); + } + if ($request->filled('filter_kelas')) { + $query->whereHas('kelas', function($q) use ($request) { + $q->where('kelas.id_kelas', $request->filter_kelas); + }); + } + $mapels = $query->get(); + + $filename = 'daftar-mapel-' . date('Ymd') . '.csv'; + $headers = [ + 'Content-Type' => 'text/csv', + 'Content-Disposition' => "attachment; filename=\"$filename\"", + ]; + + $callback = function () use ($mapels) { + $file = fopen('php://output', 'w'); + fprintf($file, chr(0xEF).chr(0xBB).chr(0xBF)); + fputcsv($file, ['No', 'ID Mapel', 'Nama Mata Pelajaran', 'Kelas']); + foreach ($mapels as $i => $mapel) { + $kelas = $mapel->kelas->map(fn($k) => $k->tingkat . ' ' . $k->nama_kelas)->join(', '); + fputcsv($file, [$i + 1, $mapel->id_mapel, $mapel->nama_mapel, $kelas]); + } + fclose($file); + }; + + return response()->stream($callback, 200, $headers); +} } diff --git a/app/Http/Controllers/Admin/SiswaController.php b/app/Http/Controllers/Admin/SiswaController.php index cdfff82..ca34179 100644 --- a/app/Http/Controllers/Admin/SiswaController.php +++ b/app/Http/Controllers/Admin/SiswaController.php @@ -7,6 +7,7 @@ use App\Models\Kelas; use Illuminate\Http\Request; use Illuminate\Support\Facades\Hash; +use Barryvdh\DomPDF\Facade\Pdf; class SiswaController extends Controller { @@ -113,4 +114,62 @@ public function destroy($id) return redirect()->route('admin.siswa.index') ->with('success', 'Data siswa berhasil dihapus!'); } + + public function downloadPdf(Request $request) +{ + $query = Siswa::with('kelas'); + if ($request->filled('search')) { + $search = $request->search; + $query->where('nama', 'like', "%$search%") + ->orWhere('nisn', 'like', "%$search%"); + } + if ($request->filled('filter_kelas')) { + $query->where('id_kelas', $request->filter_kelas); + } + $siswas = $query->get(); + + $pdf = Pdf::loadView('admin.siswa.pdf', compact('siswas')) + ->setPaper('a4', 'landscape'); + + return $pdf->download('daftar-siswa-' . date('Ymd') . '.pdf'); +} + +public function downloadExcel(Request $request) +{ + $query = Siswa::with('kelas'); + if ($request->filled('search')) { + $search = $request->search; + $query->where('nama', 'like', "%$search%") + ->orWhere('nisn', 'like', "%$search%"); + } + if ($request->filled('filter_kelas')) { + $query->where('id_kelas', $request->filter_kelas); + } + $siswas = $query->get(); + + $filename = 'daftar-siswa-' . date('Ymd') . '.csv'; + $headers = [ + 'Content-Type' => 'text/csv', + 'Content-Disposition' => "attachment; filename=\"$filename\"", + ]; + + $callback = function () use ($siswas) { + $file = fopen('php://output', 'w'); + fprintf($file, chr(0xEF).chr(0xBB).chr(0xBF)); + fputcsv($file, ['No', 'NISN', 'Nama', 'Tempat Lahir', 'Tanggal Lahir', 'Kelas']); + foreach ($siswas as $i => $siswa) { + fputcsv($file, [ + $i + 1, + $siswa->nisn, + $siswa->nama, + $siswa->tempat_lahir, + \Carbon\Carbon::parse($siswa->tanggal_lahir)->format('d M Y'), + $siswa->kelas->tingkat . ' - ' . $siswa->kelas->nama_kelas, + ]); + } + fclose($file); + }; + + return response()->stream($callback, 200, $headers); +} } \ No newline at end of file diff --git a/app/Models/Challenge.php b/app/Models/Challenge.php index d64f508..e108ac1 100644 --- a/app/Models/Challenge.php +++ b/app/Models/Challenge.php @@ -19,8 +19,12 @@ class Challenge extends Model 'deskripsi', 'exp', 'id_badge', + 'durasi_pengerjaan', 'tenggat_waktu', ]; + protected $casts = [ + 'durasi_pengerjaan' => 'integer', + ]; public function kelas() { diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 452e6b6..a8b0e5a 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -3,22 +3,17 @@ namespace App\Providers; use Illuminate\Support\ServiceProvider; +use Illuminate\Pagination\Paginator; class AppServiceProvider extends ServiceProvider { - /** - * Register any application services. - */ public function register(): void { // } - /** - * Bootstrap any application services. - */ public function boot(): void { - // + Paginator::defaultView('vendor.pagination.bootstrap-5'); } -} +} \ No newline at end of file diff --git a/composer.json b/composer.json index 38e8622..024246b 100644 --- a/composer.json +++ b/composer.json @@ -7,6 +7,7 @@ "license": "MIT", "require": { "php": "^8.2", + "barryvdh/laravel-dompdf": "^3.1", "doctrine/dbal": "^4.4", "laravel/framework": "^12.0", "laravel/tinker": "^2.10.1" diff --git a/composer.lock b/composer.lock index e8dd399..711e819 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,85 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b431c9cde1a46957fa68826ee65622af", + "content-hash": "ff0b1f9e9305b6ad7e2e60e462da8ee3", "packages": [ + { + "name": "barryvdh/laravel-dompdf", + "version": "v3.1.2", + "source": { + "type": "git", + "url": "https://github.com/barryvdh/laravel-dompdf.git", + "reference": "ee3b72b19ccdf57d0243116ecb2b90261344dedc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/ee3b72b19ccdf57d0243116ecb2b90261344dedc", + "reference": "ee3b72b19ccdf57d0243116ecb2b90261344dedc", + "shasum": "" + }, + "require": { + "dompdf/dompdf": "^3.0", + "illuminate/support": "^9|^10|^11|^12|^13.0", + "php": "^8.1" + }, + "require-dev": { + "larastan/larastan": "^2.7|^3.0", + "orchestra/testbench": "^7|^8|^9.16|^10|^11.0", + "phpro/grumphp": "^2.5", + "squizlabs/php_codesniffer": "^3.5" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "PDF": "Barryvdh\\DomPDF\\Facade\\Pdf", + "Pdf": "Barryvdh\\DomPDF\\Facade\\Pdf" + }, + "providers": [ + "Barryvdh\\DomPDF\\ServiceProvider" + ] + }, + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Barryvdh\\DomPDF\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "A DOMPDF Wrapper for Laravel", + "keywords": [ + "dompdf", + "laravel", + "pdf" + ], + "support": { + "issues": "https://github.com/barryvdh/laravel-dompdf/issues", + "source": "https://github.com/barryvdh/laravel-dompdf/tree/v3.1.2" + }, + "funding": [ + { + "url": "https://fruitcake.nl", + "type": "custom" + }, + { + "url": "https://github.com/barryvdh", + "type": "github" + } + ], + "time": "2026-02-21T08:51:10+00:00" + }, { "name": "brick/math", "version": "0.14.0", @@ -531,6 +608,161 @@ ], "time": "2024-02-05T11:56:58+00:00" }, + { + "name": "dompdf/dompdf", + "version": "v3.1.5", + "source": { + "type": "git", + "url": "https://github.com/dompdf/dompdf.git", + "reference": "f11ead23a8a76d0ff9bbc6c7c8fd7e05ca328496" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/dompdf/zipball/f11ead23a8a76d0ff9bbc6c7c8fd7e05ca328496", + "reference": "f11ead23a8a76d0ff9bbc6c7c8fd7e05ca328496", + "shasum": "" + }, + "require": { + "dompdf/php-font-lib": "^1.0.0", + "dompdf/php-svg-lib": "^1.0.0", + "ext-dom": "*", + "ext-mbstring": "*", + "masterminds/html5": "^2.0", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "ext-gd": "*", + "ext-json": "*", + "ext-zip": "*", + "mockery/mockery": "^1.3", + "phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11", + "squizlabs/php_codesniffer": "^3.5", + "symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0" + }, + "suggest": { + "ext-gd": "Needed to process images", + "ext-gmagick": "Improves image processing performance", + "ext-imagick": "Improves image processing performance", + "ext-zlib": "Needed for pdf stream compression" + }, + "type": "library", + "autoload": { + "psr-4": { + "Dompdf\\": "src/" + }, + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1" + ], + "authors": [ + { + "name": "The Dompdf Community", + "homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md" + } + ], + "description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter", + "homepage": "https://github.com/dompdf/dompdf", + "support": { + "issues": "https://github.com/dompdf/dompdf/issues", + "source": "https://github.com/dompdf/dompdf/tree/v3.1.5" + }, + "time": "2026-03-03T13:54:37+00:00" + }, + { + "name": "dompdf/php-font-lib", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/dompdf/php-font-lib.git", + "reference": "a6e9a688a2a80016ac080b97be73d3e10c444c9a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/a6e9a688a2a80016ac080b97be73d3e10c444c9a", + "reference": "a6e9a688a2a80016ac080b97be73d3e10c444c9a", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11 || ^12" + }, + "type": "library", + "autoload": { + "psr-4": { + "FontLib\\": "src/FontLib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "The FontLib Community", + "homepage": "https://github.com/dompdf/php-font-lib/blob/master/AUTHORS.md" + } + ], + "description": "A library to read, parse, export and make subsets of different types of font files.", + "homepage": "https://github.com/dompdf/php-font-lib", + "support": { + "issues": "https://github.com/dompdf/php-font-lib/issues", + "source": "https://github.com/dompdf/php-font-lib/tree/1.0.2" + }, + "time": "2026-01-20T14:10:26+00:00" + }, + { + "name": "dompdf/php-svg-lib", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/dompdf/php-svg-lib.git", + "reference": "8259ffb930817e72b1ff1caef5d226501f3dfeb1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/8259ffb930817e72b1ff1caef5d226501f3dfeb1", + "reference": "8259ffb930817e72b1ff1caef5d226501f3dfeb1", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1 || ^8.0", + "sabberworm/php-css-parser": "^8.4 || ^9.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11" + }, + "type": "library", + "autoload": { + "psr-4": { + "Svg\\": "src/Svg" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "The SvgLib Community", + "homepage": "https://github.com/dompdf/php-svg-lib/blob/master/AUTHORS.md" + } + ], + "description": "A library to read, parse and export to PDF SVG files.", + "homepage": "https://github.com/dompdf/php-svg-lib", + "support": { + "issues": "https://github.com/dompdf/php-svg-lib/issues", + "source": "https://github.com/dompdf/php-svg-lib/tree/1.0.2" + }, + "time": "2026-01-02T16:01:13+00:00" + }, { "name": "dragonmantank/cron-expression", "version": "v3.4.0", @@ -2163,6 +2395,73 @@ ], "time": "2024-12-08T08:18:47+00:00" }, + { + "name": "masterminds/html5", + "version": "2.10.0", + "source": { + "type": "git", + "url": "https://github.com/Masterminds/html5-php.git", + "reference": "fcf91eb64359852f00d921887b219479b4f21251" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251", + "reference": "fcf91eb64359852f00d921887b219479b4f21251", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Masterminds\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matt Butcher", + "email": "technosophos@gmail.com" + }, + { + "name": "Matt Farina", + "email": "matt@mattfarina.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + } + ], + "description": "An HTML5 parser and serializer.", + "homepage": "http://masterminds.github.io/html5-php", + "keywords": [ + "HTML5", + "dom", + "html", + "parser", + "querypath", + "serializer", + "xml" + ], + "support": { + "issues": "https://github.com/Masterminds/html5-php/issues", + "source": "https://github.com/Masterminds/html5-php/tree/2.10.0" + }, + "time": "2025-07-25T09:04:22+00:00" + }, { "name": "monolog/monolog", "version": "3.9.0", @@ -3479,6 +3778,86 @@ }, "time": "2025-09-04T20:59:21+00:00" }, + { + "name": "sabberworm/php-css-parser", + "version": "v9.3.0", + "source": { + "type": "git", + "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git", + "reference": "88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949", + "reference": "88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": "^7.2.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "thecodingmachine/safe": "^1.3 || ^2.5 || ^3.4" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "1.4.0", + "phpstan/extension-installer": "1.4.3", + "phpstan/phpstan": "1.12.32 || 2.1.32", + "phpstan/phpstan-phpunit": "1.4.2 || 2.0.8", + "phpstan/phpstan-strict-rules": "1.6.2 || 2.0.7", + "phpunit/phpunit": "8.5.52", + "rawr/phpunit-data-provider": "3.3.1", + "rector/rector": "1.2.10 || 2.2.8", + "rector/type-perfect": "1.0.0 || 2.1.0", + "squizlabs/php_codesniffer": "4.0.1", + "thecodingmachine/phpstan-safe-rule": "1.2.0 || 1.4.1" + }, + "suggest": { + "ext-mbstring": "for parsing UTF-8 CSS" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "9.4.x-dev" + } + }, + "autoload": { + "files": [ + "src/Rule/Rule.php", + "src/RuleSet/RuleContainer.php" + ], + "psr-4": { + "Sabberworm\\CSS\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Raphael Schweikert" + }, + { + "name": "Oliver Klee", + "email": "github@oliverklee.de" + }, + { + "name": "Jake Hotson", + "email": "jake.github@qzdesign.co.uk" + } + ], + "description": "Parser for CSS Files written in PHP", + "homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser", + "keywords": [ + "css", + "parser", + "stylesheet" + ], + "support": { + "issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues", + "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v9.3.0" + }, + "time": "2026-03-03T17:31:43+00:00" + }, { "name": "symfony/clock", "version": "v7.3.0", @@ -5956,6 +6335,149 @@ ], "time": "2025-09-11T10:12:26+00:00" }, + { + "name": "thecodingmachine/safe", + "version": "v3.4.0", + "source": { + "type": "git", + "url": "https://github.com/thecodingmachine/safe.git", + "reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/705683a25bacf0d4860c7dea4d7947bfd09eea19", + "reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.4", + "phpstan/phpstan": "^2", + "phpunit/phpunit": "^10", + "squizlabs/php_codesniffer": "^3.2" + }, + "type": "library", + "autoload": { + "files": [ + "lib/special_cases.php", + "generated/apache.php", + "generated/apcu.php", + "generated/array.php", + "generated/bzip2.php", + "generated/calendar.php", + "generated/classobj.php", + "generated/com.php", + "generated/cubrid.php", + "generated/curl.php", + "generated/datetime.php", + "generated/dir.php", + "generated/eio.php", + "generated/errorfunc.php", + "generated/exec.php", + "generated/fileinfo.php", + "generated/filesystem.php", + "generated/filter.php", + "generated/fpm.php", + "generated/ftp.php", + "generated/funchand.php", + "generated/gettext.php", + "generated/gmp.php", + "generated/gnupg.php", + "generated/hash.php", + "generated/ibase.php", + "generated/ibmDb2.php", + "generated/iconv.php", + "generated/image.php", + "generated/imap.php", + "generated/info.php", + "generated/inotify.php", + "generated/json.php", + "generated/ldap.php", + "generated/libxml.php", + "generated/lzf.php", + "generated/mailparse.php", + "generated/mbstring.php", + "generated/misc.php", + "generated/mysql.php", + "generated/mysqli.php", + "generated/network.php", + "generated/oci8.php", + "generated/opcache.php", + "generated/openssl.php", + "generated/outcontrol.php", + "generated/pcntl.php", + "generated/pcre.php", + "generated/pgsql.php", + "generated/posix.php", + "generated/ps.php", + "generated/pspell.php", + "generated/readline.php", + "generated/rnp.php", + "generated/rpminfo.php", + "generated/rrd.php", + "generated/sem.php", + "generated/session.php", + "generated/shmop.php", + "generated/sockets.php", + "generated/sodium.php", + "generated/solr.php", + "generated/spl.php", + "generated/sqlsrv.php", + "generated/ssdeep.php", + "generated/ssh2.php", + "generated/stream.php", + "generated/strings.php", + "generated/swoole.php", + "generated/uodbc.php", + "generated/uopz.php", + "generated/url.php", + "generated/var.php", + "generated/xdiff.php", + "generated/xml.php", + "generated/xmlrpc.php", + "generated/yaml.php", + "generated/yaz.php", + "generated/zip.php", + "generated/zlib.php" + ], + "classmap": [ + "lib/DateTime.php", + "lib/DateTimeImmutable.php", + "lib/Exceptions/", + "generated/Exceptions/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHP core functions that throw exceptions instead of returning FALSE on error", + "support": { + "issues": "https://github.com/thecodingmachine/safe/issues", + "source": "https://github.com/thecodingmachine/safe/tree/v3.4.0" + }, + "funding": [ + { + "url": "https://github.com/OskarStark", + "type": "github" + }, + { + "url": "https://github.com/shish", + "type": "github" + }, + { + "url": "https://github.com/silasjoisten", + "type": "github" + }, + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2026-02-04T18:08:13+00:00" + }, { "name": "tijsverkoyen/css-to-inline-styles", "version": "v2.3.0", diff --git a/database/migrations/2026_04_19_131126_add_durasi_pengerjaan_to_challenges_table.php b/database/migrations/2026_04_19_131126_add_durasi_pengerjaan_to_challenges_table.php new file mode 100644 index 0000000..e1f4d1a --- /dev/null +++ b/database/migrations/2026_04_19_131126_add_durasi_pengerjaan_to_challenges_table.php @@ -0,0 +1,24 @@ +unsignedSmallInteger('durasi_pengerjaan')->nullable()->after('tenggat_waktu') + ->comment('Durasi pengerjaan dalam menit. NULL = tidak ada batas durasi.'); + }); + } + + public function down(): void + { + Schema::table('challenges', function (Blueprint $table) { + $table->dropColumn('durasi_pengerjaan'); + }); + } +}; \ No newline at end of file diff --git a/resources/views/admin/challenge/index.blade.php b/resources/views/admin/challenge/index.blade.php index aef8f43..69b0c5b 100644 --- a/resources/views/admin/challenge/index.blade.php +++ b/resources/views/admin/challenge/index.blade.php @@ -1,3 +1,11 @@ +{{-- + FILE: resources/views/admin/challenge/index.blade.php + PERUBAHAN: + - Tambah field "Durasi Pengerjaan (menit)" di form Tambah & Edit + - Kolom durasi di tabel + - Logika timer siswa berubah: pakai durasi, bukan tenggat +--}} + @extends('admin.layouts.app') @section('title', 'Daftar Challenge') @@ -11,14 +19,12 @@ margin-bottom: 10px; margin-top: -20px; } - .custom-card { background: white; border-radius: 20px; border: 2px solid #e5e5e5; padding: 25px; } - .btn-primary-custom { background: #2b8ef3; color: white; @@ -33,9 +39,7 @@ cursor: pointer; font-family: 'Poppins', sans-serif; } - .table-header { background: #a5e6ba; } - .search-box { background: #a5e6ba; border-radius: 30px; @@ -44,24 +48,19 @@ align-items: center; gap: 8px; } - .search-box input { border: none; outline: none; background: transparent; width: 160px; } - .action-icon { width: 20px; cursor: pointer; margin: 0 4px; } - -/* Icon kecil inline (di dalam teks / badge / label) */ .inline-icon { width: 16px; height: 16px; vertical-align: middle; display: inline-block; } - .deadline-badge { font-size: 11px; font-weight: 700; @@ -71,10 +70,8 @@ align-items: center; gap: 4px; } - .deadline-aktif { background: #dcfce7; color: #16a34a; } .deadline-lewat { background: #fee2e2; color: #ef4444; } - .kelas-chip { display: inline-block; background: #e6f0ff; @@ -85,7 +82,6 @@ border-radius: 99px; margin: 1px; } - .soal-count { background: #f0fdf4; color: #16a34a; @@ -95,6 +91,20 @@ border-radius: 99px; } +/* Badge durasi */ +.durasi-badge { + background: #ede9fe; + color: #5b21b6; + font-size: 11px; + font-weight: 700; + padding: 3px 10px; + border-radius: 99px; + display: inline-flex; + align-items: center; + gap: 4px; + white-space: nowrap; +} + .alert-success-custom { background: #dcfce7; color: #166534; @@ -108,14 +118,12 @@ gap: 8px; } -/* ── MODAL SHARED ─────────────────────────────────── */ +/* ── MODAL ─────────────────────────────── */ .modal-content { border-radius: 16px; border: none; box-shadow: 0 10px 40px rgba(0,0,0,0.2); } - -/* Header kuning (Tambah) */ .modal-header-yellow { background: #f9c946; color: #1e293b; @@ -130,24 +138,12 @@ align-items: center; gap: 8px; } -.modal-header-yellow .btn-close { filter: none; } - -/* Header ungu (Edit — tetap seperti semula) */ -.modal-header-challenge { - background: linear-gradient(135deg, #667eea, #764ba2); - color: white; - border-bottom: none; - border-radius: 16px 16px 0 0; -} -.modal-header-challenge .btn-close { filter: brightness(0) invert(1); } - .modal-body label { font-weight: 600; font-size: 13px; } -/* ── STEP INDICATOR ───────────────────────────────── */ +/* ── STEP INDICATOR ───────────────────── */ .step-indicator { display: flex; align-items: center; - gap: 0; margin-bottom: 20px; background: #f8fafc; border-radius: 12px; @@ -155,14 +151,10 @@ border: 1px solid #e2e8f0; } .step-dot { - width: 30px; - height: 30px; + width: 30px; height: 30px; border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - font-size: 13px; - font-weight: 800; + display: flex; align-items: center; justify-content: center; + font-size: 13px; font-weight: 800; flex-shrink: 0; transition: all 0.3s; } @@ -170,16 +162,14 @@ .step-dot.done { background: #16a34a; color: white; } .step-dot.inactive { background: #e2e8f0; color: #94a3b8; } .step-label { - font-size: 12px; - font-weight: 700; + font-size: 12px; font-weight: 700; margin-left: 8px; transition: color 0.3s; } .step-label.active { color: #1e293b; } .step-label.inactive { color: #94a3b8; } .step-line { - flex: 1; - height: 2px; + flex: 1; height: 2px; background: #e2e8f0; margin: 0 12px; border-radius: 2px; @@ -187,8 +177,7 @@ position: relative; } .step-line-fill { - position: absolute; - inset: 0; + position: absolute; inset: 0; background: #16a34a; transform: scaleX(0); transform-origin: left; @@ -196,11 +185,11 @@ } .step-line-fill.filled { transform: scaleX(1); } -/* ── STEP PANELS ──────────────────────────────────── */ +/* ── STEP PANELS ──────────────────────── */ .step-panel { display: none; } .step-panel.active { display: block; } -/* ── SOAL CARD ────────────────────────────────────── */ +/* ── SOAL CARD ────────────────────────── */ .soal-card { background: #f8fafc; border: 1px solid #e2e8f0; @@ -210,184 +199,135 @@ position: relative; } .soal-card .soal-number { - position: absolute; - top: -10px; - left: 16px; - background: #667eea; - color: white; - font-size: 11px; - font-weight: 700; - padding: 2px 10px; - border-radius: 99px; + position: absolute; top: -10px; left: 16px; + background: #667eea; color: white; + font-size: 11px; font-weight: 700; + padding: 2px 10px; border-radius: 99px; } .soal-card .btn-hapus-soal { - position: absolute; - top: 10px; - right: 12px; - background: #fee2e2; - color: #ef4444; - border: none; - border-radius: 8px; - width: 28px; - height: 28px; - font-size: 14px; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; + position: absolute; top: 10px; right: 12px; + background: #fee2e2; color: #ef4444; + border: none; border-radius: 8px; + width: 28px; height: 28px; + font-size: 14px; cursor: pointer; + display: flex; align-items: center; justify-content: center; } .soal-card .btn-hapus-soal:hover { background: #fca5a5; } - .opsi-grid { display: grid; grid-template-columns: 1fr 1fr; - gap: 8px; - margin-top: 8px; + gap: 8px; margin-top: 8px; } .opsi-item { display: flex; flex-direction: column; gap: 4px; } .opsi-item label { font-size: 12px; color: #64748b; font-weight: 600; } .opsi-item input { border-radius: 8px; border: 1px solid #cbd5e1; padding: 6px 10px; font-size: 13px; } - .jawaban-row { - display: flex; - gap: 12px; - align-items: center; + display: flex; gap: 12px; align-items: center; margin-top: 10px; - background: #fff; - border-radius: 8px; - padding: 8px 12px; - border: 1px solid #e2e8f0; + background: #fff; border-radius: 8px; + padding: 8px 12px; border: 1px solid #e2e8f0; } .jawaban-row label { font-size: 12px; color: #64748b; font-weight: 600; min-width: 90px; } - .btn-tambah-soal { background: linear-gradient(135deg, #667eea, #764ba2); - color: white; - border: none; - border-radius: 10px; - padding: 9px 18px; - font-size: 13px; - font-weight: 600; - cursor: pointer; - width: 100%; - margin-top: 4px; + color: white; border: none; border-radius: 10px; + padding: 9px 18px; font-size: 13px; font-weight: 600; + cursor: pointer; width: 100%; margin-top: 4px; font-family: 'Poppins', sans-serif; } - .kelas-checkbox-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; } .kelas-check-item { - display: flex; - align-items: center; - gap: 8px; - background: #f8fafc; - border: 1px solid #e2e8f0; - border-radius: 8px; - padding: 8px 10px; - cursor: pointer; - transition: all 0.2s; + display: flex; align-items: center; gap: 8px; + background: #f8fafc; border: 1px solid #e2e8f0; + border-radius: 8px; padding: 8px 10px; + cursor: pointer; transition: all 0.2s; } .kelas-check-item:hover { background: #e6f0ff; border-color: #2b8ef3; } -.kelas-check-item input[type="checkbox"] { cursor: pointer; } +/* ── MODAL FIXED HEIGHT ───────────────── */ .modal-dialog-fixed .modal-content { - max-height: 90vh; - overflow: hidden; - display: flex; - flex-direction: column; + max-height: 90vh; overflow: hidden; + display: flex; flex-direction: column; } - -/* form harus ikut flex agar modal-body bisa grow */ -.modal-dialog-fixed form { - display: contents; -} - +.modal-dialog-fixed form { display: contents; } .modal-dialog-fixed .modal-header, -.modal-dialog-fixed .modal-footer { - flex-shrink: 0; -} - +.modal-dialog-fixed .modal-footer { flex-shrink: 0; } .modal-dialog-fixed .modal-body { - flex: 1 1 auto; - overflow: hidden; - display: flex; - flex-direction: column; - min-height: 0; - padding-bottom: 0; + flex: 1 1 auto; overflow: hidden; + display: flex; flex-direction: column; + min-height: 0; padding-bottom: 0; } - -/* step-indicator tidak ikut scroll */ -.modal-dialog-fixed .step-indicator { - flex-shrink: 0; - margin-bottom: 16px; -} - -.modal-dialog-fixed .step-panel { - display: none; -} - +.modal-dialog-fixed .step-indicator { flex-shrink: 0; margin-bottom: 16px; } +.modal-dialog-fixed .step-panel { display: none; } .modal-dialog-fixed .step-panel.active { - display: flex; - flex-direction: column; - flex: 1 1 auto; - min-height: 0; + display: flex; flex-direction: column; + flex: 1 1 auto; min-height: 0; } - -/* Step 1: scroll jika form terlalu panjang */ -#tambah-step-1, -#edit-step-1 { - overflow-y: auto; - padding-right: 4px; -} - -/* Step 2: soal-scroll-area yang mengelola scroll */ -#tambah-step-2, -#edit-step-2 { - overflow: hidden; -} - +#tambah-step-1, #edit-step-1 { overflow-y: auto; padding-right: 4px; } +#tambah-step-2, #edit-step-2 { overflow: hidden; } .soal-scroll-area { - flex: 1 1 auto; - min-height: 0; - overflow-y: auto; - padding-right: 6px; + flex: 1 1 auto; min-height: 0; + overflow-y: auto; padding-right: 6px; scroll-behavior: smooth; } - .soal-scroll-area::-webkit-scrollbar { width: 6px; } .soal-scroll-area::-webkit-scrollbar-track { background: #f1f5f9; border-radius: 99px; } .soal-scroll-area::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 99px; } .soal-scroll-area::-webkit-scrollbar-thumb:hover { background: #94a3b8; } -.section-divider { - display: flex; - align-items: center; - gap: 6px; - font-size: 13px; - font-weight: 700; - color: #667eea; - border-bottom: 2px solid #e6f0ff; - padding-bottom: 6px; - margin: 16px 0 12px; +/* ── DURASI FIELD ─────────────────────── */ +.durasi-input-wrap { + position: relative; } - -/* ── FOOTER BUTTONS ───────────────────────────────── */ -.btn-green { - background: #16a34a; - color: white; - border: none; - border-radius: 10px; - padding: 9px 22px; - font-size: 14px; - font-weight: 700; - cursor: pointer; - font-family: 'Poppins', sans-serif; +.durasi-input-wrap input { + padding-right: 60px; +} +.durasi-input-wrap .durasi-unit { + position: absolute; + right: 12px; top: 50%; + transform: translateY(-50%); + font-size: 12px; font-weight: 700; + color: #5b21b6; + pointer-events: none; +} +.durasi-hint { + font-size: 11px; + color: #94a3b8; + margin-top: 4px; + font-style: italic; +} +/* Preview badge durasi di form */ +.durasi-preview { display: inline-flex; align-items: center; gap: 6px; + background: #ede9fe; + color: #5b21b6; + font-size: 12px; + font-weight: 700; + padding: 5px 14px; + border-radius: 99px; + margin-top: 6px; + transition: all 0.2s; +} + +.section-divider { + display: flex; align-items: center; gap: 6px; + font-size: 13px; font-weight: 700; color: #667eea; + border-bottom: 2px solid #e6f0ff; + padding-bottom: 6px; margin: 16px 0 12px; +} + +.btn-green { + background: #16a34a; color: white; + border: none; border-radius: 10px; + padding: 9px 22px; font-size: 14px; font-weight: 700; + cursor: pointer; font-family: 'Poppins', sans-serif; + display: inline-flex; align-items: center; gap: 6px; transition: background 0.2s; } .btn-green:hover { background: #15803d; } @@ -405,7 +345,7 @@
-{{-- ============================================================ --}} -{{-- MODAL EDIT --}} -{{-- ============================================================ --}} +{{-- ============================================================ + MODAL EDIT +============================================================ --}}
diff --git a/resources/views/admin/guru/pdf.blade.php b/resources/views/admin/guru/pdf.blade.php new file mode 100644 index 0000000..d7c31d5 --- /dev/null +++ b/resources/views/admin/guru/pdf.blade.php @@ -0,0 +1,62 @@ + + + + +Daftar Guru + + + + +
+

DAFTAR GURU

+

Dicetak pada {{ now()->format('d M Y, H:i') }}

+
+ + + + + + + + + + + + + @foreach($gurus as $i => $guru) + + + + + + + + @endforeach + +
NoNama LengkapNIPMata PelajaranKelas
{{ $i + 1 }}{{ $guru->nama }}{{ $guru->nip }} + @foreach($guru->mengajars as $m) +
{{ optional($m->mapel)->nama_mapel ?? '-' }}
+ @endforeach +
+ @foreach($guru->mengajars as $m) +
{{ optional($m->kelas)->tingkat }} {{ optional($m->kelas)->nama_kelas }}
+ @endforeach +
+ + + + + \ No newline at end of file diff --git a/resources/views/admin/kelas/index.blade.php b/resources/views/admin/kelas/index.blade.php index 419df4f..c3d18b5 100644 --- a/resources/views/admin/kelas/index.blade.php +++ b/resources/views/admin/kelas/index.blade.php @@ -111,11 +111,18 @@
- +