Update project and prepare for JTI Polije upload
This commit is contained in:
parent
5f30be4811
commit
17c93a4252
|
|
@ -0,0 +1,26 @@
|
||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteBase /E31230887/
|
||||||
|
|
||||||
|
# 1. Handle Storage (Internal Rewrite)
|
||||||
|
# Mapping /storage/... ke /public/storage/... secara internal
|
||||||
|
RewriteRule ^storage/(.*)$ public/storage/$1 [L]
|
||||||
|
|
||||||
|
# 2. Handle Other Static Assets (img, build, images, favicon, robots.txt)
|
||||||
|
# Menghindari redirect R=302 agar URL tetap bersih tanpa /public/
|
||||||
|
RewriteCond %{REQUEST_URI} !^/E31230887/public/
|
||||||
|
RewriteRule ^(img|build|images|favicon\.ico|robots\.txt)(.*)$ public/$1$2 [L]
|
||||||
|
|
||||||
|
# 3. Handle Laravel Front Controller
|
||||||
|
# Jika file fisik tidak ada, lempar ke index.php
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
RewriteRule ^ index.php [L]
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
Options -Indexes
|
||||||
|
|
||||||
|
<FilesMatch "^\.env">
|
||||||
|
Order allow,deny
|
||||||
|
Deny from all
|
||||||
|
</FilesMatch>
|
||||||
|
|
@ -117,41 +117,41 @@ private function tentukanKoordinatRak($nomor_panggil)
|
||||||
|
|
||||||
return match (true) {
|
return match (true) {
|
||||||
$kode_utama >= 0 && $kode_utama <= 99 => match (true) {
|
$kode_utama >= 0 && $kode_utama <= 99 => match (true) {
|
||||||
$kode_utama <= 19 => ['x' => 13.00, 'y' => 22.00], // Rak 01
|
$kode_utama <= 19 => ['x' => 12.00, 'y' => 13.00], // Rak 01
|
||||||
$kode_utama <= 50 => ['x' => 18.00, 'y' => 22.00], // Rak 02
|
$kode_utama <= 50 => ['x' => 17.00, 'y' => 13.00], // Rak 02
|
||||||
default => ['x' => 25.00, 'y' => 22.00], // Rak 03-05
|
default => ['x' => 22.00, 'y' => 13.00], // Rak 03-05
|
||||||
},
|
},
|
||||||
$kode_utama >= 100 && $kode_utama <= 199 => match (true) {
|
$kode_utama >= 100 && $kode_utama <= 199 => match (true) {
|
||||||
$kode_utama <= 150 => ['x' => 43.00, 'y' => 20.00], // Rak 06-10
|
$kode_utama <= 150 => ['x' => 35.00, 'y' => 13.00], // Rak 06-10
|
||||||
default => ['x' => 57.00, 'y' => 20.00], // Rak 11-14
|
default => ['x' => 35.00, 'y' => 17.00], // Rak 11-14
|
||||||
},
|
},
|
||||||
$kode_utama >= 200 && $kode_utama <= 299 => match (true) {
|
$kode_utama >= 200 && $kode_utama <= 299 => match (true) {
|
||||||
$kode_utama == 297 => ['x' => 25.00, 'y' => 38.00], // Rak 25-32 (Islam)
|
$kode_utama == 297 => ['x' => 14.00, 'y' => 38.00], // Rak 25-32 (Islam)
|
||||||
default => ['x' => 13.00, 'y' => 38.00], // Rak 15-24
|
default => ['x' => 14.00, 'y' => 30.00], // Rak 15-24
|
||||||
},
|
},
|
||||||
$kode_utama >= 300 && $kode_utama <= 399 => match (true) {
|
$kode_utama >= 300 && $kode_utama <= 399 => match (true) {
|
||||||
$kode_utama <= 330 => ['x' => 43.00, 'y' => 30.00], // Rak 33-36
|
$kode_utama <= 330 => ['x' => 38.00, 'y' => 23.00], // Rak 33-36
|
||||||
$kode_utama <= 360 => ['x' => 50.00, 'y' => 30.00], // Rak 37-40
|
$kode_utama <= 360 => ['x' => 43.00, 'y' => 23.00], // Rak 37-40
|
||||||
default => ['x' => 57.00, 'y' => 30.00], // Rak 41-44
|
default => ['x' => 48.00, 'y' => 23.00], // Rak 41-44
|
||||||
},
|
},
|
||||||
$kode_utama >= 400 && $kode_utama <= 499 => ['x' => 18.00, 'y' => 62.00], // Rak 45
|
$kode_utama >= 400 && $kode_utama <= 499 => ['x' => 14.00, 'y' => 58.00], // Rak 45
|
||||||
$kode_utama >= 500 && $kode_utama <= 599 => ['x' => 50.00, 'y' => 74.00], // Rak 46-48
|
$kode_utama >= 500 && $kode_utama <= 599 => ['x' => 38.00, 'y' => 72.00], // Rak 46-48
|
||||||
$kode_utama >= 600 && $kode_utama <= 699 => match (true) {
|
$kode_utama >= 600 && $kode_utama <= 699 => match (true) {
|
||||||
$kode_utama <= 610 => ['x' => 35.00, 'y' => 85.00], // Rak 49-53
|
$kode_utama <= 610 => ['x' => 28.00, 'y' => 83.00], // Rak 49-53
|
||||||
$kode_utama <= 630 => ['x' => 45.00, 'y' => 85.00], // Rak 54-58
|
$kode_utama <= 630 => ['x' => 36.00, 'y' => 83.00], // Rak 54-58
|
||||||
$kode_utama <= 650 => ['x' => 55.00, 'y' => 85.00], // Rak 59-63
|
$kode_utama <= 650 => ['x' => 44.00, 'y' => 83.00], // Rak 59-63
|
||||||
default => ['x' => 65.00, 'y' => 85.00], // Rak 64-68
|
default => ['x' => 52.00, 'y' => 83.00], // Rak 64-68
|
||||||
},
|
},
|
||||||
$kode_utama >= 700 && $kode_utama <= 799 => match (true) {
|
$kode_utama >= 700 && $kode_utama <= 799 => match (true) {
|
||||||
$kode_utama <= 739 => ['x' => 77.00, 'y' => 22.00], // Rak 71
|
$kode_utama <= 739 => ['x' => 82.00, 'y' => 12.00], // Rak 71
|
||||||
$kode_utama <= 769 => ['x' => 82.00, 'y' => 22.00], // Rak 72
|
$kode_utama <= 769 => ['x' => 86.00, 'y' => 12.00], // Rak 72
|
||||||
$kode_utama <= 789 => ['x' => 87.00, 'y' => 22.00], // Rak 73
|
$kode_utama <= 789 => ['x' => 82.00, 'y' => 16.00], // Rak 73
|
||||||
default => ['x' => 82.00, 'y' => 22.00], // Rak 74
|
default => ['x' => 86.00, 'y' => 16.00], // Rak 74
|
||||||
},
|
},
|
||||||
$kode_utama >= 800 && $kode_utama <= 899 => ['x' => 82.00, 'y' => 32.00], // Rak 77-79
|
$kode_utama >= 800 && $kode_utama <= 899 => ['x' => 82.00, 'y' => 25.00], // Rak 77-79
|
||||||
$kode_utama >= 900 && $kode_utama <= 999 => match (true) {
|
$kode_utama >= 900 && $kode_utama <= 999 => match (true) {
|
||||||
$kode_utama <= 919 => ['x' => 77.00, 'y' => 42.00], // Rak 69-70
|
$kode_utama <= 919 => ['x' => 82.00, 'y' => 30.00], // Rak 69-70
|
||||||
default => ['x' => 87.00, 'y' => 42.00], // Rak 80-84
|
default => ['x' => 82.00, 'y' => 35.00], // Rak 80-84
|
||||||
},
|
},
|
||||||
default => ['x' => null, 'y' => null],
|
default => ['x' => null, 'y' => null],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -58,84 +58,49 @@ public function store(Request $request)
|
||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
'id_anggota' => 'required|exists:anggotas,id',
|
'id_anggota' => 'required|exists:anggotas,id',
|
||||||
'id_buku' => 'required|exists:buku,id_buku',
|
'id_buku' => 'required|exists:buku,id_buku',
|
||||||
|
'id_buku_2' => 'nullable|exists:buku,id_buku|different:id_buku',
|
||||||
'tanggal_pinjam' => 'required|date_format:Y-m-d|after_or_equal:2000-01-01|before_or_equal:2100-12-31',
|
'tanggal_pinjam' => 'required|date_format:Y-m-d|after_or_equal:2000-01-01|before_or_equal:2100-12-31',
|
||||||
'tanggal_kembali' => 'required|date_format:Y-m-d|after_or_equal:tanggal_pinjam|before_or_equal:2100-12-31',
|
'tanggal_kembali' => 'required|date_format:Y-m-d|after_or_equal:tanggal_pinjam|before_or_equal:2100-12-31',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$validated['status_peminjaman'] = 'Dipinjam';
|
$status = 'Dipinjam';
|
||||||
|
|
||||||
// 2. Kurangi Stok Buku
|
// 2. Kurangi Stok Buku Pertama & Simpan
|
||||||
$buku = Buku::findOrFail($validated['id_buku']);
|
$buku1 = Buku::findOrFail($validated['id_buku']);
|
||||||
$buku->decrement('eksemplar');
|
$buku1->decrement('eksemplar');
|
||||||
|
|
||||||
// 3. Simpan ke Database
|
$peminjaman1 = Peminjaman::create([
|
||||||
$peminjaman = Peminjaman::create($validated);
|
'id_anggota' => $validated['id_anggota'],
|
||||||
$peminjaman->load(['buku', 'anggota']);
|
'id_buku' => $validated['id_buku'],
|
||||||
|
'tanggal_pinjam' => $validated['tanggal_pinjam'],
|
||||||
$waSuccess = false;
|
'tanggal_kembali' => $validated['tanggal_kembali'],
|
||||||
|
'status_peminjaman' => $status,
|
||||||
// 4. Proses Kirim WA (Format Struk Teks Resmi)
|
|
||||||
try {
|
|
||||||
$targetNum = $peminjaman->anggota->no_hp ?? '';
|
|
||||||
$fonnteToken = 'vpzqxF2ZGgTGz9F5UbUS'; // Token Fonnte
|
|
||||||
|
|
||||||
// Standarisasi Format Nomor ke awalan 62
|
|
||||||
if (!empty($targetNum)) {
|
|
||||||
$targetNum = preg_replace('/^0/', '62', trim($targetNum));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($targetNum) && !empty($fonnteToken)) {
|
|
||||||
// Merangkai Teks Menyerupai Struk Kertas
|
|
||||||
$pesanStruk = "🏢 *PERPUSTAKAAN DAERAH JEMBER*\n";
|
|
||||||
$pesanStruk .= "Jl. Mastrip No. 1, Kabupaten Jember\n";
|
|
||||||
$pesanStruk .= "===============================\n\n";
|
|
||||||
$pesanStruk .= "📄 *BUKTI PEMINJAMAN BUKU*\n";
|
|
||||||
$pesanStruk .= "No. Transaksi : PMJ-{$peminjaman->id_peminjaman}\n";
|
|
||||||
$pesanStruk .= "Tanggal Cetak : " . \Carbon\Carbon::now()->format('d-m-Y H:i') . "\n\n";
|
|
||||||
$pesanStruk .= "*DATA PEMINJAM*\n";
|
|
||||||
$pesanStruk .= "Nama : {$peminjaman->anggota->nama}\n";
|
|
||||||
$pesanStruk .= "No. HP : {$peminjaman->anggota->no_hp}\n\n";
|
|
||||||
$pesanStruk .= "*DETAIL BUKU*\n";
|
|
||||||
$pesanStruk .= "Judul : {$peminjaman->buku->judul}\n";
|
|
||||||
$pesanStruk .= "Kode Pengembalian : {$peminjaman->buku->bibid}\n";
|
|
||||||
$pesanStruk .= "Pinjam : " . \Carbon\Carbon::parse($peminjaman->tanggal_pinjam)->format('d F Y') . "\n";
|
|
||||||
$pesanStruk .= "Kembali: *" . \Carbon\Carbon::parse($peminjaman->tanggal_kembali)->format('d F Y') . "*\n\n";
|
|
||||||
$pesanStruk .= "===============================\n";
|
|
||||||
$pesanStruk .= "⚠️ *Catatan:*\n";
|
|
||||||
$pesanStruk .= "Tunjukkan Kode Pengembalian ke Admin saat pengembalian buku.\n";
|
|
||||||
$pesanStruk .= "Harap kembalikan buku tepat waktu.\n";
|
|
||||||
$pesanStruk .= "Denda keterlambatan: Rp 1.000/hari.\n\n";
|
|
||||||
$pesanStruk .= "Terima kasih atas kunjungan Anda!\n";
|
|
||||||
$pesanStruk .= "_Sistem Sarakata - TA 2026_";
|
|
||||||
|
|
||||||
// Eksekusi Pengiriman via Http Laravel
|
|
||||||
$response = \Illuminate\Support\Facades\Http::withoutVerifying()->timeout(15)->withHeaders([
|
|
||||||
'Authorization' => $fonnteToken,
|
|
||||||
])->post('https://api.fonnte.com/send', [
|
|
||||||
'target' => $targetNum,
|
|
||||||
'message' => $pesanStruk,
|
|
||||||
]);
|
]);
|
||||||
|
$peminjaman1->load(['buku', 'anggota']);
|
||||||
|
|
||||||
if ($response->successful() && ($response->json('status') == true)) {
|
$waSuccess = $this->kirimWaPeminjaman($peminjaman1, false);
|
||||||
|
|
||||||
|
// 3. Proses Buku Kedua (Opsional)
|
||||||
|
if (!empty($validated['id_buku_2'])) {
|
||||||
|
$buku2 = Buku::findOrFail($validated['id_buku_2']);
|
||||||
|
$buku2->decrement('eksemplar');
|
||||||
|
|
||||||
|
$peminjaman2 = Peminjaman::create([
|
||||||
|
'id_anggota' => $validated['id_anggota'],
|
||||||
|
'id_buku' => $validated['id_buku_2'],
|
||||||
|
'tanggal_pinjam' => $validated['tanggal_pinjam'],
|
||||||
|
'tanggal_kembali' => $validated['tanggal_kembali'],
|
||||||
|
'status_peminjaman' => $status,
|
||||||
|
]);
|
||||||
|
$peminjaman2->load(['buku', 'anggota']);
|
||||||
|
|
||||||
|
$wa2Success = $this->kirimWaPeminjaman($peminjaman2, false);
|
||||||
|
if ($wa2Success) {
|
||||||
$waSuccess = true;
|
$waSuccess = true;
|
||||||
} else {
|
|
||||||
\Illuminate\Support\Facades\Log::warning("Fonnte Log: Gagal Terkirim", [
|
|
||||||
'target' => $targetNum,
|
|
||||||
'http_status' => $response->status(),
|
|
||||||
'body' => $response->body()
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
\Illuminate\Support\Facades\Log::warning('Fonnte Log: Token / No HP kosong', [
|
|
||||||
'target' => $targetNum ?? 'kosong',
|
|
||||||
'token_set' => !empty($fonnteToken),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
\Illuminate\Support\Facades\Log::error("Error WA Pengiriman: " . $e->getMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Notifikasi Kembali ke Layar Admin
|
// 4. Notifikasi Kembali ke Layar Admin
|
||||||
$msg = 'Transaksi peminjaman berhasil dicatat.';
|
$msg = 'Transaksi peminjaman berhasil dicatat.';
|
||||||
if ($waSuccess) {
|
if ($waSuccess) {
|
||||||
$msg .= ' Struk WA berhasil terkirim kepada Anggota.';
|
$msg .= ' Struk WA berhasil terkirim kepada Anggota.';
|
||||||
|
|
@ -310,6 +275,16 @@ public function resendWa($id)
|
||||||
{
|
{
|
||||||
$peminjaman = Peminjaman::with(['buku', 'anggota'])->findOrFail($id);
|
$peminjaman = Peminjaman::with(['buku', 'anggota'])->findOrFail($id);
|
||||||
|
|
||||||
|
$success = $this->kirimWaPeminjaman($peminjaman, true);
|
||||||
|
if ($success) {
|
||||||
|
return back()->with('success', 'Struk WhatsApp berhasil dikirim ulang ke nomor ' . $peminjaman->anggota->no_hp);
|
||||||
|
} else {
|
||||||
|
return back()->with('error', 'Gagal mengirim ulang WA. Silakan cek log Fonnte.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function kirimWaPeminjaman($peminjaman, $isSalinan = false)
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
$targetNum = $peminjaman->anggota->no_hp ?? '';
|
$targetNum = $peminjaman->anggota->no_hp ?? '';
|
||||||
$fonnteToken = env('FONNTE_TOKEN', 'vpzqxF2ZGgTGz9F5UbUS');
|
$fonnteToken = env('FONNTE_TOKEN', 'vpzqxF2ZGgTGz9F5UbUS');
|
||||||
|
|
@ -319,10 +294,12 @@ public function resendWa($id)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($targetNum) && !empty($fonnteToken)) {
|
if (!empty($targetNum) && !empty($fonnteToken)) {
|
||||||
|
$tipeStruk = $isSalinan ? "SALINAN BUKTI PEMINJAMAN" : "BUKTI PEMINJAMAN BUKU";
|
||||||
|
|
||||||
$pesanStruk = "🏢 *PERPUSTAKAAN DAERAH JEMBER*\n";
|
$pesanStruk = "🏢 *PERPUSTAKAAN DAERAH JEMBER*\n";
|
||||||
$pesanStruk .= "Jl. Mastrip No. 1, Kabupaten Jember\n";
|
$pesanStruk .= "Jl. Mastrip No. 1, Kabupaten Jember\n";
|
||||||
$pesanStruk .= "===============================\n\n";
|
$pesanStruk .= "===============================\n\n";
|
||||||
$pesanStruk .= "📄 *SALINAN BUKTI PEMINJAMAN*\n";
|
$pesanStruk .= "📄 *{$tipeStruk}*\n";
|
||||||
$pesanStruk .= "No. Transaksi : PMJ-{$peminjaman->id_peminjaman}\n";
|
$pesanStruk .= "No. Transaksi : PMJ-{$peminjaman->id_peminjaman}\n";
|
||||||
$pesanStruk .= "Tanggal Cetak : " . \Carbon\Carbon::now()->format('d-m-Y H:i') . "\n\n";
|
$pesanStruk .= "Tanggal Cetak : " . \Carbon\Carbon::now()->format('d-m-Y H:i') . "\n\n";
|
||||||
$pesanStruk .= "*DATA PEMINJAM*\n";
|
$pesanStruk .= "*DATA PEMINJAM*\n";
|
||||||
|
|
@ -330,12 +307,12 @@ public function resendWa($id)
|
||||||
$pesanStruk .= "No. HP : {$peminjaman->anggota->no_hp}\n\n";
|
$pesanStruk .= "No. HP : {$peminjaman->anggota->no_hp}\n\n";
|
||||||
$pesanStruk .= "*DETAIL BUKU*\n";
|
$pesanStruk .= "*DETAIL BUKU*\n";
|
||||||
$pesanStruk .= "Judul : {$peminjaman->buku->judul}\n";
|
$pesanStruk .= "Judul : {$peminjaman->buku->judul}\n";
|
||||||
$pesanStruk .= "Kode Panggil : {$peminjaman->buku->bibid}\n";
|
$pesanStruk .= "Kode Pengembalian : {$peminjaman->buku->bibid}\n";
|
||||||
$pesanStruk .= "Pinjam : " . \Carbon\Carbon::parse($peminjaman->tanggal_pinjam)->format('d F Y') . "\n";
|
$pesanStruk .= "Pinjam : " . \Carbon\Carbon::parse($peminjaman->tanggal_pinjam)->format('d F Y') . "\n";
|
||||||
$pesanStruk .= "Kembali: *" . \Carbon\Carbon::parse($peminjaman->tanggal_kembali)->format('d F Y') . "*\n\n";
|
$pesanStruk .= "Kembali: *" . \Carbon\Carbon::parse($peminjaman->tanggal_kembali)->format('d F Y') . "*\n\n";
|
||||||
$pesanStruk .= "===============================\n";
|
$pesanStruk .= "===============================\n";
|
||||||
$pesanStruk .= "⚠️ *Catatan:*\n";
|
$pesanStruk .= "⚠️ *Catatan:*\n";
|
||||||
$pesanStruk .= "Tunjukkan Kode Panggil ke Admin saat pengembalian buku.\n";
|
$pesanStruk .= "Tunjukkan Kode Pengembalian ke Admin saat pengembalian buku.\n";
|
||||||
$pesanStruk .= "Harap kembalikan buku tepat waktu.\n";
|
$pesanStruk .= "Harap kembalikan buku tepat waktu.\n";
|
||||||
$pesanStruk .= "Denda keterlambatan: Rp 1.000/hari.\n\n";
|
$pesanStruk .= "Denda keterlambatan: Rp 1.000/hari.\n\n";
|
||||||
$pesanStruk .= "Terima kasih atas kunjungan Anda!\n";
|
$pesanStruk .= "Terima kasih atas kunjungan Anda!\n";
|
||||||
|
|
@ -349,17 +326,18 @@ public function resendWa($id)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($response->successful() && ($response->json('status') == true)) {
|
if ($response->successful() && ($response->json('status') == true)) {
|
||||||
return back()->with('success', 'Struk WhatsApp berhasil dikirim ulang ke nomor ' . $targetNum);
|
return true;
|
||||||
} else {
|
} else {
|
||||||
\Illuminate\Support\Facades\Log::warning("Fonnte Log: Gagal Terkirim Ulang", ['body' => $response->body()]);
|
\Illuminate\Support\Facades\Log::warning("Fonnte Log: Gagal Terkirim", [
|
||||||
return back()->with('error', 'Gagal mengirim ulang WA. API Fonnte menolak koneksi (Status: '.$response->status().').');
|
'target' => $targetNum,
|
||||||
|
'http_status' => $response->status(),
|
||||||
|
'body' => $response->body()
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return back()->with('error', 'Nomor HP anggota kosong atau Token Fonnte belum dikonfigurasi.');
|
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Illuminate\Support\Facades\Log::error("Error WA Pengiriman Ulang: " . $e->getMessage());
|
\Illuminate\Support\Facades\Log::error("Error WA Pengiriman: " . $e->getMessage());
|
||||||
return back()->with('error', 'Terjadi kesalahan sistem saat menghubungi server WhatsApp.');
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,23 +8,85 @@
|
||||||
|
|
||||||
class LaporanController extends Controller
|
class LaporanController extends Controller
|
||||||
{
|
{
|
||||||
public function kehadiran()
|
public function kehadiran(Request $request)
|
||||||
{
|
{
|
||||||
$bukuTamu = BukuTamu::with('user')
|
$query = BukuTamu::with('user')->orderBy('tanggal_kunjungan', 'desc');
|
||||||
->orderBy('tanggal_kunjungan', 'desc')
|
|
||||||
->get();
|
// Filter Bulan & Tahun
|
||||||
|
if ($request->filled('bulan')) {
|
||||||
|
$query->whereMonth('tanggal_kunjungan', $request->input('bulan'));
|
||||||
|
}
|
||||||
|
if ($request->filled('tahun')) {
|
||||||
|
$query->whereYear('tanggal_kunjungan', $request->input('tahun'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$bukuTamu = $query->get();
|
||||||
|
|
||||||
|
// Slice data berdasarkan rentang baris (Limit Cetak)
|
||||||
|
if ($request->filled('limit_start') || $request->filled('limit_end')) {
|
||||||
|
$start = $request->filled('limit_start') ? (int)$request->input('limit_start') : 1;
|
||||||
|
$offset = max(0, $start - 1);
|
||||||
|
if ($request->filled('limit_end')) {
|
||||||
|
$end = (int)$request->input('limit_end');
|
||||||
|
$length = max(0, $end - $offset);
|
||||||
|
$bukuTamu = $bukuTamu->slice($offset, $length);
|
||||||
|
} else {
|
||||||
|
$bukuTamu = $bukuTamu->slice($offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return view('laporan.kehadiran', compact('bukuTamu'));
|
return view('laporan.kehadiran', compact('bukuTamu'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function peminjaman(Request $request)
|
public function peminjaman(Request $request)
|
||||||
{
|
{
|
||||||
$query = Peminjaman::with(['anggota', 'user', 'buku'])->orderBy('tanggal_pinjam', 'desc');
|
$query = Peminjaman::with(['anggota', 'user', 'buku.kategori'])->orderBy('tanggal_pinjam', 'desc');
|
||||||
|
|
||||||
// Optional filtering by month/year if needed (can be added later)
|
// 1. Filter Bulan & Tahun
|
||||||
|
if ($request->filled('bulan')) {
|
||||||
|
$query->whereMonth('tanggal_pinjam', $request->input('bulan'));
|
||||||
|
}
|
||||||
|
if ($request->filled('tahun')) {
|
||||||
|
$query->whereYear('tanggal_pinjam', $request->input('tahun'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Filter Kategori Buku (Berdasarkan DDC / Nomor Panggil)
|
||||||
|
if ($request->filled('id_kategori')) {
|
||||||
|
$classDigit = $request->input('id_kategori'); // '0', '1', ..., '9'
|
||||||
|
$query->whereHas('buku', function ($q) use ($classDigit) {
|
||||||
|
$q->where('nomor_panggil', 'like', "{$classDigit}%");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
$peminjaman = $query->get();
|
$peminjaman = $query->get();
|
||||||
|
|
||||||
return view('laporan.peminjaman', compact('peminjaman'));
|
// Slice data berdasarkan rentang baris (Limit Cetak)
|
||||||
|
if ($request->filled('limit_start') || $request->filled('limit_end')) {
|
||||||
|
$start = $request->filled('limit_start') ? (int)$request->input('limit_start') : 1;
|
||||||
|
$offset = max(0, $start - 1);
|
||||||
|
if ($request->filled('limit_end')) {
|
||||||
|
$end = (int)$request->input('limit_end');
|
||||||
|
$length = max(0, $end - $offset);
|
||||||
|
$peminjaman = $peminjaman->slice($offset, $length);
|
||||||
|
} else {
|
||||||
|
$peminjaman = $peminjaman->slice($offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kategori berdasarkan DDC & Lokasi Rak sesuai permintaan user
|
||||||
|
$categories = [
|
||||||
|
'0' => '000-099 : Karya Umum (Rak 01-05)',
|
||||||
|
'1' => '100-199 : Filsafat & Psikologi (Rak 06-14)',
|
||||||
|
'2' => '200-299 : Agama (Rak 15-32)',
|
||||||
|
'3' => '300-399 : Ilmu Sosial (Rak 33-44)',
|
||||||
|
'4' => '400-499 : Bahasa (Rak 45)',
|
||||||
|
'5' => '500-599 : Ilmu Murni / Sains (Rak 46-48)',
|
||||||
|
'6' => '600-699 : Ilmu Terapan (Rak 49-68)',
|
||||||
|
'7' => '700-799 : Kesenian & Olahraga (Rak 71-74)',
|
||||||
|
'8' => '800-899 : Sastra (Rak 77-79)',
|
||||||
|
'9' => '900-999 : Geografi & Sejarah (Rak 69-70, Rak 80-84)'
|
||||||
|
];
|
||||||
|
|
||||||
|
return view('laporan.peminjaman', compact('peminjaman', 'categories'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,20 +7,19 @@
|
||||||
|
|
||||||
class AppServiceProvider extends ServiceProvider
|
class AppServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Register any application services.
|
|
||||||
*/
|
|
||||||
public function register(): void
|
public function register(): void
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Bootstrap any application services.
|
|
||||||
*/
|
|
||||||
public function boot(): void
|
public function boot(): void
|
||||||
{
|
{
|
||||||
Paginator::useTailwind();
|
Paginator::useTailwind();
|
||||||
}
|
|
||||||
|
|
||||||
|
// Paksa URL Utama & HTTPS di Production untuk menjamin asset() & route() konsisten
|
||||||
|
if (config('app.env') !== 'local') {
|
||||||
|
\Illuminate\Support\Facades\URL::forceRootUrl(config('app.url'));
|
||||||
|
\Illuminate\Support\Facades\URL::forceScheme('https');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Script untuk membuat Symlink (Storage Link) di Shared Hosting
|
||||||
|
* Jalankan file ini sekali saja melalui browser: https://ta.myhost.id/E31230887/buat_link.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
$target = __DIR__ . '/storage/app/public';
|
||||||
|
$link = __DIR__ . '/public/storage';
|
||||||
|
|
||||||
|
echo "<h2>🔧 Memperbaiki Jembatan Storage (Symlink)</h2>";
|
||||||
|
echo "<p>Target: <code>$target</code></p>";
|
||||||
|
echo "<p>Link: <code>$link</code></p>";
|
||||||
|
|
||||||
|
if (file_exists($link)) {
|
||||||
|
echo "<p>⚠️ Menghapus link/folder storage lama...</p>";
|
||||||
|
if (is_link($link)) {
|
||||||
|
unlink($link);
|
||||||
|
} else {
|
||||||
|
// Jika ternyata folder biasa (bukan link), kita amankan dengan ganti nama
|
||||||
|
rename($link, $link . '_backup_' . time());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symlink($target, $link)) {
|
||||||
|
echo "<h3 style='color: green;'>✅ Jembatan Storage Berhasil Dibuat!</h3>";
|
||||||
|
echo "<p>Sekarang gambar buku Anda seharusnya sudah muncul di website.</p>";
|
||||||
|
echo "<a href='./'>Kembali ke Website</a>";
|
||||||
|
} else {
|
||||||
|
echo "<h3 style='color: red;'>❌ Gagal membuat jembatan symlink.</h3>";
|
||||||
|
echo "<p>Beberapa hosting membatasi fungsi symlink(). Jika ini terjadi, beri tahu asisten AI Anda untuk menggunakan metode .htaccess redirect.</p>";
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
$target = __DIR__ . '/public/storage';
|
||||||
|
echo "Path: $target\n";
|
||||||
|
echo "Is Link: " . (is_link($target) ? 'YES' : 'NO') . "\n";
|
||||||
|
echo "Is Dir: " . (is_dir($target) ? 'YES' : 'NO') . "\n";
|
||||||
|
if (is_link($target)) {
|
||||||
|
echo "Readlink: " . readlink($target) . "\n";
|
||||||
|
}
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use Illuminate\Database\Migrations\Migration;
|
|
||||||
use Illuminate\Database\Schema\Blueprint;
|
|
||||||
use Illuminate\Support\Facades\Schema;
|
|
||||||
|
|
||||||
return new class extends Migration
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Run the migrations.
|
|
||||||
*/
|
|
||||||
public function up()
|
|
||||||
{
|
|
||||||
Schema::create('bukus', function (Blueprint $table) {
|
|
||||||
$table->id();
|
|
||||||
$table->string('bibid')->nullable();
|
|
||||||
$table->string('judul');
|
|
||||||
$table->string('edisi')->nullable();
|
|
||||||
$table->string('pengarang');
|
|
||||||
$table->string('penerbit');
|
|
||||||
$table->year('tahun_terbit')->nullable();
|
|
||||||
$table->text('deskripsi_fisik')->nullable();
|
|
||||||
$table->string('nomor_panggil')->nullable();
|
|
||||||
$table->string('konten_digital')->nullable();
|
|
||||||
$table->integer('eksemplar')->default(1);
|
|
||||||
$table->unsignedBigInteger('id_kategori')->nullable();
|
|
||||||
$table->string('cover')->nullable();
|
|
||||||
$table->float('lokasi_x')->nullable();
|
|
||||||
$table->float('lokasi_y')->nullable();
|
|
||||||
$table->timestamps();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reverse the migrations.
|
|
||||||
*/
|
|
||||||
public function down(): void
|
|
||||||
{
|
|
||||||
Schema::dropIfExists('bukus');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
// File debug sementara — HAPUS setelah selesai!
|
||||||
|
echo "<pre>";
|
||||||
|
echo "DOCUMENT_ROOT: " . $_SERVER['DOCUMENT_ROOT'] . "\n";
|
||||||
|
echo "REQUEST_URI: " . $_SERVER['REQUEST_URI'] . "\n";
|
||||||
|
echo "SCRIPT_FILENAME: " . $_SERVER['SCRIPT_FILENAME'] . "\n";
|
||||||
|
echo "__DIR__: " . __DIR__ . "\n";
|
||||||
|
echo "\n--- Cek keberadaan file ---\n";
|
||||||
|
echo "img/denah.webp via __DIR__: " . (file_exists(__DIR__ . '/img/denah.webp') ? '✅ ADA' : '❌ TIDAK ADA') . "\n";
|
||||||
|
echo "public/img/denah.webp via __DIR__: " . (file_exists(__DIR__ . '/public/img/denah.webp') ? '✅ ADA' : '❌ TIDAK ADA') . "\n";
|
||||||
|
echo "DOCUMENT_ROOT/img/denah.webp: " . (file_exists($_SERVER['DOCUMENT_ROOT'] . '/img/denah.webp') ? '✅ ADA' : '❌ TIDAK ADA') . "\n";
|
||||||
|
echo "DOCUMENT_ROOT/E31230887/img/denah.webp: " . (file_exists($_SERVER['DOCUMENT_ROOT'] . '/E31230887/img/denah.webp') ? '✅ ADA' : '❌ TIDAK ADA') . "\n";
|
||||||
|
echo "</pre>";
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// Bootstrap Laravel dari folder public/
|
||||||
|
require __DIR__ . '/public/index.php';
|
||||||
|
|
@ -1,6 +1,31 @@
|
||||||
@extends('layouts.app')
|
@extends('layouts.app')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
|
<!-- CDNs for icons, TomSelect and sweetalert -->
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/tom-select@2.2.2/dist/css/tom-select.css" rel="stylesheet">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/tom-select@2.2.2/dist/js/tom-select.complete.min.js"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* TomSelect Custom Styling matching dashboard */
|
||||||
|
.ts-control {
|
||||||
|
border: 1px solid #d1d5db !important;
|
||||||
|
background-color: #ffffff !important;
|
||||||
|
border-radius: 0.5rem !important;
|
||||||
|
padding: 0.75rem 1rem !important;
|
||||||
|
font-size: 0.875rem !important;
|
||||||
|
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05) !important;
|
||||||
|
}
|
||||||
|
.ts-control.focus {
|
||||||
|
border-color: #3b82f6 !important;
|
||||||
|
box-shadow: 0 0 0 1px #3b82f6 !important;
|
||||||
|
}
|
||||||
|
.ts-control input {
|
||||||
|
font-size: 0.875rem !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<div class="container mx-auto px-4 py-8 max-w-2xl">
|
<div class="container mx-auto px-4 py-8 max-w-2xl">
|
||||||
<div class="bg-white shadow-lg rounded-xl overflow-hidden border border-gray-100">
|
<div class="bg-white shadow-lg rounded-xl overflow-hidden border border-gray-100">
|
||||||
<div class="p-6 bg-blue-50 border-b border-blue-100">
|
<div class="p-6 bg-blue-50 border-b border-blue-100">
|
||||||
|
|
@ -34,19 +59,30 @@ class="w-full border-gray-300 rounded-lg shadow-sm focus:border-blue-500 focus:r
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Pilih Aset Buku (Hanya yang
|
<label class="block text-sm font-medium text-gray-700 mb-2">Pilih Buku Utama (Pindai Barcode / Cari Judul)</label>
|
||||||
tersedia)</label>
|
<select name="id_buku" id="select-buku-peminjaman" required>
|
||||||
<select name="id_buku"
|
<option value="">-- Pilih Buku Pertama --</option>
|
||||||
class="w-full border-gray-300 rounded-lg shadow-sm focus:border-blue-500 focus:ring-blue-500">
|
|
||||||
<option value="">-- Pilih Buku --</option>
|
|
||||||
@foreach ($buku as $b)
|
@foreach ($buku as $b)
|
||||||
<option value="{{ $b->id_buku }}" {{ old('id_buku') == $b->id_buku ? 'selected' : '' }}>
|
<option value="{{ $b->id_buku }}" data-bibid="{{ $b->bibid }}" {{ old('id_buku') == $b->id_buku ? 'selected' : '' }}>
|
||||||
{{ $b->bibid }} - {{ $b->judul }} (Stok: {{ $b->eksemplar }})
|
{{ $b->bibid }} - {{ $b->judul }} (Stok: {{ $b->eksemplar }})
|
||||||
</option>
|
</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Pilih Buku Kedua (Opsional)</label>
|
||||||
|
<select name="id_buku_2" id="select-buku-peminjaman-2">
|
||||||
|
<option value="">-- Pilih Buku Kedua (Kosongkan jika hanya 1) --</option>
|
||||||
|
@foreach ($buku as $b)
|
||||||
|
<option value="{{ $b->id_buku }}" data-bibid="{{ $b->bibid }}" {{ old('id_buku_2') == $b->id_buku ? 'selected' : '' }}>
|
||||||
|
{{ $b->bibid }} - {{ $b->judul }} (Stok: {{ $b->eksemplar }})
|
||||||
|
</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -83,5 +119,131 @@ class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-8 rounded-lg s
|
||||||
btn.innerHTML = 'Memproses...';
|
btn.innerHTML = 'Memproses...';
|
||||||
btn.classList.add('opacity-50', 'cursor-not-allowed');
|
btn.classList.add('opacity-50', 'cursor-not-allowed');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let scanBuffer = "";
|
||||||
|
let lastKeyTime = Date.now();
|
||||||
|
|
||||||
|
// Global barcode scan detection
|
||||||
|
document.addEventListener('keypress', function(e) {
|
||||||
|
const target = e.target;
|
||||||
|
|
||||||
|
if (target.tagName === 'INPUT' && target.type !== 'submit' && target.type !== 'button' && target.type !== 'checkbox' && target.type !== 'radio') {
|
||||||
|
if (!target.classList.contains('ts-control') && !target.closest('.ts-wrapper')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (target.tagName === 'TEXTAREA' || target.tagName === 'SELECT') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentTime = Date.now();
|
||||||
|
|
||||||
|
if (currentTime - lastKeyTime > 100) {
|
||||||
|
scanBuffer = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
lastKeyTime = currentTime;
|
||||||
|
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
if (scanBuffer.length >= 2) {
|
||||||
|
e.preventDefault();
|
||||||
|
const cleanCode = scanBuffer.trim();
|
||||||
|
handleGlobalScan(cleanCode);
|
||||||
|
scanBuffer = "";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (e.key.length === 1) {
|
||||||
|
scanBuffer += e.key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleGlobalScan(bibid) {
|
||||||
|
const select1 = document.getElementById('select-buku-peminjaman');
|
||||||
|
const select2 = document.getElementById('select-buku-peminjaman-2');
|
||||||
|
|
||||||
|
if (!select1) return;
|
||||||
|
|
||||||
|
function findVal(selectEl) {
|
||||||
|
const options = selectEl.options;
|
||||||
|
for (let i = 0; i < options.length; i++) {
|
||||||
|
if (options[i].getAttribute('data-bibid') === bibid) {
|
||||||
|
return { value: options[i].value, text: options[i].text };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const item = findVal(select1);
|
||||||
|
if (!item) {
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'error',
|
||||||
|
title: 'Buku Tidak Ditemukan',
|
||||||
|
text: 'Kode buku "' + bibid + '" tidak terdaftar atau tidak tersedia.',
|
||||||
|
timer: 2000,
|
||||||
|
showConfirmButton: false,
|
||||||
|
toast: true,
|
||||||
|
position: 'top-end'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let targetSelect = null;
|
||||||
|
if (select1.tomselect && !select1.tomselect.getValue()) {
|
||||||
|
targetSelect = select1;
|
||||||
|
} else if (select2 && select2.tomselect && !select2.tomselect.getValue()) {
|
||||||
|
targetSelect = select2;
|
||||||
|
} else {
|
||||||
|
targetSelect = select1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetSelect && targetSelect.tomselect) {
|
||||||
|
const otherSelect = (targetSelect === select1) ? select2 : select1;
|
||||||
|
if (otherSelect && otherSelect.tomselect && otherSelect.tomselect.getValue() === item.value) {
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'warning',
|
||||||
|
title: 'Buku Sudah Dipilih',
|
||||||
|
text: 'Buku ini sudah dipilih pada slot lainnya.',
|
||||||
|
timer: 2000,
|
||||||
|
showConfirmButton: false,
|
||||||
|
toast: true,
|
||||||
|
position: 'top-end'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetSelect.tomselect.setValue(item.value);
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'success',
|
||||||
|
title: 'Buku Berhasil Dipilih',
|
||||||
|
text: item.text,
|
||||||
|
timer: 1500,
|
||||||
|
showConfirmButton: false,
|
||||||
|
toast: true,
|
||||||
|
position: 'top-end'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Initialize TomSelect for books
|
||||||
|
const ts1 = new TomSelect('#select-buku-peminjaman', { maxOptions: null });
|
||||||
|
const ts2 = new TomSelect('#select-buku-peminjaman-2', { maxOptions: null });
|
||||||
|
|
||||||
|
// Focus on first book dropdown
|
||||||
|
setTimeout(() => {
|
||||||
|
ts1.focus();
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
// Prevent Enter key from submitting form on text/select inputs
|
||||||
|
const forms = document.querySelectorAll('form');
|
||||||
|
forms.forEach(form => {
|
||||||
|
form.addEventListener('keydown', function(e) {
|
||||||
|
if (e.key === 'Enter' && e.target.tagName !== 'BUTTON' && e.target.type !== 'submit') {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,16 @@
|
||||||
tanggal_pinjam: '{{ old('tanggal_pinjam') ?? '' }}',
|
tanggal_pinjam: '{{ old('tanggal_pinjam') ?? '' }}',
|
||||||
tanggal_kembali: '{{ old('tanggal_kembali') ?? '' }}'
|
tanggal_kembali: '{{ old('tanggal_kembali') ?? '' }}'
|
||||||
},
|
},
|
||||||
|
init() {
|
||||||
|
this.$watch('isModalPeminjamanOpen', value => {
|
||||||
|
if (value) {
|
||||||
|
setTimeout(() => {
|
||||||
|
const ts1 = document.getElementById('select-buku-peminjaman');
|
||||||
|
if (ts1 && ts1.tomselect) ts1.tomselect.focus();
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
openEditModal(id, anggotaId, buku, pinjam, kembali) {
|
openEditModal(id, anggotaId, buku, pinjam, kembali) {
|
||||||
this.editData = { id: id, id_anggota: anggotaId, id_buku: buku, tanggal_pinjam: pinjam, tanggal_kembali: kembali };
|
this.editData = { id: id, id_anggota: anggotaId, id_buku: buku, tanggal_pinjam: pinjam, tanggal_kembali: kembali };
|
||||||
this.isModalEditOpen = true;
|
this.isModalEditOpen = true;
|
||||||
|
|
@ -252,20 +262,35 @@ class="mt-1 block w-full border-gray-200 focus:border-indigo-500 focus:ring-indi
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
<div>
|
<div>
|
||||||
<x-input-label value="Pilih Buku (Hanya yang tersedia)" />
|
<x-input-label value="Pilih Buku Utama (Pindai Barcode / Cari Judul)" />
|
||||||
<select name="id_buku" x-init="new TomSelect($el, { maxOptions: null })"
|
<select name="id_buku" id="select-buku-peminjaman" x-init="new TomSelect($el, { maxOptions: null })"
|
||||||
class="mt-1 block w-full border-gray-200 focus:border-indigo-500 focus:ring-indigo-500 rounded-xl shadow-sm bg-gray-50/50 p-3"
|
class="mt-1 block w-full border-gray-200 focus:border-indigo-500 focus:ring-indigo-500 rounded-xl shadow-sm bg-gray-50/50 p-3"
|
||||||
required>
|
required>
|
||||||
<option value="">-- Pilih Buku --</option>
|
<option value="">-- Pilih Buku Pertama --</option>
|
||||||
@foreach ($buku as $b)
|
@foreach ($buku as $b)
|
||||||
<option value="{{ $b->id_buku }}"
|
<option value="{{ $b->id_buku }}" data-bibid="{{ $b->bibid }}"
|
||||||
{{ old('id_buku') == $b->id_buku ? 'selected' : '' }}>
|
{{ old('id_buku') == $b->id_buku ? 'selected' : '' }}>
|
||||||
{{ $b->bibid }} - {{ $b->judul }} (Stok: {{ $b->eksemplar }})
|
{{ $b->bibid }} - {{ $b->judul }} (Stok: {{ $b->eksemplar }})
|
||||||
</option>
|
</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<x-input-label value="Pilih Buku Kedua (Opsional)" />
|
||||||
|
<select name="id_buku_2" id="select-buku-peminjaman-2" x-init="new TomSelect($el, { maxOptions: null })"
|
||||||
|
class="mt-1 block w-full border-gray-200 focus:border-indigo-500 focus:ring-indigo-500 rounded-xl shadow-sm bg-gray-50/50 p-3">
|
||||||
|
<option value="">-- Pilih Buku Kedua (Kosongkan jika hanya 1) --</option>
|
||||||
|
@foreach ($buku as $b)
|
||||||
|
<option value="{{ $b->id_buku }}" data-bibid="{{ $b->bibid }}"
|
||||||
|
{{ old('id_buku_2') == $b->id_buku ? 'selected' : '' }}>
|
||||||
|
{{ $b->bibid }} - {{ $b->judul }} (Stok: {{ $b->eksemplar }})
|
||||||
|
</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -376,7 +401,7 @@ class="bg-green-50 text-green-700 p-3 rounded-lg text-center font-bold text-xs m
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<form :action="'/admin/peminjaman/' + kembaliData.id + '/kembali'" method="POST">
|
<form :action="'{{ url('admin/peminjaman') }}/' + kembaliData.id + '/kembali'" method="POST">
|
||||||
@csrf
|
@csrf
|
||||||
@method('PUT')
|
@method('PUT')
|
||||||
<div class="flex items-center justify-end gap-2 pt-3 border-t border-gray-100">
|
<div class="flex items-center justify-end gap-2 pt-3 border-t border-gray-100">
|
||||||
|
|
@ -424,7 +449,7 @@ class="w-10 h-10 rounded-full bg-gray-50 hover:bg-red-50 text-gray-400 hover:tex
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form :action="'/admin/peminjaman/' + editData.id" method="POST" class="space-y-6">
|
<form :action="'{{ url('admin/peminjaman') }}/' + editData.id" method="POST" class="space-y-6">
|
||||||
@csrf
|
@csrf
|
||||||
@method('PUT')
|
@method('PUT')
|
||||||
<input type="hidden" name="peminjaman_id_edit" :value="editData.id">
|
<input type="hidden" name="peminjaman_id_edit" :value="editData.id">
|
||||||
|
|
@ -517,7 +542,7 @@ class="text-gray-400 hover:text-gray-600 transition-colors">
|
||||||
buku akan otomatis dikembalikan jika status masih dipinjam.</p>
|
buku akan otomatis dikembalikan jika status masih dipinjam.</p>
|
||||||
|
|
||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
<form :action="'/admin/peminjaman/' + deleteId" method="POST" class="w-full m-0">
|
<form :action="'{{ url('admin/peminjaman') }}/' + deleteId" method="POST" class="w-full m-0">
|
||||||
@csrf
|
@csrf
|
||||||
@method('DELETE')
|
@method('DELETE')
|
||||||
<button type="submit"
|
<button type="submit"
|
||||||
|
|
@ -536,3 +561,123 @@ class="w-full py-4 bg-gray-50 hover:bg-gray-100 text-gray-600 rounded-2xl font-b
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
<script>
|
||||||
|
let scanBuffer = "";
|
||||||
|
let lastKeyTime = Date.now();
|
||||||
|
|
||||||
|
// Global barcode scan detection
|
||||||
|
document.addEventListener('keypress', function(e) {
|
||||||
|
const target = e.target;
|
||||||
|
|
||||||
|
if (target.tagName === 'INPUT' && target.type !== 'submit' && target.type !== 'button' && target.type !== 'checkbox' && target.type !== 'radio') {
|
||||||
|
if (!target.classList.contains('ts-control') && !target.closest('.ts-wrapper')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (target.tagName === 'TEXTAREA' || target.tagName === 'SELECT') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentTime = Date.now();
|
||||||
|
|
||||||
|
if (currentTime - lastKeyTime > 100) {
|
||||||
|
scanBuffer = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
lastKeyTime = currentTime;
|
||||||
|
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
if (scanBuffer.length >= 2) {
|
||||||
|
e.preventDefault();
|
||||||
|
const cleanCode = scanBuffer.trim();
|
||||||
|
handleGlobalScan(cleanCode);
|
||||||
|
scanBuffer = "";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (e.key.length === 1) {
|
||||||
|
scanBuffer += e.key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleGlobalScan(bibid) {
|
||||||
|
const select1 = document.getElementById('select-buku-peminjaman');
|
||||||
|
const select2 = document.getElementById('select-buku-peminjaman-2');
|
||||||
|
|
||||||
|
if (!select1) return;
|
||||||
|
|
||||||
|
function findVal(selectEl) {
|
||||||
|
const options = selectEl.options;
|
||||||
|
for (let i = 0; i < options.length; i++) {
|
||||||
|
if (options[i].getAttribute('data-bibid') === bibid) {
|
||||||
|
return { value: options[i].value, text: options[i].text };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const item = findVal(select1);
|
||||||
|
if (!item) {
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'error',
|
||||||
|
title: 'Buku Tidak Ditemukan',
|
||||||
|
text: 'Kode buku "' + bibid + '" tidak terdaftar atau tidak tersedia.',
|
||||||
|
timer: 2000,
|
||||||
|
showConfirmButton: false,
|
||||||
|
toast: true,
|
||||||
|
position: 'top-end'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let targetSelect = null;
|
||||||
|
if (select1.tomselect && !select1.tomselect.getValue()) {
|
||||||
|
targetSelect = select1;
|
||||||
|
} else if (select2 && select2.tomselect && !select2.tomselect.getValue()) {
|
||||||
|
targetSelect = select2;
|
||||||
|
} else {
|
||||||
|
targetSelect = select1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetSelect && targetSelect.tomselect) {
|
||||||
|
const otherSelect = (targetSelect === select1) ? select2 : select1;
|
||||||
|
if (otherSelect && otherSelect.tomselect && otherSelect.tomselect.getValue() === item.value) {
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'warning',
|
||||||
|
title: 'Buku Sudah Dipilih',
|
||||||
|
text: 'Buku ini sudah dipilih pada slot lainnya.',
|
||||||
|
timer: 2000,
|
||||||
|
showConfirmButton: false,
|
||||||
|
toast: true,
|
||||||
|
position: 'top-end'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetSelect.tomselect.setValue(item.value);
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'success',
|
||||||
|
title: 'Buku Berhasil Dipilih',
|
||||||
|
text: item.text,
|
||||||
|
timer: 1500,
|
||||||
|
showConfirmButton: false,
|
||||||
|
toast: true,
|
||||||
|
position: 'top-end'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const forms = document.querySelectorAll('form');
|
||||||
|
forms.forEach(form => {
|
||||||
|
form.addEventListener('keydown', function(e) {
|
||||||
|
if (e.key === 'Enter' && e.target.tagName !== 'BUTTON' && e.target.type !== 'submit') {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
@extends('layouts.admin')
|
@extends('layouts.admin')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="container mx-auto px-4 py-8 max-w-3xl">
|
<div class="container mx-auto px-4 py-8 max-w-3xl">
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<a href="{{ route('admin.peminjaman.index') }}" class="text-blue-600 hover:text-blue-800 font-medium">← Kembali ke Daftar Sirkulasi</a>
|
<a href="{{ route('admin.pengembalian.index') }}" class="text-blue-600 hover:text-blue-800 font-medium">←
|
||||||
|
Kembali ke Daftar Pengembalian</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-white shadow-lg rounded-xl overflow-hidden border border-gray-100 mb-8">
|
<div class="bg-white shadow-lg rounded-xl overflow-hidden border border-gray-100 mb-8">
|
||||||
|
|
@ -13,8 +14,14 @@
|
||||||
|
|
||||||
<form action="{{ route('admin.peminjaman.proses_scan') }}" method="POST" class="max-w-md mx-auto relative">
|
<form action="{{ route('admin.peminjaman.proses_scan') }}" method="POST" class="max-w-md mx-auto relative">
|
||||||
@csrf
|
@csrf
|
||||||
<input type="text" name="bibid" autofocus autocomplete="off" placeholder="Scan Barcode di sini..." class="w-full pl-12 pr-4 py-4 text-center text-xl font-mono border-2 border-gray-700 bg-gray-800 text-white rounded-lg shadow-sm focus:border-blue-500 focus:ring-blue-500 focus:bg-gray-900 transition-colors">
|
<input type="text" name="bibid" autofocus autocomplete="off" placeholder="Scan Barcode di sini..."
|
||||||
<svg class="w-6 h-6 text-gray-500 absolute left-4 top-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v1m6 11h2m-6 0h-2v4m0-11v3m0 0h.01M12 12h4.01M16 20h4M4 12h4m12 0h.01M5 8h2a1 1 0 001-1V5a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1zm14 0h2a1 1 0 001-1V5a1 1 0 00-1-1h-2a1 1 0 00-1 1v2a1 1 0 001 1zM5 20h2a1 1 0 001-1v-2a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1z"></path></svg>
|
class="w-full pl-12 pr-4 py-4 text-center text-xl font-mono border-2 border-gray-700 bg-gray-800 text-white rounded-lg shadow-sm focus:border-blue-500 focus:ring-blue-500 focus:bg-gray-900 transition-colors">
|
||||||
|
<svg class="w-6 h-6 text-gray-500 absolute left-4 top-4" fill="none" stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M12 4v1m6 11h2m-6 0h-2v4m0-11v3m0 0h.01M12 12h4.01M16 20h4M4 12h4m12 0h.01M5 8h2a1 1 0 001-1V5a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1zm14 0h2a1 1 0 001-1V5a1 1 0 00-1-1h-2a1 1 0 00-1 1v2a1 1 0 001 1zM5 20h2a1 1 0 001-1v-2a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1z">
|
||||||
|
</path>
|
||||||
|
</svg>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -30,14 +37,16 @@
|
||||||
<div class="bg-white shadow-xl rounded-xl overflow-hidden border-2 border-green-500">
|
<div class="bg-white shadow-xl rounded-xl overflow-hidden border-2 border-green-500">
|
||||||
<div class="p-6 bg-green-50 border-b border-green-100 flex justify-between items-center">
|
<div class="p-6 bg-green-50 border-b border-green-100 flex justify-between items-center">
|
||||||
<h2 class="text-xl font-bold text-green-900">Data Transaksi Ditemukan</h2>
|
<h2 class="text-xl font-bold text-green-900">Data Transaksi Ditemukan</h2>
|
||||||
<span class="bg-green-200 text-green-800 px-3 py-1 rounded-full text-xs font-bold uppercase">#{{ $peminjaman->id_peminjaman }}</span>
|
<span
|
||||||
|
class="bg-green-200 text-green-800 px-3 py-1 rounded-full text-xs font-bold uppercase">#{{ $peminjaman->id_peminjaman }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="p-6 grid grid-cols-1 md:grid-cols-2 gap-8">
|
<div class="p-6 grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<span class="block text-xs font-bold text-gray-500 uppercase">Peminjam</span>
|
<span class="block text-xs font-bold text-gray-500 uppercase">Peminjam</span>
|
||||||
<span class="block text-lg font-bold text-gray-900">{{ $peminjaman->anggota?->nama ?? ($peminjaman->user?->name ?? 'Anonim') }}</span>
|
<span
|
||||||
|
class="block text-lg font-bold text-gray-900">{{ $peminjaman->anggota?->nama ?? ($peminjaman->user?->name ?? 'Anonim') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="block text-xs font-bold text-gray-500 uppercase">Aset Buku</span>
|
<span class="block text-xs font-bold text-gray-500 uppercase">Aset Buku</span>
|
||||||
|
|
@ -53,32 +62,40 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col space-y-4">
|
<div class="flex flex-col space-y-4">
|
||||||
<div class="bg-blue-900 rounded-xl p-5 text-center text-white shadow-inner flex-1 flex flex-col justify-center border border-blue-800">
|
<div
|
||||||
<span class="block text-xs font-bold text-blue-300 uppercase tracking-widest mb-2">Panduan Pengembalian Rak Fisik</span>
|
class="bg-blue-900 rounded-xl p-5 text-center text-white shadow-inner flex-1 flex flex-col justify-center border border-blue-800">
|
||||||
|
<span class="block text-xs font-bold text-blue-300 uppercase tracking-widest mb-2">Panduan
|
||||||
|
Pengembalian Rak Fisik</span>
|
||||||
<span class="block text-4xl font-black mb-1 drop-shadow-md">{{ $lokasi['rak'] }}</span>
|
<span class="block text-4xl font-black mb-1 drop-shadow-md">{{ $lokasi['rak'] }}</span>
|
||||||
<span class="block text-sm text-blue-100 font-medium bg-blue-950/50 py-1 rounded-full w-max mx-auto px-4 mt-2 border border-blue-700/50">{{ $lokasi['area'] }}</span>
|
<span
|
||||||
|
class="block text-sm text-blue-100 font-medium bg-blue-950/50 py-1 rounded-full w-max mx-auto px-4 mt-2 border border-blue-700/50">{{ $lokasi['area'] }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if($denda > 0)
|
@if($denda > 0)
|
||||||
<div class="bg-red-50 border-2 border-red-200 rounded-xl p-4 text-center">
|
<div class="bg-red-50 border-2 border-red-200 rounded-xl p-4 text-center">
|
||||||
<span class="block text-xs font-bold text-red-600 uppercase mb-1">Denda Keterlambatan</span>
|
<span class="block text-xs font-bold text-red-600 uppercase mb-1">Denda Keterlambatan</span>
|
||||||
<span class="block text-2xl font-black text-red-700">Rp {{ number_format($denda, 0, ',', '.') }}</span>
|
<span class="block text-2xl font-black text-red-700">Rp
|
||||||
|
{{ number_format($denda, 0, ',', '.') }}</span>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="p-6 border-t border-gray-100 bg-gray-50 flex justify-end">
|
<div class="p-6 border-t border-gray-100 bg-gray-50 flex justify-end">
|
||||||
<form action="{{ route('admin.peminjaman.kembalikan', $peminjaman->id_peminjaman) }}" method="POST" onsubmit="return confirm('Selesaikan transaksi dan pulihkan stok buku?');">
|
<form action="{{ route('admin.peminjaman.kembalikan', $peminjaman->id_peminjaman) }}" method="POST"
|
||||||
|
onsubmit="return confirm('Selesaikan transaksi dan pulihkan stok buku?');">
|
||||||
@csrf
|
@csrf
|
||||||
@method('PUT')
|
@method('PUT')
|
||||||
<button type="submit" class="bg-green-600 hover:bg-green-700 text-white font-bold py-4 px-8 rounded-lg shadow-md transition duration-300 w-full md:w-auto text-lg flex items-center gap-2">
|
<button type="submit"
|
||||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
class="bg-green-600 hover:bg-green-700 text-white font-bold py-4 px-8 rounded-lg shadow-md transition duration-300 w-full md:w-auto text-lg flex items-center gap-2">
|
||||||
|
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||||
|
</svg>
|
||||||
Konfirmasi Pengembalian
|
Konfirmasi Pengembalian
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
@ -5,14 +5,78 @@
|
||||||
@section('content')
|
@section('content')
|
||||||
<x-page-header title="Laporan Kehadiran" />
|
<x-page-header title="Laporan Kehadiran" />
|
||||||
<x-card>
|
<x-card>
|
||||||
<div class="mb-4 flex flex-col md:flex-row justify-between items-center gap-4">
|
<!-- Filter Form (Sembunyikan saat cetak) -->
|
||||||
<p class="text-gray-500 text-sm">Berikut adalah daftar rekapitulasi kehadiran pengunjung dan anggota perpustakaan.</p>
|
<form method="GET" action="{{ route('admin.laporan.kehadiran') }}" class="mb-6 bg-gray-50 p-5 rounded-2xl border border-gray-200/60 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-4 items-end print:hidden">
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-bold text-gray-700 mb-1.5 uppercase tracking-wide">Bulan</label>
|
||||||
|
<select name="bulan" class="w-full bg-white border border-gray-200 text-gray-800 text-sm rounded-xl focus:ring-blue-500 focus:border-blue-500 block p-3 shadow-sm outline-none">
|
||||||
|
<option value="">-- Semua Bulan --</option>
|
||||||
|
@foreach([
|
||||||
|
'1' => 'Januari', '2' => 'Februari', '3' => 'Maret', '4' => 'April',
|
||||||
|
'5' => 'Mei', '6' => 'Juni', '7' => 'Juli', '8' => 'Agustus',
|
||||||
|
'9' => 'September', '10' => 'Oktober', '11' => 'November', '12' => 'Desember'
|
||||||
|
] as $num => $name)
|
||||||
|
<option value="{{ $num }}" {{ request('bulan') == $num ? 'selected' : '' }}>{{ $name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-bold text-gray-700 mb-1.5 uppercase tracking-wide">Tahun</label>
|
||||||
|
<select name="tahun" class="w-full bg-white border border-gray-200 text-gray-800 text-sm rounded-xl focus:ring-blue-500 focus:border-blue-500 block p-3 shadow-sm outline-none">
|
||||||
|
<option value="">-- Semua Tahun --</option>
|
||||||
|
@for($y = date('Y') + 1; $y >= date('Y') - 4; $y--)
|
||||||
|
<option value="{{ $y }}" {{ request('tahun', date('Y')) == $y ? 'selected' : '' }}>{{ $y }}</option>
|
||||||
|
@endfor
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-bold text-gray-700 mb-1.5 uppercase tracking-wide">Dari Baris</label>
|
||||||
|
<input type="number" name="limit_start" value="{{ request('limit_start') }}" min="1" placeholder="Contoh: 1" class="w-full bg-white border border-gray-200 text-gray-800 text-sm rounded-xl focus:ring-blue-500 focus:border-blue-500 block p-3 shadow-sm outline-none">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-bold text-gray-700 mb-1.5 uppercase tracking-wide">Sampai Baris</label>
|
||||||
|
<input type="number" name="limit_end" value="{{ request('limit_end') }}" min="1" placeholder="Contoh: 20" class="w-full bg-white border border-gray-200 text-gray-800 text-sm rounded-xl focus:ring-blue-500 focus:border-blue-500 block p-3 shadow-sm outline-none">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<button type="submit" class="flex-grow bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-4 rounded-xl shadow-md transition duration-300 text-sm flex items-center justify-center gap-2">
|
||||||
|
<i class="fas fa-filter"></i> Filter
|
||||||
|
</button>
|
||||||
|
@if(request()->anyFilled(['bulan', 'tahun', 'limit_start', 'limit_end']))
|
||||||
|
<a href="{{ route('admin.laporan.kehadiran') }}" class="bg-gray-100 hover:bg-red-50 border border-gray-200 text-gray-500 hover:text-red-500 p-3 rounded-xl shadow-sm transition duration-300 flex items-center justify-center" title="Reset Filter">
|
||||||
|
<i class="fas fa-times"></i>
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="mb-4 flex flex-col md:flex-row justify-between items-center gap-4 print:hidden">
|
||||||
|
<p class="text-gray-500 text-sm">Berikut adalah daftar rekapitulasi kehadiran pengunjung yang disaring.</p>
|
||||||
<button onclick="window.print()" class="bg-gray-800 hover:bg-gray-900 text-white px-4 py-2 rounded-lg text-sm font-bold shadow-sm transition-all flex items-center gap-2">
|
<button onclick="window.print()" class="bg-gray-800 hover:bg-gray-900 text-white px-4 py-2 rounded-lg text-sm font-bold shadow-sm transition-all flex items-center gap-2">
|
||||||
<i class="fas fa-print"></i> Cetak PDF / Print
|
<i class="fas fa-print"></i> Cetak PDF / Print
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="overflow-x-auto print:overflow-visible">
|
<div class="overflow-x-auto print:overflow-visible">
|
||||||
|
<!-- Print Header (Hanya terlihat saat cetak/print) -->
|
||||||
|
<div class="hidden print:block mb-6 border-b-2 border-gray-800 pb-4 text-center">
|
||||||
|
<h1 class="text-2xl font-black uppercase tracking-wide text-gray-900">Laporan Rekapitulasi Kehadiran</h1>
|
||||||
|
<h2 class="text-sm font-bold text-gray-700 mt-1">PERPUSTAKAAN DAERAH JEMBER</h2>
|
||||||
|
<p class="text-xs text-gray-500 mt-0.5">Jl. Mastrip No. 1, Kabupaten Jember</p>
|
||||||
|
<div class="text-[11px] text-gray-600 mt-3 flex flex-wrap justify-center gap-x-4 gap-y-1 font-medium border-t border-gray-100 pt-3">
|
||||||
|
@if(request('bulan') || request('tahun'))
|
||||||
|
<span>Periode:
|
||||||
|
{{ request('bulan') ? Carbon\Carbon::create()->month((int) request('bulan'))->translatedFormat('F') : 'Semua Bulan' }}
|
||||||
|
{{ request('tahun') ?? '' }}
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
<span>Dicetak Pada: {{ \Carbon\Carbon::now()->translatedFormat('d F Y H:i') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<x-table>
|
<x-table>
|
||||||
<x-slot name="head">
|
<x-slot name="head">
|
||||||
<x-th>No</x-th>
|
<x-th>No</x-th>
|
||||||
|
|
@ -24,7 +88,7 @@
|
||||||
|
|
||||||
@forelse($bukuTamu as $item)
|
@forelse($bukuTamu as $item)
|
||||||
<tr class="hover:bg-gray-50 transition-colors border-b border-gray-100 last:border-0">
|
<tr class="hover:bg-gray-50 transition-colors border-b border-gray-100 last:border-0">
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ $loop->iteration }}</td>
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ (request('limit_start') ? (int)request('limit_start') : 1) + $loop->index }}</td>
|
||||||
<td class="px-6 py-4">
|
<td class="px-6 py-4">
|
||||||
@if($item->user)
|
@if($item->user)
|
||||||
{{-- Member path: data dari users --}}
|
{{-- Member path: data dari users --}}
|
||||||
|
|
@ -59,22 +123,68 @@
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@media print {
|
@media print {
|
||||||
body * {
|
/* Hide layout elements not needed for print */
|
||||||
visibility: hidden;
|
header, aside, .sidebar, nav, footer, button, .print\:hidden, form, .mb-4 {
|
||||||
}
|
|
||||||
.sidebar, header, nav, footer, button, .mb-4 {
|
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
.print\:overflow-visible, .print\:overflow-visible * {
|
|
||||||
visibility: visible !important;
|
/* Reset body, main, and containers to allow natural multi-page flow */
|
||||||
|
html, body {
|
||||||
|
height: auto !important;
|
||||||
|
min-height: auto !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
background-color: #fff !important;
|
||||||
|
color: #000 !important;
|
||||||
}
|
}
|
||||||
.print\:overflow-visible {
|
|
||||||
position: absolute;
|
/* Force the relative layout container to overflow naturally */
|
||||||
left: 0;
|
div.flex.flex-1.overflow-hidden.relative {
|
||||||
top: 0;
|
display: block !important;
|
||||||
width: 100%;
|
height: auto !important;
|
||||||
margin: 0 !important;
|
min-height: auto !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
position: static !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
height: auto !important;
|
||||||
|
min-height: auto !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
position: static !important;
|
||||||
|
display: block !important;
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset card and table parent wrappers */
|
||||||
|
.bg-white, .shadow-xl, .rounded-3xl, .p-6, .p-8 {
|
||||||
|
background: transparent !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
border: none !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
height: auto !important;
|
||||||
|
min-height: auto !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adjust table styles for print */
|
||||||
|
table {
|
||||||
|
width: 100% !important;
|
||||||
|
border-collapse: collapse !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
padding: 8px 12px !important;
|
||||||
|
border: 1px solid #ddd !important;
|
||||||
|
font-size: 11px !important;
|
||||||
|
color: #000 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Avoid page breaks inside table rows */
|
||||||
|
tr {
|
||||||
|
page-break-inside: avoid !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,91 @@
|
||||||
@section('content')
|
@section('content')
|
||||||
<x-page-header title="Laporan Peminjaman" />
|
<x-page-header title="Laporan Peminjaman" />
|
||||||
<x-card>
|
<x-card>
|
||||||
<div class="mb-4 flex flex-col md:flex-row justify-between items-center gap-4">
|
<!-- Filter Form (Sembunyikan saat cetak) -->
|
||||||
<p class="text-gray-500 text-sm">Berikut adalah seluruh rekap data peminjaman buku perpustakaan.</p>
|
<form method="GET" action="{{ route('admin.laporan.peminjaman') }}" class="mb-6 bg-gray-50 p-5 rounded-2xl border border-gray-200/60 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6 gap-4 items-end print:hidden">
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-bold text-gray-700 mb-1.5 uppercase tracking-wide">Bulan</label>
|
||||||
|
<select name="bulan" class="w-full bg-white border border-gray-200 text-gray-800 text-sm rounded-xl focus:ring-blue-500 focus:border-blue-500 block p-3 shadow-sm outline-none">
|
||||||
|
<option value="">-- Semua Bulan --</option>
|
||||||
|
@foreach([
|
||||||
|
'1' => 'Januari', '2' => 'Februari', '3' => 'Maret', '4' => 'April',
|
||||||
|
'5' => 'Mei', '6' => 'Juni', '7' => 'Juli', '8' => 'Agustus',
|
||||||
|
'9' => 'September', '10' => 'Oktober', '11' => 'November', '12' => 'Desember'
|
||||||
|
] as $num => $name)
|
||||||
|
<option value="{{ $num }}" {{ request('bulan') == $num ? 'selected' : '' }}>{{ $name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-bold text-gray-700 mb-1.5 uppercase tracking-wide">Tahun</label>
|
||||||
|
<select name="tahun" class="w-full bg-white border border-gray-200 text-gray-800 text-sm rounded-xl focus:ring-blue-500 focus:border-blue-500 block p-3 shadow-sm outline-none">
|
||||||
|
<option value="">-- Semua Tahun --</option>
|
||||||
|
@for($y = date('Y') + 1; $y >= date('Y') - 4; $y--)
|
||||||
|
<option value="{{ $y }}" {{ request('tahun', date('Y')) == $y ? 'selected' : '' }}>{{ $y }}</option>
|
||||||
|
@endfor
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-bold text-gray-700 mb-1.5 uppercase tracking-wide">Kategori & Lokasi Buku</label>
|
||||||
|
<select name="id_kategori" class="w-full bg-white border border-gray-200 text-gray-800 text-sm rounded-xl focus:ring-blue-500 focus:border-blue-500 block p-3 shadow-sm outline-none">
|
||||||
|
<option value="">-- Semua Kategori --</option>
|
||||||
|
@foreach($categories as $key => $name)
|
||||||
|
<option value="{{ $key }}" {{ request('id_kategori') === (string)$key ? 'selected' : '' }}>{{ $name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-bold text-gray-700 mb-1.5 uppercase tracking-wide">Dari Baris</label>
|
||||||
|
<input type="number" name="limit_start" value="{{ request('limit_start') }}" min="1" placeholder="Contoh: 1" class="w-full bg-white border border-gray-200 text-gray-800 text-sm rounded-xl focus:ring-blue-500 focus:border-blue-500 block p-3 shadow-sm outline-none">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-bold text-gray-700 mb-1.5 uppercase tracking-wide">Sampai Baris</label>
|
||||||
|
<input type="number" name="limit_end" value="{{ request('limit_end') }}" min="1" placeholder="Contoh: 20" class="w-full bg-white border border-gray-200 text-gray-800 text-sm rounded-xl focus:ring-blue-500 focus:border-blue-500 block p-3 shadow-sm outline-none">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<button type="submit" class="flex-grow bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-4 rounded-xl shadow-md transition duration-300 text-sm flex items-center justify-center gap-2">
|
||||||
|
<i class="fas fa-filter"></i> Filter
|
||||||
|
</button>
|
||||||
|
@if(request()->anyFilled(['bulan', 'tahun', 'id_kategori', 'limit_start', 'limit_end']))
|
||||||
|
<a href="{{ route('admin.laporan.peminjaman') }}" class="bg-gray-100 hover:bg-red-50 border border-gray-200 text-gray-500 hover:text-red-500 p-3 rounded-xl shadow-sm transition duration-300 flex items-center justify-center" title="Reset Filter">
|
||||||
|
<i class="fas fa-times"></i>
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="mb-4 flex flex-col md:flex-row justify-between items-center gap-4 print:hidden">
|
||||||
|
<p class="text-gray-500 text-sm">Berikut adalah rekap data peminjaman buku perpustakaan yang disaring.</p>
|
||||||
<button onclick="window.print()" class="bg-gray-800 hover:bg-gray-900 text-white px-4 py-2 rounded-lg text-sm font-bold shadow-sm transition-all flex items-center gap-2">
|
<button onclick="window.print()" class="bg-gray-800 hover:bg-gray-900 text-white px-4 py-2 rounded-lg text-sm font-bold shadow-sm transition-all flex items-center gap-2">
|
||||||
<i class="fas fa-print"></i> Cetak Laporan
|
<i class="fas fa-print"></i> Cetak Laporan
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="overflow-x-auto print:overflow-visible">
|
<div class="overflow-x-auto print:overflow-visible">
|
||||||
|
<!-- Print Header (Hanya terlihat saat cetak/print) -->
|
||||||
|
<div class="hidden print:block mb-6 border-b-2 border-gray-800 pb-4 text-center">
|
||||||
|
<h1 class="text-2xl font-black uppercase tracking-wide text-gray-900">Laporan Rekapitulasi Peminjaman</h1>
|
||||||
|
<h2 class="text-sm font-bold text-gray-700 mt-1">PERPUSTAKAAN DAERAH JEMBER</h2>
|
||||||
|
<p class="text-xs text-gray-500 mt-0.5">Jl. Mastrip No. 1, Kabupaten Jember</p>
|
||||||
|
<div class="text-[11px] text-gray-600 mt-3 flex flex-wrap justify-center gap-x-4 gap-y-1 font-medium border-t border-gray-100 pt-3">
|
||||||
|
@if(request('bulan') || request('tahun'))
|
||||||
|
<span>Periode:
|
||||||
|
{{ request('bulan') ? Carbon\Carbon::create()->month((int) request('bulan'))->translatedFormat('F') : 'Semua Bulan' }}
|
||||||
|
{{ request('tahun') ?? '' }}
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
@if(request('id_kategori') !== null && isset($categories[request('id_kategori')]))
|
||||||
|
<span>Kategori: {{ $categories[request('id_kategori')] }}</span>
|
||||||
|
@endif
|
||||||
|
<span>Dicetak Pada: {{ \Carbon\Carbon::now()->translatedFormat('d F Y H:i') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<x-table>
|
<x-table>
|
||||||
<x-slot name="head">
|
<x-slot name="head">
|
||||||
<x-th>No</x-th>
|
<x-th>No</x-th>
|
||||||
|
|
@ -27,7 +104,7 @@
|
||||||
|
|
||||||
@forelse($peminjaman as $index => $item)
|
@forelse($peminjaman as $index => $item)
|
||||||
<tr class="hover:bg-gray-50 transition-colors border-b border-gray-100 last:border-0">
|
<tr class="hover:bg-gray-50 transition-colors border-b border-gray-100 last:border-0">
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ $index + 1 }}</td>
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ (request('limit_start') ? (int)request('limit_start') : 1) + $loop->index }}</td>
|
||||||
<td class="px-6 py-4">
|
<td class="px-6 py-4">
|
||||||
@if($item->anggota)
|
@if($item->anggota)
|
||||||
<div class="text-sm font-bold text-gray-900">{{ $item->anggota->nama }}</div>
|
<div class="text-sm font-bold text-gray-900">{{ $item->anggota->nama }}</div>
|
||||||
|
|
@ -80,22 +157,68 @@
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@media print {
|
@media print {
|
||||||
body * {
|
/* Hide layout elements not needed for print */
|
||||||
visibility: hidden;
|
header, aside, .sidebar, nav, footer, button, .print\:hidden, form, .mb-4 {
|
||||||
}
|
|
||||||
.sidebar, header, nav, footer, button, .mb-4 {
|
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
.print\:overflow-visible, .print\:overflow-visible * {
|
|
||||||
visibility: visible !important;
|
/* Reset body, main, and containers to allow natural multi-page flow */
|
||||||
|
html, body {
|
||||||
|
height: auto !important;
|
||||||
|
min-height: auto !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
background-color: #fff !important;
|
||||||
|
color: #000 !important;
|
||||||
}
|
}
|
||||||
.print\:overflow-visible {
|
|
||||||
position: absolute;
|
/* Force the relative layout container to overflow naturally */
|
||||||
left: 0;
|
div.flex.flex-1.overflow-hidden.relative {
|
||||||
top: 0;
|
display: block !important;
|
||||||
width: 100%;
|
height: auto !important;
|
||||||
margin: 0 !important;
|
min-height: auto !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
position: static !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
height: auto !important;
|
||||||
|
min-height: auto !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
position: static !important;
|
||||||
|
display: block !important;
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset card and table parent wrappers */
|
||||||
|
.bg-white, .shadow-xl, .rounded-3xl, .p-6, .p-8 {
|
||||||
|
background: transparent !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
border: none !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
height: auto !important;
|
||||||
|
min-height: auto !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adjust table styles for print */
|
||||||
|
table {
|
||||||
|
width: 100% !important;
|
||||||
|
border-collapse: collapse !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
padding: 8px 12px !important;
|
||||||
|
border: 1px solid #ddd !important;
|
||||||
|
font-size: 11px !important;
|
||||||
|
color: #000 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Avoid page breaks inside table rows */
|
||||||
|
tr {
|
||||||
|
page-break-inside: avoid !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="id">
|
<html lang="id">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>@yield('title', 'Admin Dashboard') - SARAKATA</title>
|
<title>@yield('title', 'Admin Dashboard') - SARAKATA</title>
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap"
|
||||||
|
rel="stylesheet">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
<link href="https://cdn.jsdelivr.net/npm/tom-select@2.2.2/dist/css/tom-select.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/tom-select@2.2.2/dist/css/tom-select.css" rel="stylesheet">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/tom-select@2.2.2/dist/js/tom-select.complete.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/tom-select@2.2.2/dist/js/tom-select.complete.min.js"></script>
|
||||||
|
|
@ -16,14 +18,19 @@
|
||||||
extend: {
|
extend: {
|
||||||
fontFamily: { sans: ['Inter', 'sans-serif'] },
|
fontFamily: { sans: ['Inter', 'sans-serif'] },
|
||||||
colors: {
|
colors: {
|
||||||
primary: { 50:'#eef2ff',100:'#e0e7ff',200:'#c7d2fe',300:'#a5b4fc',400:'#818cf8',500:'#6366f1',600:'#4f46e5',700:'#4338ca',800:'#3730a3',900:'#312e81' },
|
primary: { 50: '#eef2ff', 100: '#e0e7ff', 200: '#c7d2fe', 300: '#a5b4fc', 400: '#818cf8', 500: '#6366f1', 600: '#4f46e5', 700: '#4338ca', 800: '#3730a3', 900: '#312e81' },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
.gradient-text { background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 50%, #2563eb 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; }
|
.gradient-text {
|
||||||
|
background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 50%, #2563eb 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
}
|
||||||
|
|
||||||
/* TomSelect Custom Styling */
|
/* TomSelect Custom Styling */
|
||||||
.ts-control {
|
.ts-control {
|
||||||
|
|
@ -34,57 +41,71 @@
|
||||||
font-size: 0.875rem !important;
|
font-size: 0.875rem !important;
|
||||||
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05) !important;
|
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ts-control.focus {
|
.ts-control.focus {
|
||||||
border-color: #6366f1 !important;
|
border-color: #6366f1 !important;
|
||||||
box-shadow: 0 0 0 1px #6366f1 !important;
|
box-shadow: 0 0 0 1px #6366f1 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ts-control input {
|
.ts-control input {
|
||||||
font-size: 0.875rem !important;
|
font-size: 0.875rem !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-gray-50 font-sans antialiased flex flex-col h-screen overflow-hidden" x-data="{ sidebarOpen: false }">
|
<body class="bg-gray-50 font-sans antialiased flex flex-col h-screen overflow-hidden" x-data="{ sidebarOpen: false }">
|
||||||
|
|
||||||
{{-- TOP HEADER --}}
|
{{-- TOP HEADER --}}
|
||||||
<header class="bg-gradient-to-r from-primary-600 via-primary-700 to-primary-800 text-white h-16 flex items-center justify-between px-6 shadow-lg z-20">
|
<header
|
||||||
|
class="bg-gradient-to-r from-primary-600 via-primary-700 to-primary-800 text-white h-16 flex items-center justify-between px-6 shadow-lg z-20">
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<!-- Mobile Hamburger -->
|
<!-- Mobile Hamburger -->
|
||||||
<button @click="sidebarOpen = true" class="md:hidden w-9 h-9 bg-white/15 hover:bg-white/25 rounded-xl flex items-center justify-center backdrop-blur-sm transition focus:outline-none">
|
<button @click="sidebarOpen = true"
|
||||||
|
class="md:hidden w-9 h-9 bg-white/15 hover:bg-white/25 rounded-xl flex items-center justify-center backdrop-blur-sm transition focus:outline-none">
|
||||||
<i class="fas fa-bars text-white"></i>
|
<i class="fas fa-bars text-white"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="hidden md:flex w-9 h-9 bg-white/15 rounded-xl items-center justify-center backdrop-blur-sm">
|
<div class="hidden md:flex w-9 h-9 bg-white/15 rounded-xl items-center justify-center backdrop-blur-sm">
|
||||||
<i class="fas fa-book-open text-lg"></i>
|
<i class="fas fa-book-open text-lg"></i>
|
||||||
</div>
|
</div>
|
||||||
<h1 class="text-base font-bold tracking-wide">SARAKATA <span class="font-normal text-primary-200 hidden sm:inline">— Sistem Informasi Perpustakaan</span></h1>
|
<h1 class="text-base font-bold tracking-wide">SARAKATA <span
|
||||||
|
class="font-normal text-primary-200 hidden sm:inline">— Sistem Informasi Perpustakaan</span></h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex items-center gap-4">
|
||||||
<form method="POST" action="{{ route('logout') }}">
|
<form method="POST" action="{{ route('logout') }}">
|
||||||
@csrf
|
@csrf
|
||||||
<button class="flex items-center gap-2 px-3 py-1.5 rounded-lg bg-white/10 hover:bg-white/20 transition text-sm font-medium">
|
<button
|
||||||
|
class="flex items-center gap-2 px-3 py-1.5 rounded-lg bg-white/10 hover:bg-white/20 transition text-sm font-medium">
|
||||||
<i class="fas fa-sign-out-alt text-xs"></i> Logout
|
<i class="fas fa-sign-out-alt text-xs"></i> Logout
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<div class="w-9 h-9 rounded-xl overflow-hidden border-2 border-white/30">
|
<div class="w-9 h-9 rounded-xl overflow-hidden border-2 border-white/30">
|
||||||
<img src="https://ui-avatars.com/api/?name={{ auth()->user()->name ?? 'Admin' }}&background=6366f1&color=fff" class="w-full h-full object-cover">
|
<img src="https://ui-avatars.com/api/?name={{ auth()->user()->name ?? 'Admin' }}&background=6366f1&color=fff"
|
||||||
|
class="w-full h-full object-cover">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="flex flex-1 overflow-hidden relative">
|
<div class="flex flex-1 overflow-hidden relative">
|
||||||
<!-- Overlay Khusus Mobile -->
|
<!-- Overlay Khusus Mobile -->
|
||||||
<div x-show="sidebarOpen" x-transition.opacity class="fixed inset-0 bg-gray-900/60 z-40 md:hidden backdrop-blur-sm" @click="sidebarOpen = false" style="display: none;"></div>
|
<div x-show="sidebarOpen" x-transition.opacity
|
||||||
|
class="fixed inset-0 bg-gray-900/60 z-40 md:hidden backdrop-blur-sm" @click="sidebarOpen = false"
|
||||||
|
style="display: none;"></div>
|
||||||
|
|
||||||
{{-- SIDEBAR --}}
|
{{-- SIDEBAR --}}
|
||||||
<aside :class="sidebarOpen ? 'translate-x-0' : '-translate-x-full'" class="w-64 bg-white shadow-2xl flex flex-col overflow-y-auto z-50 border-r border-gray-100 absolute inset-y-0 left-0 transform md:relative md:translate-x-0 transition-transform duration-300 ease-in-out h-full">
|
<aside :class="sidebarOpen ? 'translate-x-0' : '-translate-x-full'"
|
||||||
|
class="w-64 bg-white shadow-2xl flex flex-col overflow-y-auto z-50 border-r border-gray-100 absolute inset-y-0 left-0 transform md:relative md:translate-x-0 transition-transform duration-300 ease-in-out h-full">
|
||||||
|
|
||||||
{{-- Profile --}}
|
{{-- Profile --}}
|
||||||
<div class="flex flex-col items-center py-8 border-b border-gray-100 px-4">
|
<div class="flex flex-col items-center py-8 border-b border-gray-100 px-4">
|
||||||
<div class="w-20 h-20 rounded-2xl overflow-hidden border-4 border-primary-100 shadow-lg shadow-primary-100">
|
<div
|
||||||
<img src="https://ui-avatars.com/api/?name={{ auth()->user()->name ?? 'Admin' }}&background=6366f1&color=fff&size=128" class="w-full h-full object-cover">
|
class="w-20 h-20 rounded-2xl overflow-hidden border-4 border-primary-100 shadow-lg shadow-primary-100">
|
||||||
|
<img src="https://ui-avatars.com/api/?name={{ auth()->user()->name ?? 'Admin' }}&background=6366f1&color=fff&size=128"
|
||||||
|
class="w-full h-full object-cover">
|
||||||
</div>
|
</div>
|
||||||
<h2 class="mt-4 font-bold text-gray-800 text-lg">{{ auth()->user()->name ?? 'Admin' }}</h2>
|
<h2 class="mt-4 font-bold text-gray-800 text-lg">{{ auth()->user()->name ?? 'Admin' }}</h2>
|
||||||
<span class="px-3 py-1 mt-1.5 text-[10px] font-bold text-primary-700 bg-primary-50 rounded-full uppercase tracking-wider">Administrator</span>
|
<span
|
||||||
|
class="px-3 py-1 mt-1.5 text-[10px] font-bold text-primary-700 bg-primary-50 rounded-full uppercase tracking-wider">Administrator</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- Navigation --}}
|
{{-- Navigation --}}
|
||||||
|
|
@ -113,24 +134,29 @@ class="w-full flex items-center justify-between px-4 py-3 rounded-xl transition-
|
||||||
<i class="fas fa-users w-5 text-center"></i>
|
<i class="fas fa-users w-5 text-center"></i>
|
||||||
<span class="font-semibold text-sm">Data Anggota</span>
|
<span class="font-semibold text-sm">Data Anggota</span>
|
||||||
</div>
|
</div>
|
||||||
<i :class="open ? 'rotate-180' : ''" class="fas fa-chevron-down text-[10px] transition-transform duration-200"></i>
|
<i :class="open ? 'rotate-180' : ''"
|
||||||
|
class="fas fa-chevron-down text-[10px] transition-transform duration-200"></i>
|
||||||
</button>
|
</button>
|
||||||
<div x-show="open" x-transition class="pl-12 pr-3 py-1 space-y-1">
|
<div x-show="open" x-transition class="pl-12 pr-3 py-1 space-y-1">
|
||||||
<a href="{{ route('admin.anggota.tamu') }}" class="block px-3 py-2 text-xs font-medium text-gray-400 hover:text-primary-600 hover:bg-primary-50 rounded-lg transition">Buku Tamu</a>
|
<a href="{{ route('admin.anggota.tamu') }}"
|
||||||
<a href="{{ route('admin.anggota.member.index') }}" class="block px-3 py-2 text-xs font-medium text-gray-400 hover:text-primary-600 hover:bg-primary-50 rounded-lg transition">Data Member</a>
|
class="block px-3 py-2 text-xs font-medium text-gray-400 hover:text-primary-600 hover:bg-primary-50 rounded-lg transition">Buku
|
||||||
|
Tamu</a>
|
||||||
|
<a href="{{ route('admin.anggota.member.index') }}"
|
||||||
|
class="block px-3 py-2 text-xs font-medium text-gray-400 hover:text-primary-600 hover:bg-primary-50 rounded-lg transition">Data
|
||||||
|
Member</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.peminjaman.index') }}"
|
<a href="{{ route('admin.peminjaman.index') }}"
|
||||||
class="flex items-center gap-3 px-4 py-3 rounded-xl transition-all duration-300 mb-1
|
class="flex items-center gap-3 px-4 py-3 rounded-xl transition-all duration-300 mb-1
|
||||||
{{ request()->routeIs('admin.peminjaman.*') ? 'bg-gradient-to-r from-primary-500 to-primary-600 text-white shadow-lg shadow-primary-200' : 'text-gray-500 hover:bg-primary-50 hover:text-primary-600' }}">
|
{{ request()->routeIs('admin.peminjaman.*') && !request()->routeIs('admin.peminjaman.scan') ? 'bg-gradient-to-r from-primary-500 to-primary-600 text-white shadow-lg shadow-primary-200' : 'text-gray-500 hover:bg-primary-50 hover:text-primary-600' }}">
|
||||||
<i class="fas fa-file-export w-5 text-center"></i>
|
<i class="fas fa-file-export w-5 text-center"></i>
|
||||||
<span class="font-semibold text-sm">Data Peminjaman</span>
|
<span class="font-semibold text-sm">Data Peminjaman</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.pengembalian.index') }}"
|
<a href="{{ route('admin.pengembalian.index') }}"
|
||||||
class="flex items-center gap-3 px-4 py-3 rounded-xl transition-all duration-300 mb-1
|
class="flex items-center gap-3 px-4 py-3 rounded-xl transition-all duration-300 mb-1
|
||||||
{{ request()->routeIs('admin.pengembalian.*') ? 'bg-gradient-to-r from-primary-500 to-primary-600 text-white shadow-lg shadow-primary-200' : 'text-gray-500 hover:bg-primary-50 hover:text-primary-600' }}">
|
{{ request()->routeIs('admin.pengembalian.*') || request()->routeIs('admin.peminjaman.scan') ? 'bg-gradient-to-r from-primary-500 to-primary-600 text-white shadow-lg shadow-primary-200' : 'text-gray-500 hover:bg-primary-50 hover:text-primary-600' }}">
|
||||||
<i class="fas fa-file-import w-5 text-center"></i>
|
<i class="fas fa-file-import w-5 text-center"></i>
|
||||||
<span class="font-semibold text-sm">Data Pengembalian</span>
|
<span class="font-semibold text-sm">Data Pengembalian</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -144,11 +170,16 @@ class="w-full flex items-center justify-between px-4 py-3 rounded-xl transition-
|
||||||
<i class="fas fa-chart-bar w-5 text-center"></i>
|
<i class="fas fa-chart-bar w-5 text-center"></i>
|
||||||
<span class="font-semibold text-sm">Laporan</span>
|
<span class="font-semibold text-sm">Laporan</span>
|
||||||
</div>
|
</div>
|
||||||
<i :class="open ? 'rotate-180' : ''" class="fas fa-chevron-down text-[10px] transition-transform duration-200"></i>
|
<i :class="open ? 'rotate-180' : ''"
|
||||||
|
class="fas fa-chevron-down text-[10px] transition-transform duration-200"></i>
|
||||||
</button>
|
</button>
|
||||||
<div x-show="open" x-transition class="pl-12 pr-3 py-1 space-y-1">
|
<div x-show="open" x-transition class="pl-12 pr-3 py-1 space-y-1">
|
||||||
<a href="{{ route('admin.laporan.kehadiran') }}" class="block px-3 py-2 text-xs font-medium text-gray-400 hover:text-primary-600 hover:bg-primary-50 rounded-lg transition">Lap. Kehadiran</a>
|
<a href="{{ route('admin.laporan.kehadiran') }}"
|
||||||
<a href="{{ route('admin.laporan.peminjaman') }}" class="block px-3 py-2 text-xs font-medium text-gray-400 hover:text-primary-600 hover:bg-primary-50 rounded-lg transition">Lap. Peminjaman</a>
|
class="block px-3 py-2 text-xs font-medium text-gray-400 hover:text-primary-600 hover:bg-primary-50 rounded-lg transition">Lap.
|
||||||
|
Kehadiran</a>
|
||||||
|
<a href="{{ route('admin.laporan.peminjaman') }}"
|
||||||
|
class="block px-3 py-2 text-xs font-medium text-gray-400 hover:text-primary-600 hover:bg-primary-50 rounded-lg transition">Lap.
|
||||||
|
Peminjaman</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -217,4 +248,5 @@ class="flex items-center gap-3 px-4 py-3 rounded-xl transition-all duration-300
|
||||||
</script>
|
</script>
|
||||||
@stack('scripts')
|
@stack('scripts')
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
<title>@yield('title', 'Sarakata — Perpustakaan Digital')</title>
|
<title>@yield('title', 'Sarakata — Perpustakaan Digital')</title>
|
||||||
<meta name="description" content="Sarakata - Sistem Informasi Perpustakaan Digital untuk Generasi Modern">
|
<meta name="description" content="Sarakata - Sistem Informasi Perpustakaan Digital untuk Generasi Modern">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="shortcut icon" href="{{ asset('favicon.ico') }}" type="image/x-icon">
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap"
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap"
|
||||||
rel="stylesheet">
|
rel="stylesheet">
|
||||||
|
|
@ -127,7 +128,8 @@ class="text-[10px] font-bold text-gray-500 uppercase tracking-widest mt-1 hidden
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- Hamburger Button for Mobile -->
|
<!-- Hamburger Button for Mobile -->
|
||||||
<button id="mobile-menu-btn" class="md:hidden text-gray-600 hover:text-primary-600 focus:outline-none p-2 rounded-lg bg-gray-50">
|
<button id="mobile-menu-btn"
|
||||||
|
class="md:hidden text-gray-600 hover:text-primary-600 focus:outline-none p-2 rounded-lg bg-gray-50">
|
||||||
<i class="fas fa-bars text-xl"></i>
|
<i class="fas fa-bars text-xl"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|
@ -171,29 +173,39 @@ class="px-5 py-2.5 bg-gradient-to-r from-green-600 to-green-700 text-white round
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Mobile Menu -->
|
<!-- Mobile Menu -->
|
||||||
<div id="mobile-menu" class="hidden md:hidden bg-white/95 backdrop-blur-xl border-t border-gray-100 shadow-xl absolute w-full left-0 top-full flex-col gap-4 px-6 py-6 transition-all">
|
<div id="mobile-menu"
|
||||||
<a href="{{ route('home') }}" class="block font-bold text-gray-700 hover:text-primary-600 py-2 border-b border-gray-50">Beranda</a>
|
class="hidden md:hidden bg-white/95 backdrop-blur-xl border-t border-gray-100 shadow-xl absolute w-full left-0 top-full flex-col gap-4 px-6 py-6 transition-all">
|
||||||
<a href="{{ route('katalog.index') }}" class="block font-bold text-gray-700 hover:text-primary-600 py-2 border-b border-gray-50">Katalog Buku</a>
|
<a href="{{ route('home') }}"
|
||||||
<a href="{{ route('home') }}#fitur" class="block font-bold text-gray-700 hover:text-primary-600 py-2 border-b border-gray-50">Fitur</a>
|
class="block font-bold text-gray-700 hover:text-primary-600 py-2 border-b border-gray-50">Beranda</a>
|
||||||
<a href="{{ route('home') }}#rekomendasi" class="block font-bold text-gray-700 hover:text-primary-600 py-2 border-b border-gray-50">Koleksi</a>
|
<a href="{{ route('katalog.index') }}"
|
||||||
|
class="block font-bold text-gray-700 hover:text-primary-600 py-2 border-b border-gray-50">Katalog
|
||||||
|
Buku</a>
|
||||||
|
<a href="{{ route('home') }}#fitur"
|
||||||
|
class="block font-bold text-gray-700 hover:text-primary-600 py-2 border-b border-gray-50">Fitur</a>
|
||||||
|
<a href="{{ route('home') }}#rekomendasi"
|
||||||
|
class="block font-bold text-gray-700 hover:text-primary-600 py-2 border-b border-gray-50">Koleksi</a>
|
||||||
|
|
||||||
<div class="flex flex-col gap-3 mt-4">
|
<div class="flex flex-col gap-3 mt-4">
|
||||||
@guest
|
@guest
|
||||||
<button onclick="openGuestModal()" class="w-full px-5 py-3 bg-primary-50 text-primary-600 rounded-xl font-bold hover:bg-primary-100 transition-colors text-center flex items-center justify-center">
|
<button onclick="openGuestModal()"
|
||||||
|
class="w-full px-5 py-3 bg-primary-50 text-primary-600 rounded-xl font-bold hover:bg-primary-100 transition-colors text-center flex items-center justify-center">
|
||||||
<i class="fas fa-book-reader mr-1.5"></i> Buku Tamu
|
<i class="fas fa-book-reader mr-1.5"></i> Buku Tamu
|
||||||
</button>
|
</button>
|
||||||
<a href="{{ route('login') }}" class="w-full px-5 py-3 bg-gradient-to-r from-primary-600 to-primary-700 text-white rounded-xl font-bold shadow-lg shadow-primary-200 text-center">
|
<a href="{{ route('login') }}"
|
||||||
|
class="w-full px-5 py-3 bg-gradient-to-r from-primary-600 to-primary-700 text-white rounded-xl font-bold shadow-lg shadow-primary-200 text-center">
|
||||||
<i class="fas fa-sign-in-alt mr-1.5"></i> Login
|
<i class="fas fa-sign-in-alt mr-1.5"></i> Login
|
||||||
</a>
|
</a>
|
||||||
@endguest
|
@endguest
|
||||||
|
|
||||||
@auth
|
@auth
|
||||||
@if (auth()->user()->role === 'admin')
|
@if (auth()->user()->role === 'admin')
|
||||||
<a href="{{ route('admin.dashboard') }}" class="w-full px-5 py-3 bg-gradient-to-r from-primary-600 to-primary-700 text-white rounded-xl font-bold shadow-lg text-center">
|
<a href="{{ route('admin.dashboard') }}"
|
||||||
|
class="w-full px-5 py-3 bg-gradient-to-r from-primary-600 to-primary-700 text-white rounded-xl font-bold shadow-lg text-center">
|
||||||
<i class="fas fa-tachometer-alt mr-1.5"></i> Dashboard Admin
|
<i class="fas fa-tachometer-alt mr-1.5"></i> Dashboard Admin
|
||||||
</a>
|
</a>
|
||||||
@else
|
@else
|
||||||
<a href="{{ route('user.dashboard') }}" class="w-full px-5 py-3 bg-gradient-to-r from-green-600 to-green-700 text-white rounded-xl font-bold shadow-lg text-center">
|
<a href="{{ route('user.dashboard') }}"
|
||||||
|
class="w-full px-5 py-3 bg-gradient-to-r from-green-600 to-green-700 text-white rounded-xl font-bold shadow-lg text-center">
|
||||||
<i class="fas fa-user mr-1.5"></i> Dashboard Anggota
|
<i class="fas fa-user mr-1.5"></i> Dashboard Anggota
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
|
|
@ -235,8 +247,7 @@ class="w-10 h-10 bg-gradient-to-br from-primary-500 to-primary-700 rounded-xl fl
|
||||||
Buku</a></li>
|
Buku</a></li>
|
||||||
<li><a href="{{ route('home') }}#fitur" class="hover:text-white transition-colors">Fitur</a>
|
<li><a href="{{ route('home') }}#fitur" class="hover:text-white transition-colors">Fitur</a>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="{{ route('home') }}#rekomendasi"
|
<li><a href="{{ route('home') }}#rekomendasi" class="hover:text-white transition-colors">Koleksi
|
||||||
class="hover:text-white transition-colors">Koleksi
|
|
||||||
Buku</a></li>
|
Buku</a></li>
|
||||||
<li><a href="{{ route('buku_tamu.index') }}" class="hover:text-white transition-colors">Buku
|
<li><a href="{{ route('buku_tamu.index') }}" class="hover:text-white transition-colors">Buku
|
||||||
Tamu</a></li>
|
Tamu</a></li>
|
||||||
|
|
@ -276,38 +287,47 @@ class="fab fa-twitter text-sm"></i></a>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<!-- Global Guest Modal -->
|
<!-- Global Guest Modal -->
|
||||||
<div id="guestModal" class="fixed inset-0 bg-gray-900/60 backdrop-blur-sm hidden z-[100] flex items-center justify-center p-4 transition-opacity duration-300">
|
<div id="guestModal"
|
||||||
|
class="fixed inset-0 bg-gray-900/60 backdrop-blur-sm hidden z-[100] flex items-center justify-center p-4 transition-opacity duration-300">
|
||||||
<div class="bg-white rounded-[2rem] shadow-2xl max-w-md w-full overflow-hidden transform transition-all">
|
<div class="bg-white rounded-[2rem] shadow-2xl max-w-md w-full overflow-hidden transform transition-all">
|
||||||
<div class="p-8 text-center relative">
|
<div class="p-8 text-center relative">
|
||||||
<!-- Close Button -->
|
<!-- Close Button -->
|
||||||
<button onclick="closeGuestModal()" class="absolute top-4 right-4 text-gray-400 hover:text-gray-600 transition-colors w-8 h-8 rounded-full hover:bg-gray-100 flex items-center justify-center">
|
<button onclick="closeGuestModal()"
|
||||||
|
class="absolute top-4 right-4 text-gray-400 hover:text-gray-600 transition-colors w-8 h-8 rounded-full hover:bg-gray-100 flex items-center justify-center">
|
||||||
<i class="fas fa-times"></i>
|
<i class="fas fa-times"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- Icon Box -->
|
<!-- Icon Box -->
|
||||||
<div class="w-16 h-16 bg-gradient-to-br from-primary-500 to-primary-600 text-white rounded-2xl flex items-center justify-center mx-auto mb-5 text-2xl shadow-lg shadow-primary-200">
|
<div
|
||||||
|
class="w-16 h-16 bg-gradient-to-br from-primary-500 to-primary-600 text-white rounded-2xl flex items-center justify-center mx-auto mb-5 text-2xl shadow-lg shadow-primary-200">
|
||||||
<i class="fas fa-user-check"></i>
|
<i class="fas fa-user-check"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3 class="text-2xl font-black text-gray-900 tracking-tight">Selamat Datang!</h3>
|
<h3 class="text-2xl font-black text-gray-900 tracking-tight">Selamat Datang!</h3>
|
||||||
<p class="text-gray-500 text-sm mt-2 leading-relaxed">Apakah Anda sudah terdaftar sebagai anggota Sarakata?</p>
|
<p class="text-gray-500 text-sm mt-2 leading-relaxed">Apakah Anda sudah terdaftar sebagai anggota
|
||||||
|
Sarakata?</p>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 gap-3 mt-8">
|
<div class="grid grid-cols-1 gap-3 mt-8">
|
||||||
<!-- Member Option -->
|
<!-- Member Option -->
|
||||||
<a href="{{ route('buku_tamu.index') }}" class="flex items-center gap-4 p-4 border-2 border-primary-100 rounded-2xl hover:border-primary-300 hover:bg-primary-50/50 transition-all group cursor-pointer shadow-sm hover:shadow-md">
|
<a href="{{ route('buku_tamu.index') }}"
|
||||||
<div class="w-12 h-12 bg-primary-100 rounded-xl flex items-center justify-center text-primary-600 group-hover:bg-gradient-to-br group-hover:from-primary-500 group-hover:to-primary-600 group-hover:text-white transition-all shadow-sm group-hover:shadow-primary-300">
|
class="flex items-center gap-4 p-4 border-2 border-primary-100 rounded-2xl hover:border-primary-300 hover:bg-primary-50/50 transition-all group cursor-pointer shadow-sm hover:shadow-md">
|
||||||
|
<div
|
||||||
|
class="w-12 h-12 bg-primary-100 rounded-xl flex items-center justify-center text-primary-600 group-hover:bg-gradient-to-br group-hover:from-primary-500 group-hover:to-primary-600 group-hover:text-white transition-all shadow-sm group-hover:shadow-primary-300">
|
||||||
<i class="fas fa-id-card"></i>
|
<i class="fas fa-id-card"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-left flex-1 border-gray-100">
|
<div class="text-left flex-1 border-gray-100">
|
||||||
<div class="font-bold text-gray-900 text-sm">Saya Anggota</div>
|
<div class="font-bold text-gray-900 text-sm">Saya Anggota</div>
|
||||||
<div class="text-xs text-gray-400">Punya No. Anggota</div>
|
<div class="text-xs text-gray-400">Punya No. Anggota</div>
|
||||||
</div>
|
</div>
|
||||||
<i class="fas fa-chevron-right text-primary-300 group-hover:text-primary-500 transition-colors"></i>
|
<i
|
||||||
|
class="fas fa-chevron-right text-primary-300 group-hover:text-primary-500 transition-colors"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- Visitor Option -->
|
<!-- Visitor Option -->
|
||||||
<a href="{{ route('buku_tamu.index', ['tipe' => 'tamu']) }}" class="flex items-center gap-4 p-4 border-2 border-gray-100 rounded-2xl hover:border-gray-300 hover:bg-gray-50 transition-all group cursor-pointer shadow-sm hover:shadow-md">
|
<a href="{{ route('buku_tamu.index', ['tipe' => 'tamu']) }}"
|
||||||
<div class="w-12 h-12 bg-gray-100 rounded-xl flex items-center justify-center text-gray-500 group-hover:bg-gray-800 group-hover:text-white transition-all shadow-sm">
|
class="flex items-center gap-4 p-4 border-2 border-gray-100 rounded-2xl hover:border-gray-300 hover:bg-gray-50 transition-all group cursor-pointer shadow-sm hover:shadow-md">
|
||||||
|
<div
|
||||||
|
class="w-12 h-12 bg-gray-100 rounded-xl flex items-center justify-center text-gray-500 group-hover:bg-gray-800 group-hover:text-white transition-all shadow-sm">
|
||||||
<i class="fas fa-user-friends"></i>
|
<i class="fas fa-user-friends"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-left flex-1 border-gray-100">
|
<div class="text-left flex-1 border-gray-100">
|
||||||
|
|
@ -323,7 +343,7 @@ class="fab fa-twitter text-sm"></i></a>
|
||||||
|
|
||||||
@stack('scripts')
|
@stack('scripts')
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
const btn = document.getElementById('mobile-menu-btn');
|
const btn = document.getElementById('mobile-menu-btn');
|
||||||
const menu = document.getElementById('mobile-menu');
|
const menu = document.getElementById('mobile-menu');
|
||||||
const icon = btn.querySelector('i');
|
const icon = btn.querySelector('i');
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,10 @@ class="absolute bottom-0 left-0 -ml-20 -mb-20 w-72 h-72 rounded-full bg-indigo-3
|
||||||
|
|
||||||
<div class="container mx-auto px-4 relative z-10">
|
<div class="container mx-auto px-4 relative z-10">
|
||||||
<div class="text-center max-w-3xl mx-auto">
|
<div class="text-center max-w-3xl mx-auto">
|
||||||
<h1 class="text-3xl sm:text-4xl md:text-5xl font-extrabold text-white mb-4 sm:mb-6 tracking-tight leading-tight">
|
<h1
|
||||||
Eksplorasi <span class="text-transparent bg-clip-text bg-gradient-to-r from-blue-200 to-cyan-200">Katalog
|
class="text-3xl sm:text-4xl md:text-5xl font-extrabold text-white mb-4 sm:mb-6 tracking-tight leading-tight">
|
||||||
|
Eksplorasi <span
|
||||||
|
class="text-transparent bg-clip-text bg-gradient-to-r from-blue-200 to-cyan-200">Katalog
|
||||||
Perpustakaan</span>
|
Perpustakaan</span>
|
||||||
</h1>
|
</h1>
|
||||||
<p class="text-blue-100 text-sm sm:text-lg md:text-xl mb-8 sm:mb-10 font-light px-2 sm:px-0">
|
<p class="text-blue-100 text-sm sm:text-lg md:text-xl mb-8 sm:mb-10 font-light px-2 sm:px-0">
|
||||||
|
|
@ -27,7 +29,8 @@ class="absolute bottom-0 left-0 -ml-20 -mb-20 w-72 h-72 rounded-full bg-indigo-3
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- Search Bar -->
|
<!-- Search Bar -->
|
||||||
<form action="{{ route('katalog.index') }}" method="GET" class="relative group max-w-2xl mx-auto px-2 sm:px-0">
|
<form action="{{ route('katalog.index') }}" method="GET"
|
||||||
|
class="relative group max-w-2xl mx-auto px-2 sm:px-0">
|
||||||
<div class="absolute inset-y-0 left-2 sm:left-0 pl-4 flex items-center pointer-events-none">
|
<div class="absolute inset-y-0 left-2 sm:left-0 pl-4 flex items-center pointer-events-none">
|
||||||
<svg class="h-5 w-5 sm:h-6 sm:w-6 text-gray-400 group-focus-within:text-blue-500 transition-colors"
|
<svg class="h-5 w-5 sm:h-6 sm:w-6 text-gray-400 group-focus-within:text-blue-500 transition-colors"
|
||||||
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
|
@ -35,8 +38,7 @@ class="absolute bottom-0 left-0 -ml-20 -mb-20 w-72 h-72 rounded-full bg-indigo-3
|
||||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<input type="text" name="search" value="{{ $search }}"
|
<input type="text" name="search" value="{{ $search }}" placeholder="Cari judul buku, pengarang..."
|
||||||
placeholder="Cari judul buku, pengarang..."
|
|
||||||
class="block w-full pl-10 pr-24 sm:pl-12 sm:pr-32 py-3.5 sm:py-4 bg-white/95 backdrop-blur-sm border-0 rounded-xl sm:rounded-2xl shadow-xl focus:ring-4 focus:ring-blue-500/30 text-gray-800 text-sm sm:text-lg transition-all placeholder-gray-400">
|
class="block w-full pl-10 pr-24 sm:pl-12 sm:pr-32 py-3.5 sm:py-4 bg-white/95 backdrop-blur-sm border-0 rounded-xl sm:rounded-2xl shadow-xl focus:ring-4 focus:ring-blue-500/30 text-gray-800 text-sm sm:text-lg transition-all placeholder-gray-400">
|
||||||
<button type="submit"
|
<button type="submit"
|
||||||
class="absolute right-3.5 sm:right-2 top-1.5 bottom-1.5 sm:top-2 sm:bottom-2 bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 text-white font-semibold px-5 sm:px-6 lg:px-8 rounded-lg sm:rounded-xl shadow-md transition-all transform hover:scale-[1.02] active:scale-[0.98] text-sm sm:text-base">
|
class="absolute right-3.5 sm:right-2 top-1.5 bottom-1.5 sm:top-2 sm:bottom-2 bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 text-white font-semibold px-5 sm:px-6 lg:px-8 rounded-lg sm:rounded-xl shadow-md transition-all transform hover:scale-[1.02] active:scale-[0.98] text-sm sm:text-base">
|
||||||
|
|
@ -65,19 +67,14 @@ class="absolute right-3.5 sm:right-2 top-1.5 bottom-1.5 sm:top-2 sm:bottom-2 bg-
|
||||||
class="group bg-white rounded-2xl shadow-sm hover:shadow-2xl border border-gray-100 overflow-hidden transition-all duration-300 transform {{ $habis ? 'grayscale opacity-75 cursor-not-allowed' : 'hover:-translate-y-1' }} flex flex-col h-full">
|
class="group bg-white rounded-2xl shadow-sm hover:shadow-2xl border border-gray-100 overflow-hidden transition-all duration-300 transform {{ $habis ? 'grayscale opacity-75 cursor-not-allowed' : 'hover:-translate-y-1' }} flex flex-col h-full">
|
||||||
<!-- Book Cover -->
|
<!-- Book Cover -->
|
||||||
<div class="relative w-full pt-[140%] overflow-hidden bg-gray-50 flex-shrink-0">
|
<div class="relative w-full pt-[140%] overflow-hidden bg-gray-50 flex-shrink-0">
|
||||||
@if ($item->cover)
|
@php
|
||||||
<img src="{{ asset('storage/' . $item->cover) }}" alt="{{ $item->judul }}"
|
$coverPath = $item->cover ?? $item->sampul;
|
||||||
|
$finalPath = $coverPath ? (Str::contains($coverPath, '/') ? $coverPath : 'covers/' . $coverPath) : null;
|
||||||
|
@endphp
|
||||||
|
@if ($finalPath)
|
||||||
|
<img src="{{ asset('storage/' . $finalPath) }}" alt="{{ $item->judul }}"
|
||||||
class="absolute inset-0 w-full h-full object-cover {{ !$habis ? 'group-hover:scale-110' : '' }} transition-transform duration-700 ease-in-out"
|
class="absolute inset-0 w-full h-full object-cover {{ !$habis ? 'group-hover:scale-110' : '' }} transition-transform duration-700 ease-in-out"
|
||||||
onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';">
|
onerror="this.src='https://ui-avatars.com/api/?name={{ urlencode($item->judul) }}&background=F3F4F6&color=6366F1&size=512&bold=true';">
|
||||||
<div
|
|
||||||
class="hidden absolute inset-0 flex flex-col items-center justify-center text-gray-300 bg-gray-100 {{ !$habis ? 'group-hover:bg-gray-200' : '' }} transition-colors duration-300">
|
|
||||||
<svg class="w-12 h-12 mb-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"
|
|
||||||
d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253">
|
|
||||||
</path>
|
|
||||||
</svg>
|
|
||||||
<span class="text-xs font-medium">Cover Tidak Tersedia</span>
|
|
||||||
</div>
|
|
||||||
@else
|
@else
|
||||||
<div
|
<div
|
||||||
class="absolute inset-0 flex flex-col items-center justify-center text-gray-300 bg-gray-100 {{ !$habis ? 'group-hover:bg-gray-200' : '' }} transition-colors duration-300">
|
class="absolute inset-0 flex flex-col items-center justify-center text-gray-300 bg-gray-100 {{ !$habis ? 'group-hover:bg-gray-200' : '' }} transition-colors duration-300">
|
||||||
|
|
@ -92,8 +89,7 @@ class="absolute inset-0 flex flex-col items-center justify-center text-gray-300
|
||||||
|
|
||||||
@if ($habis)
|
@if ($habis)
|
||||||
<!-- Overlay Dipinjam Semua -->
|
<!-- Overlay Dipinjam Semua -->
|
||||||
<div
|
<div class="absolute inset-0 bg-red-900/30 backdrop-blur-[1px] flex items-center justify-center z-10">
|
||||||
class="absolute inset-0 bg-red-900/30 backdrop-blur-[1px] flex items-center justify-center z-10">
|
|
||||||
<div
|
<div
|
||||||
class="bg-red-600/90 text-white font-black text-sm md:text-base px-6 py-2 border-y-2 border-white transform -rotate-12 shadow-2xl tracking-widest uppercase pointer-events-none">
|
class="bg-red-600/90 text-white font-black text-sm md:text-base px-6 py-2 border-y-2 border-white transform -rotate-12 shadow-2xl tracking-widest uppercase pointer-events-none">
|
||||||
TIDAK TERSEDIA
|
TIDAK TERSEDIA
|
||||||
|
|
|
||||||
|
|
@ -202,9 +202,14 @@ class="absolute right-1 top-1 bottom-1 w-10 flex items-center justify-center bg-
|
||||||
<div class="md:col-span-12 lg:col-span-3">
|
<div class="md:col-span-12 lg:col-span-3">
|
||||||
<div
|
<div
|
||||||
class="bg-white rounded-3xl shadow-[0_10px_40px_-10px_rgba(0,0,0,0.08)] border border-gray-50 p-5 flex flex-col items-center text-center overflow-hidden transition-transform duration-500 hover:-translate-y-2">
|
class="bg-white rounded-3xl shadow-[0_10px_40px_-10px_rgba(0,0,0,0.08)] border border-gray-50 p-5 flex flex-col items-center text-center overflow-hidden transition-transform duration-500 hover:-translate-y-2">
|
||||||
@if ($buku->cover)
|
@php
|
||||||
<img src="{{ asset('storage/' . $buku->cover) }}" alt="{{ $buku->judul }}"
|
$coverPath = $buku->cover ?? $buku->sampul;
|
||||||
class="w-full aspect-[3/4] object-cover rounded-2xl mb-6 shadow-md border border-gray-100">
|
$finalPath = $coverPath ? (Str::contains($coverPath, '/') ? $coverPath : 'covers/' . $coverPath) : null;
|
||||||
|
@endphp
|
||||||
|
@if ($finalPath)
|
||||||
|
<img src="{{ asset('storage/' . $finalPath) }}" alt="{{ $buku->judul }}"
|
||||||
|
class="w-full aspect-[3/4] object-cover rounded-2xl mb-6 shadow-md border border-gray-100"
|
||||||
|
onerror="this.src='https://ui-avatars.com/api/?name={{ urlencode($buku->judul) }}&background=F3F4F6&color=6366F1&size=512&bold=true';">
|
||||||
@else
|
@else
|
||||||
<div
|
<div
|
||||||
class="w-full aspect-[3/4] bg-gradient-to-br from-indigo-50 to-blue-50 rounded-2xl flex items-center justify-center mb-6 overflow-hidden relative shadow-inner border border-blue-100/50">
|
class="w-full aspect-[3/4] bg-gradient-to-br from-indigo-50 to-blue-50 rounded-2xl flex items-center justify-center mb-6 overflow-hidden relative shadow-inner border border-blue-100/50">
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@
|
||||||
<div
|
<div
|
||||||
class="flex flex-col md:flex-row justify-between items-start md:items-center mb-10 gap-4 text-center md:text-left">
|
class="flex flex-col md:flex-row justify-between items-start md:items-center mb-10 gap-4 text-center md:text-left">
|
||||||
<div class="w-full md:w-auto">
|
<div class="w-full md:w-auto">
|
||||||
<div
|
<div class="inline-flex items-center gap-2 px-4 py-2 bg-blue-100 rounded-full mb-4 mx-auto md:mx-0">
|
||||||
class="inline-flex items-center gap-2 px-4 py-2 bg-blue-100 rounded-full mb-4 mx-auto md:mx-0">
|
|
||||||
<i class="fas fa-fire text-red-500 text-xs"></i>
|
<i class="fas fa-fire text-red-500 text-xs"></i>
|
||||||
<span class="text-xs font-semibold text-blue-800 tracking-wide">Paling Laris</span>
|
<span class="text-xs font-semibold text-blue-800 tracking-wide">Paling Laris</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -39,15 +38,18 @@ class="bg-blue-600/90 backdrop-blur-md text-white text-[10px] sm:text-xs font-bo
|
||||||
|
|
||||||
<!-- Book Cover -->
|
<!-- Book Cover -->
|
||||||
<div class="relative w-full pt-[140%] overflow-hidden bg-gray-50 flex-shrink-0">
|
<div class="relative w-full pt-[140%] overflow-hidden bg-gray-50 flex-shrink-0">
|
||||||
@if ($item->cover ?? $item->sampul)
|
@php
|
||||||
<img src="{{ asset('storage/' . ($item->cover ?? $item->sampul)) }}"
|
$coverPath = $item->cover ?? $item->sampul;
|
||||||
alt="{{ $item->judul }}"
|
$finalPath = $coverPath ? (Str::contains($coverPath, '/') ? $coverPath : 'covers/' . $coverPath) : null;
|
||||||
class="absolute inset-0 w-full h-full object-cover {{ !$habis ? 'group-hover:scale-110' : '' }} transition-transform duration-700 ease-in-out">
|
@endphp
|
||||||
|
@if ($finalPath)
|
||||||
|
<img src="{{ asset('storage/' . $finalPath) }}" alt="{{ $item->judul }}"
|
||||||
|
class="absolute inset-0 w-full h-full object-cover {{ !$habis ? 'group-hover:scale-110' : '' }} transition-transform duration-700 ease-in-out"
|
||||||
|
onerror="this.src='https://ui-avatars.com/api/?name={{ urlencode($item->judul) }}&background=F3F4F6&color=6366F1&size=512&bold=true';">
|
||||||
@else
|
@else
|
||||||
<div
|
<div
|
||||||
class="absolute inset-0 flex flex-col items-center justify-center text-gray-300 bg-gray-100 {{ !$habis ? 'group-hover:bg-gray-200' : '' }} transition-colors duration-300">
|
class="absolute inset-0 flex flex-col items-center justify-center text-gray-300 bg-gray-100 {{ !$habis ? 'group-hover:bg-gray-200' : '' }} transition-colors duration-300">
|
||||||
<svg class="w-12 h-12 mb-2" fill="none" stroke="currentColor"
|
<svg class="w-12 h-12 mb-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"
|
||||||
d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253">
|
d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253">
|
||||||
</path>
|
</path>
|
||||||
|
|
|
||||||
|
|
@ -42,15 +42,19 @@ class="bg-gradient-to-r from-yellow-400 to-orange-500 text-white text-[9px] sm:t
|
||||||
|
|
||||||
<!-- Book Cover -->
|
<!-- Book Cover -->
|
||||||
<div class="relative w-full pt-[140%] overflow-hidden bg-gray-50 flex-shrink-0">
|
<div class="relative w-full pt-[140%] overflow-hidden bg-gray-50 flex-shrink-0">
|
||||||
@if ($item->cover ?? $item->sampul)
|
@php
|
||||||
<img src="{{ asset('storage/' . ($item->cover ?? $item->sampul)) }}"
|
$coverPath = $item->cover ?? $item->sampul;
|
||||||
alt="{{ $item->judul }}"
|
// Cek apakah path sudah mengandung folder, jika tidak default ke 'covers/'
|
||||||
class="absolute inset-0 w-full h-full object-cover {{ !$habis ? 'group-hover:scale-110' : '' }} transition-transform duration-700 ease-in-out">
|
$finalPath = $coverPath ? (Str::contains($coverPath, '/') ? $coverPath : 'covers/' . $coverPath) : null;
|
||||||
|
@endphp
|
||||||
|
@if ($finalPath)
|
||||||
|
<img src="{{ asset('storage/' . $finalPath) }}" alt="{{ $item->judul }}"
|
||||||
|
class="absolute inset-0 w-full h-full object-cover {{ !$habis ? 'group-hover:scale-110' : '' }} transition-transform duration-700 ease-in-out"
|
||||||
|
onerror="this.src='https://ui-avatars.com/api/?name={{ urlencode($item->judul) }}&background=EBF4FF&color=7F9CF5&size=512&bold=true';">
|
||||||
@else
|
@else
|
||||||
<div
|
<div
|
||||||
class="absolute inset-0 flex flex-col items-center justify-center text-gray-300 bg-gray-100 {{ !$habis ? 'group-hover:bg-gray-200' : '' }} transition-colors duration-300">
|
class="absolute inset-0 flex flex-col items-center justify-center text-gray-300 bg-gray-100 {{ !$habis ? 'group-hover:bg-gray-200' : '' }} transition-colors duration-300">
|
||||||
<svg class="w-12 h-12 mb-2" fill="none" stroke="currentColor"
|
<svg class="w-12 h-12 mb-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"
|
||||||
d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253">
|
d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253">
|
||||||
</path>
|
</path>
|
||||||
|
|
|
||||||
|
|
@ -14,41 +14,41 @@
|
||||||
|
|
||||||
$koordinat = match (true) {
|
$koordinat = match (true) {
|
||||||
$kode_utama >= 0 && $kode_utama <= 99 => match (true) {
|
$kode_utama >= 0 && $kode_utama <= 99 => match (true) {
|
||||||
$kode_utama <= 19 => ['x' => 13.00, 'y' => 22.00], // Rak 01
|
$kode_utama <= 19 => ['x' => 12.00, 'y' => 13.00], // Rak 01
|
||||||
$kode_utama <= 50 => ['x' => 18.00, 'y' => 22.00], // Rak 02
|
$kode_utama <= 50 => ['x' => 17.00, 'y' => 13.00], // Rak 02
|
||||||
default => ['x' => 25.00, 'y' => 22.00], // Rak 03-05
|
default => ['x' => 22.00, 'y' => 13.00], // Rak 03-05
|
||||||
},
|
},
|
||||||
$kode_utama >= 100 && $kode_utama <= 199 => match (true) {
|
$kode_utama >= 100 && $kode_utama <= 199 => match (true) {
|
||||||
$kode_utama <= 150 => ['x' => 43.00, 'y' => 20.00], // Rak 06-10
|
$kode_utama <= 150 => ['x' => 35.00, 'y' => 13.00], // Rak 06-10
|
||||||
default => ['x' => 57.00, 'y' => 20.00], // Rak 11-14
|
default => ['x' => 35.00, 'y' => 17.00], // Rak 11-14
|
||||||
},
|
},
|
||||||
$kode_utama >= 200 && $kode_utama <= 299 => match (true) {
|
$kode_utama >= 200 && $kode_utama <= 299 => match (true) {
|
||||||
$kode_utama == 297 => ['x' => 25.00, 'y' => 38.00], // Rak 25-32 (Islam)
|
$kode_utama == 297 => ['x' => 14.00, 'y' => 38.00], // Rak 25-32 (Islam)
|
||||||
default => ['x' => 13.00, 'y' => 38.00], // Rak 15-24
|
default => ['x' => 14.00, 'y' => 30.00], // Rak 15-24
|
||||||
},
|
},
|
||||||
$kode_utama >= 300 && $kode_utama <= 399 => match (true) {
|
$kode_utama >= 300 && $kode_utama <= 399 => match (true) {
|
||||||
$kode_utama <= 330 => ['x' => 43.00, 'y' => 30.00], // Rak 33-36
|
$kode_utama <= 330 => ['x' => 38.00, 'y' => 23.00], // Rak 33-36
|
||||||
$kode_utama <= 360 => ['x' => 50.00, 'y' => 30.00], // Rak 37-40
|
$kode_utama <= 360 => ['x' => 43.00, 'y' => 23.00], // Rak 37-40
|
||||||
default => ['x' => 57.00, 'y' => 30.00], // Rak 41-44
|
default => ['x' => 48.00, 'y' => 23.00], // Rak 41-44
|
||||||
},
|
},
|
||||||
$kode_utama >= 400 && $kode_utama <= 499 => ['x' => 18.00, 'y' => 62.00], // Rak 45
|
$kode_utama >= 400 && $kode_utama <= 499 => ['x' => 14.00, 'y' => 58.00], // Rak 45
|
||||||
$kode_utama >= 500 && $kode_utama <= 599 => ['x' => 50.00, 'y' => 74.00], // Rak 46-48
|
$kode_utama >= 500 && $kode_utama <= 599 => ['x' => 38.00, 'y' => 72.00], // Rak 46-48
|
||||||
$kode_utama >= 600 && $kode_utama <= 699 => match (true) {
|
$kode_utama >= 600 && $kode_utama <= 699 => match (true) {
|
||||||
$kode_utama <= 610 => ['x' => 35.00, 'y' => 85.00], // Rak 49-53
|
$kode_utama <= 610 => ['x' => 28.00, 'y' => 83.00], // Rak 49-53
|
||||||
$kode_utama <= 630 => ['x' => 45.00, 'y' => 85.00], // Rak 54-58
|
$kode_utama <= 630 => ['x' => 36.00, 'y' => 83.00], // Rak 54-58
|
||||||
$kode_utama <= 650 => ['x' => 55.00, 'y' => 85.00], // Rak 59-63
|
$kode_utama <= 650 => ['x' => 44.00, 'y' => 83.00], // Rak 59-63
|
||||||
default => ['x' => 65.00, 'y' => 85.00], // Rak 64-68
|
default => ['x' => 52.00, 'y' => 83.00], // Rak 64-68
|
||||||
},
|
},
|
||||||
$kode_utama >= 700 && $kode_utama <= 799 => match (true) {
|
$kode_utama >= 700 && $kode_utama <= 799 => match (true) {
|
||||||
$kode_utama <= 739 => ['x' => 77.00, 'y' => 22.00], // Rak 71
|
$kode_utama <= 739 => ['x' => 82.00, 'y' => 12.00], // Rak 71
|
||||||
$kode_utama <= 769 => ['x' => 82.00, 'y' => 22.00], // Rak 72
|
$kode_utama <= 769 => ['x' => 86.00, 'y' => 12.00], // Rak 72
|
||||||
$kode_utama <= 789 => ['x' => 87.00, 'y' => 22.00], // Rak 73
|
$kode_utama <= 789 => ['x' => 82.00, 'y' => 16.00], // Rak 73
|
||||||
default => ['x' => 82.00, 'y' => 22.00], // Rak 74
|
default => ['x' => 86.00, 'y' => 16.00], // Rak 74
|
||||||
},
|
},
|
||||||
$kode_utama >= 800 && $kode_utama <= 899 => ['x' => 82.00, 'y' => 32.00], // Rak 77-79
|
$kode_utama >= 800 && $kode_utama <= 899 => ['x' => 82.00, 'y' => 25.00], // Rak 77-79
|
||||||
$kode_utama >= 900 && $kode_utama <= 999 => match (true) {
|
$kode_utama >= 900 && $kode_utama <= 999 => match (true) {
|
||||||
$kode_utama <= 919 => ['x' => 77.00, 'y' => 42.00], // Rak 69-70
|
$kode_utama <= 919 => ['x' => 82.00, 'y' => 30.00], // Rak 69-70
|
||||||
default => ['x' => 87.00, 'y' => 42.00], // Rak 80-84
|
default => ['x' => 82.00, 'y' => 35.00], // Rak 80-84
|
||||||
},
|
},
|
||||||
default => ['x' => null, 'y' => null],
|
default => ['x' => null, 'y' => null],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue