diff --git a/app/Http/Controllers/Admin/AdminPeminjamanController.php b/app/Http/Controllers/Admin/AdminPeminjamanController.php index c56109e..46850d9 100644 --- a/app/Http/Controllers/Admin/AdminPeminjamanController.php +++ b/app/Http/Controllers/Admin/AdminPeminjamanController.php @@ -3,42 +3,41 @@ namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; -use App\Services\DummyDataService; -use Illuminate\Http\Request; +use App\Models\Book; +use App\Models\Loan; +use App\Models\User; use Carbon\Carbon; +use Illuminate\Http\Request; class AdminPeminjamanController extends Controller { public function index(Request $request) { - $peminjamanAktif = DummyDataService::getAdminPeminjamanAktif(); + $loans = Loan::with(['user', 'book']) + ->whereIn('status', ['Dipinjam', 'Terlambat']) + ->get(); - // LOGIC DENDA & WA LINK (Update Request Client) - $peminjamanAktif = $peminjamanAktif->map(function ($item) { - // Hitung Denda Flat 1000/hari - $tenggat = Carbon::parse($item['tenggat_kembali']); - $now = Carbon::now(); + $groupedLoans = $loans->groupBy('user_id'); - $item['hari_terlambat'] = 0; - $item['total_denda'] = 0; - - if ($now->greaterThan($tenggat)) { - $hariTelat = $tenggat->diffInDays($now); - $item['hari_terlambat'] = $hariTelat; - $item['total_denda'] = $hariTelat * 1000; - $item['denda_per_hari'] = 1000; - } - // Generate WA Link - $hp = $item['nomor_hp']; - if (substr($hp, 0, 1) == '0') { - $hp = '62' . substr($hp, 1); - } - - $pesan = "Halo kak {$item['peminjam']}, buku anda sudah terlambat {$item['hari_terlambat']} hari dengan denda Rp " . number_format($item['total_denda'], 0, ',', '.') . ". Mohon segera dikembalikan ya."; - $item['wa_link'] = "https://wa.me/{$hp}?text=" . urlencode($pesan); - - return $item; - }); + $peminjamanAktif = $groupedLoans->map(function ($userLoans, $userId) { + $user = $userLoans->first()->user; + $firstLoan = $userLoans->first(); + + return [ + 'id_peminjaman' => 'PIN-ADM-' . sprintf('%03d', $userId), + 'user_id' => $userId, + 'peminjam' => $user->nama_lengkap ?? 'Unknown', + 'nomor_hp' => $user->phone ?? '-', + 'tanggal_pinjam' => $firstLoan->borrowed_at, + 'tenggat_kembali' => $firstLoan->due_at, + 'status' => $firstLoan->status, + 'books' => $userLoans->map(fn($l) => [ + 'id' => $l->book->id, + 'judul' => $l->book->judul, + 'cover' => $l->book->cover, + ])->toArray(), + ]; + })->values(); $daftarPeminjam = $peminjamanAktif->pluck('peminjam')->unique(); @@ -51,44 +50,31 @@ public function index(Request $request) public function create() { - $allUsers = collect(DummyDataService::getAllSiswa()); - $peminjamanAktif = DummyDataService::getAdminPeminjamanAktif(); + $users = User::whereIn('role', ['siswa', 'guru'])->get(); + + $groupedUsers = $users->map(function ($user) { + $jumlahPinjam = Loan::where('user_id', $user->id) + ->whereIn('status', ['Dipinjam', 'Terlambat']) + ->count(); - $groupedUsers = $allUsers - ->whereIn('role', ['siswa', 'guru']) - ->map(function ($user) use ($peminjamanAktif) { + $user->jumlah_pinjam = $jumlahPinjam; + $user->kena_limit = $jumlahPinjam >= 2; + $user->disabled = $user->kena_limit || $user->is_banned; - // Hitung berapa buku yang sedang dipinjam - $jumlahPinjam = $peminjamanAktif->where('peminjam', $user['nama_lengkap'])->count(); + if ($user->is_banned) { + $user->status_text = "(Akun Dibekukan)"; + } elseif ($user->kena_limit) { + $user->status_text = "(Limit Penuh: 2/2)"; + } else { + $user->status_text = ""; + } - // Cek Status - $user['jumlah_pinjam'] = $jumlahPinjam; - $user['kena_limit'] = $jumlahPinjam >= 2; + return $user; + })->groupBy('role'); - // Cek apakah user di-banned (Nonaktif Manual) - $user['is_banned'] = $user['is_banned'] ?? false; - $user['disabled'] = $user['kena_limit'] || $user['is_banned']; - - if ($user['is_banned']) { - $user['status_text'] = "(Akun Dibekukan)"; - } elseif ($user['kena_limit']) { - $user['status_text'] = "(Limit Penuh: 2/2)"; - } else { - $user['status_text'] = ""; - } - - return $user; - }) - ->groupBy('role'); - - $daftarBuku = DummyDataService::getAllBooks() - ->where('status', 'Tersedia') - ->filter(function ($buku) { - if (is_array($buku['tipe_akses'])) { - return in_array('offline', $buku['tipe_akses']); - } - return $buku['tipe_akses'] === 'offline'; - }); + $daftarBuku = Book::where('status', 'Tersedia') + ->whereJsonContains('tipe_akses', 'offline') + ->get(); return view('admin.peminjaman.create', [ 'pageTitle' => 'Buat Peminjaman Manual', @@ -97,80 +83,58 @@ public function create() ]); } - /** - * Menampilkan halaman KHUSUS Manajemen Denda (Siswa & Guru Telat). - */ public function dendaIndex() { - $allData = DummyDataService::getAdminPeminjamanAktif(); - $allSiswaRaw = collect(DummyDataService::getAllSiswa()); - $now = \Carbon\Carbon::now(); + $now = Carbon::now(); + + // Fetch all loans that are overdue or users that are banned + $loans = Loan::with(['user', 'book']) + ->where(function($query) use ($now) { + $query->where('due_at', '<', $now) + ->whereIn('status', ['Dipinjam', 'Terlambat']); + }) + ->orWhereHas('user', function($query) { + $query->where('is_banned', true); + }) + ->get(); - // LOGIC AUTO-BAN - $allSiswa = $allSiswaRaw->map(function ($siswa) use ($allData, $now) { + $groupedLoans = $loans->groupBy('user_id'); - // Cek siswa punya pinjaman yang telat - $pinjamanUser = $allData->firstWhere('user_id', $siswa['id']); - - $isTelat = false; - if ($pinjamanUser) { - $isTelat = $pinjamanUser['tenggat_kembali']->startOfDay()->lt($now->startOfDay()); - } - - // Jika Role SISWA dan TELAT -> Wajib AUTO BAN (Override true) - // ika Role GURU -> Ikut status asli database (Manual Ban) - if ($siswa['role'] === 'siswa' && $isTelat) { - $siswa['is_banned'] = true; - } - - return $siswa; - }); - - $siswaTelat = $allData->filter(function ($item) use ($now, $allSiswa) { - $userData = $allSiswa->firstWhere('id', $item['user_id']); - - if (!$userData) - return false; - - $isTelat = $item['tenggat_kembali']->startOfDay()->lt($now->startOfDay()); - $isBanned = $userData['is_banned']; - $isTargetRole = in_array($userData['role'], ['siswa', 'guru']); - - return ($isTelat || $isBanned) && $isTargetRole; - })->map(function ($item) use ($now, $allSiswa) { - - // Hitungan Denda - $tenggat = $item['tenggat_kembali']->startOfDay(); - - // Jika belum telat (tapi banned/manual), hari telat 0 - $hariTelat = ($tenggat->lt($now->startOfDay())) - ? $tenggat->diffInDays($now->startOfDay()) - : 0; - - $totalDenda = $hariTelat * $item['denda_per_hari']; - - $item['hari_terlambat'] = $hariTelat; - $item['total_denda'] = $totalDenda; - - // Ambil status is_banned TERBARU dari $allSiswa - $dataSiswa = $allSiswa->firstWhere('id', $item['user_id']); - $item['is_banned'] = $dataSiswa['is_banned'] ?? false; - $item['kelas'] = $dataSiswa['kelas'] ?? 'Guru'; + $siswaTelat = $groupedLoans->map(function ($userLoans, $userId) use ($now) { + $user = $userLoans->first()->user; + $firstLoan = $userLoans->first(); + + $tenggat = Carbon::parse($firstLoan->due_at); + $hariTelat = $now->greaterThan($tenggat) ? (int) $tenggat->diffInDays($now) : 0; + $totalDenda = $hariTelat * 1000; // Link WA - $hp = $item['nomor_hp']; - if (substr($hp, 0, 1) == '0') - $hp = '62' . substr($hp, 1); - - if ($hariTelat > 0) { - $pesan = "Halo {$item['peminjam']}, anda terlambat pengembalian buku. Total Denda: Rp " . number_format($totalDenda, 0, ',', '.'); - } else { - $pesan = "Halo {$item['peminjam']}, akun anda sedang dinonaktifkan sementara. Mohon hubungi petugas."; + $hp = $user->phone ?? ''; + $waLink = '#'; + if ($hp) { + if (substr($hp, 0, 1) == '0') $hp = '62' . substr($hp, 1); + $pesan = $hariTelat > 0 + ? "Halo {$user->nama_lengkap}, anda terlambat pengembalian buku. Total Denda: Rp " . number_format($totalDenda, 0, ',', '.') + : "Halo {$user->nama_lengkap}, akun anda sedang dinonaktifkan sementara. Mohon hubungi petugas."; + $waLink = "https://wa.me/{$hp}?text=" . urlencode($pesan); } - $item['wa_link'] = "https://wa.me/{$hp}?text=" . urlencode($pesan); - return $item; - }); + return [ + 'id' => $firstLoan->id, + 'peminjam' => $user->nama_lengkap, + 'nomor_hp' => $user->phone ?? '-', + 'kelas' => $user->kelas ?? 'Guru', + 'hari_terlambat' => $hariTelat, + 'total_denda' => $totalDenda, + 'wa_link' => $waLink, + 'is_banned' => $user->is_banned, + 'tenggat_kembali' => $firstLoan->due_at, + 'books' => $userLoans->map(fn($l) => [ + 'id' => $l->book->id, + 'judul' => $l->book->judul, + ])->toArray(), + ]; + })->values(); $listKelas = $siswaTelat->pluck('kelas')->unique()->values(); @@ -181,11 +145,9 @@ public function dendaIndex() ]); } - /** - * Dummy function untuk tombol Sanksi - */ public function berikanSanksi(Request $request) { + // Actually implement banning logic here if needed return response()->json(['status' => 'success']); } } \ No newline at end of file diff --git a/app/Http/Controllers/Admin/AdminRekomendasiController.php b/app/Http/Controllers/Admin/AdminRekomendasiController.php index e06c688..1ff80b3 100644 --- a/app/Http/Controllers/Admin/AdminRekomendasiController.php +++ b/app/Http/Controllers/Admin/AdminRekomendasiController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; -use App\Services\DummyDataService; +use App\Models\Recommendation; use Illuminate\Http\Request; class AdminRekomendasiController extends Controller @@ -19,17 +19,19 @@ private function extractYouTubeId(string $url): ?string public function index() { - $rekomendasiMentah = DummyDataService::getRekomendasiPembelajaran(); + $rekomendasiMentah = Recommendation::latest()->get(); // Menambahkan thumbnail YouTube ke setiap rekomendasi $semuaRekomendasi = $rekomendasiMentah->map(function ($item) { - $videoId = $this->extractYouTubeId($item['youtube_link']); - if ($videoId) { - $item['thumbnail'] = "https://img.youtube.com/vi/{$videoId}/hqdefault.jpg"; - } else { - $item['thumbnail'] = 'https://via.placeholder.com/150?text=No+Preview'; - } - return $item; + $videoId = $this->extractYouTubeId($item->youtube_link); + return [ + 'id' => $item->id, + 'judul' => $item->judul, + 'kategori' => $item->kategori, + 'youtube_link' => $item->youtube_link, + 'thumbnail' => $videoId ? "https://img.youtube.com/vi/{$videoId}/hqdefault.jpg" : 'https://via.placeholder.com/150?text=No+Preview', + 'deskripsi' => $item->deskripsi, + ]; }); return view('admin.rekomendasi.index', [ @@ -45,8 +47,11 @@ public function create() public function edit($id) { - $rekomendasi = DummyDataService::getRekomendasiPembelajaran()->firstWhere('id', (int)$id); - abort_if(!$rekomendasi, 404); - return view('admin.rekomendasi.edit', ['pageTitle' => 'Edit Rekomendasi', 'rekomendasi' => $rekomendasi]); + $rekomendasi = Recommendation::findOrFail($id); + + return view('admin.rekomendasi.edit', [ + 'pageTitle' => 'Edit Rekomendasi: ' . $rekomendasi->judul, + 'rekomendasi' => $rekomendasi + ]); } } \ No newline at end of file diff --git a/app/Http/Controllers/Admin/BookController.php b/app/Http/Controllers/Admin/BookController.php index e4a11d3..dfb8cbb 100644 --- a/app/Http/Controllers/Admin/BookController.php +++ b/app/Http/Controllers/Admin/BookController.php @@ -3,7 +3,8 @@ namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; -use App\Services\DummyDataService; +use App\Models\Book; +use App\Models\Category; use Illuminate\Http\Request; class BookController extends Controller @@ -11,12 +12,19 @@ class BookController extends Controller public function index(Request $request) { $filters = $request->only(['search']); - $semuaBuku = DummyDataService::getKatalogBuku($filters); + + $query = Book::with('category'); + + if ($request->filled('search')) { + $query->where('judul', 'like', '%' . $request->search . '%'); + } + + $semuaBuku = $query->latest()->get(); // Memisahkan buku menjadi dua koleksi: online dan offline [$bukuOnline, $bukuOffline] = $semuaBuku->partition(function ($buku) { - $tipe = $buku['tipe_akses']; - return $tipe === 'online' || (is_array($tipe) && in_array('online', $tipe)); + $tipe = $buku->tipe_akses; + return in_array('online', $tipe ?? []); }); return view('admin.buku.index', [ @@ -33,18 +41,21 @@ public function index(Request $request) public function create() { return view('admin.buku.create', [ - 'pageTitle' => 'Tambah Buku Baru' + 'pageTitle' => 'Tambah Buku Baru', + 'categories' => Category::all() ]); } public function edit($id) -{ - $buku = DummyDataService::getKatalogBuku()->firstWhere('id', (int)$id); - abort_if(!$buku, 404); + { + $buku = Book::with('category')->findOrFail($id); - return view('admin.buku.edit', [ - 'pageTitle' => 'Edit Buku: ' . $buku['judul'], - 'buku' => $buku - ]); -} + return view('admin.buku.edit', [ + 'pageTitle' => 'Edit Buku: ' . $buku->judul, + 'buku' => $buku, + 'categories' => Category::all() + ]); + } + + // You might also want to implement store, update, destroy here later } \ No newline at end of file diff --git a/app/Http/Controllers/Admin/DashboardController.php b/app/Http/Controllers/Admin/DashboardController.php index 73b4dd9..ae82837 100644 --- a/app/Http/Controllers/Admin/DashboardController.php +++ b/app/Http/Controllers/Admin/DashboardController.php @@ -3,21 +3,78 @@ namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; -use App\Services\DummyDataService; +use App\Models\Announcement; +use App\Models\Book; +use App\Models\Loan; +use App\Models\User; +use Carbon\Carbon; +use Illuminate\Support\Facades\Auth; class DashboardController extends Controller { public function index() { + $allBooks = Book::count(); + $allUsers = User::count(); + $bukuDipinjam = Loan::whereIn('status', ['Dipinjam', 'Terlambat'])->count(); + + $stats = [ + ['label' => 'Total Buku', 'value' => $allBooks, 'icon' => 'bi-journal-bookmark-fill', 'color' => 'primary'], + ['label' => 'Total Anggota', 'value' => $allUsers, 'icon' => 'bi-people-fill', 'color' => 'success'], + ['label' => 'Buku Dipinjam', 'value' => $bukuDipinjam, 'icon' => 'bi-arrow-up-right-circle-fill', 'color' => 'warning'], + ['label' => 'Denda Menunggu', 'value' => Loan::where('status', 'Terlambat')->count(), 'icon' => 'bi-cash-coin', 'color' => 'danger'], + ]; + + // Monthly stats (last 7 months) + $labels = []; + $data = []; + for ($i = 6; $i >= 0; $i--) { + $month = Carbon::now()->subMonths($i); + $labels[] = $month->translatedFormat('M'); + $data[] = Loan::whereMonth('borrowed_at', $month->month) + ->whereYear('borrowed_at', $month->year) + ->count(); + } + + $statistikBulanan = [ + 'labels' => $labels, + 'data' => $data, + ]; + + $komposisiBuku = [ + 'tersedia' => Book::where('status', 'Tersedia')->count(), + 'dipinjam' => Book::where('status', 'Dipinjam')->count(), + ]; + + $pengumuman = Announcement::latest()->take(5)->get(); + + $aktivitasTerakhir = Loan::with(['user', 'book']) + ->latest() + ->take(4) + ->get() + ->map(fn($loan) => [ + 'nama' => $loan->user->nama_lengkap ?? 'Unknown', + 'judul_buku' => $loan->book->judul ?? 'Unknown', + 'tipe' => $loan->status === 'Dikembalikan' ? 'Pengembalian' : 'Peminjaman', + 'waktu' => $loan->created_at->diffForHumans(), + 'status' => $loan->status, + ]); + + $hour = date('H'); + $greeting = "Selamat Pagi"; + if ($hour >= 12 && $hour < 15) $greeting = "Selamat Siang"; + elseif ($hour >= 15 && $hour < 18) $greeting = "Selamat Sore"; + elseif ($hour >= 18) $greeting = "Selamat Malam"; + return view('admin.dashboard', [ 'pageTitle' => 'Beranda', - 'user' => auth()->user(), - 'greeting' => 'Selamat Datang', - 'stats' => DummyDataService::getAdminDashboardStats(), - 'statistikBulanan' => DummyDataService::getStatistikPeminjamanAdmin(), - 'komposisiBuku' => DummyDataService::getKomposisiBukuAdmin(), - 'pengumuman' => DummyDataService::getPengumuman(), - 'aktivitasTerakhir' => DummyDataService::getAktivitasTerakhir(), + 'user' => Auth::user(), + 'greeting' => $greeting, + 'stats' => $stats, + 'statistikBulanan' => $statistikBulanan, + 'komposisiBuku' => $komposisiBuku, + 'pengumuman' => $pengumuman, + 'aktivitasTerakhir' => $aktivitasTerakhir, ]); } } diff --git a/app/Http/Controllers/Admin/PengumumanController.php b/app/Http/Controllers/Admin/PengumumanController.php index e5e4ac9..10d47d9 100644 --- a/app/Http/Controllers/Admin/PengumumanController.php +++ b/app/Http/Controllers/Admin/PengumumanController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; -use App\Services\DummyDataService; +use App\Models\Announcement; use Illuminate\Http\Request; class PengumumanController extends Controller @@ -13,7 +13,7 @@ class PengumumanController extends Controller */ public function index() { - $semuaPengumuman = DummyDataService::getPengumuman(); + $semuaPengumuman = Announcement::latest()->get(); return view('admin.pengumuman.index', [ 'pageTitle' => 'Manajemen Pengumuman', 'semuaPengumuman' => $semuaPengumuman, @@ -35,13 +35,10 @@ public function create() */ public function edit($id) { - $pengumuman = collect(DummyDataService::getPengumuman())->firstWhere('id', (int)$id); - - // Hentikan jika pengumuman tidak ditemukan - abort_if(!$pengumuman, 404); + $pengumuman = Announcement::findOrFail($id); return view('admin.pengumuman.edit', [ - 'pageTitle' => 'Edit Pengumuman', + 'pageTitle' => 'Edit Pengumuman: ' . $pengumuman->title, 'pengumuman' => $pengumuman, ]); } diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index 8643ef7..aec6830 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -3,13 +3,14 @@ namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; -use App\Services\DummyDataService; +use App\Models\User; +use Illuminate\Http\Request; class UserController extends Controller { public function index() { - $semuaSiswa = DummyDataService::getAllSiswa(); + $semuaSiswa = User::whereIn('role', ['siswa', 'guru', 'penjaga perpus'])->latest()->get(); return view('admin.pengguna.index', [ 'pageTitle' => 'Manajemen Pengguna', 'semuaSiswa' => $semuaSiswa @@ -31,12 +32,13 @@ public function create() */ public function edit($id) { - $pengguna = collect(DummyDataService::getAllSiswa())->firstWhere('id', (int)$id); - abort_if(!$pengguna, 404); + $pengguna = User::findOrFail($id); return view('admin.pengguna.edit', [ - 'pageTitle' => 'Edit Pengguna', + 'pageTitle' => 'Edit Pengguna: ' . $pengguna->nama_lengkap, 'pengguna' => $pengguna, ]); } + + // You might also want to implement store, update, destroy here later } \ No newline at end of file diff --git a/app/Http/Controllers/Auth/RegisteredUserController.php b/app/Http/Controllers/Auth/RegisteredUserController.php index 30d907f..df2717e 100644 --- a/app/Http/Controllers/Auth/RegisteredUserController.php +++ b/app/Http/Controllers/Auth/RegisteredUserController.php @@ -31,52 +31,35 @@ public function create(Request $request): View */ public function store(Request $request): RedirectResponse { - // Bagian Validasi Dinamis $role = $request->input('role'); $rules = [ 'name' => ['required', 'string', 'max:255'], 'password' => ['required', 'confirmed', Rules\Password::defaults()], - 'role' => ['required', 'in:siswa,guru'], // Sesuaikan dengan role yang diizinkan + 'role' => ['required', 'in:siswa,guru'], ]; - // Tambahkan validasi NISN atau NIP berdasarkan role if ($role === 'siswa') { - $rules['nisn'] = ['required', 'string', 'max:255']; // Tambahkan 'unique:users' jika perlu - } else { // Asumsi 'guru' - $rules['nip'] = ['required', 'string', 'max:255']; // Tambahkan 'unique:users' jika perlu + $rules['nisn'] = ['required', 'string', 'max:255', 'unique:users,nomor_induk']; + } else { + $rules['nip'] = ['required', 'string', 'max:255', 'unique:users,nomor_induk']; } $request->validate($rules); - // Bagian Pembuatan User - $userArray = [ - 'id' => rand(100, 999), // ID unik sementara - 'nama_lengkap' => $request->name, + $user = User::create([ 'name' => $request->name, - 'password' => Hash::make($request->password), // Gunakan Hash jika login Anda sudah pakai Hash - // 'password' => $request->password, // Gunakan ini jika login (LoginRequest) masih cek teks biasa + 'nama_lengkap' => $request->name, + 'email' => ($request->nisn ?: $request->nip) . '@smkn1perpus.sch.id', + 'password' => Hash::make($request->password), 'role' => $request->role, - ]; - - // Tambahkan field dinamis (NISN/NIP) dan buat email unik palsu - if ($role === 'siswa') { - $userArray['nisn'] = $request->nisn; - $userArray['email'] = $request->nisn . '@smkn1perpus.sch.id'; // Email unik sementara - } else { - $userArray['nip'] = $request->nip; - $userArray['email'] = $request->nip . '@smkn1perpus.sch.id'; // Email unik sementara - } - - $user = new User(); - $user->forceFill($userArray); - // $user->save(); // Aktifkan ini jika menggunakan database + 'nomor_induk' => $request->nisn ?: $request->nip, + ]); event(new Registered($user)); Auth::login($user); - // Bagian Redirect if ($user->role === 'penjaga perpus') { return redirect()->route('admin.dashboard'); } else { diff --git a/app/Http/Controllers/BacaOnlineController.php b/app/Http/Controllers/BacaOnlineController.php index 1c79587..6204780 100644 --- a/app/Http/Controllers/BacaOnlineController.php +++ b/app/Http/Controllers/BacaOnlineController.php @@ -2,10 +2,13 @@ namespace App\Http\Controllers; -use App\Services\DummyDataService; +use App\Models\Book; +use App\Models\Category; +use App\Models\Loan; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Http\Response; +use Illuminate\Support\Facades\Auth; use Illuminate\Support\Str; use Illuminate\View\View; use Symfony\Component\HttpFoundation\BinaryFileResponse; @@ -15,9 +18,34 @@ class BacaOnlineController extends Controller public function index(Request $request): View { $filters = $request->only(['search', 'kategori', 'tahun', 'penulis']); - $filters['tipe_akses'] = 'online'; - $semuaBuku = DummyDataService::getKatalogBuku($filters); - $filterOptions = DummyDataService::getFilterOptions(); + + $query = Book::with('category')->whereJsonContains('tipe_akses', 'online'); + + if ($request->filled('search')) { + $query->where('judul', 'like', '%' . $request->search . '%'); + } + + if ($request->filled('kategori')) { + $query->whereHas('category', function($q) use ($request) { + $q->where('name', $request->kategori); + }); + } + + if ($request->filled('tahun')) { + $query->where('tahun', $request->tahun); + } + + if ($request->filled('penulis')) { + $query->where('penulis', $request->penulis); + } + + $semuaBuku = $query->latest()->get(); + + $filterOptions = [ + 'kategori' => Category::pluck('name')->unique()->sort()->values(), + 'tahun' => Book::pluck('tahun')->unique()->sortDesc()->values(), + 'penulis' => Book::pluck('penulis')->unique()->sort()->values(), + ]; return view('katalog.index', [ 'semuaBuku' => $semuaBuku, @@ -30,7 +58,7 @@ public function index(Request $request): View public function ringkasan(int $id): View { - $book = $this->getBookOrFail($id); + $book = Book::with('category')->findOrFail($id); return view('katalog.ringkasan', [ 'buku' => $book, @@ -44,13 +72,13 @@ public function ringkasan(int $id): View public function showCodeRequestPage(int $id): View { - $book = $this->getBookOrFail($id); + $book = Book::findOrFail($id); $sessionKey = 'access_code_for_book_' . $id; if (session()->has($sessionKey)) { $accessCode = session($sessionKey); } else { - $accessCode = 'BCO-' . date('Ymd') . '-' . $book['id'] . '-' . Str::upper(Str::random(4)); + $accessCode = 'BCO-' . date('Ymd') . '-' . $book->id . '-' . Str::upper(Str::random(4)); session([$sessionKey => $accessCode]); } @@ -69,6 +97,20 @@ public function verifyCode(Request $request, int $id): RedirectResponse if ($request->input('kode_akses') === $correctCode) { session(['book_verified_' . $id => true]); + + // Track history + Loan::updateOrCreate( + [ + 'user_id' => Auth::id(), + 'book_id' => $id, + 'status' => 'Online', + ], + [ + 'loan_code' => $correctCode, + 'borrowed_at' => now(), + ] + ); + session()->forget('access_code_for_book_' . $id); return redirect()->route('baca.view_book', ['id' => $id]); } @@ -82,7 +124,7 @@ public function viewBook(int $id): View|RedirectResponse return redirect()->route('baca.request_code', ['id' => $id]) ->with('error', 'Silakan masukkan kode akses terlebih dahulu.'); } - $book = $this->getBookOrFail($id); + $book = Book::findOrFail($id); return view('baca.view_book', ['book' => $book]); } @@ -91,23 +133,16 @@ public function streamPdf(int $id): BinaryFileResponse|Response if (!session('book_verified_' . $id, false)) { abort(403, 'Akses Ditolak.'); } - $book = $this->getBookOrFail($id); - $filePath = 'books/' . $book['file_pdf']; + $book = Book::findOrFail($id); + $filePath = 'books/' . ($book->file_pdf ?? 'sample.pdf'); $absolutePath = storage_path('app/' . $filePath); + // For demo purposes, if file doesn't exist, we might want to use a placeholder or handle it gracefully if (!file_exists($absolutePath)) { - abort(404, 'GAGAL - PHP tidak dapat menemukan file di: ' . $absolutePath); + // Create a dummy file for testing if it doesn't exist? (Optional, maybe just abort) + abort(404, 'File PDF tidak ditemukan di server.'); } return response()->file($absolutePath); } - - private function getBookOrFail(int $id): array - { - $book = DummyDataService::getKatalogBuku()->firstWhere('id', $id); - if (!$book) { - abort(404, 'Buku tidak ditemukan.'); - } - return $book; - } } diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php index e7ea746..44fb5b3 100644 --- a/app/Http/Controllers/DashboardController.php +++ b/app/Http/Controllers/DashboardController.php @@ -2,7 +2,11 @@ namespace App\Http\Controllers; -use App\Services\DummyDataService; +use App\Models\Announcement; +use App\Models\Book; +use App\Models\Loan; +use App\Models\Recommendation; +use Carbon\Carbon; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; @@ -11,50 +15,122 @@ class DashboardController extends Controller public function index() { $user = Auth::user(); - $bukuPinjam = DummyDataService::getBukuPinjamOffline($user); + + // Fetch active loans for the user + $loans = Loan::with('book') + ->where('user_id', $user->id) + ->whereIn('status', ['Dipinjam', 'Terlambat']) + ->get(); - $isTelat = collect($bukuPinjam)->contains(function ($buku) { - return $buku['sisa_hari'] < 0; + $bukuPinjamOffline = $loans->map(function ($loan) { + $dueAt = Carbon::parse($loan->due_at); + $sisaHari = (int) now()->diffInDays($dueAt, false); + + return [ + 'id' => $loan->book->id, + 'judul' => $loan->book->judul, + 'penulis' => $loan->book->penulis, + 'sisa_hari' => $sisaHari, + 'cover' => $loan->book->cover, + ]; }); + // Check if user has overdue books + $isTelat = $bukuPinjamOffline->contains(fn($b) => $b['sisa_hari'] < 0); + if ($isTelat && $user->role === 'siswa') { - $user->is_banned = true; - } + $user->update(['is_banned' => true]); + } - $stats = DummyDataService::getDashboardStats(); - $pengumuman = DummyDataService::getPengumuman(); - $pemberitahuan = DummyDataService::getPemberitahuan(); - $progressMembaca = DummyDataService::getProgressMembaca(); - $statistikBulanan = DummyDataService::getStatistikBulanan(); - $bukuPinjamOffline = $bukuPinjam; - $bacaBukuOnline = DummyDataService::getBacaBukuOnline($user); - $rekomendasiPembelajaran = DummyDataService::getRekomendasiPembelajaran(); - $personalNotif = DummyDataService::getNotifikasiForUser($user); + // Stats calculation + $stats = [ + ['label' => 'Buku yang dipinjam', 'value' => $loans->count(), 'icon' => 'bi-book-half', 'color' => 'primary'], + ['label' => 'Tenggat Waktu', 'value' => $bukuPinjamOffline->where('sisa_hari', '<=', 3)->where('sisa_hari', '>=', 0)->count(), 'icon' => 'bi-clock-history', 'color' => 'danger'], + ['label' => 'Buku dikembalikan', 'value' => Loan::where('user_id', $user->id)->where('status', 'Dikembalikan')->count(), 'icon' => 'bi-check-circle', 'color' => 'success'], + ['label' => 'History Baca', 'value' => Loan::where('user_id', $user->id)->count(), 'icon' => 'bi-hourglass-split', 'color' => 'warning'], + ]; - // Cek apakah ada notifikasi denda aktif - $dendaAlert = collect($personalNotif)->where('type', 'denda_active'); + $pengumuman = Announcement::latest()->take(5)->get(); + + // Placeholder for pemberitahuan (system notifications) + $pemberitahuan = collect([ + ['type' => 'info', 'icon' => 'bi-bell-fill', 'title' => 'Selamat Datang', 'content' => 'Selamat datang di perpustakaan digital SMKN 1.', 'badge' => 'Baru'] + ]); - // Menambahkan thumbnail YouTube ke setiap rekomendasi - $rekomendasiPembelajaran = $rekomendasiPembelajaran->map(function ($item) { - $videoId = $this->extractYouTubeId($item['youtube_link']); - if ($videoId) { - $item['thumbnail'] = "https://img.youtube.com/vi/{$videoId}/hqdefault.jpg"; - } else { - $item['thumbnail'] = 'https://via.placeholder.com/150?text=No+Preview'; - } - return $item; + $progressMembaca = ['selesai' => 70, 'sisa' => 30]; // Still dummy as we don't track pages yet + $statistikBulanan = [ + 'labels' => ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul'], + 'data' => [10, 15, 8, 20, 18, 25, 22], + ]; + + // Online books (books with 'online' in tipe_akses) + $bacaBukuOnline = $loans->filter(function ($loan) { + return in_array('online', $loan->book->tipe_akses ?? []); + })->map(fn($loan) => [ + 'judul' => $loan->book->judul, + 'penulis' => $loan->book->penulis, + 'progress' => 0, // Placeholder + 'cover' => $loan->book->cover, + ]); + + $recommendations = Recommendation::all(); + $rekomendasiPembelajaran = $recommendations->map(function ($item) { + $videoId = $this->extractYouTubeId($item->youtube_link); + return [ + 'id' => $item->id, + 'judul' => $item->judul, + 'kategori' => $item->kategori, + 'thumbnail' => $videoId ? "https://img.youtube.com/vi/{$videoId}/hqdefault.jpg" : 'https://via.placeholder.com/150?text=No+Preview', + 'youtube_link' => $item->youtube_link, + 'deskripsi' => $item->deskripsi, + ]; }); - $dendaAlert = collect($personalNotif)->where('type', 'denda_active'); + // Dynamic notifications based on loans + $personalNotif = collect(); + foreach ($bukuPinjamOffline as $buku) { + if ($buku['sisa_hari'] < 0) { + $hariTelat = abs($buku['sisa_hari']); + $denda = $hariTelat * 1000; + $personalNotif->push([ + 'icon' => 'bi-exclamation-octagon-fill', + 'color' => 'danger', + 'title' => 'TERLAMBAT: ' . $buku['judul'], + 'content' => "Telat {$hariTelat} hari. Denda: Rp " . number_format($denda, 0, ',', '.'), + 'time' => 'Sekarang', + 'read' => false, + 'type' => 'denda_active', + ]); + } elseif ($buku['sisa_hari'] <= 3) { + $personalNotif->push([ + 'icon' => 'bi-exclamation-triangle-fill', + 'color' => 'warning', + 'title' => 'Jatuh Tempo: ' . $buku['judul'], + 'content' => "Sisa waktu tinggal " . $buku['sisa_hari'] . " hari lagi.", + 'time' => 'Segera', + 'read' => false, + 'type' => 'warning_jatuh_tempo', + ]); + } + } + + $personalNotif->push([ + 'icon' => 'bi-info-circle-fill', + 'color' => 'primary', + 'title' => 'Selamat Datang!', + 'content' => 'Jelajahi koleksi buku terbaru kami.', + 'time' => 'Baru saja', + 'read' => true, + 'type' => 'info', + ]); + + $dendaAlert = $personalNotif->where('type', 'denda_active'); $hour = date('H'); $greeting = "Selamat Pagi"; - if ($hour >= 12 && $hour < 15) - $greeting = "Selamat Siang"; - elseif ($hour >= 15 && $hour < 18) - $greeting = "Selamat Sore"; - elseif ($hour >= 18) - $greeting = "Selamat Malam"; + if ($hour >= 12 && $hour < 15) $greeting = "Selamat Siang"; + elseif ($hour >= 15 && $hour < 18) $greeting = "Selamat Sore"; + elseif ($hour >= 18) $greeting = "Selamat Malam"; return view('dashboard', compact( 'user', @@ -70,10 +146,7 @@ public function index() 'rekomendasiPembelajaran' ))->with('notifikasi', $personalNotif); } - - /** - * Helper function untuk mengekstrak ID video dari URL YouTube. - */ + private function extractYouTubeId(string $url): ?string { preg_match('/(v=|vi=|youtu.be\/|embed\/|\/v\/|\?v=|\&v=)(.+?)\b/i', $url, $matches); diff --git a/app/Http/Controllers/Guru/LaporanController.php b/app/Http/Controllers/Guru/LaporanController.php index 35d3f38..4e7459f 100644 --- a/app/Http/Controllers/Guru/LaporanController.php +++ b/app/Http/Controllers/Guru/LaporanController.php @@ -3,16 +3,74 @@ namespace App\Http\Controllers\Guru; use App\Http\Controllers\Controller; -use App\Services\DummyDataService; +use App\Models\Book; +use App\Models\Category; +use App\Models\Loan; +use App\Models\User; +use Carbon\Carbon; use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; class LaporanController extends Controller { public function index() { - $laporan = DummyDataService::getLaporanMinatBaca(); - $siswaTeraktif = DummyDataService::getSiswaTeraktif(); - $aktivitasMingguan = DummyDataService::getAktivitasMingguan(); + // 1. Laporan Minat Baca (Buku Terpopuler & Kategori Populer) + $bukuTerpopuler = Book::withCount('loans') + ->orderBy('loans_count', 'desc') + ->take(3) + ->get() + ->map(fn($book) => [ + 'judul' => $book->judul, + 'penulis' => $book->penulis, + 'total_pembaca' => $book->loans_count, + 'cover' => $book->cover, + ]); + + $kategoriPopuler = Category::withCount(['books as total_pembaca' => function ($query) { + $query->join('loans', 'books.id', '=', 'loans.book_id'); + }]) + ->orderBy('total_pembaca', 'desc') + ->take(4) + ->get() + ->map(fn($cat) => [ + 'nama' => $cat->name, + 'total_pembaca' => $cat->total_pembaca, + 'trend' => 'naik', // Placeholder + 'icon' => 'bi-arrow-up-right', + ]); + + $laporan = [ + 'buku_terpopuler' => $bukuTerpopuler, + 'kategori_populer' => $kategoriPopuler, + 'insight' => 'Siswa menunjukkan minat baca yang dinamis. Kategori ' . ($kategoriPopuler->first()['nama'] ?? 'Populer') . ' menjadi favorit saat ini.', + ]; + + // 2. Siswa Teraktif + $siswaTeraktif = User::where('role', 'siswa') + ->withCount('loans') + ->orderBy('loans_count', 'desc') + ->take(10) + ->get() + ->map(fn($user) => [ + 'nama' => $user->nama_lengkap, + 'total_buku' => $user->loans_count, + 'kelas' => $user->kelas ?? 'N/A', + ]); + + // 3. Aktivitas Mingguan (7 hari terakhir) + $labels = []; + $data = []; + for ($i = 6; $i >= 0; $i--) { + $date = Carbon::now()->subDays($i); + $labels[] = $date->translatedFormat('l'); + $data[] = Loan::whereDate('borrowed_at', $date->toDateString())->count(); + } + + $aktivitasMingguan = [ + 'labels' => $labels, + 'data' => $data, + ]; return view('guru.laporan.index', [ 'pageTitle' => 'Laporan Minat Baca Siswa', diff --git a/app/Http/Controllers/KatalogController.php b/app/Http/Controllers/KatalogController.php index af3a3e4..5af8063 100644 --- a/app/Http/Controllers/KatalogController.php +++ b/app/Http/Controllers/KatalogController.php @@ -2,7 +2,10 @@ namespace App\Http\Controllers; -use App\Services\DummyDataService; +use App\Models\Book; +use App\Models\Category; +use App\Models\Loan; +use Carbon\Carbon; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; @@ -14,15 +17,46 @@ public function index(Request $request) $isBanned = false; if ($user && $user->role === 'siswa') { - $bukuPinjam = DummyDataService::getBukuPinjamOffline($user); - $isTelat = collect($bukuPinjam)->contains(fn($b) => $b['sisa_hari'] < 0); - $isBannedManual = $user->is_banned ?? false; - $isBanned = $isTelat || $isBannedManual; + // Check for overdue loans + $hasOverdue = Loan::where('user_id', $user->id) + ->whereIn('status', ['Dipinjam', 'Terlambat']) + ->where('due_at', '<', now()) + ->exists(); + + $isBanned = $hasOverdue || ($user->is_banned ?? false); } $filters = $request->only(['search', 'kategori', 'tahun', 'penulis']); - $semuaBuku = DummyDataService::getKatalogBuku($filters); - $filterOptions = DummyDataService::getFilterOptions(); + + // Query books with filters + $query = Book::with('category'); + + if ($request->filled('search')) { + $query->where('judul', 'like', '%' . $request->search . '%'); + } + + if ($request->filled('kategori')) { + $query->whereHas('category', function($q) use ($request) { + $q->where('name', $request->kategori); + }); + } + + if ($request->filled('tahun')) { + $query->where('tahun', $request->tahun); + } + + if ($request->filled('penulis')) { + $query->where('penulis', $request->penulis); + } + + $semuaBuku = $query->latest()->get(); + + // Get filter options dynamically + $filterOptions = [ + 'kategori' => Category::pluck('name')->unique()->sort()->values(), + 'tahun' => Book::pluck('tahun')->unique()->sortDesc()->values(), + 'penulis' => Book::pluck('penulis')->unique()->sort()->values(), + ]; return view('katalog.index', [ 'semuaBuku' => $semuaBuku, diff --git a/app/Http/Controllers/PeminjamanController.php b/app/Http/Controllers/PeminjamanController.php index 54a833a..4c88e24 100644 --- a/app/Http/Controllers/PeminjamanController.php +++ b/app/Http/Controllers/PeminjamanController.php @@ -2,30 +2,60 @@ namespace App\Http\Controllers; -use App\Services\DummyDataService; +use App\Models\Book; +use App\Models\Category; +use App\Models\Loan; +use Carbon\Carbon; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Str; class PeminjamanController extends Controller { public function index(Request $request) { - $user = \Illuminate\Support\Facades\Auth::user(); - $bukuPinjam = \App\Services\DummyDataService::getBukuPinjamOffline($user); - $isTelat = collect($bukuPinjam)->contains(function ($buku) { - return $buku['sisa_hari'] < 0; - }); + $user = Auth::user(); - $isBannedManual = $user->is_banned ?? false; + // Check for overdue loans + $hasOverdue = Loan::where('user_id', $user->id) + ->whereIn('status', ['Dipinjam', 'Terlambat']) + ->where('due_at', '<', now()) + ->exists(); - if (($isTelat || $isBannedManual) && $user->role === 'siswa') { + if (($hasOverdue || $user->is_banned) && $user->role === 'siswa') { return redirect()->route('dashboard')->with('error', 'AKSES DITOLAK: Akun Anda sedang dibekukan karena ada buku terlambat!'); } $filters = $request->only(['search', 'kategori', 'tahun', 'penulis']); - $filters['tipe_akses'] = 'offline'; - $semuaBuku = DummyDataService::getKatalogBuku($filters); - $filterOptions = DummyDataService::getFilterOptions(); + + $query = Book::with('category')->whereJsonContains('tipe_akses', 'offline'); + + if ($request->filled('search')) { + $query->where('judul', 'like', '%' . $request->search . '%'); + } + + if ($request->filled('kategori')) { + $query->whereHas('category', function($q) use ($request) { + $q->where('name', $request->kategori); + }); + } + + if ($request->filled('tahun')) { + $query->where('tahun', $request->tahun); + } + + if ($request->filled('penulis')) { + $query->where('penulis', $request->penulis); + } + + $semuaBuku = $query->latest()->get(); + + $filterOptions = [ + 'kategori' => Category::pluck('name')->unique()->sort()->values(), + 'tahun' => Book::pluck('tahun')->unique()->sortDesc()->values(), + 'penulis' => Book::pluck('penulis')->unique()->sort()->values(), + ]; return view('katalog.index', [ 'semuaBuku' => $semuaBuku, @@ -39,7 +69,7 @@ public function index(Request $request) public function ringkasan($id) { $user = Auth::user(); - $buku = DummyDataService::getKatalogBuku()->firstWhere('id', $id); + $buku = Book::with('category')->findOrFail($id); return view('katalog.ringkasan', [ 'user' => $user, @@ -52,13 +82,14 @@ public function ringkasan($id) ]); } - public function form($id) { $user = Auth::user(); - $buku = DummyDataService::getKatalogBuku()->firstWhere('id', $id); - $filters = ['tipe_akses' => 'offline']; - $semuaBuku = DummyDataService::getKatalogBuku($filters); + $buku = Book::with('category')->findOrFail($id); + + $semuaBuku = Book::whereJsonContains('tipe_akses', 'offline') + ->where('status', 'Tersedia') + ->get(); return view('peminjaman.form', compact('user', 'buku', 'semuaBuku')); } @@ -67,21 +98,31 @@ public function store(Request $request) { $request->validate([ 'buku_ids' => 'required|array|min:1|max:3', - 'buku_ids.*' => 'integer' + 'buku_ids.*' => 'exists:books,id' ]); $bukuIds = $request->input('buku_ids'); - foreach ($bukuIds as $bukuId) { - // Di backend nanti kayak gini - // Peminjaman::create([ - // 'user_id' => auth()->id(), - // 'book_id' => $bukuId, - // 'tanggal_pinjam' => now(), - // 'tanggal_kembali' => now()->addDays(7), - // 'status' => 'dipinjam' - // ]); - } + DB::transaction(function () use ($bukuIds) { + foreach ($bukuIds as $bukuId) { + $book = Book::lockForUpdate()->find($bukuId); + + if ($book->status !== 'Tersedia') { + throw new \Exception("Buku '{$book->judul}' sudah tidak tersedia."); + } + + Loan::create([ + 'user_id' => Auth::id(), + 'book_id' => $bukuId, + 'loan_code' => 'PIN-' . date('Ym') . '-' . strtoupper(Str::random(4)) . '-' . $bukuId, + 'borrowed_at' => now(), + 'due_at' => now()->addDays(7), + 'status' => 'Dipinjam', + ]); + + $book->update(['status' => 'Dipinjam']); + } + }); return redirect()->route('dashboard') ->with('success', 'Berhasil meminjam ' . count($bukuIds) . ' buku!'); diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index 912d71c..fad62f6 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -3,12 +3,15 @@ namespace App\Http\Controllers; use App\Http\Requests\ProfileUpdateRequest; +use App\Models\Book; +use App\Models\Loan; +use App\Models\User; +use Carbon\Carbon; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Redirect; use Illuminate\View\View; -use App\Services\DummyDataService; class ProfileController extends Controller { @@ -19,7 +22,7 @@ public function index(): RedirectResponse|View { $user = Auth::user(); if (!$user) { - return redirect()->route(route: 'login'); + return redirect()->route('login'); } $viewData = ['user' => $user]; @@ -27,20 +30,68 @@ public function index(): RedirectResponse|View // Menyiapkan data berdasarkan role pengguna if ($user->role === 'penjaga perpus') { // Data untuk Penjaga Perpus: Statistik global & aktivitas terkini - $viewData['statistik'] = DummyDataService::getAdminDashboardStats(); - $viewData['aktivitasTerakhir'] = DummyDataService::getAktivitasTerakhir(); + $viewData['statistik'] = [ + ['label' => 'Total Buku', 'value' => Book::count(), 'icon' => 'bi-journal-bookmark-fill', 'color' => 'primary'], + ['label' => 'Total Anggota', 'value' => User::count(), 'icon' => 'bi-people-fill', 'color' => 'success'], + ['label' => 'Buku Dipinjam', 'value' => Loan::whereIn('status', ['Dipinjam', 'Terlambat'])->count(), 'icon' => 'bi-arrow-up-right-circle-fill', 'color' => 'warning'], + ['label' => 'Denda Menunggu', 'value' => Loan::where('status', 'Terlambat')->count(), 'icon' => 'bi-cash-coin', 'color' => 'danger'], + ]; + $viewData['aktivitasTerakhir'] = Loan::with(['user', 'book'])->latest()->take(4)->get()->map(fn($loan) => [ + 'nama' => $loan->user->nama_lengkap ?? 'Unknown', + 'judul_buku' => $loan->book->judul ?? 'Unknown', + 'tipe' => $loan->status === 'Dikembalikan' ? 'Pengembalian' : 'Peminjaman', + 'waktu' => $loan->created_at->diffForHumans(), + 'status' => $loan->status, + ]); } elseif ($user->role === 'guru') { - // Data untuk Guru: Data personal + ringkasan laporan minat baca - $viewData['bukuOffline'] = DummyDataService::getBukuPinjamOffline($user); - $viewData['bukuOnline'] = DummyDataService::getBacaBukuOnline($user); - $viewData['laporan'] = DummyDataService::getLaporanMinatBaca(); + // Data untuk Guru + $loans = Loan::with('book')->where('user_id', $user->id)->whereIn('status', ['Dipinjam', 'Terlambat'])->get(); + + $viewData['bukuOffline'] = $loans->map(fn($loan) => [ + 'judul' => $loan->book->judul, + 'penulis' => $loan->book->penulis, + 'sisa_hari' => (int) now()->diffInDays(Carbon::parse($loan->due_at), false), + 'cover' => $loan->book->cover, + ]); + + $viewData['bukuOnline'] = $loans->filter(fn($loan) => in_array('online', $loan->book->tipe_akses ?? []))->map(fn($loan) => [ + 'judul' => $loan->book->judul, + 'penulis' => $loan->book->penulis, + 'progress' => 0, + 'cover' => $loan->book->cover, + ]); + + // Analytics for Guru (simplified for profile view) + $viewData['laporan'] = [ + 'buku_terpopuler' => Book::withCount('loans')->orderBy('loans_count', 'desc')->take(3)->get(), + 'insight' => 'Siswa aktif meminjam buku kategori Sains.' + ]; } else { - // Data default untuk Siswa - $viewData['bukuOffline'] = DummyDataService::getBukuPinjamOffline($user); - $viewData['bukuOnline'] = DummyDataService::getBacaBukuOnline($user); - $viewData['statistik'] = DummyDataService::getDashboardStats(); + // Data untuk Siswa + $loans = Loan::with('book')->where('user_id', $user->id)->whereIn('status', ['Dipinjam', 'Terlambat'])->get(); + + $viewData['bukuOffline'] = $loans->map(fn($loan) => [ + 'judul' => $loan->book->judul, + 'penulis' => $loan->book->penulis, + 'sisa_hari' => (int) now()->diffInDays(Carbon::parse($loan->due_at), false), + 'cover' => $loan->book->cover, + ]); + + $viewData['bukuOnline'] = $loans->filter(fn($loan) => in_array('online', $loan->book->tipe_akses ?? []))->map(fn($loan) => [ + 'judul' => $loan->book->judul, + 'penulis' => $loan->book->penulis, + 'progress' => 0, + 'cover' => $loan->book->cover, + ]); + + $viewData['statistik'] = [ + ['label' => 'Buku dipinjam', 'value' => $loans->count(), 'icon' => 'bi-book-half', 'color' => 'primary'], + ['label' => 'Tenggat Waktu', 'value' => $viewData['bukuOffline']->where('sisa_hari', '<=', 3)->where('sisa_hari', '>=', 0)->count(), 'icon' => 'bi-clock-history', 'color' => 'danger'], + ['label' => 'Buku dikembalikan', 'value' => Loan::where('user_id', $user->id)->where('status', 'Dikembalikan')->count(), 'icon' => 'bi-check-circle', 'color' => 'success'], + ['label' => 'History Baca', 'value' => Loan::where('user_id', $user->id)->count(), 'icon' => 'bi-hourglass-split', 'color' => 'warning'], + ]; } return view('profile.index', $viewData); diff --git a/app/Http/Controllers/RekomendasiController.php b/app/Http/Controllers/RekomendasiController.php index 6d91141..ca75006 100644 --- a/app/Http/Controllers/RekomendasiController.php +++ b/app/Http/Controllers/RekomendasiController.php @@ -2,7 +2,7 @@ namespace App\Http\Controllers; -use App\Services\DummyDataService; +use App\Models\Recommendation; class RekomendasiController extends Controller { @@ -17,20 +17,20 @@ private function extractYouTubeId(string $url): ?string public function show($id) { - $rekomendasi = DummyDataService::getRekomendasiPembelajaran()->firstWhere('id', (int)$id); - abort_if(!$rekomendasi, 404); + $rekomendasi = Recommendation::findOrFail($id); - // Menambahkan thumbnail YouTube ke setiap rekomendasi $embedLink = null; - $videoId = $this->extractYouTubeId($rekomendasi['youtube_link']); + $videoId = $this->extractYouTubeId($rekomendasi->youtube_link); if ($videoId) { $embedLink = "https://www.youtube.com/embed/" . $videoId; } - $rekomendasi['youtube_embed_link'] = $embedLink; + + $data = $rekomendasi->toArray(); + $data['youtube_embed_link'] = $embedLink; return view('rekomendasiShow', [ - 'pageTitle' => $rekomendasi['judul'], - 'rekomendasi' => $rekomendasi, + 'pageTitle' => $rekomendasi->judul, + 'rekomendasi' => $data, ]); } } \ No newline at end of file diff --git a/app/Http/Controllers/RiwayatController.php b/app/Http/Controllers/RiwayatController.php index 9180c87..18b014f 100644 --- a/app/Http/Controllers/RiwayatController.php +++ b/app/Http/Controllers/RiwayatController.php @@ -2,18 +2,43 @@ namespace App\Http\Controllers; -use App\Services\DummyDataService; +use App\Models\Loan; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Auth; // Tambahkan ini +use Illuminate\Support\Facades\Auth; class RiwayatController extends Controller { public function offlineIndex() { - $user = \Illuminate\Support\Facades\Auth::user(); - if (!$user) $user = (object) ['id' => 1]; + $user = Auth::user(); + + $loans = Loan::with('book.category') + ->where('user_id', $user->id) + ->whereIn('status', ['Dipinjam', 'Dikembalikan', 'Terlambat']) + ->latest() + ->get(); - $riwayatOffline = DummyDataService::getRiwayatOffline($user); + $riwayatOffline = $loans->map(fn($loan) => [ + 'id' => $loan->id, + 'id_peminjaman' => $loan->loan_code, + 'kode_buku' => $loan->book->kode_buku, + 'judul_utama' => $loan->book->judul, + 'tanggal_pinjam' => $loan->borrowed_at->format('d/m/Y'), + 'tanggal_kembali' => $loan->due_at ? $loan->due_at->format('d/m/Y') : '-', + 'status' => $loan->status, + 'books' => [ + [ + 'id' => $loan->book->id, + 'judul' => $loan->book->judul, + 'kode_buku' => $loan->book->kode_buku, + 'cover' => $loan->book->cover, + 'deskripsi' => 'Buku ' . $loan->book->judul, + 'kategori' => $loan->book->category->name ?? 'Tanpa Kategori', + 'tahun' => $loan->book->tahun, + 'keterangan' => $loan->status === 'Terlambat' ? 'Buku Terlambat' : null, + ] + ] + ]); return view('riwayat.offline', [ 'pageTitle' => 'Riwayat Peminjaman Offline', @@ -23,7 +48,32 @@ public function offlineIndex() public function onlineIndex() { - $riwayatOnline = DummyDataService::getRiwayatOnline(); + $user = Auth::user(); + + $loans = Loan::with('book.category') + ->where('user_id', $user->id) + ->where('status', 'Online') + ->latest() + ->get(); + + $riwayatOnline = $loans->map(fn($loan) => [ + 'id' => $loan->id, + 'id_baca' => $loan->loan_code, + 'judul_buku' => $loan->book->judul, + 'tanggal_akses' => $loan->borrowed_at->format('d/m/Y'), + 'status' => 'Selesai', + 'books' => [ + [ + 'id' => $loan->book->id, + 'judul' => $loan->book->judul, + 'cover' => $loan->book->cover, + 'deskripsi' => 'Buku ' . $loan->book->judul, + 'kategori' => $loan->book->category->name ?? 'Tanpa Kategori', + 'tahun' => $loan->book->tahun, + 'keterangan' => null + ] + ] + ]); return view('riwayat.online', [ 'pageTitle' => 'Riwayat Baca Online', diff --git a/app/Http/Requests/Auth/LoginRequest.php b/app/Http/Requests/Auth/LoginRequest.php index fc9d73e..133504c 100644 --- a/app/Http/Requests/Auth/LoginRequest.php +++ b/app/Http/Requests/Auth/LoginRequest.php @@ -52,64 +52,50 @@ public function rules(): array */ public function authenticate(): void { - // Pastikan pengguna tidak mencoba login terlalu sering (mencegah brute-force). $this->ensureIsNotRateLimited(); - // Ambil data yang dikirim dari form login. $roleDariForm = $this->input('role'); - $allUsers = DummyDataService::getAllSiswa(); - $inputPassword = $this->input('password'); - $userArray = null; - - // Tentukan field mana yang akan menerima pesan error jika gagal (nisn atau email). + $loginIdentifier = $this->input('nisn') ?: $this->input('nip'); + $password = $this->input('password'); + $errorField = $this->filled('nisn') ? 'nisn' : 'nip'; - // Cari data pengguna berdasarkan input yang diberikan. - if ($this->filled('nisn')) { - // Jika form diisi dengan 'nisn', cari pengguna berdasarkan 'nisn'. - $userArray = collect($allUsers)->firstWhere('nisn', $this->input('nisn')); - } else { - // Jika tidak, cari pengguna berdasarkan 'nip'. - $userArray = collect($allUsers)->firstWhere('nip', $this->input('nip')); + if (!Auth::attempt(['nomor_induk' => $loginIdentifier, 'password' => $password], $this->boolean('remember'))) { + RateLimiter::hit($this->throttleKey()); + + throw ValidationException::withMessages([ + $errorField => trans('auth.failed'), + ]); } - // Lakukan Pengecekan Kredensial dan Role. - if ($userArray && $userArray['password'] === $inputPassword) { - - // Cek #2: Jika kredensial benar, apakah role pengguna sesuai dengan form yang digunakan? - if (isset($userArray['role']) && $userArray['role'] === $roleDariForm) { - - // Buat objek User dari data dummy. - $userModel = new User(); - $userArray['name'] = $userArray['nama_lengkap']; - $userModel->forceFill($userArray); + $user = Auth::user(); - // Loginkan pengguna secara resmi ke dalam sistem. - Auth::login($userModel); + // Cek jika role sesuai + if ($user->role !== $roleDariForm) { + Auth::logout(); + $this->session()->invalidate(); + $this->session()->regenerateToken(); - // Reset hitungan percobaan login yang gagal. - RateLimiter::clear($this->throttleKey()); - return; // Proses autentikasi berhasil. + RateLimiter::hit($this->throttleKey()); - } else { - // Tambah hitungan percobaan login yang gagal. - RateLimiter::hit($this->throttleKey()); - - // Ambil nama role asli pengguna untuk ditampilkan di pesan error. - $actualRole = Str::title($userArray['role'] ?? 'Tidak Dikenal'); - - // Lemparkan error validasi khusus 'forbidden' dengan pesan yang jelas. - throw ValidationException::withMessages([ - 'forbidden' => "Akses ditolak. Akun ini terdaftar sebagai {$actualRole}.", - ]); - } + $actualRole = Str::title($user->role ?? 'Tidak Dikenal'); + throw ValidationException::withMessages([ + 'forbidden' => "Akses ditolak. Akun ini terdaftar sebagai {$actualRole}.", + ]); } - // Jika pengguna tidak ditemukan atau password salah. - RateLimiter::hit($this->throttleKey()); - throw ValidationException::withMessages([ - $errorField => trans('auth.failed'), // Pesan error umum "These credentials do not match...". - ]); + // Cek jika akun di-banned + if ($user->is_banned) { + Auth::logout(); + $this->session()->invalidate(); + $this->session()->regenerateToken(); + + throw ValidationException::withMessages([ + 'forbidden' => "Akun Anda telah dinonaktifkan. Silakan hubungi admin.", + ]); + } + + RateLimiter::clear($this->throttleKey()); } /** diff --git a/app/Models/Announcement.php b/app/Models/Announcement.php new file mode 100644 index 0000000..d4615e6 --- /dev/null +++ b/app/Models/Announcement.php @@ -0,0 +1,10 @@ + 'array', + 'is_new' => 'boolean', + ]; + + public function category() + { + return $this->belongsTo(Category::class); + } + + public function loans() + { + return $this->hasMany(Loan::class); + } +} diff --git a/app/Models/Category.php b/app/Models/Category.php new file mode 100644 index 0000000..92aeed3 --- /dev/null +++ b/app/Models/Category.php @@ -0,0 +1,15 @@ +hasMany(Book::class); + } +} diff --git a/app/Models/Loan.php b/app/Models/Loan.php new file mode 100644 index 0000000..b825af0 --- /dev/null +++ b/app/Models/Loan.php @@ -0,0 +1,29 @@ + 'datetime', + 'due_at' => 'datetime', + 'returned_at' => 'datetime', + ]; + + public function user() + { + return $this->belongsTo(User::class); + } + + public function book() + { + return $this->belongsTo(Book::class); + } +} diff --git a/app/Models/Recommendation.php b/app/Models/Recommendation.php new file mode 100644 index 0000000..9f76dae --- /dev/null +++ b/app/Models/Recommendation.php @@ -0,0 +1,10 @@ +where('user_id', $user->id) + ->whereIn('status', ['Dipinjam', 'Terlambat']) + ->get(); + + $notifikasi = collect(); + + foreach ($loans as $loan) { + $dueAt = Carbon::parse($loan->due_at); + $sisaHari = (int) now()->diffInDays($dueAt, false); + + if ($sisaHari < 0) { + $notifikasi->push([ + 'icon' => 'bi-exclamation-octagon-fill', + 'color' => 'danger', + 'title' => 'TERLAMBAT: ' . $loan->book->judul, + 'content' => "Segera kembalikan buku. Denda berlaku.", + 'time' => 'Sekarang', + 'read' => false, + 'type' => 'denda_active', + ]); + } elseif ($sisaHari <= 3) { + $notifikasi->push([ + 'icon' => 'bi-exclamation-triangle-fill', + 'color' => 'warning', + 'title' => 'Jatuh Tempo: ' . $loan->book->judul, + 'content' => "Tersisa {$sisaHari} hari lagi.", + 'time' => 'Segera', + 'read' => false, + 'type' => 'warning_jatuh_tempo', + ]); + } + } + $unreadCount = $notifikasi->where('read', false)->count(); $view->with('notifikasi', $notifikasi); $view->with('unreadNotificationsCount', $unreadCount); diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index ab98e25..bdfbd30 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -22,9 +22,6 @@ class AuthServiceProvider extends ServiceProvider */ public function boot(): void { - // Daftarkan provider kustom kita di sini - Auth::provider('dummy', function ($app, array $config) { - return new DummyUserProvider(); - }); + // } } \ No newline at end of file diff --git a/config/auth.php b/config/auth.php index 688de68..48e4d3f 100644 --- a/config/auth.php +++ b/config/auth.php @@ -38,7 +38,7 @@ 'guards' => [ 'web' => [ 'driver' => 'session', - 'provider' => 'dummy', + 'provider' => 'users', ], ], @@ -64,10 +64,6 @@ 'driver' => 'eloquent', 'model' => env('AUTH_MODEL', App\Models\User::class), ], - - 'dummy' => [ - 'driver' => 'dummy', - ], ], /* diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index 584104c..9eb12c9 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -25,9 +25,12 @@ public function definition(): array { return [ 'name' => fake()->name(), + 'nama_lengkap' => fake()->name(), 'email' => fake()->unique()->safeEmail(), 'email_verified_at' => now(), 'password' => static::$password ??= Hash::make('password'), + 'nomor_induk' => fake()->unique()->numerify('##########'), + 'role' => 'siswa', 'remember_token' => Str::random(10), ]; } diff --git a/database/migrations/0001_01_01_000000_create_users_table.php b/database/migrations/0001_01_01_000000_create_users_table.php index 05fb5d9..fecf661 100644 --- a/database/migrations/0001_01_01_000000_create_users_table.php +++ b/database/migrations/0001_01_01_000000_create_users_table.php @@ -14,9 +14,17 @@ public function up(): void Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('name'); + $table->string('nama_lengkap')->nullable(); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); + $table->string('nomor_induk')->unique(); + $table->string('phone')->nullable(); + $table->string('nuptk')->nullable(); + $table->string('role'); + $table->boolean('is_banned')->default(false); + $table->string('kelas')->nullable(); + $table->string('golongan')->nullable(); $table->rememberToken(); $table->timestamps(); }); diff --git a/database/migrations/2026_02_04_093110_create_classes_table.php b/database/migrations/2026_02_04_093110_create_classes_table.php new file mode 100644 index 0000000..8720389 --- /dev/null +++ b/database/migrations/2026_02_04_093110_create_classes_table.php @@ -0,0 +1,30 @@ +id(); + $table->string('class'); + $table->string('class_name'); + $table->foreignId('id_users')->nullable()->constrained('users')->onDelete('cascade'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('classes'); + } +}; diff --git a/database/migrations/2026_02_04_191120_create_categories_table.php b/database/migrations/2026_02_04_191120_create_categories_table.php new file mode 100644 index 0000000..4fe1bd3 --- /dev/null +++ b/database/migrations/2026_02_04_191120_create_categories_table.php @@ -0,0 +1,29 @@ +id(); + $table->string('name'); + $table->string('slug')->unique(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('categories'); + } +}; diff --git a/database/migrations/2026_02_04_191121_create_books_table.php b/database/migrations/2026_02_04_191121_create_books_table.php new file mode 100644 index 0000000..a6a7d51 --- /dev/null +++ b/database/migrations/2026_02_04_191121_create_books_table.php @@ -0,0 +1,36 @@ +id(); + $table->string('judul'); + $table->string('penulis'); + $table->string('cover')->nullable(); + $table->string('kode_buku')->unique(); + $table->foreignId('category_id')->constrained('categories')->onDelete('cascade'); + $table->integer('tahun'); + $table->string('status')->default('Tersedia'); + $table->boolean('is_new')->default(false); + $table->json('tipe_akses'); // ['online', 'offline'] + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('books'); + } +}; diff --git a/database/migrations/2026_02_04_191122_create_loans_table.php b/database/migrations/2026_02_04_191122_create_loans_table.php new file mode 100644 index 0000000..536be9b --- /dev/null +++ b/database/migrations/2026_02_04_191122_create_loans_table.php @@ -0,0 +1,34 @@ +id(); + $table->foreignId('user_id')->constrained('users')->onDelete('cascade'); + $table->foreignId('book_id')->constrained('books')->onDelete('cascade'); + $table->string('loan_code')->unique(); + $table->timestamp('borrowed_at')->useCurrent(); + $table->timestamp('due_at')->nullable(); + $table->timestamp('returned_at')->nullable(); + $table->string('status'); // Dipinjam, Dikembalikan, Terlambat, Online + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('loans'); + } +}; diff --git a/database/migrations/2026_02_04_191128_create_announcements_table.php b/database/migrations/2026_02_04_191128_create_announcements_table.php new file mode 100644 index 0000000..b208f90 --- /dev/null +++ b/database/migrations/2026_02_04_191128_create_announcements_table.php @@ -0,0 +1,31 @@ +id(); + $table->string('type'); // warning, info, success, etc. + $table->string('icon'); + $table->string('title'); + $table->text('content'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('announcements'); + } +}; diff --git a/database/migrations/2026_02_04_191128_create_recommendations_table.php b/database/migrations/2026_02_04_191128_create_recommendations_table.php new file mode 100644 index 0000000..4bfa79b --- /dev/null +++ b/database/migrations/2026_02_04_191128_create_recommendations_table.php @@ -0,0 +1,31 @@ +id(); + $table->string('judul'); + $table->string('kategori'); + $table->string('youtube_link'); + $table->text('deskripsi'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('recommendations'); + } +}; diff --git a/database/seeders/AnnouncementSeeder.php b/database/seeders/AnnouncementSeeder.php new file mode 100644 index 0000000..b634bbd --- /dev/null +++ b/database/seeders/AnnouncementSeeder.php @@ -0,0 +1,30 @@ + $data['id']], + [ + 'type' => $data['type'], + 'icon' => $data['icon'], + 'title' => $data['title'], + 'content' => $data['content'], + ] + ); + } + } +} diff --git a/database/seeders/BookSeeder.php b/database/seeders/BookSeeder.php new file mode 100644 index 0000000..df74ab0 --- /dev/null +++ b/database/seeders/BookSeeder.php @@ -0,0 +1,39 @@ +first(); + + Book::updateOrCreate( + ['kode_buku' => $data['kode_buku']], + [ + 'id' => $data['id'], + 'judul' => $data['judul'], + 'penulis' => $data['penulis'], + 'cover' => $data['cover'], + 'category_id' => $category ? $category->id : null, + 'tahun' => $data['tahun'], + 'status' => $data['status'], + 'is_new' => $data['is_new'], + 'tipe_akses' => is_array($data['tipe_akses']) ? $data['tipe_akses'] : [$data['tipe_akses']], + ] + ); + } + } +} diff --git a/database/seeders/CategorySeeder.php b/database/seeders/CategorySeeder.php new file mode 100644 index 0000000..c928d19 --- /dev/null +++ b/database/seeders/CategorySeeder.php @@ -0,0 +1,32 @@ +pluck('kategori') + ->merge(collect($recommendations)->pluck('kategori')) + ->unique() + ->filter(); + + foreach ($categories as $name) { + Category::updateOrCreate( + ['slug' => Str::slug($name)], + ['name' => $name] + ); + } + } +} diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index d01a0ef..403030f 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -13,11 +13,15 @@ class DatabaseSeeder extends Seeder */ public function run(): void { - // User::factory(10)->create(); - - User::factory()->create([ - 'name' => 'Test User', - 'email' => 'test@example.com', + // User seeder is already handled or skipped as per user request + + $this->call([ + UserSeeder::class, + CategorySeeder::class, + BookSeeder::class, + RecommendationSeeder::class, + AnnouncementSeeder::class, + LoanSeeder::class, ]); } } diff --git a/database/seeders/LoanSeeder.php b/database/seeders/LoanSeeder.php new file mode 100644 index 0000000..c6635b0 --- /dev/null +++ b/database/seeders/LoanSeeder.php @@ -0,0 +1,49 @@ + $user->id, + 'book_id' => $book->id, + 'status' => $data['status'], + ], + [ + 'loan_code' => 'PIN-' . date('Ym') . '-' . sprintf('%03d', $book->id), + 'borrowed_at' => Carbon::now()->subDays(7), + 'due_at' => Carbon::now()->addDays($data['sisa_hari'] ?? 7), + 'status' => $data['status'], + ] + ); + } + } + } + } + } +} diff --git a/database/seeders/RecommendationSeeder.php b/database/seeders/RecommendationSeeder.php new file mode 100644 index 0000000..7f2d733 --- /dev/null +++ b/database/seeders/RecommendationSeeder.php @@ -0,0 +1,30 @@ + $data['id']], + [ + 'judul' => $data['judul'], + 'kategori' => $data['kategori'], + 'youtube_link' => $data['youtube_link'], + 'deskripsi' => $data['deskripsi'], + ] + ); + } + } +} diff --git a/database/seeders/UserSeeder.php b/database/seeders/UserSeeder.php new file mode 100644 index 0000000..54cd82d --- /dev/null +++ b/database/seeders/UserSeeder.php @@ -0,0 +1,53 @@ + $nomorInduk], + [ + 'id' => $data['id'], + 'name' => $data['nama_lengkap'], + 'nama_lengkap' => $data['nama_lengkap'], + 'email' => $data['email'], + 'password' => Hash::make($data['password']), + 'phone' => $data['nomor_hp'] ?? null, + 'role' => $data['role'], + 'is_banned' => $data['is_banned'] ?? false, + 'kelas' => $data['kelas'] ?? null, + 'golongan' => $data['golongan'] ?? null, + ] + ); + } + + // Default admin + User::updateOrCreate( + ['nomor_induk' => 'admin'], + [ + 'name' => 'Admin Perpustakaan', + 'nama_lengkap' => 'Admin Perpustakaan', + 'email' => 'admin@smkn1perpus.sch.id', + 'password' => Hash::make('password'), + 'role' => 'penjaga perpus', + ] + ); + } +} diff --git a/routes/web.php b/routes/web.php index 190b642..7c9e49d 100644 --- a/routes/web.php +++ b/routes/web.php @@ -37,7 +37,7 @@ // --- RUTE UNTUK PENGGUNA TERAUTENTIKASI (SISWA, GURU, & PENJAGA PERPUS) --- Route::middleware(['auth'])->group(function () { - + // Rute Umum untuk Siswa & Guru Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard'); Route::get('/katalog', [KatalogController::class, 'index'])->name('katalog.index'); @@ -80,11 +80,11 @@ // --- GRUP RUTE KHUSUS UNTUK ADMIN / PENJAGA PERPUSTAKAAN --- Route::middleware(['auth', 'role:penjaga perpus'])->prefix('admin')->name('admin.')->group(function () { Route::get('/dashboard', [AdminDashboardController::class, 'index'])->name('dashboard'); - + Route::get('/buku', [AdminBookController::class, 'index'])->name('buku.index'); Route::get('/buku/tambah', [AdminBookController::class, 'create'])->name('buku.create'); Route::get('/buku/{id}/edit', [AdminBookController::class, 'edit'])->name('buku.edit'); - + Route::get('/pengguna', [AdminUserController::class, 'index'])->name('pengguna.index'); Route::get('/pengguna/tambah', [AdminUserController::class, 'create'])->name('pengguna.create'); Route::get('/pengguna/{id}/edit', [AdminUserController::class, 'edit'])->name('pengguna.edit'); @@ -98,9 +98,9 @@ Route::get('/rekomendasi/tambah', [AdminRekomendasiController::class, 'create'])->name('rekomendasi.create'); Route::get('/rekomendasi/{id}/edit', [AdminRekomendasiController::class, 'edit'])->name('rekomendasi.edit'); - Route::get('/peminjaman', [AdminPeminjamanController::class, 'index'])->name('peminjaman.index'); - Route::get('/peminjaman/tambah', [AdminPeminjamanController::class, 'create'])->name('peminjaman.create'); - + Route::get('/peminjaman', [AdminPeminjamanController::class, 'index'])->name('peminjaman.index'); + Route::get('/peminjaman/tambah', [AdminPeminjamanController::class, 'create'])->name('peminjaman.create'); + Route::get('/denda', [AdminPeminjamanController::class, 'dendaIndex'])->name('denda.index'); Route::post('/denda/sanksi', [AdminPeminjamanController::class, 'berikanSanksi'])->name('denda.sanksi'); }); @@ -111,4 +111,4 @@ Route::post('/admin/login', [AdminLoginController::class, 'store'])->name('admin.login.store'); }); -require __DIR__ . '/auth.php'; \ No newline at end of file +require __DIR__ . '/auth.php';