feat: manajemen peminjaman with refactor color pallet and ui
This commit is contained in:
parent
7d73285b60
commit
f61187c5c0
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\DummyDataService;
|
||||
use Illuminate\Http\Request;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class AdminPeminjamanController extends Controller
|
||||
{
|
||||
/**
|
||||
* Menampilkan halaman utama manajemen peminjaman (Tabel).
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
// Panggil data dari DummyDataService
|
||||
$peminjamanAktif = DummyDataService::getAdminPeminjamanAktif();
|
||||
$daftarPeminjam = $peminjamanAktif->pluck('peminjam')->unique();
|
||||
|
||||
|
||||
return view('admin.peminjaman.index', [
|
||||
'pageTitle' => 'Manajemen Peminjaman',
|
||||
'peminjamanAktif' => $peminjamanAktif,
|
||||
'daftarPeminjam' => $daftarPeminjam,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Menampilkan formulir untuk membuat peminjaman manual.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$allUsers = collect(DummyDataService::getAllSiswa());
|
||||
|
||||
// Kelompokkan berdasarkan 'role'
|
||||
$groupedUsers = $allUsers
|
||||
->whereIn('role', ['siswa', 'guru'])
|
||||
->groupBy('role');
|
||||
|
||||
// Filter hanya buku offline
|
||||
$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';
|
||||
});
|
||||
|
||||
return view('admin.peminjaman.create', [
|
||||
'pageTitle' => 'Buat Peminjaman Manual',
|
||||
'groupedUsers' => $groupedUsers,
|
||||
'daftarBuku' => $daftarBuku,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -37,9 +37,9 @@ public function rules(): array
|
|||
];
|
||||
}
|
||||
|
||||
// Jika tidak (untuk 'guru' dan 'penjaga perpus'), validasi 'email' dan 'password'.
|
||||
// Jika tidak (untuk 'guru' dan 'penjaga perpus')
|
||||
return [
|
||||
'email' => ['required', 'string', 'email'],
|
||||
'nip' => ['required', 'string'],
|
||||
'password' => ['required', 'string'],
|
||||
];
|
||||
}
|
||||
|
|
@ -62,15 +62,15 @@ public function authenticate(): void
|
|||
$userArray = null;
|
||||
|
||||
// Tentukan field mana yang akan menerima pesan error jika gagal (nisn atau email).
|
||||
$errorField = $this->filled('nisn') ? 'nisn' : 'email';
|
||||
$errorField = $this->filled('nisn') ? 'nisn' : 'nip';
|
||||
|
||||
// Langkah 2: 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 'email'.
|
||||
$userArray = collect($allUsers)->firstWhere('email', $this->input('email'));
|
||||
// Jika tidak, cari pengguna berdasarkan 'nip'.
|
||||
$userArray = collect($allUsers)->firstWhere('nip', $this->input('nip'));
|
||||
}
|
||||
|
||||
// Langkah 3: Lakukan Pengecekan Kredensial dan Role.
|
||||
|
|
@ -144,7 +144,7 @@ public function ensureIsNotRateLimited(): void
|
|||
public function throttleKey(): string
|
||||
{
|
||||
// Gunakan 'nisn' jika ada, jika tidak, gunakan 'email' sebagai identitas.
|
||||
$loginIdentifier = $this->input('nisn') ?: $this->input('email');
|
||||
$loginIdentifier = $this->input('nisn') ?: $this->input('nip');
|
||||
return Str::transliterate(Str::lower($loginIdentifier) . '|' . $this->ip());
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace App\Services;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
||||
class DummyDataService
|
||||
{
|
||||
/**
|
||||
|
|
@ -24,6 +26,7 @@ public static function getAllSiswa(): array
|
|||
[
|
||||
'id' => 2,
|
||||
'nama_lengkap' => 'Budi Santoso',
|
||||
'nip' => '197812312005011',
|
||||
'email' => 'budi.santoso@smkn1perpus.sch.id',
|
||||
'password' => 'password',
|
||||
'role' => 'penjaga perpus',
|
||||
|
|
@ -54,6 +57,7 @@ public static function getAllSiswa(): array
|
|||
[
|
||||
'id' => 5,
|
||||
'nama_lengkap' => 'Rina Marlina',
|
||||
'nip' => '198506152010012',
|
||||
'email' => 'rina.marlina@smkn1perpus.sch.id',
|
||||
'password' => 'password',
|
||||
'role' => 'guru',
|
||||
|
|
@ -72,6 +76,164 @@ public static function getAktivitasMingguan(): array
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Data dummy untuk tabel peminjaman aktif di dashboard admin.
|
||||
*/
|
||||
public static function getAdminPeminjamanAktif(): \Illuminate\Support\Collection
|
||||
{
|
||||
return collect([
|
||||
[
|
||||
'id_peminjaman' => 'PIN-202510-001',
|
||||
'peminjam' => 'Silvi Rahmawati',
|
||||
'nomor_hp' => '08123456789',
|
||||
'tanggal_pinjam' => Carbon::now()->subDays(12),
|
||||
'tenggat_kembali' => Carbon::now()->subDays(5), // Terlambat 5 hari
|
||||
'denda_per_hari' => 1000,
|
||||
'books' => [
|
||||
['id' => 5, 'judul' => 'Si Anak Pintar'],
|
||||
['id' => 8, 'judul' => 'Ayah'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'id_peminjaman' => 'PIN-202510-002',
|
||||
'peminjam' => 'Andi Pratama',
|
||||
'nomor_hp' => '081556677889',
|
||||
'tanggal_pinjam' => Carbon::now()->subDays(4),
|
||||
'tenggat_kembali' => Carbon::now()->addDays(3), // Sisa 3 hari
|
||||
'denda_per_hari' => 1000,
|
||||
'books' => [
|
||||
['id' => 7, 'judul' => 'The Last Spell Breather'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'id_peminjaman' => 'PIN-202510-003',
|
||||
'peminjam' => 'Siti Nurhaliza',
|
||||
'nomor_hp' => '081998877665',
|
||||
'tanggal_pinjam' => Carbon::now()->subDays(7),
|
||||
'tenggat_kembali' => Carbon::now(), // Hari ini
|
||||
'denda_per_hari' => 1000,
|
||||
'books' => [
|
||||
['id' => 1, 'judul' => 'Modul Ajar IPAS'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'id_peminjaman' => 'PIN-202510-004',
|
||||
'peminjam' => 'Dewi Lestari',
|
||||
'nomor_hp' => '082134567891',
|
||||
'tanggal_pinjam' => Carbon::now()->subDays(15),
|
||||
'tenggat_kembali' => Carbon::now()->subDays(8), // Terlambat 8 hari
|
||||
'denda_per_hari' => 1000,
|
||||
'books' => [
|
||||
['id' => 2, 'judul' => 'Modul Ajar Pendidikan Pancasila'],
|
||||
['id' => 6, 'judul' => 'Matematika Dasar'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'id_peminjaman' => 'PIN-202510-005',
|
||||
'peminjam' => 'Eko Prasetyo',
|
||||
'nomor_hp' => '085612345678',
|
||||
'tanggal_pinjam' => Carbon::now()->subDays(2),
|
||||
'tenggat_kembali' => Carbon::now()->addDays(5), // Sisa 5 hari
|
||||
'denda_per_hari' => 1000,
|
||||
'books' => [
|
||||
['id' => 9, 'judul' => 'Senja, Hujan, & Cerita yang Telah Usai'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'id_peminjaman' => 'PIN-202510-006',
|
||||
'peminjam' => 'Rina Marlina',
|
||||
'nomor_hp' => '081987654321',
|
||||
'tanggal_pinjam' => Carbon::now()->subDays(10),
|
||||
'tenggat_kembali' => Carbon::now()->subDays(3), // Terlambat 3 hari
|
||||
'denda_per_hari' => 1000,
|
||||
'books' => [
|
||||
['id' => 4, 'judul' => 'Modul Pembelajaran Seni Budaya'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'id_peminjaman' => 'PIN-202510-007',
|
||||
'peminjam' => 'Budi Santoso',
|
||||
'nomor_hp' => '082298765432',
|
||||
'tanggal_pinjam' => Carbon::now()->subDays(6),
|
||||
'tenggat_kembali' => Carbon::now()->addDays(1), // Sisa 1 hari
|
||||
'denda_per_hari' => 1000,
|
||||
'books' => [
|
||||
['id' => 3, 'judul' => 'Modul Belajar Sosiologi'],
|
||||
['id' => 10, 'judul' => 'Hijrah itu Cinta'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'id_peminjaman' => 'PIN-202510-008',
|
||||
'peminjam' => 'Putri Amelia',
|
||||
'nomor_hp' => '085743219876',
|
||||
'tanggal_pinjam' => Carbon::now()->subDays(18),
|
||||
'tenggat_kembali' => Carbon::now()->subDays(11), // Terlambat 11 hari
|
||||
'denda_per_hari' => 1000,
|
||||
'books' => [
|
||||
['id' => 1, 'judul' => 'Modul Ajar IPAS'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'id_peminjaman' => 'PIN-202510-009',
|
||||
'peminjam' => 'Ahmad Haziq',
|
||||
'nomor_hp' => '081345678902',
|
||||
'tanggal_pinjam' => Carbon::now()->subDays(3),
|
||||
'tenggat_kembali' => Carbon::now()->addDays(4), // Sisa 4 hari
|
||||
'denda_per_hari' => 1000,
|
||||
'books' => [
|
||||
['id' => 7, 'judul' => 'The Last Spell Breather'],
|
||||
['id' => 8, 'judul' => 'Ayah'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'id_peminjaman' => 'PIN-202510-010',
|
||||
'peminjam' => 'John Wick',
|
||||
'nomor_hp' => '082187654309',
|
||||
'tanggal_pinjam' => Carbon::now()->subDays(8),
|
||||
'tenggat_kembali' => Carbon::now()->subDays(1), // Terlambat 1 hari
|
||||
'denda_per_hari' => 1000,
|
||||
'books' => [
|
||||
['id' => 5, 'judul' => 'Si Anak Pintar'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'id_peminjaman' => 'PIN-202510-011',
|
||||
'peminjam' => 'Silvi Rahmawati',
|
||||
'nomor_hp' => '08123456789',
|
||||
'tanggal_pinjam' => Carbon::now()->subDays(5),
|
||||
'tenggat_kembali' => Carbon::now()->addDays(2), // Sisa 2 hari
|
||||
'denda_per_hari' => 1000,
|
||||
'books' => [
|
||||
['id' => 2, 'judul' => 'Modul Ajar Pendidikan Pancasila'],
|
||||
['id' => 4, 'judul' => 'Modul Pembelajaran Seni Budaya'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'id_peminjaman' => 'PIN-202510-012',
|
||||
'peminjam' => 'Andi Pratama',
|
||||
'nomor_hp' => '081556677889',
|
||||
'tanggal_pinjam' => Carbon::now()->subDays(20),
|
||||
'tenggat_kembali' => Carbon::now()->subDays(13), // Terlambat 13 hari
|
||||
'denda_per_hari' => 1000,
|
||||
'books' => [
|
||||
['id' => 6, 'judul' => 'Matematika Dasar'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'id_peminjaman' => 'PIN-202510-013',
|
||||
'peminjam' => 'Siti Nurhaliza',
|
||||
'nomor_hp' => '081998877665',
|
||||
'tanggal_pinjam' => Carbon::now()->subDays(1),
|
||||
'tenggat_kembali' => Carbon::now()->addDays(6), // Sisa 6 hari
|
||||
'denda_per_hari' => 1000,
|
||||
'books' => [
|
||||
['id' => 9, 'judul' => 'Senja, Hujan, & Cerita yang Telah Usai'],
|
||||
['id' => 10, 'judul' => 'Hijrah itu Cinta'],
|
||||
]
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
*Data Dummy untuk fitur Rekomendasi Pembelajaran.
|
||||
*/
|
||||
|
|
@ -586,7 +748,7 @@ public static function getRiwayatOffline(): array
|
|||
'deskripsi' => 'Buku ini berisi ajakan kepada anak-anak untuk semangat pergi ke sekolah dan menuntut ilmu.',
|
||||
'kategori' => 'Pendidikan',
|
||||
'tahun' => 2022,
|
||||
'keterangan' => 'Buku dikembalikan dalam kondisi baik.'
|
||||
'keterangan' => 'Buku dikembalikan dalam kondisi baik. Terdapat denda keterlambatan 2 hari: Rp 2.000,-'
|
||||
]
|
||||
]
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,5 +1 @@
|
|||
<svg width="621" height="534" viewBox="0 0 621 534" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M83.3452 135.773C84.9945 135.934 86.7545 136.111 88.6163 136.307C101.882 137.71 120.258 140.035 140.682 143.715C182.126 151.184 229.744 163.863 260.92 184.324C268.096 189.033 277.103 195.927 284.543 201.848C288.213 204.768 291.41 207.378 293.688 209.257C294.825 210.195 295.73 210.95 296.347 211.465C296.655 211.723 296.892 211.921 297.048 212.053C297.127 212.118 297.185 212.167 297.223 212.199C297.242 212.215 297.255 212.226 297.264 212.234L297.273 212.241L306.654 220.164L316.273 212.534L316.274 212.533C316.276 212.532 316.28 212.529 316.284 212.526C316.294 212.518 316.309 212.506 316.33 212.489C316.372 212.456 316.437 212.405 316.524 212.336C316.697 212.199 316.959 211.993 317.299 211.726C317.981 211.191 318.981 210.409 320.237 209.437C322.75 207.49 326.278 204.786 330.324 201.764C338.519 195.642 348.462 188.502 356.376 183.645C387.873 164.31 434.969 151.843 475.62 144.262C495.677 140.522 513.673 138.057 526.649 136.528C528.253 136.339 529.779 136.165 531.223 136.004L531.222 374.631C529.176 374.616 526.959 374.61 524.586 374.624C510.859 374.705 491.833 375.374 470.627 377.736C428.932 382.381 375.914 393.851 339.235 422.801C328.618 431.181 317.428 443.469 309.27 453.073C308.645 453.808 308.036 454.533 307.44 455.244C307.064 454.757 306.684 454.263 306.297 453.764C298.887 444.23 288.756 432.007 279.163 423.407C245.403 393.141 190.851 381.739 147.867 377.28C125.852 374.996 105.817 374.443 91.2955 374.457C88.4254 374.46 85.7661 374.486 83.3447 374.524L83.3452 135.773Z" stroke="#435EBE" stroke-width="30"/>
|
||||
<path d="M307.203 64.55C311.666 64.55 317.586 67.7484 322.947 76.9934C328.159 85.9823 331.703 99.0617 331.703 114.05C331.703 129.038 328.159 142.118 322.947 151.107C317.586 160.352 311.666 163.55 307.203 163.55C302.739 163.55 296.819 160.352 291.458 151.107C286.246 142.118 282.703 129.038 282.703 114.05C282.703 99.0617 286.246 85.9823 291.458 76.9934C296.819 67.7484 302.739 64.55 307.203 64.55Z" stroke="#435EBE" stroke-width="20"/>
|
||||
<path d="M291.703 276.55C291.703 284.834 298.418 291.55 306.703 291.55C314.987 291.55 321.703 284.834 321.703 276.55H306.703H291.703ZM306.703 216.55H291.703V276.55H306.703H321.703V216.55H306.703Z" fill="#435EBE"/>
|
||||
</svg>
|
||||
<svg width="621" height="534" viewBox="0 0 621 534" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M83.345 135.773c1.65.161 3.41.338 5.271.534 13.266 1.403 31.642 3.728 52.066 7.408 41.444 7.469 89.062 20.148 120.238 40.609 7.176 4.709 16.183 11.603 23.623 17.524 3.67 2.92 6.867 5.53 9.145 7.409 1.137.938 2.042 1.693 2.659 2.208l.701.588.175.146.041.035.009.007 9.381 7.923 9.619-7.63.001-.001.01-.007.046-.037.194-.153.775-.61a729 729 0 0 1 13.025-9.962c8.195-6.122 18.138-13.262 26.052-18.119 31.497-19.335 78.593-31.802 119.244-39.383 20.057-3.74 38.053-6.205 51.029-7.734a735 735 0 0 1 4.574-.524l-.001 238.627a500 500 0 0 0-6.636-.007c-13.727.081-32.753.75-53.959 3.112-41.695 4.645-94.713 16.115-131.392 45.065-10.617 8.38-21.807 20.668-29.965 30.272q-.937 1.104-1.83 2.171-.563-.731-1.143-1.48c-7.41-9.534-17.541-21.757-27.134-30.357-33.76-30.266-88.312-41.668-131.296-46.127-22.015-2.284-42.05-2.837-56.571-2.823-2.87.003-5.53.029-7.951.067z" stroke="#fff" stroke-width="30"/><path d="M307.203 64.55c4.463 0 10.383 3.198 15.744 12.443 5.212 8.99 8.756 22.069 8.756 37.057s-3.544 28.068-8.756 37.057c-5.361 9.245-11.281 12.443-15.744 12.443-4.464 0-10.384-3.198-15.745-12.443-5.212-8.989-8.755-22.069-8.755-37.057s3.543-28.068 8.755-37.057c5.361-9.245 11.281-12.443 15.745-12.443Z" stroke="#fff" stroke-width="20"/><path d="M291.703 276.55c0 8.284 6.715 15 15 15s15-6.716 15-15zm15-60h-15v60h30v-60z" fill="#fff"/></svg>
|
||||
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.4 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 7.7 KiB |
|
|
@ -114,9 +114,9 @@ body {
|
|||
background-color: map-get($grays, "light");
|
||||
}
|
||||
|
||||
// Sidebar fixed di kiri dengan support minimize dan responsive
|
||||
// Sidebar
|
||||
.sidebar {
|
||||
width: 250px;
|
||||
width: 270px;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
|
|
@ -151,7 +151,7 @@ body {
|
|||
}
|
||||
|
||||
.main-wrapper {
|
||||
margin-left: 240px;
|
||||
margin-left: 260px;
|
||||
}
|
||||
|
||||
.sidebar.minimized {
|
||||
|
|
@ -172,10 +172,9 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
// Mobile: sidebar tersembunyi, muncul dengan toggle
|
||||
@media (max-width: 991.98px) {
|
||||
.sidebar {
|
||||
left: -250px;
|
||||
left: -270px;
|
||||
}
|
||||
|
||||
.sidebar.active {
|
||||
|
|
@ -186,21 +185,35 @@ body {
|
|||
// Styling navigasi sidebar
|
||||
.sidebar .nav-link {
|
||||
font-weight: 500;
|
||||
color: #555;
|
||||
margin: 0.3rem 0;
|
||||
border-radius: 0.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sidebar .nav-link.active {
|
||||
background: rgba(67, 94, 190, 0.1);
|
||||
color: #5a5fba;
|
||||
font-weight: 600;
|
||||
}
|
||||
.sidebar.bg-primary {
|
||||
.nav-link {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
i { color: rgba(255, 255, 255, 0.85); }
|
||||
|
||||
.sidebar .nav-link:hover:not(.active) {
|
||||
background: #f8f9fa;
|
||||
&.py-1 {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
}
|
||||
|
||||
.nav-link:hover:not(.active),
|
||||
.nav-link.py-1:hover {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
color: #fff;
|
||||
i { color: #fff; }
|
||||
}
|
||||
|
||||
.nav-link.active {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
i { color: #fff; }
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar.minimized .nav-link .ms-auto {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
@use "sass:color";
|
||||
|
||||
// ===================================
|
||||
// VARIABLES & MAPS // ===================================
|
||||
// ===================================//
|
||||
// VARIABLES & MAPS
|
||||
// ===================================//
|
||||
|
||||
// Theme Colors Map
|
||||
$theme-colors: (
|
||||
"primary": #5a81fa,
|
||||
"secondary": #5a5fba,
|
||||
"primary": #0A4174,
|
||||
"secondary": #49769F,
|
||||
"success": #14b8a6,
|
||||
"info": #3b82f6,
|
||||
"warning": #fb923c,
|
||||
"info": #7BBDE8,
|
||||
"warning": #fbb716,
|
||||
"danger": #f43f5e,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,291 @@
|
|||
<x-app-layout>
|
||||
@section('page-title', $pageTitle)
|
||||
|
||||
<div class="d-flex align-items-center mb-4">
|
||||
<a href="{{ route('admin.peminjaman.index') }}" class="btn btn-outline-secondary me-3">
|
||||
<i class="bi bi-arrow-left"></i>
|
||||
</a>
|
||||
<h3 class="my-0 fw-bold">Formulir Peminjaman Manual</h3>
|
||||
</div>
|
||||
|
||||
<form action="#" method="POST" id="formPeminjaman" autocomplete="off"> @csrf
|
||||
<div class="row g-4">
|
||||
|
||||
<div class="col-lg-7">
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-body p-4">
|
||||
|
||||
<h5 class="fw-bold mb-3">Data Peminjaman</h5>
|
||||
<div class="mb-3">
|
||||
<label for="peminjam_id" class="form-label">Pilih Peminjam (Siswa/Guru)</label>
|
||||
|
||||
<select class="form-control" id="peminjam_id" name="peminjam_id"
|
||||
placeholder="Cari nama atau email...">
|
||||
<option value="">Pilih...</option>
|
||||
@foreach ($groupedUsers as $role => $users)
|
||||
<optgroup label="{{ ucfirst($role) }}">
|
||||
@foreach ($users as $user)
|
||||
<option value="{{ $user['id'] }}">{{ $user['nama_lengkap'] }}</option>
|
||||
@endforeach
|
||||
</optgroup>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label for="tanggal_pinjam" class="form-label">Tanggal Pinjam</label>
|
||||
<input type="text" class="form-control" id="tanggal_pinjam" name="tanggal_pinjam"
|
||||
placeholder="Pilih tanggal pinjam">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="tanggal_kembali" class="form-label">Tenggat Kembali</label>
|
||||
<input type="text" class="form-control" id="tanggal_kembali"
|
||||
name="tanggal_kembali" placeholder="Pilih tenggat kembali">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="my-4">
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h5 class="fw-bold m-0">Buku Terpilih</h5>
|
||||
<span class="badge bg-primary-soft" id="counterBuku">0 Buku</span>
|
||||
</div>
|
||||
|
||||
<div id="daftarBukuPinjam" class="mb-3">
|
||||
<div id="emptyStateBuku" class="text-center text-muted py-4">
|
||||
<i class="bi bi-collection fs-1" style="opacity: 0.25;"></i>
|
||||
<p class="mb-0 mt-2">Belum ada buku yang dipilih.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="hiddenInputs"></div>
|
||||
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-save me-1"></i> Simpan Peminjaman
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-5">
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-header bg-white py-3">
|
||||
<h5 class="fw-bold m-0">Pilih Buku</h5>
|
||||
</div>
|
||||
<div class="card-body p-4">
|
||||
<div class="mb-3">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-white"><i class="bi bi-search"></i></span>
|
||||
<input type="text" class="form-control border-start-0" id="searchBuku"
|
||||
placeholder="Cari judul atau penulis...">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="bookSelectionList" style="max-height: 600px; overflow-y: auto;">
|
||||
@foreach ($daftarBuku as $buku)
|
||||
<div class="book-option p-2" data-book-id="{{ $buku['id'] }}"
|
||||
data-book-title="{{ strtolower($buku['judul']) }}"
|
||||
data-book-author="{{ strtolower($buku['penulis']) }}"
|
||||
data-book-cover="{{ asset($buku['cover']) }}"
|
||||
data-book-kategori="{{ $buku['kategori'] }}">
|
||||
|
||||
<div class="d-flex align-items-center book-item-list"
|
||||
onclick="toggleBookSelection(this, {{ $buku['id'] }})"
|
||||
style="cursor: pointer;">
|
||||
<img src="{{ asset($buku['cover']) }}" alt="Cover"
|
||||
class="rounded me-3"
|
||||
style="width: 50px; height: 70px; object-fit: cover;">
|
||||
<div class="flex-grow-1">
|
||||
<h6 class="fw-bold mb-1 line-clamp-2">{{ $buku['judul'] }}</h6>
|
||||
<p class="text-muted small mb-1">{{ $buku['penulis'] }}</p>
|
||||
<span
|
||||
class="badge bg-info-soft">{{ $buku['kategori'] }}</span>
|
||||
</div>
|
||||
<div class="form-check ms-3">
|
||||
<input class="form-check-input book-checkbox" type="checkbox"
|
||||
value="{{ $buku['id'] }}"
|
||||
id="book-check-{{ $buku['id'] }}"
|
||||
style="pointer-events: none;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
|
||||
// Inisialisasi Library & Simpan Instansinya
|
||||
|
||||
const tomSelect = new TomSelect("#peminjam_id", {
|
||||
create: false,
|
||||
sortField: {
|
||||
field: "text",
|
||||
direction: "asc"
|
||||
}
|
||||
});
|
||||
|
||||
const tglPinjam = flatpickr("#tanggal_pinjam", {
|
||||
dateFormat: "Y-m-d",
|
||||
altInput: true,
|
||||
altFormat: "d/m/Y",
|
||||
defaultDate: "today",
|
||||
locale: "id",
|
||||
onChange: function(selectedDates, dateStr) {
|
||||
if (selectedDates.length > 0) {
|
||||
tglKembali.set("minDate", new Date(selectedDates[0]).fp_incr(1));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const tglKembali = flatpickr("#tanggal_kembali", {
|
||||
dateFormat: "Y-m-d",
|
||||
altInput: true,
|
||||
altFormat: "d/m/Y",
|
||||
defaultDate: new Date().fp_incr(7),
|
||||
locale: "id",
|
||||
minDate: new Date().fp_incr(1)
|
||||
});
|
||||
|
||||
|
||||
// Logika Pemilihan Buku
|
||||
|
||||
const MAX_BOOKS = 3;
|
||||
let selectedBookIds = new Set();
|
||||
const allBooks = new Map();
|
||||
document.querySelectorAll('.book-option').forEach(el => {
|
||||
const id = el.dataset.bookId;
|
||||
allBooks.set(id, {
|
||||
id: id,
|
||||
title: el.querySelector('h6').textContent,
|
||||
author: el.querySelector('p').textContent,
|
||||
cover: el.dataset.bookCover
|
||||
});
|
||||
});
|
||||
|
||||
const daftarBukuPinjamEl = document.getElementById('daftarBukuPinjam');
|
||||
const hiddenInputsEl = document.getElementById('hiddenInputs');
|
||||
const counterBukuEl = document.getElementById('counterBuku');
|
||||
const emptyStateBukuEl = document.getElementById('emptyStateBuku');
|
||||
|
||||
// Fungsi render
|
||||
function renderSelectedBooks() {
|
||||
daftarBukuPinjamEl.querySelectorAll('.selected-book-item').forEach(el => el.remove());
|
||||
hiddenInputsEl.innerHTML = '';
|
||||
|
||||
if (selectedBookIds.size === 0) {
|
||||
emptyStateBukuEl.style.display = 'block';
|
||||
} else {
|
||||
emptyStateBukuEl.style.display = 'none';
|
||||
}
|
||||
|
||||
selectedBookIds.forEach(id => {
|
||||
const book = allBooks.get(String(id));
|
||||
if (!book) return;
|
||||
|
||||
const itemHtml = `
|
||||
<div class="selected-book-item book-item d-flex align-items-start p-3 mb-2 rounded" data-selected-id="${id}">
|
||||
<img src="${book.cover}" alt="Cover" class="rounded me-3" style="width: 45px; height: 60px; object-fit: cover;">
|
||||
<div class="flex-grow-1">
|
||||
<h6 class="fw-bold mb-0 line-clamp-1">${book.title}</h6>
|
||||
<p class="text-muted small mb-0">${book.author}</p>
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-outline-danger remove-book" onclick="removeBook(${id})">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
daftarBukuPinjamEl.insertAdjacentHTML('beforeend', itemHtml);
|
||||
|
||||
const inputHtml = `<input type="hidden" name="buku_ids[]" value="${id}">`;
|
||||
hiddenInputsEl.insertAdjacentHTML('beforeend', inputHtml);
|
||||
});
|
||||
|
||||
counterBukuEl.textContent = `${selectedBookIds.size} Buku`;
|
||||
}
|
||||
|
||||
// Fungsi search
|
||||
const searchBukuInput = document.getElementById('searchBuku');
|
||||
searchBukuInput.addEventListener('keyup', function() {
|
||||
const searchTerm = this.value.toLowerCase();
|
||||
document.querySelectorAll('.book-option').forEach(el => {
|
||||
const title = el.dataset.bookTitle;
|
||||
const author = el.dataset.bookAuthor;
|
||||
if (title.includes(searchTerm) || author.includes(searchTerm)) {
|
||||
el.style.display = 'block';
|
||||
} else {
|
||||
el.style.display = 'none';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Global function untuk toggle selection
|
||||
window.toggleBookSelection = function(itemElement, id) {
|
||||
const checkbox = itemElement.querySelector('.book-checkbox');
|
||||
const stringId = String(id);
|
||||
|
||||
if (selectedBookIds.has(stringId)) {
|
||||
selectedBookIds.delete(stringId);
|
||||
checkbox.checked = false;
|
||||
itemElement.style.background = 'transparent';
|
||||
} else {
|
||||
if (selectedBookIds.size >= MAX_BOOKS) {
|
||||
alert(`Maaf, Anda hanya dapat memilih maksimal ${MAX_BOOKS} buku.`);
|
||||
return;
|
||||
}
|
||||
|
||||
selectedBookIds.add(stringId);
|
||||
checkbox.checked = true;
|
||||
itemElement.style.background = 'rgba(var(--bs-primary-rgb), 0.05)';
|
||||
}
|
||||
renderSelectedBooks();
|
||||
}
|
||||
|
||||
// Global function untuk remove
|
||||
window.removeBook = function(id) {
|
||||
const stringId = String(id);
|
||||
selectedBookIds.delete(stringId);
|
||||
|
||||
const itemElement = document.querySelector(`.book-option[data-book-id="${id}"] .book-item-list`);
|
||||
if (itemElement) {
|
||||
itemElement.querySelector('.book-checkbox').checked = false;
|
||||
itemElement.style.background = 'transparent';
|
||||
}
|
||||
|
||||
renderSelectedBooks();
|
||||
}
|
||||
|
||||
// Logika Reset Saat Reload Halaman
|
||||
|
||||
const form = document.getElementById('formPeminjaman');
|
||||
form.reset();
|
||||
|
||||
tomSelect.clear();
|
||||
|
||||
tglPinjam.setDate("today", false);
|
||||
tglKembali.setDate(new Date().fp_incr(7), false);
|
||||
|
||||
selectedBookIds.clear();
|
||||
|
||||
document.querySelectorAll('.book-option').forEach(el => {
|
||||
el.querySelector('.book-checkbox').checked = false;
|
||||
el.querySelector('.book-item-list').style.background = 'transparent';
|
||||
});
|
||||
|
||||
renderSelectedBooks();
|
||||
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
</x-app-layout>
|
||||
|
|
@ -0,0 +1,280 @@
|
|||
<x-app-layout>
|
||||
@section('page-title', $pageTitle)
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h3 class="my-0 fw-bold">Manajemen Peminjaman</h3>
|
||||
<p class="text-muted mb-0">Daftar ini hanya menampilkan buku yang masih berstatus "Dipinjam".</p>
|
||||
</div>
|
||||
<a href="{{ route('admin.peminjaman.create') }}" class="btn btn-primary">
|
||||
<i class="bi bi-plus-circle me-1"></i>Buat Peminjaman Manual
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table id="peminjamanTable" class="table table-striped table-hover nowrap" style="width:100%">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>NO</th>
|
||||
<th>ID PEMINJAMAN</th>
|
||||
<th>NAMA PEMINJAM</th>
|
||||
<th>JUDUL BUKU</th>
|
||||
<th>TGL. PINJAM</th>
|
||||
<th>TENGGAT KEMBALI</th>
|
||||
<th>STATUS</th>
|
||||
<th>AKSI</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@php
|
||||
$now = \Carbon\Carbon::now();
|
||||
$counter = 1;
|
||||
@endphp
|
||||
@forelse ($peminjamanAktif as $transaksi)
|
||||
@php
|
||||
$tenggat = $transaksi['tenggat_kembali'];
|
||||
$isTerlambat = $now->startOfDay()->isAfter($tenggat->startOfDay());
|
||||
$isHariIni = $now->startOfDay()->isSameDay($tenggat->startOfDay());
|
||||
$selisihHari = $now->startOfDay()->diffInDays($tenggat->startOfDay(), false);
|
||||
|
||||
$statusKeterlambatan = '';
|
||||
$dendaKeterlambatan = 0;
|
||||
$statusClass = '';
|
||||
|
||||
if ($isTerlambat) {
|
||||
$hariTerlambat = $tenggat->startOfDay()->diffInDays($now->startOfDay());
|
||||
$statusKeterlambatan = "Terlambat $hariTerlambat hari";
|
||||
$dendaKeterlambatan = $hariTerlambat * $transaksi['denda_per_hari'];
|
||||
$statusClass = 'badge rounded-pill bg-danger-subtle text-danger-emphasis';
|
||||
} elseif ($isHariIni) {
|
||||
$statusKeterlambatan = 'Hari ini';
|
||||
$statusClass = 'badge rounded-pill bg-warning-subtle text-warning-emphasis';
|
||||
} else {
|
||||
$sisaHari = abs($selisihHari);
|
||||
$statusKeterlambatan = "Sisa $sisaHari hari";
|
||||
$statusClass = 'badge rounded-pill bg-success-subtle text-success-emphasis';
|
||||
}
|
||||
@endphp
|
||||
|
||||
@foreach ($transaksi['books'] as $index => $buku)
|
||||
<tr>
|
||||
<td>{{ $counter++ }}</td>
|
||||
<td>
|
||||
<span
|
||||
class="badge bg-primary-light text-primary fw-semibold">{{ $transaksi['id_peminjaman'] }}</span>
|
||||
</td>
|
||||
<td>{{ $transaksi['peminjam'] }}</td>
|
||||
<td>{{ $buku['judul'] }}</td>
|
||||
<td>{{ $transaksi['tanggal_pinjam']->format('d/m/Y') }}</td>
|
||||
<td>{{ $transaksi['tenggat_kembali']->format('d/m/Y') }}</td>
|
||||
<td>
|
||||
<span class="badge {{ $statusClass }}">{{ $statusKeterlambatan }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-outline-primary" data-bs-toggle="modal"
|
||||
data-bs-target="#modalPengembalian-{{ $transaksi['id_peminjaman'] }}-{{ $buku['id'] }}">
|
||||
Proses Pengembalian
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<div class="modal fade"
|
||||
id="modalPengembalian-{{ $transaksi['id_peminjaman'] }}-{{ $buku['id'] }}"
|
||||
tabindex="-1" aria-labelledby="modalLabel-{{ $buku['id'] }}" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg modal-dialog-centered">
|
||||
<div class="modal-content border-0 shadow-lg rounded-3">
|
||||
<div class="modal-header p-4">
|
||||
<h1 class="modal-title fs-5" id="modalLabel-{{ $buku['id'] }}">
|
||||
Proses Pengembalian Buku</h1>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"
|
||||
aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body p-4">
|
||||
<div class="row g-4">
|
||||
<div class="col-md-6">
|
||||
<h6 class="fw-bold">Informasi Peminjaman</h6>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small text-muted">Nama Peminjam</label>
|
||||
<input type="text" class="form-control"
|
||||
value="{{ $transaksi['peminjam'] }}" readonly>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small text-muted">Judul Buku</label>
|
||||
<input type="text" class="form-control"
|
||||
value="{{ $buku['judul'] }}" readonly>
|
||||
</div>
|
||||
<hr>
|
||||
<h6 class="fw-bold">1. Kondisi Buku</h6>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input radio-kondisi" type="radio"
|
||||
name="kondisi_buku_{{ $buku['id'] }}"
|
||||
id="kondisi_baik_{{ $buku['id'] }}" value="baik"
|
||||
checked data-denda="0">
|
||||
<label class="form-check-label"
|
||||
for="kondisi_baik_{{ $buku['id'] }}">
|
||||
Kondisi Baik
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input radio-kondisi" type="radio"
|
||||
name="kondisi_buku_{{ $buku['id'] }}"
|
||||
id="kondisi_rusak_{{ $buku['id'] }}" value="rusak"
|
||||
data-denda="0">
|
||||
<label class="form-check-label"
|
||||
for="kondisi_rusak_{{ $buku['id'] }}">
|
||||
Buku Rusak
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check mb-3">
|
||||
<input class="form-check-input radio-kondisi" type="radio"
|
||||
name="kondisi_buku_{{ $buku['id'] }}"
|
||||
id="kondisi_hilang_{{ $buku['id'] }}" value="hilang"
|
||||
data-denda="0">
|
||||
<label class="form-check-label"
|
||||
for="kondisi_hilang_{{ $buku['id'] }}">
|
||||
Buku Hilang
|
||||
</label>
|
||||
</div>
|
||||
<div class="mb-3 d-none denda-rusak-input-wrapper">
|
||||
<label class="form-label text-danger">Denda
|
||||
Kerusakan/Kehilangan (Rp)</label>
|
||||
<input type="number"
|
||||
class="form-control denda-rusak-input" value="0"
|
||||
placeholder="Masukkan nominal denda">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<h6 class="fw-bold">2. Status Keterlambatan</h6>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small text-muted">Status</label>
|
||||
<input type="text" class="form-control"
|
||||
value="{{ $statusKeterlambatan }}" readonly>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small text-muted">Denda
|
||||
Keterlambatan</label>
|
||||
<input type="text"
|
||||
class="form-control denda-keterlambatan-display"
|
||||
value="Rp {{ number_format($dendaKeterlambatan, 0, ',', '.') }}"
|
||||
readonly
|
||||
data-denda-keterlambatan="{{ $dendaKeterlambatan }}">
|
||||
</div>
|
||||
<hr>
|
||||
<h6 class="fw-bold">3. Rangkuman & Aksi</h6>
|
||||
<div class="mb-3">
|
||||
<label for="catatan_petugas_{{ $buku['id'] }}"
|
||||
class="form-label small text-muted">Catatan Petugas
|
||||
(Opsional)</label>
|
||||
<textarea class="form-control" id="catatan_petugas_{{ $buku['id'] }}" rows="2"></textarea>
|
||||
</div>
|
||||
<div class="form-check form-switch mb-3">
|
||||
<input class="form-check-input" type="checkbox"
|
||||
role="switch" id="notif_wa_{{ $buku['id'] }}"
|
||||
checked>
|
||||
<label class="form-check-label"
|
||||
for="notif_wa_{{ $buku['id'] }}">
|
||||
Kirim notifikasi ke WA ({{ $transaksi['nomor_hp'] }})
|
||||
</label>
|
||||
</div>
|
||||
<div class="p-3 bg-primary-light rounded-3 text-primary">
|
||||
<h5 class="fw-bold mb-0 text-center">Total Denda Diterima
|
||||
</h5>
|
||||
<h3 class="fw-bold mb-0 text-center total-denda-display">
|
||||
Rp {{ number_format($dendaKeterlambatan, 0, ',', '.') }}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer p-4">
|
||||
<button type="button" class="btn btn-outline-secondary"
|
||||
data-bs-dismiss="modal">Batal</button>
|
||||
<button type="button" class="btn btn-primary">Konfirmasi
|
||||
Pengembalian</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="8" class="text-center py-5">
|
||||
<div class="empty-state">
|
||||
<i class="bi bi-journal-x"></i>
|
||||
<p>Tidak ada data peminjaman yang sedang aktif.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
// Inisialisasi DataTables
|
||||
$(document).ready(function() {
|
||||
$('#peminjamanTable').DataTable({
|
||||
pageLength: 10,
|
||||
order: [
|
||||
[0, 'asc']
|
||||
],
|
||||
"language": {
|
||||
"url": "//cdn.datatables.net/plug-ins/1.13.6/i18n/id.json"
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Logika Modal
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
function formatRupiah(angka) {
|
||||
return new Intl.NumberFormat('id-ID', {
|
||||
style: 'currency',
|
||||
currency: 'IDR',
|
||||
minimumFractionDigits: 0
|
||||
}).format(angka).replace(/\s/g, '');
|
||||
}
|
||||
|
||||
function hitungTotalDenda(modal) {
|
||||
const dendaKeterlambatanEl = modal.querySelector('.denda-keterlambatan-display');
|
||||
const dendaRusakEl = modal.querySelector('.denda-rusak-input');
|
||||
const totalDendaEl = modal.querySelector('.total-denda-display');
|
||||
const dendaKeterlambatan = parseInt(dendaKeterlambatanEl.dataset.dendaKeterlambatan) || 0;
|
||||
const dendaRusak = parseInt(dendaRusakEl.value) || 0;
|
||||
const totalDenda = dendaKeterlambatan + dendaRusak;
|
||||
totalDendaEl.textContent = formatRupiah(totalDenda);
|
||||
}
|
||||
|
||||
const radioKondisi = document.querySelectorAll('.radio-kondisi');
|
||||
radioKondisi.forEach(radio => {
|
||||
radio.addEventListener('change', function() {
|
||||
const modal = this.closest('.modal-content');
|
||||
const dendaRusakWrapper = modal.querySelector('.denda-rusak-input-wrapper');
|
||||
const dendaRusakInput = modal.querySelector('.denda-rusak-input');
|
||||
if (this.value === 'rusak' || this.value === 'hilang') {
|
||||
dendaRusakWrapper.classList.remove('d-none');
|
||||
} else {
|
||||
dendaRusakWrapper.classList.add('d-none');
|
||||
dendaRusakInput.value = 0;
|
||||
}
|
||||
hitungTotalDenda(modal);
|
||||
});
|
||||
});
|
||||
|
||||
const dendaRusakInputs = document.querySelectorAll('.denda-rusak-input');
|
||||
dendaRusakInputs.forEach(input => {
|
||||
input.addEventListener('input', function() {
|
||||
const modal = this.closest('.modal-content');
|
||||
hitungTotalDenda(modal);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
</x-app-layout>
|
||||
|
|
@ -20,10 +20,10 @@
|
|||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Alamat Email</label>
|
||||
<input id="email" class="form-control" type="email" name="email" required autofocus />
|
||||
<x-input-error :messages="$errors->get('email')" class="mt-2" />
|
||||
</div>
|
||||
<label for="nip" class="form-label">Nomor Induk Pegawai (NIP)</label>
|
||||
<input id="nip" class="form-control" type="text" name="nip" required autofocus />
|
||||
<x-input-error :messages="$errors->get('nip')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Kata Sandi</label>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
@if ($role == 'siswa')
|
||||
Masukan NISN dan kata sandi Anda.
|
||||
@else
|
||||
Masukan Email dan kata sandi Anda.
|
||||
Masukan NIP dan kata sandi Anda.
|
||||
@endif
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -27,13 +27,12 @@
|
|||
<div class="mb-3">
|
||||
<label for="nisn" class="form-label">Nomor Induk Siswa Nasional (NISN)</label>
|
||||
<input id="nisn" class="form-control" type="text" name="nisn" required autofocus />
|
||||
<x-input-error :messages="$errors->get('nisn')" class="mt-2" /> {{-- <-- Pastikan ini ada --}}
|
||||
</div>
|
||||
<x-input-error :messages="$errors->get('nisn')" class="mt-2" />
|
||||
@else
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Alamat Email</label>
|
||||
<input id="email" class="form-control" type="email" name="email" required autofocus />
|
||||
<x-input-error :messages="$errors->get('email')" class="mt-2" /> {{-- <-- Pastikan ini ada --}}
|
||||
<label for="nip" class="form-label">Nomor Induk Pegawai (NIP)</label>
|
||||
<input id="nip" class="form-control" type="text" name="nip" required autofocus />
|
||||
<x-input-error :messages="$errors->get('nip')" class="mt-2" />
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
@props(['buku'])
|
||||
|
||||
<div class="card border-0 shadow-sm h-100 book-card">
|
||||
<div class="card border-0 shadow-sm h-100 book-card bg-info-light">
|
||||
<div class="row g-0 h-100">
|
||||
<div class="col-4">
|
||||
<div class="book-cover-container d-flex align-items-center justify-content-center p-3 h-100">
|
||||
|
|
|
|||
|
|
@ -192,8 +192,7 @@ class="badge bg-{{ $item['type'] }}-soft text-{{ $item['type'] }} rounded-pill p
|
|||
@forelse($bukuPinjamOffline as $buku)
|
||||
<div class="col-xl-4 col-md-6" x-show="expanded || {{ $loop->index }} < 3" x-transition>
|
||||
<x-book-card :buku="$buku">
|
||||
<div class="alert alert-danger border-0 py-2 px-3 mb-0 d-flex align-items-center">
|
||||
<i class="bi bi-clock-fill me-2"></i>
|
||||
<div class="d-flex align-items-center text-danger"> <i class="bi bi-clock-fill me-2"></i>
|
||||
<span class="fw-bold small">Sisa: {{ $buku['sisa_hari'] }} hari</span>
|
||||
</div>
|
||||
</x-book-card>
|
||||
|
|
@ -234,10 +233,10 @@ class="badge bg-{{ $item['type'] }}-soft text-{{ $item['type'] }} rounded-pill p
|
|||
<x-book-card :buku="$buku">
|
||||
<div class="progress-wrapper">
|
||||
<div class="d-flex justify-content-between align-items-center mb-1">
|
||||
<span class="small text-muted">Progress</span>
|
||||
<span class="small fw-bold text-primary">{{ $buku['progress'] }}%</span>
|
||||
<span class="small text-dark">Progress</span> <span
|
||||
class="small fw-bold text-primary">{{ $buku['progress'] }}%</span>
|
||||
</div>
|
||||
<div class="progress" style="height: 8px;">
|
||||
<div class="progress bg-white" style="height: 8px;">
|
||||
<div class="progress-bar bg-primary rounded-pill"
|
||||
style="width: {{ $buku['progress'] }}%" role="progressbar"></div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.7/css/dataTables.bootstrap5.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.5.0/css/responsive.bootstrap5.min.css">
|
||||
|
||||
<!-- Tom Select -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/tom-select/dist/css/tom-select.bootstrap5.min.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
|
@ -98,6 +100,9 @@ class="notification-item d-flex my-1 rounded-3 text-body text-decoration-none @i
|
|||
<script src="https://cdn.datatables.net/responsive/2.5.0/js/dataTables.responsive.min.js"></script>
|
||||
<script src="https://cdn.datatables.net/responsive/2.5.0/js/responsive.bootstrap5.min.js"></script>
|
||||
|
||||
<!-- Tom Select -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/tom-select/dist/js/tom-select.complete.min.js"></script>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<aside id="sidebar" class="sidebar bg-white">
|
||||
<aside id="sidebar" class="sidebar bg-primary">
|
||||
<div class="sidebar-header d-flex justify-content-between align-items-center px-3 py-3 py-md-2">
|
||||
<a href="{{ Auth::user()->role == 'penjaga perpus' ? route('admin.dashboard') : route('dashboard') }}"
|
||||
class="d-flex align-items-center text-decoration-none" style="gap: 0.75rem;">
|
||||
<img src="{{ asset('images/logo/icon.svg') }}" alt="Ikon Perpus" style="height: 32px;" class="mt-md-2">
|
||||
<div class="d-flex align-items-center mt-md-2" style="gap: 0.75rem;">
|
||||
<div class="vr bg-primary sidebar-title" style="width: 2px; height: 24px;"></div>
|
||||
<img src="{{ asset('images/logo/name.svg') }}" alt="Perpus" style="height: 24px;"
|
||||
<div class="d-flex align-items-center mt-md-2" style="gap: 1rem;">
|
||||
<div class="vr bg-white sidebar-title" style="width: 3px; height: 32px;"></div>
|
||||
<img src="{{ asset('images/logo/name.svg') }}" alt="Perpus" style="height: 30px;"
|
||||
class="sidebar-title">
|
||||
</div>
|
||||
</a>
|
||||
|
|
@ -16,12 +16,12 @@ class="sidebar-title">
|
|||
{{-- Info User di Bagian atas (Hanya Muncul di Mobile) --}}
|
||||
{{-- ======================================================= --}}
|
||||
<div class="p-3 d-lg-none">
|
||||
<div class="bg-primary-subtle p-3 rounded-2">
|
||||
<h6 class="nav-text mb-0 fw-bold text-truncate d-block text-primary-emphasis">{{ Auth::user()->name }}</h6>
|
||||
|
||||
<small class="nav-text text-dark text-truncate d-block">{{ Auth::user()->email }}</small>
|
||||
<div class="bg-primary-subtle p-3 rounded-2">
|
||||
<h6 class="nav-text mb-0 fw-bold text-truncate d-block text-primary-emphasis">{{ Auth::user()->name }}</h6>
|
||||
|
||||
<small class="nav-text text-dark text-truncate d-block">{{ Auth::user()->email }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul class="nav flex-column px-2 mt-2">
|
||||
|
||||
|
|
@ -35,6 +35,10 @@ class="bi bi-grid-1x2-fill"></i><span class="nav-text ms-2">Beranda</span></a>
|
|||
class="nav-link {{ request()->routeIs('admin.buku.*') ? 'active' : '' }}"><i
|
||||
class="bi bi-book-fill"></i><span class="nav-text ms-2">Manajemen Buku</span></a>
|
||||
</li>
|
||||
<li class="nav-item"> <a href="{{ route('admin.peminjaman.index') }}"
|
||||
class="nav-link {{ request()->routeIs('admin.peminjaman.*') ? 'active' : '' }}"> <i
|
||||
class="bi bi-arrow-left-right"></i><span class="nav-text ms-2">Manajemen Pinjaman</span> </a>
|
||||
</li>
|
||||
<li class="nav-item"><a href="{{ route('admin.pengumuman.index') }}"
|
||||
class="nav-link {{ request()->routeIs('admin.pengumuman.*') ? 'active' : '' }}"><i
|
||||
class="bi bi-megaphone-fill"></i><span class="nav-text ms-2">Pengumuman</span></a>
|
||||
|
|
@ -127,7 +131,7 @@ class="nav-link py-1 {{ request()->routeIs('riwayat.online') ? 'active' : '' }}"
|
|||
@endif
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
{{-- Aksi User (Hanya Muncul di Mobile) --}}
|
||||
<div class="mt-auto p-2 d-lg-none">
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table id="riwayatOfflineTable" class="table table-striped dt-responsive nowrap" style="width:100%">
|
||||
|
||||
<thead>
|
||||
<tr>
|
||||
<th>NO</th>
|
||||
|
|
@ -39,7 +38,7 @@ class="badge rounded-pill bg-warning-subtle text-warning-emphasis">{{ $transaksi
|
|||
@endif
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-info btn-sm text-white" data-bs-toggle="modal"
|
||||
<button class="btn btn-primary btn-sm text-white" data-bs-toggle="modal"
|
||||
data-bs-target="#detailModal" data-transaksi-id="{{ $transaksi['id'] }}"
|
||||
data-buku-id="{{ $buku['id'] }}">
|
||||
Detail
|
||||
|
|
@ -49,8 +48,7 @@ class="badge rounded-pill bg-warning-subtle text-warning-emphasis">{{ $transaksi
|
|||
@endforeach
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="6" class="text-center">Tidak ada riwayat peminjaman.</td>
|
||||
</tr>
|
||||
<td colspan="7" class="text-center">Tidak ada riwayat peminjaman.</td> </tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -127,12 +125,14 @@ class="bi bi-book-half me-2 text-primary"></i>Detail Riwayat</h5>
|
|||
|
||||
const keteranganHtml = buku.keterangan ?
|
||||
`
|
||||
<tr>
|
||||
<td class="fw-bold align-text-top text-start">Keterangan</td>
|
||||
<td class="align-text-top">:</td>
|
||||
<td class="text-start">${buku.keterangan}</td>
|
||||
</tr>
|
||||
` : '';
|
||||
<hr class="my-3">
|
||||
<div class="alert alert-warning border-0 bg-warning-subtle mb-0">
|
||||
<h6 class="fw-bold mb-1 text-warning-emphasis"><i class="bi bi-info-circle-fill me-2"></i>Catatan Petugas</h6>
|
||||
<p class="mb-0">${buku.keterangan}</p>
|
||||
</div>
|
||||
` :
|
||||
'';
|
||||
|
||||
|
||||
const contentHTML = `
|
||||
<div class="text-center mb-4">
|
||||
|
|
@ -161,13 +161,13 @@ class="bi bi-book-half me-2 text-primary"></i>Detail Riwayat</h5>
|
|||
<td>:</td>
|
||||
<td class="text-start">${buku.tahun}</td>
|
||||
</tr>
|
||||
${keteranganHtml}
|
||||
</tbody>
|
||||
</table>
|
||||
`;
|
||||
|
||||
${keteranganHtml} `;
|
||||
|
||||
modalBody.innerHTML = contentHTML;
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
</x-app-layout>
|
||||
</x-app-layout>
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
<span class="badge rounded-pill bg-success-subtle text-success-emphasis">{{ $transaksi['status'] }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-info btn-sm text-white" data-bs-toggle="modal"
|
||||
<button class="btn btn-primary btn-sm text-white" data-bs-toggle="modal"
|
||||
data-bs-target="#detailModal" data-transaksi-id="{{ $transaksi['id'] }}"
|
||||
data-buku-id="{{ $buku['id'] }}">
|
||||
Detail
|
||||
|
|
@ -120,17 +120,17 @@ class="bi bi-book-half me-2 text-primary"></i>Detail Riwayat</h5>
|
|||
<table class="table table-borderless table-sm">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="fw-bold" style="width: 35%;">ID Baca</td>
|
||||
<td class="fw-bold text-start" style="width: 35%;">ID Baca</td>
|
||||
<td style="width: 1%;">:</td>
|
||||
<td class="text-start">${transaksiItem.id_baca}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fw-bold">Kategori Buku</td>
|
||||
<td class="fw-bold text-start">Kategori Buku</td>
|
||||
<td>:</td>
|
||||
<td class="text-start"><span class="badge bg-primary-subtle text-primary-emphasis rounded-pill px-3 py-2">${buku.kategori}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fw-bold">Tahun Terbit</td>
|
||||
<td class="fw-bold text-start">Tahun Terbit</td>
|
||||
<td>:</td>
|
||||
<td class="text-start">${buku.tahun}</td>
|
||||
</tr>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
use App\Http\Controllers\Admin\AdminPeminjamanController;
|
||||
use App\Http\Controllers\Admin\AdminRekomendasiController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
|
|
@ -96,6 +97,9 @@
|
|||
::class, 'index'])->name('rekomendasi.index');
|
||||
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');
|
||||
});
|
||||
|
||||
// --- RUTE LOGIN KHUSUS ADMIN ---
|
||||
|
|
|
|||
Loading…
Reference in New Issue