Fix: kategori table migration and update admin buku views

This commit is contained in:
Lutfi Hakim 2026-04-30 07:51:09 +07:00
parent 5f8202e7ca
commit f64ea3a4fa
12 changed files with 1698 additions and 1409 deletions

View File

@ -12,9 +12,9 @@ public function index(Request $request)
$originalSearch = $request->input('search');
$bukuPopuler = Buku::withCount('peminjaman')
->orderBy('peminjaman_count', 'desc')
->take(5)
->get();
->orderBy('peminjaman_count', 'desc')
->take(5)
->get();
if (empty($originalSearch)) {
$buku = Buku::paginate(12);
@ -31,7 +31,7 @@ public function index(Request $request)
$words = explode(' ', $cleanInput);
// Filter stopword
$filteredWords = array_filter($words, function($word) use ($stopwords) {
$filteredWords = array_filter($words, function ($word) use ($stopwords) {
return !in_array($word, $stopwords) && trim($word) !== '';
});
@ -72,7 +72,7 @@ public function index(Request $request)
}
// Urutkan berdasarkan similarity_score terbesar (descending)
usort($hasil, function($a, $b) {
usort($hasil, function ($a, $b) {
return $b->similarity_score <=> $a->similarity_score;
});
@ -141,9 +141,13 @@ public function show($id)
private function getRekomendasi($targetBuku)
{
$semuaBuku = Buku::where('id_buku', '!=', $targetBuku->id_buku)
->whereNotNull('nomor_panggil')
->get();
$semuaBuku = Buku::where('id', '!=', $targetBuku->id)
->get();
// Jika nomor_panggil tidak ada, tampilkan rekomendasi berdasarkan buku populer
if (empty($targetBuku->nomor_panggil)) {
return $semuaBuku->take(4);
}
$hasil = [];
$targetDdc = substr(preg_replace('/[^0-9]/', '', $targetBuku->nomor_panggil), 0, 3);
@ -153,6 +157,8 @@ private function getRekomendasi($targetBuku)
}
foreach ($semuaBuku as $b) {
if (empty($b->nomor_panggil)) continue;
$pembandingDdc = substr(preg_replace('/[^0-9]/', '', $b->nomor_panggil), 0, 3);
if (strlen($pembandingDdc) < 3) continue;
@ -173,7 +179,7 @@ private function getRekomendasi($targetBuku)
}
}
usort($hasil, function($a, $b) {
usort($hasil, function ($a, $b) {
return $b->similarity_score <=> $a->similarity_score;
});
@ -189,23 +195,23 @@ private function prediksiLokasiRak($nomor_panggil)
$kode_utama = (int) substr(trim($nomor_panggil), 0, 3);
return match (true) {
$kode_utama >= 0 && $kode_utama <= 99 => match(true) {
$kode_utama >= 0 && $kode_utama <= 99 => match (true) {
$kode_utama <= 19 => ['rak' => 'Rak 01', 'area' => 'Karya Umum (Bibliografi)', 'kode_rak' => 'rak_000'],
$kode_utama <= 50 => ['rak' => 'Rak 02', 'area' => 'Karya Umum (Ensiklopedia)', 'kode_rak' => 'rak_000'],
default => ['rak' => 'Rak 03-05', 'area' => 'Karya Umum Lainnya', 'kode_rak' => 'rak_000'],
},
$kode_utama >= 100 && $kode_utama <= 199 => match(true) {
$kode_utama >= 100 && $kode_utama <= 199 => match (true) {
$kode_utama <= 150 => ['rak' => 'Rak 06-10', 'area' => 'Filsafat', 'kode_rak' => 'rak_100'],
default => ['rak' => 'Rak 11-14', 'area' => 'Psikologi', 'kode_rak' => 'rak_100'],
},
$kode_utama >= 200 && $kode_utama <= 299 => match(true) {
$kode_utama >= 200 && $kode_utama <= 299 => match (true) {
$kode_utama == 297 => ['rak' => 'Rak 25-32', 'area' => 'Agama Islam', 'kode_rak' => 'rak_200'],
default => ['rak' => 'Rak 15-24', 'area' => 'Agama Umum & Lainnya', 'kode_rak' => 'rak_200'],
},
$kode_utama >= 300 && $kode_utama <= 399 => match(true) {
$kode_utama >= 300 && $kode_utama <= 399 => match (true) {
$kode_utama <= 330 => ['rak' => 'Rak 33-36', 'area' => 'Sosiologi & Ilmu Politik', 'kode_rak' => 'rak_300'],
$kode_utama <= 360 => ['rak' => 'Rak 37-40', 'area' => 'Ekonomi & Hukum', 'kode_rak' => 'rak_300'],
default => ['rak' => 'Rak 41-44', 'area' => 'Pendidikan & Adat', 'kode_rak' => 'rak_300'],
@ -215,14 +221,14 @@ private function prediksiLokasiRak($nomor_panggil)
$kode_utama >= 500 && $kode_utama <= 599 => ['rak' => 'Rak 46-48', 'area' => 'Ilmu Murni', 'kode_rak' => 'rak_500'],
$kode_utama >= 600 && $kode_utama <= 699 => match(true) {
$kode_utama >= 600 && $kode_utama <= 699 => match (true) {
$kode_utama <= 610 => ['rak' => 'Rak 49-53', 'area' => 'Ilmu Kedokteran', 'kode_rak' => 'rak_600'],
$kode_utama <= 630 => ['rak' => 'Rak 54-58', 'area' => 'Ilmu Teknik', 'kode_rak' => 'rak_600'],
$kode_utama <= 650 => ['rak' => 'Rak 59-63', 'area' => 'Pertanian', 'kode_rak' => 'rak_600'],
default => ['rak' => 'Rak 64-68', 'area' => 'Manajemen & Bisnis', 'kode_rak' => 'rak_600'],
},
$kode_utama >= 700 && $kode_utama <= 799 => match(true) {
$kode_utama >= 700 && $kode_utama <= 799 => match (true) {
$kode_utama <= 739 => ['rak' => 'Rak 71', 'area' => 'Kesenian Murni', 'kode_rak' => 'rak_700'],
$kode_utama <= 769 => ['rak' => 'Rak 72', 'area' => 'Seni Rupa & Kriya', 'kode_rak' => 'rak_700'],
$kode_utama <= 789 => ['rak' => 'Rak 73', 'area' => 'Fotografi & Musik', 'kode_rak' => 'rak_700'],
@ -231,7 +237,7 @@ private function prediksiLokasiRak($nomor_panggil)
$kode_utama >= 800 && $kode_utama <= 899 => ['rak' => 'Rak 77-79', 'area' => 'Kesusastraan (Sastra)', 'kode_rak' => 'rak_800'],
$kode_utama >= 900 && $kode_utama <= 999 => match(true) {
$kode_utama >= 900 && $kode_utama <= 999 => match (true) {
$kode_utama <= 919 => ['rak' => 'Rak 69, 70', 'area' => 'Geografi & Perjalanan', 'kode_rak' => 'rak_900'],
default => ['rak' => 'Rak 80-84', 'area' => 'Sejarah Umum', 'kode_rak' => 'rak_900'],
},

View File

@ -0,0 +1,28 @@
<?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(): void
{
Schema::create('kategori', function (Blueprint $table) {
$table->increments('id_kategori');
$table->string('nama_kategori');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('kategori');
}
};

View File

@ -19,11 +19,21 @@ public function run(): void
DB::table('buku_tamu')->insert([
[
'id_user' => $userId,
'nama_tamu' => 'Pengunjung 1',
'email' => 'pengunjung1@example.com',
'no_hp' => '081234567890',
'asal_instansi' => 'Sekolah A',
'status' => 'Aktif',
'tujuan_kunjungan' => 'Membaca Buku',
'tanggal_kunjungan' => now(),
],
[
'id_user' => $userId,
'nama_tamu' => 'Pengunjung 2',
'email' => 'pengunjung2@example.com',
'no_hp' => '082345678901',
'asal_instansi' => 'Sekolah B',
'status' => 'Aktif',
'tujuan_kunjungan' => 'Meminjam Buku',
'tanggal_kunjungan' => now()->subDay(),
],

View File

@ -16,20 +16,24 @@ class DatabaseSeeder extends Seeder
public function run(): void
{
// Admin user
User::create([
'name' => 'Admin',
'email' => 'admin@perpustakaan.com',
'password' => Hash::make('password'),
'role' => 'admin',
]);
User::updateOrCreate(
['email' => 'admin@perpustakaan.com'],
[
'name' => 'Admin',
'password' => Hash::make('password'),
'role' => 'admin',
]
);
// Regular user
User::create([
'name' => 'User Test',
'email' => 'user@perpustakaan.com',
'password' => Hash::make('password'),
'role' => 'user',
]);
User::updateOrCreate(
['email' => 'user@perpustakaan.com'],
[
'name' => 'User Test',
'password' => Hash::make('password'),
'role' => 'user',
]
);
// Sample buku
Buku::create([
@ -67,4 +71,3 @@ public function run(): void
]);
}
}

View File

@ -8,31 +8,35 @@
<x-card class="max-w-4xl mx-auto">
@if ($errors->any())
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 m-6 mb-0" role="alert">
<p class="font-bold">Validasi Gagal</p>
<ul class="list-disc ml-5">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 m-6 mb-0" role="alert">
<p class="font-bold">Validasi Gagal</p>
<ul class="list-disc ml-5">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form action="{{ route('admin.buku.update', $buku->id_buku) }}" method="POST" enctype="multipart/form-data" class="p-6 space-y-6">
<form action="{{ route('admin.buku.update', $buku->id) }}" method="POST" enctype="multipart/form-data"
class="p-6 space-y-6">
@csrf
@method('PUT')
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<x-input-label for="bibid" value="BIBID" />
<x-text-input id="bibid" name="bibid" type="text" class="mt-1 block w-full" :value="old('bibid', $buku->bibid)" />
<x-text-input id="bibid" name="bibid" type="text" class="mt-1 block w-full"
:value="old('bibid', $buku->bibid)" />
</div>
<div>
<x-input-label for="id_kategori" value="Kategori" />
<select id="id_kategori" name="id_kategori" class="mt-1 block w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm">
<select id="id_kategori" name="id_kategori"
class="mt-1 block w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm">
<option value="">Pilih Kategori</option>
@foreach($kategori as $kat)
<option value="{{ $kat->id_kategori }}" {{ old('id_kategori', $buku->id_kategori) == $kat->id_kategori ? 'selected' : '' }}>
@foreach ($kategori as $kat)
<option value="{{ $kat->id_kategori }}"
{{ old('id_kategori', $buku->id_kategori) == $kat->id_kategori ? 'selected' : '' }}>
{{ $kat->nama_kategori }}
</option>
@endforeach
@ -48,47 +52,56 @@
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<x-input-label for="pengarang" value="Pengarang" />
<x-text-input id="pengarang" name="pengarang" type="text" class="mt-1 block w-full" :value="old('pengarang', $buku->pengarang)" />
<x-text-input id="pengarang" name="pengarang" type="text" class="mt-1 block w-full"
:value="old('pengarang', $buku->pengarang)" />
</div>
<div>
<x-input-label for="nomor_panggil" value="Nomor Panggil (DDC)" />
<x-text-input id="nomor_panggil" name="nomor_panggil" type="text" class="mt-1 block w-full" :value="old('nomor_panggil', $buku->nomor_panggil)" />
<x-text-input id="nomor_panggil" name="nomor_panggil" type="text" class="mt-1 block w-full"
:value="old('nomor_panggil', $buku->nomor_panggil)" />
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div>
<x-input-label for="penerbit" value="Penerbit" />
<x-text-input id="penerbit" name="penerbit" type="text" class="mt-1 block w-full" :value="old('penerbit', $buku->penerbit)" />
<x-text-input id="penerbit" name="penerbit" type="text" class="mt-1 block w-full"
:value="old('penerbit', $buku->penerbit)" />
</div>
<div>
<x-input-label for="tahun_terbit" value="Tahun Terbit" />
<x-text-input id="tahun_terbit" name="tahun_terbit" type="number" class="mt-1 block w-full" :value="old('tahun_terbit', $buku->tahun_terbit)" />
<x-text-input id="tahun_terbit" name="tahun_terbit" type="number" class="mt-1 block w-full"
:value="old('tahun_terbit', $buku->tahun_terbit)" />
</div>
<div>
<x-input-label for="edisi" value="Edisi" />
<x-text-input id="edisi" name="edisi" type="text" class="mt-1 block w-full" :value="old('edisi', $buku->edisi)" />
<x-text-input id="edisi" name="edisi" type="text" class="mt-1 block w-full"
:value="old('edisi', $buku->edisi)" />
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<x-input-label for="deskripsi_fisik" value="Deskripsi Fisik" />
<x-text-input id="deskripsi_fisik" name="deskripsi_fisik" type="text" class="mt-1 block w-full" :value="old('deskripsi_fisik', $buku->deskripsi_fisik)" />
<x-text-input id="deskripsi_fisik" name="deskripsi_fisik" type="text" class="mt-1 block w-full"
:value="old('deskripsi_fisik', $buku->deskripsi_fisik)" />
</div>
<div>
<x-input-label for="eksemplar" value="Jumlah Eksemplar" />
<x-text-input id="eksemplar" name="eksemplar" type="number" class="mt-1 block w-full" :value="old('eksemplar', $buku->eksemplar)" />
<x-text-input id="eksemplar" name="eksemplar" type="number" class="mt-1 block w-full"
:value="old('eksemplar', $buku->eksemplar)" />
</div>
</div>
<div class="border-t border-gray-100 pt-6">
<x-input-label for="cover" value="Unggah Gambar Cover (Opsional)" />
<input type="file" id="cover" name="cover" accept="image/*" class="mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100">
<input type="file" id="cover" name="cover" accept="image/*"
class="mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100">
</div>
<div class="flex items-center justify-end gap-4 pt-4 border-t border-gray-200">
<a href="{{ route('admin.buku.index') }}" class="text-gray-600 hover:text-gray-900 font-medium text-sm">Batal</a>
<a href="{{ route('admin.buku.index') }}"
class="text-gray-600 hover:text-gray-900 font-medium text-sm">Batal</a>
<x-primary-button>
Simpan Perubahan
</x-primary-button>

View File

@ -3,208 +3,230 @@
@section('title', 'Katalog Buku')
@section('content')
<div x-data="{ isModalBukuOpen: {{ ($errors->any() || request('add') == 'true') ? 'true' : 'false' }} }">
<x-page-header title="Portofolio Katalog Buku">
<x-slot name="actions">
<button @click="isModalBukuOpen = true" class="bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 text-white px-5 py-2.5 rounded-xl shadow-lg shadow-blue-500/30 transition-all font-semibold flex items-center gap-2 transform hover:scale-105">
<i class="fas fa-plus"></i> Tambah Buku Baru
</button>
</x-slot>
</x-page-header>
<x-alert type="success" :message="session('success')" />
<div class="mb-6">
<form method="GET" action="{{ route('admin.buku.index') }}" class="flex gap-2">
<x-text-input
type="text"
name="search"
value="{{ request('search') }}"
placeholder="Cari berdasarkan Judul atau BIBID..."
class="w-full md:w-80"
/>
<x-primary-button>
Cari
</x-primary-button>
</form>
</div>
<x-card>
<x-table>
<x-slot name="head">
<x-th>BIBID</x-th>
<x-th>Judul & Pengarang</x-th>
<x-th>Kategori</x-th>
<x-th>Stok</x-th>
<x-th class="text-right">Aksi</x-th>
<div x-data="{ isModalBukuOpen: {{ $errors->any() || request('add') == 'true' ? 'true' : 'false' }} }">
<x-page-header title="Portofolio Katalog Buku">
<x-slot name="actions">
<button @click="isModalBukuOpen = true"
class="bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 text-white px-5 py-2.5 rounded-xl shadow-lg shadow-blue-500/30 transition-all font-semibold flex items-center gap-2 transform hover:scale-105">
<i class="fas fa-plus"></i> Tambah Buku Baru
</button>
</x-slot>
</x-page-header>
@forelse ($buku as $item)
<tr class="hover:bg-gray-50 transition-colors">
<td class="px-6 py-4 whitespace-nowrap text-sm font-bold text-gray-900">{{ $item->bibid }}</td>
<td class="px-6 py-4">
<div class="text-sm font-bold text-gray-900">{{ $item->judul }}</div>
<div class="text-sm text-gray-500">{{ $item->pengarang }}</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ $item->kategori->nama_kategori ?? 'Umum' }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ $item->eksemplar }}</td>
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<div class="flex justify-end gap-3">
<a href="{{ route('admin.buku.edit', $item->id_buku) }}" class="text-blue-600 hover:text-blue-900">
Edit
</a>
<form action="{{ route('admin.buku.destroy', $item->id_buku) }}"
method="POST"
onsubmit="return confirm('Apakah Anda yakin ingin menghapus aset buku ini?')">
@csrf
@method('DELETE')
<button type="submit" class="text-red-600 hover:text-red-900 font-medium transition duration-150 ease-in-out">
Hapus
</button>
</form>
</div>
</td>
</tr>
@empty
<tr>
<td colspan="5" class="px-6 py-8 text-center text-sm text-gray-500">
Tidak ada data aset buku ditemukan.
</td>
</tr>
@endforelse
</x-table>
<x-alert type="success" :message="session('success')" />
<div class="mt-4">
{{ $buku->withQueryString()->links() }}
<div class="mb-6">
<form method="GET" action="{{ route('admin.buku.index') }}" class="flex gap-2">
<x-text-input type="text" name="search" value="{{ request('search') }}"
placeholder="Cari berdasarkan Judul atau BIBID..." class="w-full md:w-80" />
<x-primary-button>
Cari
</x-primary-button>
</form>
</div>
</x-card>
<!-- MODAL TAMBAH BUKU -->
<div x-show="isModalBukuOpen" style="display: none;" class="fixed inset-0 z-50 overflow-y-auto" aria-labelledby="modal-title" role="dialog" aria-modal="true">
<div class="flex items-end justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
<!-- Background overlay -->
<div x-show="isModalBukuOpen" x-transition.opacity class="fixed inset-0 transition-opacity bg-gray-900/60 backdrop-blur-sm" aria-hidden="true" @click="isModalBukuOpen = false"></div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<x-card>
<x-table>
<x-slot name="head">
<x-th>BIBID</x-th>
<x-th>Judul & Pengarang</x-th>
<x-th>Kategori</x-th>
<x-th>Stok</x-th>
<x-th class="text-right">Aksi</x-th>
</x-slot>
<!-- Modal panel -->
<div x-show="isModalBukuOpen"
x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
class="inline-block px-4 pt-5 pb-4 overflow-hidden text-left align-bottom transition-all transform bg-white rounded-3xl shadow-2xl shadow-indigo-500/10 sm:my-8 sm:align-middle sm:max-w-4xl sm:w-full sm:p-8 border border-gray-100">
@forelse ($buku as $item)
<tr class="hover:bg-gray-50 transition-colors">
<td class="px-6 py-4 whitespace-nowrap text-sm font-bold text-gray-900">{{ $item->bibid }}</td>
<td class="px-6 py-4">
<div class="text-sm font-bold text-gray-900">{{ $item->judul }}</div>
<div class="text-sm text-gray-500">{{ $item->pengarang }}</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{{ $item->kategori->nama_kategori ?? 'Umum' }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ $item->eksemplar }}</td>
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<div class="flex justify-end gap-3">
<a href="{{ route('admin.buku.edit', $item->id) }}"
class="text-blue-600 hover:text-blue-900">
Edit
</a>
<form action="{{ route('admin.buku.destroy', $item->id) }}" method="POST"
onsubmit="return confirm('Apakah Anda yakin ingin menghapus aset buku ini?')">
@csrf
@method('DELETE')
<button type="submit"
class="text-red-600 hover:text-red-900 font-medium transition duration-150 ease-in-out">
Hapus
</button>
</form>
</div>
</td>
</tr>
@empty
<tr>
<td colspan="5" class="px-6 py-8 text-center text-sm text-gray-500">
Tidak ada data aset buku ditemukan.
</td>
</tr>
@endforelse
</x-table>
<div class="flex justify-between items-center mb-6 pl-2">
<div>
<h3 class="text-2xl font-bold text-gray-900" id="modal-title">Tambah Koleksi Buku</h3>
<p class="text-sm text-gray-500 mt-1">Masukkan detail buku baru ke dalam katalog perpustakaan.</p>
</div>
<button @click="isModalBukuOpen = false" class="w-10 h-10 rounded-full bg-gray-50 hover:bg-red-50 text-gray-400 hover:text-red-500 flex items-center justify-center transition-colors">
<i class="fas fa-times text-lg"></i>
</button>
</div>
<div class="mt-4">
{{ $buku->withQueryString()->links() }}
</div>
</x-card>
<!-- MODAL TAMBAH BUKU -->
<div x-show="isModalBukuOpen" style="display: none;" class="fixed inset-0 z-50 overflow-y-auto"
aria-labelledby="modal-title" role="dialog" aria-modal="true">
<div class="flex items-end justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
<!-- Background overlay -->
<div x-show="isModalBukuOpen" x-transition.opacity
class="fixed inset-0 transition-opacity bg-gray-900/60 backdrop-blur-sm" aria-hidden="true"
@click="isModalBukuOpen = false"></div>
@if ($errors->any())
<div class="bg-red-50 border-l-4 border-red-500 text-red-700 p-4 mb-6 rounded-r-xl text-sm shadow-sm" role="alert">
<p class="font-bold mb-1"><i class="fas fa-exclamation-circle mr-1"></i> Validasi Gagal</p>
<ul class="list-disc ml-5 space-y-1">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<form action="{{ route('admin.buku.store') }}" method="POST" enctype="multipart/form-data" class="space-y-6">
@csrf
<!-- Modal panel -->
<div x-show="isModalBukuOpen" x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
class="inline-block px-4 pt-5 pb-4 overflow-hidden text-left align-bottom transition-all transform bg-white rounded-3xl shadow-2xl shadow-indigo-500/10 sm:my-8 sm:align-middle sm:max-w-4xl sm:w-full sm:p-8 border border-gray-100">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="flex justify-between items-center mb-6 pl-2">
<div>
<x-input-label for="bibid" value="BIBID" />
<x-text-input id="bibid" name="bibid" type="text" class="mt-1 block w-full bg-gray-50/50" :value="old('bibid')" required />
<h3 class="text-2xl font-bold text-gray-900" id="modal-title">Tambah Koleksi Buku</h3>
<p class="text-sm text-gray-500 mt-1">Masukkan detail buku baru ke dalam katalog perpustakaan.
</p>
</div>
<div>
<x-input-label for="id_kategori" value="Kategori" />
<select id="id_kategori" name="id_kategori" class="mt-1 block w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-xl shadow-sm bg-gray-50/50" required>
<option value="">Pilih Kategori</option>
@foreach($kategori as $kat)
<option value="{{ $kat->id_kategori }}" {{ old('id_kategori') == $kat->id_kategori ? 'selected' : '' }}>
{{ $kat->nama_kategori }}
</option>
<button @click="isModalBukuOpen = false"
class="w-10 h-10 rounded-full bg-gray-50 hover:bg-red-50 text-gray-400 hover:text-red-500 flex items-center justify-center transition-colors">
<i class="fas fa-times text-lg"></i>
</button>
</div>
@if ($errors->any())
<div class="bg-red-50 border-l-4 border-red-500 text-red-700 p-4 mb-6 rounded-r-xl text-sm shadow-sm"
role="alert">
<p class="font-bold mb-1"><i class="fas fa-exclamation-circle mr-1"></i> Validasi Gagal</p>
<ul class="list-disc ml-5 space-y-1">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</select>
</ul>
</div>
</div>
@endif
<div>
<x-input-label for="judul" value="Judul Buku" />
<x-text-input id="judul" name="judul" type="text" class="mt-1 block w-full bg-gray-50/50" :value="old('judul')" required />
</div>
<form action="{{ route('admin.buku.store') }}" method="POST" enctype="multipart/form-data"
class="space-y-6">
@csrf
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<x-input-label for="pengarang" value="Pengarang" />
<x-text-input id="pengarang" name="pengarang" type="text" class="mt-1 block w-full bg-gray-50/50" :value="old('pengarang')" required />
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<x-input-label for="bibid" value="BIBID" />
<x-text-input id="bibid" name="bibid" type="text"
class="mt-1 block w-full bg-gray-50/50" :value="old('bibid')" required />
</div>
<div>
<x-input-label for="id_kategori" value="Kategori" />
<select id="id_kategori" name="id_kategori"
class="mt-1 block w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-xl shadow-sm bg-gray-50/50"
required>
<option value="">Pilih Kategori</option>
@foreach ($kategori as $kat)
<option value="{{ $kat->id_kategori }}"
{{ old('id_kategori') == $kat->id_kategori ? 'selected' : '' }}>
{{ $kat->nama_kategori }}
</option>
@endforeach
</select>
</div>
</div>
<div>
<x-input-label for="nomor_panggil" value="Nomor Panggil (DDC)" />
<x-text-input id="nomor_panggil" name="nomor_panggil" type="text" class="mt-1 block w-full bg-gray-50/50" :value="old('nomor_panggil')" required />
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div>
<x-input-label for="penerbit" value="Penerbit" />
<x-text-input id="penerbit" name="penerbit" type="text" class="mt-1 block w-full bg-gray-50/50" :value="old('penerbit')" />
<x-input-label for="judul" value="Judul Buku" />
<x-text-input id="judul" name="judul" type="text"
class="mt-1 block w-full bg-gray-50/50" :value="old('judul')" required />
</div>
<div>
<x-input-label for="tahun_terbit" value="Tahun Terbit" />
<x-text-input id="tahun_terbit" name="tahun_terbit" type="number" class="mt-1 block w-full bg-gray-50/50" :value="old('tahun_terbit')" />
</div>
<div>
<x-input-label for="edisi" value="Edisi" />
<x-text-input id="edisi" name="edisi" type="text" class="mt-1 block w-full bg-gray-50/50" :value="old('edisi')" />
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<x-input-label for="deskripsi_fisik" value="Deskripsi Fisik" />
<x-text-input id="deskripsi_fisik" name="deskripsi_fisik" type="text" class="mt-1 block w-full bg-gray-50/50" :value="old('deskripsi_fisik')" />
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<x-input-label for="pengarang" value="Pengarang" />
<x-text-input id="pengarang" name="pengarang" type="text"
class="mt-1 block w-full bg-gray-50/50" :value="old('pengarang')" required />
</div>
<div>
<x-input-label for="nomor_panggil" value="Nomor Panggil (DDC)" />
<x-text-input id="nomor_panggil" name="nomor_panggil" type="text"
class="mt-1 block w-full bg-gray-50/50" :value="old('nomor_panggil')" required />
</div>
</div>
<div>
<x-input-label for="eksemplar" value="Jumlah Eksemplar" />
<x-text-input id="eksemplar" name="eksemplar" type="number" class="mt-1 block w-full bg-gray-50/50" :value="old('eksemplar')" required />
</div>
</div>
<div class="border-t border-gray-100 pt-6">
<x-input-label for="cover" value="Unggah Gambar Cover (Opsional)" class="mb-2" />
<div class="flex items-center justify-center w-full">
<label for="cover" class="flex flex-col items-center justify-center w-full h-32 border-2 border-dashed border-indigo-200 rounded-2xl cursor-pointer bg-indigo-50/30 hover:bg-indigo-50 transition-colors">
<div class="flex flex-col items-center justify-center pt-5 pb-6">
<i class="fas fa-cloud-upload-alt text-3xl text-indigo-400 mb-2"></i>
<p class="mb-1 text-sm text-gray-500"><span class="font-semibold text-indigo-600">Klik untuk unggah</span> atau seret file ke sini</p>
<p class="text-xs text-gray-400">PNG, JPG, JPEG (Maks. 2MB)</p>
</div>
<input id="cover" name="cover" type="file" class="hidden" accept="image/jpeg, image/png, image/jpg" />
</label>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div>
<x-input-label for="penerbit" value="Penerbit" />
<x-text-input id="penerbit" name="penerbit" type="text"
class="mt-1 block w-full bg-gray-50/50" :value="old('penerbit')" />
</div>
<div>
<x-input-label for="tahun_terbit" value="Tahun Terbit" />
<x-text-input id="tahun_terbit" name="tahun_terbit" type="number"
class="mt-1 block w-full bg-gray-50/50" :value="old('tahun_terbit')" />
</div>
<div>
<x-input-label for="edisi" value="Edisi" />
<x-text-input id="edisi" name="edisi" type="text"
class="mt-1 block w-full bg-gray-50/50" :value="old('edisi')" />
</div>
</div>
</div>
<div class="flex items-center justify-end gap-3 pt-6 border-t border-gray-100 mt-8">
<button type="button" @click="isModalBukuOpen = false" class="px-5 py-2.5 text-gray-600 bg-gray-100 hover:bg-gray-200 hover:text-gray-900 rounded-xl font-semibold transition-colors">
Batal
</button>
<button type="submit" class="bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 text-white px-6 py-2.5 rounded-xl font-bold shadow-lg shadow-blue-500/30 transition-all transform hover:scale-105">
<i class="fas fa-save mr-2"></i> Simpan Buku
</button>
</div>
</form>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<x-input-label for="deskripsi_fisik" value="Deskripsi Fisik" />
<x-text-input id="deskripsi_fisik" name="deskripsi_fisik" type="text"
class="mt-1 block w-full bg-gray-50/50" :value="old('deskripsi_fisik')" />
</div>
<div>
<x-input-label for="eksemplar" value="Jumlah Eksemplar" />
<x-text-input id="eksemplar" name="eksemplar" type="number"
class="mt-1 block w-full bg-gray-50/50" :value="old('eksemplar')" required />
</div>
</div>
<div class="border-t border-gray-100 pt-6">
<x-input-label for="cover" value="Unggah Gambar Cover (Opsional)" class="mb-2" />
<div class="flex items-center justify-center w-full">
<label for="cover"
class="flex flex-col items-center justify-center w-full h-32 border-2 border-dashed border-indigo-200 rounded-2xl cursor-pointer bg-indigo-50/30 hover:bg-indigo-50 transition-colors">
<div class="flex flex-col items-center justify-center pt-5 pb-6">
<i class="fas fa-cloud-upload-alt text-3xl text-indigo-400 mb-2"></i>
<p class="mb-1 text-sm text-gray-500"><span
class="font-semibold text-indigo-600">Klik untuk unggah</span> atau seret
file ke sini</p>
<p class="text-xs text-gray-400">PNG, JPG, JPEG (Maks. 2MB)</p>
</div>
<input id="cover" name="cover" type="file" class="hidden"
accept="image/jpeg, image/png, image/jpg" />
</label>
</div>
</div>
<div class="flex items-center justify-end gap-3 pt-6 border-t border-gray-100 mt-8">
<button type="button" @click="isModalBukuOpen = false"
class="px-5 py-2.5 text-gray-600 bg-gray-100 hover:bg-gray-200 hover:text-gray-900 rounded-xl font-semibold transition-colors">
Batal
</button>
<button type="submit"
class="bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 text-white px-6 py-2.5 rounded-xl font-bold shadow-lg shadow-blue-500/30 transition-all transform hover:scale-105">
<i class="fas fa-save mr-2"></i> Simpan Buku
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@ -1,77 +1,85 @@
@extends('layouts.app')
@section('content')
<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="p-6 bg-blue-50 border-b border-blue-100">
<h1 class="text-2xl font-extrabold text-blue-900">Formulir Peminjaman Aset</h1>
</div>
@if ($errors->any())
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 m-6 mb-0" role="alert">
<p class="font-bold">Validasi Gagal</p>
<ul class="list-disc ml-5">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form action="{{ route('admin.peminjaman.store') }}" method="POST" class="p-6 space-y-6" id="form-peminjaman">
@csrf
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Pilih Anggota / Member</label>
<select name="id_anggota" class="w-full border-gray-300 rounded-lg shadow-sm focus:border-blue-500 focus:ring-blue-500">
<option value="">-- Pilih Member --</option>
@foreach($anggota as $a)
<option value="{{ $a->id }}" {{ old('id_anggota') == $a->id ? 'selected' : '' }}>
{{ $a->nama }} ({{ $a->no_identitas }})
</option>
@endforeach
</select>
<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="p-6 bg-blue-50 border-b border-blue-100">
<h1 class="text-2xl font-extrabold text-blue-900">Formulir Peminjaman Aset</h1>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Pilih Aset Buku (Hanya yang tersedia)</label>
<select name="id_buku" 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)
<option value="{{ $b->id_buku }}" {{ old('id_buku') == $b->id_buku ? 'selected' : '' }}>
{{ $b->bibid }} - {{ $b->judul }} (Stok: {{ $b->eksemplar }})
</option>
@endforeach
</select>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Tanggal Pinjam</label>
<input type="date" name="tanggal_pinjam" value="{{ old('tanggal_pinjam', date('Y-m-d')) }}" class="w-full border-gray-300 rounded-lg shadow-sm focus:border-blue-500 focus:ring-blue-500">
@if ($errors->any())
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 m-6 mb-0" role="alert">
<p class="font-bold">Validasi Gagal</p>
<ul class="list-disc ml-5">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Tanggal Kembali (Tenggat)</label>
<input type="date" name="tanggal_kembali" value="{{ old('tanggal_kembali', date('Y-m-d', strtotime('+7 days'))) }}" class="w-full border-gray-300 rounded-lg shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
</div>
@endif
<div class="pt-6 border-t border-gray-100 flex justify-between items-center">
<a href="{{ route('admin.peminjaman.index') }}" class="text-gray-600 hover:text-gray-900 font-medium transition duration-300">Batal</a>
<button type="submit" id="btn-submit" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-8 rounded-lg shadow-md transition duration-300 ease-in-out">
Eksekusi Transaksi
</button>
</div>
</form>
<form action="{{ route('admin.peminjaman.store') }}" method="POST" class="p-6 space-y-6" id="form-peminjaman">
@csrf
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Pilih Anggota / Member</label>
<select name="id_anggota"
class="w-full border-gray-300 rounded-lg shadow-sm focus:border-blue-500 focus:ring-blue-500">
<option value="">-- Pilih Member --</option>
@foreach ($anggota as $a)
<option value="{{ $a->id }}" {{ old('id_anggota') == $a->id ? 'selected' : '' }}>
{{ $a->nama }} ({{ $a->no_identitas }})
</option>
@endforeach
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Pilih Aset Buku (Hanya yang
tersedia)</label>
<select name="id_buku"
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)
<option value="{{ $b->id }}" {{ old('id_buku') == $b->id ? 'selected' : '' }}>
{{ $b->bibid }} - {{ $b->judul }} (Stok: {{ $b->eksemplar }})
</option>
@endforeach
</select>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Tanggal Pinjam</label>
<input type="date" name="tanggal_pinjam" value="{{ old('tanggal_pinjam', date('Y-m-d')) }}"
class="w-full border-gray-300 rounded-lg shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Tanggal Kembali (Tenggat)</label>
<input type="date" name="tanggal_kembali"
value="{{ old('tanggal_kembali', date('Y-m-d', strtotime('+7 days'))) }}"
class="w-full border-gray-300 rounded-lg shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
</div>
<div class="pt-6 border-t border-gray-100 flex justify-between items-center">
<a href="{{ route('admin.peminjaman.index') }}"
class="text-gray-600 hover:text-gray-900 font-medium transition duration-300">Batal</a>
<button type="submit" id="btn-submit"
class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-8 rounded-lg shadow-md transition duration-300 ease-in-out">
Eksekusi Transaksi
</button>
</div>
</form>
</div>
</div>
</div>
<script>
document.getElementById('form-peminjaman').addEventListener('submit', function() {
const btn = document.getElementById('btn-submit');
btn.disabled = true;
btn.innerHTML = 'Memproses...';
btn.classList.add('opacity-50', 'cursor-not-allowed');
});
</script>
<script>
document.getElementById('form-peminjaman').addEventListener('submit', function() {
const btn = document.getElementById('btn-submit');
btn.disabled = true;
btn.innerHTML = 'Memproses...';
btn.classList.add('opacity-50', 'cursor-not-allowed');
});
</script>
@endsection

View File

@ -3,461 +3,523 @@
@section('title', 'Sirkulasi Peminjaman')
@section('content')
<div x-data="{
isModalPeminjamanOpen: {{ ($errors->any() && !old('_method')) ? 'true' : 'false' }},
isModalKembaliOpen: false,
isModalEditOpen: {{ ($errors->any() && old('_method') == 'PUT') ? 'true' : 'false' }},
isModalDeleteOpen: false,
deleteId: '',
editData: {
id: '{{ old('peminjaman_id_edit') ?? '' }}',
id_anggota: '{{ old('id_anggota') ?? '' }}',
id_buku: '{{ old('id_buku') ?? '' }}',
tanggal_pinjam: '{{ old('tanggal_pinjam') ?? '' }}',
tanggal_kembali: '{{ old('tanggal_kembali') ?? '' }}'
},
openEditModal(id, anggotaId, buku, pinjam, kembali) {
this.editData = { id: id, id_anggota: anggotaId, id_buku: buku, tanggal_pinjam: pinjam, tanggal_kembali: kembali };
this.isModalEditOpen = true;
},
openDeleteModal(id) {
this.deleteId = id;
this.isModalDeleteOpen = true;
},
kembaliData: { id: '', judul: '', tgl_pinjam: '', tgl_tenggat: '', denda: 0 },
uangDibayar: '',
get kembalian() {
if (!this.uangDibayar) return 0;
return Math.max(0, this.uangDibayar - this.kembaliData.denda);
},
openKembaliModal(id, judul, pinjam, tenggat, denda) {
this.kembaliData = { id: id, judul: judul, tgl_pinjam: pinjam, tgl_tenggat: tenggat, denda: denda };
this.uangDibayar = '';
this.isModalKembaliOpen = true;
}
}" x-cloak>
<x-page-header title="Sirkulasi Peminjaman Buku">
<x-slot name="actions">
<div class="flex flex-col sm:flex-row gap-2 items-center">
<!-- Search Form -->
<form action="{{ route('admin.peminjaman.index') }}" method="GET" class="relative w-full sm:w-auto flex">
<div class="relative flex-grow min-w-[200px]">
<div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
<i class="fas fa-search text-gray-400"></i>
</div>
<input type="text" name="search" value="{{ $search ?? '' }}"
class="bg-white border border-gray-200 border-r-0 text-gray-900 text-sm rounded-l-lg focus:ring-blue-500 focus:border-blue-500 block w-full pl-9 px-3 py-2.5 shadow-sm transition-all outline-none"
placeholder="Cari judul/anggota...">
</div>
<button type="submit" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 text-sm rounded-r-lg font-bold shadow-sm transition-colors border-y border-r border-blue-600 focus:ring-2 focus:ring-blue-300">
Cari
</button>
@if(request('search'))
<a href="{{ route('admin.peminjaman.index') }}" class="ml-2 bg-gray-100 hover:bg-red-50 border border-gray-200 text-gray-500 hover:text-red-500 px-3 flex items-center justify-center rounded-lg shadow-sm transition-colors" title="Reset Pencarian">
<i class="fas fa-times"></i>
</a>
@endif
</form>
<button @click="isModalPeminjamanOpen = true" class="bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 text-white px-5 py-2.5 rounded-lg border border-transparent shadow-[0_4px_10px_rgba(37,99,235,0.2)] hover:shadow-[0_6px_15px_rgba(37,99,235,0.3)] transition-all font-semibold flex items-center gap-2 transform hover:translate-y-[-1px]">
<i class="fas fa-plus mr-1"></i> Catat Peminjaman Baru
</button>
</div>
</x-slot>
</x-page-header>
<x-alert type="success" :message="session('success')" />
<x-card>
<x-table>
<x-slot name="head">
<x-th>Anggota</x-th>
<x-th>Buku</x-th>
<x-th>Durasi Pinjam</x-th>
<x-th class="text-center">Status</x-th>
<x-th class="text-right">Aksi</x-th>
</x-slot>
@forelse ($peminjaman as $item)
<tr class="hover:bg-gray-50 transition-colors">
<td class="px-6 py-4 whitespace-nowrap">
@if($item->anggota)
<div class="text-sm font-bold text-gray-900">{{ $item->anggota->nama }}</div>
<div class="text-xs text-gray-500 mt-0.5">ID: {{ $item->anggota->no_identitas }}</div>
<div class="inline-flex items-center gap-1.5 px-2 py-1 mt-1.5 rounded bg-green-50 text-green-700 text-[11px] font-bold border border-green-200">
<i class="fab fa-whatsapp text-green-600"></i> {{ $item->anggota->no_hp ?? '-' }}
<div x-data="{
isModalPeminjamanOpen: {{ $errors->any() && !old('_method') ? 'true' : 'false' }},
isModalKembaliOpen: false,
isModalEditOpen: {{ $errors->any() && old('_method') == 'PUT' ? 'true' : 'false' }},
isModalDeleteOpen: false,
deleteId: '',
editData: {
id: '{{ old('peminjaman_id_edit') ?? '' }}',
id_anggota: '{{ old('id_anggota') ?? '' }}',
id_buku: '{{ old('id_buku') ?? '' }}',
tanggal_pinjam: '{{ old('tanggal_pinjam') ?? '' }}',
tanggal_kembali: '{{ old('tanggal_kembali') ?? '' }}'
},
openEditModal(id, anggotaId, buku, pinjam, kembali) {
this.editData = { id: id, id_anggota: anggotaId, id_buku: buku, tanggal_pinjam: pinjam, tanggal_kembali: kembali };
this.isModalEditOpen = true;
},
openDeleteModal(id) {
this.deleteId = id;
this.isModalDeleteOpen = true;
},
kembaliData: { id: '', judul: '', tgl_pinjam: '', tgl_tenggat: '', denda: 0 },
uangDibayar: '',
get kembalian() {
if (!this.uangDibayar) return 0;
return Math.max(0, this.uangDibayar - this.kembaliData.denda);
},
openKembaliModal(id, judul, pinjam, tenggat, denda) {
this.kembaliData = { id: id, judul: judul, tgl_pinjam: pinjam, tgl_tenggat: tenggat, denda: denda };
this.uangDibayar = '';
this.isModalKembaliOpen = true;
}
}" x-cloak>
<x-page-header title="Sirkulasi Peminjaman Buku">
<x-slot name="actions">
<div class="flex flex-col sm:flex-row gap-2 items-center">
<!-- Search Form -->
<form action="{{ route('admin.peminjaman.index') }}" method="GET" class="relative w-full sm:w-auto flex">
<div class="relative flex-grow min-w-[200px]">
<div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
<i class="fas fa-search text-gray-400"></i>
</div>
@else
<div class="text-sm font-bold text-gray-900">{{ $item->user?->name ?? 'Anonim' }}</div>
<div class="text-[10px] text-amber-600 font-bold uppercase italic">Riwayat User Lama</div>
<input type="text" name="search" value="{{ $search ?? '' }}"
class="bg-white border border-gray-200 border-r-0 text-gray-900 text-sm rounded-l-lg focus:ring-blue-500 focus:border-blue-500 block w-full pl-9 px-3 py-2.5 shadow-sm transition-all outline-none"
placeholder="Cari judul/anggota...">
</div>
<button type="submit"
class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 text-sm rounded-r-lg font-bold shadow-sm transition-colors border-y border-r border-blue-600 focus:ring-2 focus:ring-blue-300">
Cari
</button>
@if (request('search'))
<a href="{{ route('admin.peminjaman.index') }}"
class="ml-2 bg-gray-100 hover:bg-red-50 border border-gray-200 text-gray-500 hover:text-red-500 px-3 flex items-center justify-center rounded-lg shadow-sm transition-colors"
title="Reset Pencarian">
<i class="fas fa-times"></i>
</a>
@endif
</td>
<td class="px-6 py-4">
<div class="text-sm font-bold text-gray-900 line-clamp-1">{{ $item->buku->judul ?? 'Buku Dihapus' }}</div>
<div class="text-sm text-gray-500">{{ $item->buku->nomor_panggil ?? '-' }}</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{{ \Carbon\Carbon::parse($item->tanggal_pinjam)->format('d M Y') }} -
{{ \Carbon\Carbon::parse($item->tanggal_kembali)->format('d M Y') }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-center">
@if($item->status_peminjaman == 'Dipinjam')
@if(\Carbon\Carbon::parse($item->tanggal_kembali)->startOfDay()->lt(\Carbon\Carbon::now()->startOfDay()))
@php
$selisihHari = \Carbon\Carbon::now()->startOfDay()->diffInDays(\Carbon\Carbon::parse($item->tanggal_kembali)->startOfDay());
$estimasiDenda = $selisihHari * 1000;
@endphp
<x-badge color="red"><i class="fas fa-exclamation-triangle mr-1"></i> Terlambat</x-badge>
<div class="text-[10px] text-red-600 mt-1 font-bold animate-pulse">Denda berjalan: Rp {{ number_format($estimasiDenda, 0, ',', '.') }}</div>
</form>
<button @click="isModalPeminjamanOpen = true"
class="bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 text-white px-5 py-2.5 rounded-lg border border-transparent shadow-[0_4px_10px_rgba(37,99,235,0.2)] hover:shadow-[0_6px_15px_rgba(37,99,235,0.3)] transition-all font-semibold flex items-center gap-2 transform hover:translate-y-[-1px]">
<i class="fas fa-plus mr-1"></i> Catat Peminjaman Baru
</button>
</div>
</x-slot>
</x-page-header>
<x-alert type="success" :message="session('success')" />
<x-card>
<x-table>
<x-slot name="head">
<x-th>Anggota</x-th>
<x-th>Buku</x-th>
<x-th>Durasi Pinjam</x-th>
<x-th class="text-center">Status</x-th>
<x-th class="text-right">Aksi</x-th>
</x-slot>
@forelse ($peminjaman as $item)
<tr class="hover:bg-gray-50 transition-colors">
<td class="px-6 py-4 whitespace-nowrap">
@if ($item->anggota)
<div class="text-sm font-bold text-gray-900">{{ $item->anggota->nama }}</div>
<div class="text-xs text-gray-500 mt-0.5">ID: {{ $item->anggota->no_identitas }}</div>
<div
class="inline-flex items-center gap-1.5 px-2 py-1 mt-1.5 rounded bg-green-50 text-green-700 text-[11px] font-bold border border-green-200">
<i class="fab fa-whatsapp text-green-600"></i> {{ $item->anggota->no_hp ?? '-' }}
</div>
@else
<x-badge color="yellow">Aktif Dipinjam</x-badge>
<div class="text-sm font-bold text-gray-900">{{ $item->user?->name ?? 'Anonim' }}</div>
<div class="text-[10px] text-amber-600 font-bold uppercase italic">Riwayat User Lama</div>
@endif
@else
<x-badge color="green">Selesai</x-badge>
@if($item->denda > 0)
<div class="text-xs text-red-600 font-bold mt-1">Denda: Rp {{ number_format($item->denda, 0, ',', '.') }}</div>
</td>
<td class="px-6 py-4">
<div class="text-sm font-bold text-gray-900 line-clamp-1">
{{ $item->buku->judul ?? 'Buku Dihapus' }}</div>
<div class="text-sm text-gray-500">{{ $item->buku->nomor_panggil ?? '-' }}</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{{ \Carbon\Carbon::parse($item->tanggal_pinjam)->format('d M Y') }} -
{{ \Carbon\Carbon::parse($item->tanggal_kembali)->format('d M Y') }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-center">
@if ($item->status_peminjaman == 'Dipinjam')
@if (\Carbon\Carbon::parse($item->tanggal_kembali)->startOfDay()->lt(\Carbon\Carbon::now()->startOfDay()))
@php
$selisihHari = \Carbon\Carbon::now()
->startOfDay()
->diffInDays(\Carbon\Carbon::parse($item->tanggal_kembali)->startOfDay());
$estimasiDenda = $selisihHari * 1000;
@endphp
<x-badge color="red"><i class="fas fa-exclamation-triangle mr-1"></i>
Terlambat</x-badge>
<div class="text-[10px] text-red-600 mt-1 font-bold animate-pulse">Denda berjalan: Rp
{{ number_format($estimasiDenda, 0, ',', '.') }}</div>
@else
<x-badge color="yellow">Aktif Dipinjam</x-badge>
@endif
@else
<x-badge color="green">Selesai</x-badge>
@if ($item->denda > 0)
<div class="text-xs text-red-600 font-bold mt-1">Denda: Rp
{{ number_format($item->denda, 0, ',', '.') }}</div>
@endif
@endif
@endif
</td>
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<div class="flex items-center justify-end gap-2">
@if($item->status_peminjaman == 'Dipinjam')
@php
$dendaItem = 0;
$tglTenggat = \Carbon\Carbon::parse($item->tanggal_kembali)->startOfDay();
$tglSekarang = \Carbon\Carbon::now()->startOfDay();
if ($tglSekarang->gt($tglTenggat)) {
$dendaItem = $tglSekarang->diffInDays($tglTenggat) * 1000;
}
@endphp
<button type="button"
</td>
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<div class="flex items-center justify-end gap-2">
@if ($item->status_peminjaman == 'Dipinjam')
@php
$dendaItem = 0;
$tglTenggat = \Carbon\Carbon::parse($item->tanggal_kembali)->startOfDay();
$tglSekarang = \Carbon\Carbon::now()->startOfDay();
if ($tglSekarang->gt($tglTenggat)) {
$dendaItem = $tglSekarang->diffInDays($tglTenggat) * 1000;
}
@endphp
<button type="button"
@click="openKembaliModal('{{ $item->id_peminjaman }}', '{{ addslashes($item->buku->judul ?? 'Buku Dihapus') }}', '{{ \Carbon\Carbon::parse($item->tanggal_pinjam)->format('d M Y') }}', '{{ \Carbon\Carbon::parse($item->tanggal_kembali)->format('d M Y') }}', {{ $dendaItem }})"
class="bg-blue-100 text-blue-700 hover:bg-blue-200 px-3 py-1.5 rounded text-xs font-bold transition">
Kembalikan
Kembalikan
</button>
@else
<span
class="text-green-600 font-bold px-3 py-1.5 text-xs bg-green-50 rounded border border-green-200 flex items-center">Tuntas</span>
@endif
<a href="{{ route('admin.peminjaman.struk', $item->id_peminjaman) }}" target="_blank"
class="bg-gray-800 text-white hover:bg-gray-900 px-3 py-1.5 rounded text-xs font-bold transition flex items-center">Cetak
Struk</a>
@if ($item->status_peminjaman == 'Dipinjam')
<button type="button"
@click="openEditModal('{{ $item->id_peminjaman }}', '{{ $item->id_anggota ?? $item->id_user }}', '{{ $item->id_buku }}', '{{ \Carbon\Carbon::parse($item->tanggal_pinjam)->format('Y-m-d') }}', '{{ \Carbon\Carbon::parse($item->tanggal_kembali)->format('Y-m-d') }}')"
class="bg-yellow-100 text-yellow-700 hover:bg-yellow-200 px-2 py-1.5 rounded text-xs font-bold transition flex items-center"
title="Edit Transaksi">
<i class="fas fa-edit"></i>
</button>
@endif
<button type="button" @click="openDeleteModal('{{ $item->id_peminjaman }}')"
class="bg-red-100 text-red-700 hover:bg-red-200 px-2 py-1.5 rounded text-xs font-bold transition flex items-center"
title="Hapus Permanen">
<i class="fas fa-trash-alt"></i>
</button>
@else
<span class="text-green-600 font-bold px-3 py-1.5 text-xs bg-green-50 rounded border border-green-200 flex items-center">Tuntas</span>
@endif
<a href="{{ route('admin.peminjaman.struk', $item->id_peminjaman) }}" target="_blank" class="bg-gray-800 text-white hover:bg-gray-900 px-3 py-1.5 rounded text-xs font-bold transition flex items-center">Cetak Struk</a>
@if($item->status_peminjaman == 'Dipinjam')
<button type="button" @click="openEditModal('{{ $item->id_peminjaman }}', '{{ $item->id_anggota ?? $item->id_user }}', '{{ $item->id_buku }}', '{{ \Carbon\Carbon::parse($item->tanggal_pinjam)->format('Y-m-d') }}', '{{ \Carbon\Carbon::parse($item->tanggal_kembali)->format('Y-m-d') }}')" class="bg-yellow-100 text-yellow-700 hover:bg-yellow-200 px-2 py-1.5 rounded text-xs font-bold transition flex items-center" title="Edit Transaksi">
<i class="fas fa-edit"></i>
</button>
@endif
<button type="button" @click="openDeleteModal('{{ $item->id_peminjaman }}')" class="bg-red-100 text-red-700 hover:bg-red-200 px-2 py-1.5 rounded text-xs font-bold transition flex items-center" title="Hapus Permanen">
<i class="fas fa-trash-alt"></i>
</div>
</td>
</tr>
@empty
<tr>
<td colspan="5" class="px-6 py-8 text-center text-sm text-gray-500">
Belum ada rekam jejak transaksi.
</td>
</tr>
@endforelse
</x-table>
<div class="mt-4">
{{ $peminjaman->links() }}
</div>
</x-card>
<!-- MODAL TAMBAH PEMINJAMAN -->
<div x-show="isModalPeminjamanOpen" style="display: none;" class="fixed inset-0 z-50 overflow-y-auto"
aria-labelledby="modal-title" role="dialog" aria-modal="true">
<div class="flex items-end justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
<!-- Background overlay -->
<div x-show="isModalPeminjamanOpen" x-transition.opacity
class="fixed inset-0 transition-opacity bg-gray-900/60 backdrop-blur-sm" aria-hidden="true"
@click="isModalPeminjamanOpen = false"></div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<!-- Modal panel -->
<div x-show="isModalPeminjamanOpen" x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
class="inline-block px-4 pt-5 pb-4 overflow-hidden text-left align-bottom transition-all transform bg-white rounded-3xl shadow-2xl shadow-blue-500/10 sm:my-8 sm:align-middle sm:max-w-3xl sm:w-full sm:p-8 border border-gray-100">
<div class="flex justify-between items-center mb-6 pl-2">
<div>
<h3 class="text-2xl font-bold text-gray-900" id="modal-title">Formulir Peminjaman Buku</h3>
<p class="text-sm text-gray-500 mt-1">Pilih anggota dan judul buku yang akan dipinjamkan.</p>
</div>
<button @click="isModalPeminjamanOpen = false"
class="w-10 h-10 rounded-full bg-gray-50 hover:bg-red-50 text-gray-400 hover:text-red-500 flex items-center justify-center transition-colors">
<i class="fas fa-times text-lg"></i>
</button>
</div>
@if ($errors->any())
<div class="bg-red-50 border-l-4 border-red-500 text-red-700 p-4 mb-6 rounded-r-xl text-sm shadow-sm"
role="alert">
<p class="font-bold mb-1"><i class="fas fa-exclamation-circle mr-1"></i> Validasi Gagal</p>
<ul class="list-disc ml-5 space-y-1">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form action="{{ route('admin.peminjaman.store') }}" method="POST" class="space-y-6">
@csrf
<div>
<x-input-label value="Pilih Anggota / Member" />
<select name="id_anggota" x-init="new TomSelect($el, { maxOptions: null })"
class="mt-1 block w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-xl shadow-sm bg-gray-50/50"
required>
<option value="">-- Pilih Member --</option>
@foreach ($anggota as $a)
<option value="{{ $a->id }}"
{{ old('id_anggota') == $a->id ? 'selected' : '' }}>
{{ $a->nama }} ({{ $a->no_identitas }})
</option>
@endforeach
</select>
</div>
<div>
<x-input-label value="Pilih Buku (Hanya yang tersedia)" />
<select name="id_buku" x-init="new TomSelect($el, { maxOptions: null })"
class="mt-1 block w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-xl shadow-sm bg-gray-50/50"
required>
<option value="">-- Pilih Buku --</option>
@foreach ($buku as $b)
<option value="{{ $b->id }}" {{ old('id_buku') == $b->id ? 'selected' : '' }}>
{{ $b->bibid }} - {{ $b->judul }} (Stok: {{ $b->eksemplar }})
</option>
@endforeach
</select>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<x-input-label value="Tanggal Pinjam" />
<x-text-input type="date" name="tanggal_pinjam"
value="{{ old('tanggal_pinjam', date('Y-m-d')) }}"
class="mt-1 block w-full bg-gray-50/50" required />
</div>
<div>
<x-input-label value="Tanggal Kembali (Tenggat)" />
<x-text-input type="date" name="tanggal_kembali"
value="{{ old('tanggal_kembali', date('Y-m-d', strtotime('+7 days'))) }}"
class="mt-1 block w-full bg-gray-50/50" required />
</div>
</div>
<div class="flex items-center justify-end gap-3 pt-6 border-t border-gray-100 mt-8">
<button type="button" @click="isModalPeminjamanOpen = false"
class="px-5 py-2.5 text-gray-600 bg-gray-100 hover:bg-gray-200 hover:text-gray-900 rounded-xl font-semibold transition-colors">
Batal
</button>
<button type="submit"
class="bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 text-white px-6 py-2.5 rounded-xl font-bold shadow-lg shadow-blue-500/30 transition-all transform hover:scale-105">
<i class="fas fa-check-circle mr-2"></i> Eksekusi Transaksi
</button>
</div>
</td>
</tr>
@empty
<tr>
<td colspan="5" class="px-6 py-8 text-center text-sm text-gray-500">
Belum ada rekam jejak transaksi.
</td>
</tr>
@endforelse
</x-table>
<div class="mt-4">
{{ $peminjaman->links() }}
</div>
</x-card>
<!-- MODAL TAMBAH PEMINJAMAN -->
<div x-show="isModalPeminjamanOpen" style="display: none;" class="fixed inset-0 z-50 overflow-y-auto" aria-labelledby="modal-title" role="dialog" aria-modal="true">
<div class="flex items-end justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
<!-- Background overlay -->
<div x-show="isModalPeminjamanOpen" x-transition.opacity class="fixed inset-0 transition-opacity bg-gray-900/60 backdrop-blur-sm" aria-hidden="true" @click="isModalPeminjamanOpen = false"></div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<!-- Modal panel -->
<div x-show="isModalPeminjamanOpen"
x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
class="inline-block px-4 pt-5 pb-4 overflow-hidden text-left align-bottom transition-all transform bg-white rounded-3xl shadow-2xl shadow-blue-500/10 sm:my-8 sm:align-middle sm:max-w-3xl sm:w-full sm:p-8 border border-gray-100">
<div class="flex justify-between items-center mb-6 pl-2">
<div>
<h3 class="text-2xl font-bold text-gray-900" id="modal-title">Formulir Peminjaman Buku</h3>
<p class="text-sm text-gray-500 mt-1">Pilih anggota dan judul buku yang akan dipinjamkan.</p>
</div>
<button @click="isModalPeminjamanOpen = false" class="w-10 h-10 rounded-full bg-gray-50 hover:bg-red-50 text-gray-400 hover:text-red-500 flex items-center justify-center transition-colors">
<i class="fas fa-times text-lg"></i>
</button>
</form>
</div>
@if ($errors->any())
<div class="bg-red-50 border-l-4 border-red-500 text-red-700 p-4 mb-6 rounded-r-xl text-sm shadow-sm" role="alert">
<p class="font-bold mb-1"><i class="fas fa-exclamation-circle mr-1"></i> Validasi Gagal</p>
<ul class="list-disc ml-5 space-y-1">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form action="{{ route('admin.peminjaman.store') }}" method="POST" class="space-y-6">
@csrf
<div>
<x-input-label value="Pilih Anggota / Member" />
<select name="id_anggota" x-init="new TomSelect($el, {maxOptions: null})" class="mt-1 block w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-xl shadow-sm bg-gray-50/50" required>
<option value="">-- Pilih Member --</option>
@foreach($anggota as $a)
<option value="{{ $a->id }}" {{ old('id_anggota') == $a->id ? 'selected' : '' }}>
{{ $a->nama }} ({{ $a->no_identitas }})
</option>
@endforeach
</select>
</div>
<div>
<x-input-label value="Pilih Buku (Hanya yang tersedia)" />
<select name="id_buku" x-init="new TomSelect($el, {maxOptions: null})" class="mt-1 block w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-xl shadow-sm bg-gray-50/50" required>
<option value="">-- Pilih Buku --</option>
@foreach($buku as $b)
<option value="{{ $b->id_buku }}" {{ old('id_buku') == $b->id_buku ? 'selected' : '' }}>
{{ $b->bibid }} - {{ $b->judul }} (Stok: {{ $b->eksemplar }})
</option>
@endforeach
</select>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<x-input-label value="Tanggal Pinjam" />
<x-text-input type="date" name="tanggal_pinjam" value="{{ old('tanggal_pinjam', date('Y-m-d')) }}" class="mt-1 block w-full bg-gray-50/50" required />
</div>
<div>
<x-input-label value="Tanggal Kembali (Tenggat)" />
<x-text-input type="date" name="tanggal_kembali" value="{{ old('tanggal_kembali', date('Y-m-d', strtotime('+7 days'))) }}" class="mt-1 block w-full bg-gray-50/50" required />
</div>
</div>
<div class="flex items-center justify-end gap-3 pt-6 border-t border-gray-100 mt-8">
<button type="button" @click="isModalPeminjamanOpen = false" class="px-5 py-2.5 text-gray-600 bg-gray-100 hover:bg-gray-200 hover:text-gray-900 rounded-xl font-semibold transition-colors">
Batal
</button>
<button type="submit" class="bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 text-white px-6 py-2.5 rounded-xl font-bold shadow-lg shadow-blue-500/30 transition-all transform hover:scale-105">
<i class="fas fa-check-circle mr-2"></i> Eksekusi Transaksi
</button>
</div>
</form>
</div>
</div>
</div>
<!-- MODAL PENGEMBALIAN & PEMBAYARAN DENDA -->
<div x-show="isModalKembaliOpen" style="display: none;" class="fixed inset-0 z-50 overflow-y-auto" aria-labelledby="modal-kembali-title" role="dialog" aria-modal="true">
<div class="flex items-end justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
<div x-show="isModalKembaliOpen" x-transition.opacity class="fixed inset-0 transition-opacity bg-gray-900/60 backdrop-blur-sm" aria-hidden="true" @click="isModalKembaliOpen = false"></div>
<!-- MODAL PENGEMBALIAN & PEMBAYARAN DENDA -->
<div x-show="isModalKembaliOpen" style="display: none;" class="fixed inset-0 z-50 overflow-y-auto"
aria-labelledby="modal-kembali-title" role="dialog" aria-modal="true">
<div class="flex items-end justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
<div x-show="isModalKembaliOpen" x-transition.opacity
class="fixed inset-0 transition-opacity bg-gray-900/60 backdrop-blur-sm" aria-hidden="true"
@click="isModalKembaliOpen = false"></div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<div x-show="isModalKembaliOpen"
x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
class="inline-block px-4 pt-5 pb-4 overflow-hidden text-left align-bottom transition-all transform bg-white rounded-3xl shadow-2xl shadow-blue-500/10 sm:my-8 sm:align-middle sm:max-w-xl sm:w-full sm:p-8 border border-gray-100">
<div x-show="isModalKembaliOpen" x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
class="inline-block px-4 pt-5 pb-4 overflow-hidden text-left align-bottom transition-all transform bg-white rounded-3xl shadow-2xl shadow-blue-500/10 sm:my-8 sm:align-middle sm:max-w-xl sm:w-full sm:p-8 border border-gray-100">
<div class="flex justify-between items-center mb-6 pl-2 border-b pb-4">
<div>
<h3 class="text-xl font-bold text-gray-900" id="modal-kembali-title">Detail Pengembalian</h3>
<p class="text-xs text-gray-500 mt-1">Selesaikan transaksi peminjaman buku ini.</p>
<div class="flex justify-between items-center mb-6 pl-2 border-b pb-4">
<div>
<h3 class="text-xl font-bold text-gray-900" id="modal-kembali-title">Detail Pengembalian</h3>
<p class="text-xs text-gray-500 mt-1">Selesaikan transaksi peminjaman buku ini.</p>
</div>
<button @click="isModalKembaliOpen = false"
class="w-8 h-8 rounded-full bg-gray-50 hover:bg-red-50 text-gray-400 hover:text-red-500 flex items-center justify-center transition-colors">
<i class="fas fa-times text-sm"></i>
</button>
</div>
<button @click="isModalKembaliOpen = false" class="w-8 h-8 rounded-full bg-gray-50 hover:bg-red-50 text-gray-400 hover:text-red-500 flex items-center justify-center transition-colors">
<i class="fas fa-times text-sm"></i>
</button>
</div>
<div class="space-y-3 mb-5 bg-gray-50 p-4 rounded-xl border border-gray-100">
<div class="flex justify-between border-b border-gray-200 pb-2">
<span class="text-xs font-semibold text-gray-500">Judul Buku</span>
<span class="text-xs font-bold text-gray-900 text-right" x-text="kembaliData.judul"></span>
</div>
<div class="flex justify-between border-b border-gray-200 pb-2">
<span class="text-xs font-semibold text-gray-500">Tanggal Peminjaman</span>
<span class="text-xs font-bold text-gray-900" x-text="kembaliData.tgl_pinjam"></span>
</div>
<div class="flex justify-between border-b border-gray-200 pb-2">
<span class="text-xs font-semibold text-gray-500">Tenggat Pengembalian</span>
<span class="text-xs font-bold text-gray-900" x-text="kembaliData.tgl_tenggat"></span>
</div>
<div class="flex justify-between items-center pt-2">
<span class="text-xs font-bold text-red-600">Total Denda</span>
<span class="text-lg font-black text-red-700" x-text="'Rp ' + new Intl.NumberFormat('id-ID').format(kembaliData.denda)"></span>
</div>
</div>
<template x-if="kembaliData.denda > 0">
<div class="bg-red-50 p-4 rounded-xl border border-red-100 mb-5">
<h4 class="text-xs font-bold text-red-800 mb-2"><i class="fas fa-money-bill-wave mr-1"></i>Pembayaran Denda</h4>
<div class="space-y-3">
<div>
<label class="block text-[10px] font-semibold text-red-700 mb-1 uppercase tracking-wider">Uang yang Dibayar (Rp)</label>
<input type="number" x-model.number="uangDibayar" min="0" class="w-full text-sm border-red-200 focus:border-red-500 focus:ring-red-500 rounded-lg shadow-sm bg-white" placeholder="Nominal uang...">
</div>
<div class="flex justify-between items-center bg-white p-2.5 rounded-lg border border-red-100 shadow-sm">
<span class="text-xs font-bold text-gray-600">Kembalian:</span>
<span class="text-base font-black text-green-600" x-text="'Rp ' + new Intl.NumberFormat('id-ID').format(kembalian)"></span>
</div>
<div class="space-y-3 mb-5 bg-gray-50 p-4 rounded-xl border border-gray-100">
<div class="flex justify-between border-b border-gray-200 pb-2">
<span class="text-xs font-semibold text-gray-500">Judul Buku</span>
<span class="text-xs font-bold text-gray-900 text-right" x-text="kembaliData.judul"></span>
</div>
<div class="flex justify-between border-b border-gray-200 pb-2">
<span class="text-xs font-semibold text-gray-500">Tanggal Peminjaman</span>
<span class="text-xs font-bold text-gray-900" x-text="kembaliData.tgl_pinjam"></span>
</div>
<div class="flex justify-between border-b border-gray-200 pb-2">
<span class="text-xs font-semibold text-gray-500">Tenggat Pengembalian</span>
<span class="text-xs font-bold text-gray-900" x-text="kembaliData.tgl_tenggat"></span>
</div>
<div class="flex justify-between items-center pt-2">
<span class="text-xs font-bold text-red-600">Total Denda</span>
<span class="text-lg font-black text-red-700"
x-text="'Rp ' + new Intl.NumberFormat('id-ID').format(kembaliData.denda)"></span>
</div>
</div>
</template>
<template x-if="kembaliData.denda == 0">
<div class="bg-green-50 text-green-700 p-3 rounded-lg text-center font-bold text-xs mb-5 border border-green-100">
<i class="fas fa-check-circle mr-1"></i> Tidak ada denda keterlambatan.
</div>
</template>
<form :action="'/admin/peminjaman/' + kembaliData.id + '/kembali'" method="POST">
@csrf
@method('PUT')
<div class="flex items-center justify-end gap-2 pt-3 border-t border-gray-100">
<button type="button" @click="isModalKembaliOpen = false" class="px-4 py-2 text-xs text-gray-600 bg-gray-100 hover:bg-gray-200 rounded-lg font-semibold transition-colors">
Batal
</button>
<button type="submit"
<template x-if="kembaliData.denda > 0">
<div class="bg-red-50 p-4 rounded-xl border border-red-100 mb-5">
<h4 class="text-xs font-bold text-red-800 mb-2"><i
class="fas fa-money-bill-wave mr-1"></i>Pembayaran Denda</h4>
<div class="space-y-3">
<div>
<label
class="block text-[10px] font-semibold text-red-700 mb-1 uppercase tracking-wider">Uang
yang Dibayar (Rp)</label>
<input type="number" x-model.number="uangDibayar" min="0"
class="w-full text-sm border-red-200 focus:border-red-500 focus:ring-red-500 rounded-lg shadow-sm bg-white"
placeholder="Nominal uang...">
</div>
<div
class="flex justify-between items-center bg-white p-2.5 rounded-lg border border-red-100 shadow-sm">
<span class="text-xs font-bold text-gray-600">Kembalian:</span>
<span class="text-base font-black text-green-600"
x-text="'Rp ' + new Intl.NumberFormat('id-ID').format(kembalian)"></span>
</div>
</div>
</div>
</template>
<template x-if="kembaliData.denda == 0">
<div
class="bg-green-50 text-green-700 p-3 rounded-lg text-center font-bold text-xs mb-5 border border-green-100">
<i class="fas fa-check-circle mr-1"></i> Tidak ada denda keterlambatan.
</div>
</template>
<form :action="'/admin/peminjaman/' + kembaliData.id + '/kembali'" method="POST">
@csrf
@method('PUT')
<div class="flex items-center justify-end gap-2 pt-3 border-t border-gray-100">
<button type="button" @click="isModalKembaliOpen = false"
class="px-4 py-2 text-xs text-gray-600 bg-gray-100 hover:bg-gray-200 rounded-lg font-semibold transition-colors">
Batal
</button>
<button type="submit"
class="bg-blue-600 hover:bg-blue-700 text-white px-5 py-2 rounded-lg text-xs font-bold shadow-md transition-all"
:disabled="kembaliData.denda > 0 && uangDibayar < kembaliData.denda"
:class="(kembaliData.denda > 0 && uangDibayar < kembaliData.denda) ? 'opacity-50 cursor-not-allowed' : 'hover:scale-105'">
<i class="fas fa-save mr-1"></i> Selesaikan Transaksi
</button>
</div>
</form>
</div>
</div>
</div>
<!-- MODAL EDIT PEMINJAMAN -->
<div x-show="isModalEditOpen" style="display: none;" class="fixed inset-0 z-50 overflow-y-auto" aria-labelledby="modal-title" role="dialog" aria-modal="true">
<div class="flex items-end justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
<div x-show="isModalEditOpen" x-transition.opacity class="fixed inset-0 transition-opacity bg-gray-900/60 backdrop-blur-sm" aria-hidden="true" @click="isModalEditOpen = false"></div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<div x-show="isModalEditOpen"
x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
class="inline-block px-4 pt-5 pb-4 overflow-hidden text-left align-bottom transition-all transform bg-white rounded-3xl shadow-2xl sm:my-8 sm:align-middle sm:max-w-3xl sm:w-full sm:p-8 border border-gray-100">
<div class="flex justify-between items-center mb-6 pl-2">
<div>
<h3 class="text-2xl font-bold text-gray-900">Ubah Data Peminjaman</h3>
<p class="text-sm text-gray-500 mt-1">Perbarui informasi transaksi peminjaman.</p>
</div>
<button @click="isModalEditOpen = false" class="w-10 h-10 rounded-full bg-gray-50 hover:bg-red-50 text-gray-400 hover:text-red-500 flex items-center justify-center transition-colors">
<i class="fas fa-times text-lg"></i>
</button>
</div>
<form :action="'/admin/peminjaman/' + editData.id" method="POST" class="space-y-6">
@csrf
@method('PUT')
<input type="hidden" name="peminjaman_id_edit" :value="editData.id">
<div>
<x-input-label value="Pilih Anggota / Member" />
<select name="id_anggota" x-model="editData.id_anggota" x-init="let tsA = null; $watch('isModalEditOpen', value => { if(value && !tsA && $el.offsetHeight) setTimeout(() => { try { tsA = new TomSelect($el, {maxOptions: null}); } catch(e){} }, 100) })" class="mt-1 block w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-xl shadow-sm bg-gray-50/50" required>
<option value="">-- Pilih Member --</option>
@foreach($anggota as $a)
<option value="{{ $a->id }}">{{ $a->nama }} ({{ $a->no_identitas }})</option>
@endforeach
</select>
</div>
<div>
<x-input-label value="Pilih Buku" />
<select name="id_buku" x-model="editData.id_buku" x-init="let tsB = null; $watch('isModalEditOpen', value => { if(value && !tsB && $el.offsetHeight) setTimeout(() => { try { tsB = new TomSelect($el, {maxOptions: null}); } catch(e){} }, 100) })" class="mt-1 block w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-xl shadow-sm bg-gray-50/50" required>
<option value="">-- Pilih Buku --</option>
@foreach($buku as $b)
<option value="{{ $b->id_buku }}">{{ $b->bibid }} - {{ $b->judul }}</option>
@endforeach
</select>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<x-input-label value="Tanggal Pinjam" />
<x-text-input type="date" name="tanggal_pinjam" x-model="editData.tanggal_pinjam" class="mt-1 block w-full bg-gray-50/50" required />
</div>
<div>
<x-input-label value="Tanggal Kembali (Tenggat)" />
<x-text-input type="date" name="tanggal_kembali" x-model="editData.tanggal_kembali" class="mt-1 block w-full bg-gray-50/50" required />
</div>
</div>
<div class="flex items-center justify-end gap-3 pt-6 border-t border-gray-100 mt-8">
<button type="button" @click="isModalEditOpen = false" class="px-5 py-2.5 text-gray-600 bg-gray-100 hover:bg-gray-200 rounded-xl font-semibold transition-colors">Batal</button>
<button type="submit" class="bg-gradient-to-r from-yellow-500 to-orange-600 hover:from-yellow-600 hover:to-orange-700 text-white px-6 py-2.5 rounded-xl font-bold shadow-lg transition-all transform hover:scale-105">
<i class="fas fa-save mr-2"></i> Simpan Perubahan
</button>
</div>
</form>
</div>
</div>
</div>
<!-- MODAL KONFIRMASI HAPUS PREMIUM -->
<div x-show="isModalDeleteOpen"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="fixed inset-0 z-50 overflow-y-auto" style="display: none;">
<div class="flex items-center justify-center min-h-screen px-4">
<div class="fixed inset-0 bg-gray-900/60 backdrop-blur-sm" @click="isModalDeleteOpen = false"></div>
<div x-show="isModalDeleteOpen"
x-transition:enter="transition ease-out duration-300 transform"
x-transition:enter-start="opacity-0 scale-95 translate-y-4"
x-transition:enter-end="opacity-100 scale-100 translate-y-0"
class="relative bg-white rounded-[2rem] shadow-2xl max-w-md w-full p-8 overflow-hidden border border-gray-100">
<div class="absolute top-0 right-0 p-4">
<button @click="isModalDeleteOpen = false" class="text-gray-400 hover:text-gray-600 transition-colors">
<i class="fas fa-times"></i>
</button>
</div>
<div class="text-center">
<div class="mx-auto flex items-center justify-center h-20 w-20 rounded-full bg-red-50 mb-6">
<div class="h-12 w-12 rounded-full bg-red-100 flex items-center justify-center animate-pulse">
<i class="fas fa-trash-alt text-2xl text-red-600"></i>
</div>
</div>
<h3 class="text-2xl font-black text-gray-900 mb-2">Hapus Transaksi?</h3>
<p class="text-gray-500 mb-8 px-4 leading-relaxed">Data peminjaman ini akan dihapus permanen. Stok buku akan otomatis dikembalikan jika status masih dipinjam.</p>
<div class="flex flex-col gap-3">
<form :action="'/admin/peminjaman/' + deleteId" method="POST" class="w-full m-0">
@csrf
@method('DELETE')
<button type="submit" class="w-full py-4 bg-gradient-to-r from-red-600 to-rose-600 hover:from-red-700 hover:to-rose-700 text-white rounded-2xl font-bold shadow-lg shadow-red-500/30 transition-all transform hover:scale-[1.02] active:scale-95">
Ya, Hapus Sekarang
:class="(kembaliData.denda > 0 && uangDibayar < kembaliData.denda) ?
'opacity-50 cursor-not-allowed' : 'hover:scale-105'">
<i class="fas fa-save mr-1"></i> Selesaikan Transaksi
</button>
</form>
<button @click="isModalDeleteOpen = false" class="w-full py-4 bg-gray-50 hover:bg-gray-100 text-gray-600 rounded-2xl font-bold transition-all">
Batalkan
</div>
</form>
</div>
</div>
</div>
<!-- MODAL EDIT PEMINJAMAN -->
<div x-show="isModalEditOpen" style="display: none;" class="fixed inset-0 z-50 overflow-y-auto"
aria-labelledby="modal-title" role="dialog" aria-modal="true">
<div class="flex items-end justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
<div x-show="isModalEditOpen" x-transition.opacity
class="fixed inset-0 transition-opacity bg-gray-900/60 backdrop-blur-sm" aria-hidden="true"
@click="isModalEditOpen = false"></div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<div x-show="isModalEditOpen" x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
class="inline-block px-4 pt-5 pb-4 overflow-hidden text-left align-bottom transition-all transform bg-white rounded-3xl shadow-2xl sm:my-8 sm:align-middle sm:max-w-3xl sm:w-full sm:p-8 border border-gray-100">
<div class="flex justify-between items-center mb-6 pl-2">
<div>
<h3 class="text-2xl font-bold text-gray-900">Ubah Data Peminjaman</h3>
<p class="text-sm text-gray-500 mt-1">Perbarui informasi transaksi peminjaman.</p>
</div>
<button @click="isModalEditOpen = false"
class="w-10 h-10 rounded-full bg-gray-50 hover:bg-red-50 text-gray-400 hover:text-red-500 flex items-center justify-center transition-colors">
<i class="fas fa-times text-lg"></i>
</button>
</div>
<form :action="'/admin/peminjaman/' + editData.id" method="POST" class="space-y-6">
@csrf
@method('PUT')
<input type="hidden" name="peminjaman_id_edit" :value="editData.id">
<div>
<x-input-label value="Pilih Anggota / Member" />
<select name="id_anggota" x-model="editData.id_anggota" x-init="let tsA = null;
$watch('isModalEditOpen', value => { if (value && !tsA && $el.offsetHeight) setTimeout(() => { try { tsA = new TomSelect($el, { maxOptions: null }); } catch (e) {} }, 100) })"
class="mt-1 block w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-xl shadow-sm bg-gray-50/50"
required>
<option value="">-- Pilih Member --</option>
@foreach ($anggota as $a)
<option value="{{ $a->id }}">{{ $a->nama }} ({{ $a->no_identitas }})
</option>
@endforeach
</select>
</div>
<div>
<x-input-label value="Pilih Buku" />
<select name="id_buku" x-model="editData.id_buku" x-init="let tsB = null;
$watch('isModalEditOpen', value => { if (value && !tsB && $el.offsetHeight) setTimeout(() => { try { tsB = new TomSelect($el, { maxOptions: null }); } catch (e) {} }, 100) })"
class="mt-1 block w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-xl shadow-sm bg-gray-50/50"
required>
<option value="">-- Pilih Buku --</option>
@foreach ($buku as $b)
<option value="{{ $b->id }}">{{ $b->bibid }} - {{ $b->judul }}
</option>
@endforeach
</select>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<x-input-label value="Tanggal Pinjam" />
<x-text-input type="date" name="tanggal_pinjam" x-model="editData.tanggal_pinjam"
class="mt-1 block w-full bg-gray-50/50" required />
</div>
<div>
<x-input-label value="Tanggal Kembali (Tenggat)" />
<x-text-input type="date" name="tanggal_kembali" x-model="editData.tanggal_kembali"
class="mt-1 block w-full bg-gray-50/50" required />
</div>
</div>
<div class="flex items-center justify-end gap-3 pt-6 border-t border-gray-100 mt-8">
<button type="button" @click="isModalEditOpen = false"
class="px-5 py-2.5 text-gray-600 bg-gray-100 hover:bg-gray-200 rounded-xl font-semibold transition-colors">Batal</button>
<button type="submit"
class="bg-gradient-to-r from-yellow-500 to-orange-600 hover:from-yellow-600 hover:to-orange-700 text-white px-6 py-2.5 rounded-xl font-bold shadow-lg transition-all transform hover:scale-105">
<i class="fas fa-save mr-2"></i> Simpan Perubahan
</button>
</div>
</form>
</div>
</div>
</div>
<!-- MODAL KONFIRMASI HAPUS PREMIUM -->
<div x-show="isModalDeleteOpen" x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-200" x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0" class="fixed inset-0 z-50 overflow-y-auto" style="display: none;">
<div class="flex items-center justify-center min-h-screen px-4">
<div class="fixed inset-0 bg-gray-900/60 backdrop-blur-sm" @click="isModalDeleteOpen = false"></div>
<div x-show="isModalDeleteOpen" x-transition:enter="transition ease-out duration-300 transform"
x-transition:enter-start="opacity-0 scale-95 translate-y-4"
x-transition:enter-end="opacity-100 scale-100 translate-y-0"
class="relative bg-white rounded-[2rem] shadow-2xl max-w-md w-full p-8 overflow-hidden border border-gray-100">
<div class="absolute top-0 right-0 p-4">
<button @click="isModalDeleteOpen = false"
class="text-gray-400 hover:text-gray-600 transition-colors">
<i class="fas fa-times"></i>
</button>
</div>
<div class="text-center">
<div class="mx-auto flex items-center justify-center h-20 w-20 rounded-full bg-red-50 mb-6">
<div class="h-12 w-12 rounded-full bg-red-100 flex items-center justify-center animate-pulse">
<i class="fas fa-trash-alt text-2xl text-red-600"></i>
</div>
</div>
<h3 class="text-2xl font-black text-gray-900 mb-2">Hapus Transaksi?</h3>
<p class="text-gray-500 mb-8 px-4 leading-relaxed">Data peminjaman ini akan dihapus permanen. Stok
buku akan otomatis dikembalikan jika status masih dipinjam.</p>
<div class="flex flex-col gap-3">
<form :action="'/admin/peminjaman/' + deleteId" method="POST" class="w-full m-0">
@csrf
@method('DELETE')
<button type="submit"
class="w-full py-4 bg-gradient-to-r from-red-600 to-rose-600 hover:from-red-700 hover:to-rose-700 text-white rounded-2xl font-bold shadow-lg shadow-red-500/30 transition-all transform hover:scale-[1.02] active:scale-95">
Ya, Hapus Sekarang
</button>
</form>
<button @click="isModalDeleteOpen = false"
class="w-full py-4 bg-gray-50 hover:bg-gray-100 text-gray-600 rounded-2xl font-bold transition-all">
Batalkan
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@ -1,185 +1,221 @@
@extends('layouts.guest')
@section('content')
<!-- Hero Section -->
<div class="relative bg-gradient-to-br from-blue-900 via-indigo-800 to-blue-900 py-16 sm:py-24 overflow-hidden shadow-2xl mb-12">
<!-- Decorative background elements -->
<div class="absolute inset-0 opacity-10 bg-[url('https://www.transparenttextures.com/patterns/cubes.png')] mix-blend-overlay"></div>
<div class="absolute top-0 right-0 -mr-20 -mt-20 w-72 h-72 rounded-full bg-blue-400 mix-blend-multiply filter blur-3xl opacity-30 animate-blob"></div>
<div class="absolute bottom-0 left-0 -ml-20 -mb-20 w-72 h-72 rounded-full bg-indigo-300 mix-blend-multiply filter blur-3xl opacity-30 animate-blob animation-delay-2000"></div>
<div class="container mx-auto px-4 relative z-10">
<div class="text-center max-w-3xl mx-auto">
<h1 class="text-4xl sm:text-5xl font-extrabold text-white mb-6 tracking-tight">
Eksplorasi <span class="text-transparent bg-clip-text bg-gradient-to-r from-blue-200 to-cyan-200">Katalog Perpustakaan</span>
</h1>
<p class="text-blue-100 text-lg sm:text-xl mb-10 font-light">
Temukan ribuan koleksi buku, jurnal, dan referensi akademik untuk menginspirasi perjalanan literasi Anda.
</p>
<!-- Search Bar -->
<form action="{{ route('katalog.index') }}" method="GET" class="relative group max-w-2xl mx-auto">
<div class="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none">
<svg class="h-6 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">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
</div>
<input type="text" name="search" value="{{ $search }}" placeholder="Cari judul buku, pengarang, atau penerbit..."
class="block w-full pl-12 pr-32 py-4 bg-white/95 backdrop-blur-sm border-0 rounded-2xl shadow-xl focus:ring-4 focus:ring-blue-500/30 text-gray-800 text-lg transition-all placeholder-gray-400">
<button type="submit" class="absolute right-2 top-2 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-6 lg:px-8 rounded-xl shadow-md transition-all transform hover:scale-[1.02] active:scale-[0.98]">
Cari
</button>
</form>
<!-- Hero Section -->
<div
class="relative bg-gradient-to-br from-blue-900 via-indigo-800 to-blue-900 py-16 sm:py-24 overflow-hidden shadow-2xl mb-12">
<!-- Decorative background elements -->
<div
class="absolute inset-0 opacity-10 bg-[url('https://www.transparenttextures.com/patterns/cubes.png')] mix-blend-overlay">
</div>
<div
class="absolute top-0 right-0 -mr-20 -mt-20 w-72 h-72 rounded-full bg-blue-400 mix-blend-multiply filter blur-3xl opacity-30 animate-blob">
</div>
<div
class="absolute bottom-0 left-0 -ml-20 -mb-20 w-72 h-72 rounded-full bg-indigo-300 mix-blend-multiply filter blur-3xl opacity-30 animate-blob animation-delay-2000">
</div>
</div>
</div>
<div class="container mx-auto px-4 pb-16">
<!-- Results Info -->
@if(isset($search) && $search != '')
<div class="mb-8 flex justify-between items-center text-gray-600">
<p>Menampilkan hasil pencarian untuk: <span class="font-semibold text-gray-900">"{{ $search }}"</span></p>
</div>
@endif
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-6">
@forelse($buku as $item)
@php
$habis = ($item->eksemplar <= 0);
@endphp
<div 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 -->
<div class="relative w-full pt-[140%] overflow-hidden bg-gray-50 flex-shrink-0">
@if($item->cover)
<img src="{{ asset('storage/' . $item->cover) }}" 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">
@else
<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">
<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>
@endif
@if($habis)
<!-- Overlay Dipinjam Semua -->
<div class="absolute inset-0 bg-red-900/30 backdrop-blur-[1px] flex items-center justify-center z-10">
<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">
TIDAK TERSEDIA
</div>
</div>
@endif
<!-- Badge BUKU BARU Dinamis (Buku terbit/masuk dalam 1 tahun terakhir) -->
@php
$isBaru = false;
$tahunSekarang = date('Y');
if (isset($item->tahun_terbit) && intval($item->tahun_terbit) >= ($tahunSekarang - 1)) {
$isBaru = true;
} elseif (isset($item->created_at)) {
$tanggalMasuk = \Carbon\Carbon::parse($item->created_at);
if ($tanggalMasuk->diffInDays(now()) <= 30) {
$isBaru = true;
}
}
@endphp
@if($isBaru && !$habis)
<div class="absolute top-0 right-0 z-20">
<div class="bg-gradient-to-r from-yellow-400 to-orange-500 text-white text-[9px] sm:text-[10px] font-extrabold px-3 py-1.5 shadow-lg rounded-bl-xl origin-top-right transform">
<i class="fas fa-sparkles mr-1"></i> BUKU BARU
</div>
</div>
@endif
<!-- Overlay Badges -->
<div class="absolute top-2 inset-x-2 flex justify-between items-start z-20">
<span class="bg-white/90 backdrop-blur-md text-gray-800 text-[10px] sm:text-xs font-bold px-2 py-1 rounded shadow-sm">
{{ $item->nomor_panggil }}
</span>
@if(isset($item->similarity_score))
<span class="bg-blue-600/90 backdrop-blur-md text-white text-[10px] sm:text-xs font-semibold px-2 py-1 rounded shadow-sm">
{{ $item->similarity_score >= 1 ? 'Exact' : 'Rel: '.number_format($item->similarity_score, 1) }}
</span>
@endif
</div>
</div>
<!-- Content -->
<div class="p-4 flex-grow flex flex-col">
<h2 class="text-sm sm:text-base font-bold text-gray-900 mb-1 line-clamp-2 md:leading-snug {{ !$habis ? 'group-hover:text-blue-600 transition-colors' : '' }}" title="{{ $item->judul }}">
{{ $item->judul }}
</h2>
<p class="text-blue-600 font-medium text-xs sm:text-sm mb-2 line-clamp-1">
{{ $item->pengarang }}
<div class="container mx-auto px-4 relative z-10">
<div class="text-center max-w-3xl mx-auto">
<h1 class="text-4xl sm:text-5xl font-extrabold text-white mb-6 tracking-tight">
Eksplorasi <span class="text-transparent bg-clip-text bg-gradient-to-r from-blue-200 to-cyan-200">Katalog
Perpustakaan</span>
</h1>
<p class="text-blue-100 text-lg sm:text-xl mb-10 font-light">
Temukan ribuan koleksi buku, jurnal, dan referensi akademik untuk menginspirasi perjalanan literasi
Anda.
</p>
<div class="mt-auto pt-3 flex flex-col gap-2 border-t border-gray-50">
<div class="flex justify-between items-center text-[10px] sm:text-xs text-gray-500">
<span class="truncate pr-1">{{ $item->penerbit }}</span>
<span class="font-medium bg-gray-100 px-1.5 py-0.5 rounded">{{ $item->tahun_terbit ?? '-' }}</span>
<!-- Search Bar -->
<form action="{{ route('katalog.index') }}" method="GET" class="relative group max-w-2xl mx-auto">
<div class="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none">
<svg class="h-6 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">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
</div>
<input type="text" name="search" value="{{ $search }}"
placeholder="Cari judul buku, pengarang, atau penerbit..."
class="block w-full pl-12 pr-32 py-4 bg-white/95 backdrop-blur-sm border-0 rounded-2xl shadow-xl focus:ring-4 focus:ring-blue-500/30 text-gray-800 text-lg transition-all placeholder-gray-400">
<button type="submit"
class="absolute right-2 top-2 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-6 lg:px-8 rounded-xl shadow-md transition-all transform hover:scale-[1.02] active:scale-[0.98]">
Cari
</button>
</form>
</div>
</div>
</div>
<div class="container mx-auto px-4 pb-16">
<!-- Results Info -->
@if (isset($search) && $search != '')
<div class="mb-8 flex justify-between items-center text-gray-600">
<p>Menampilkan hasil pencarian untuk: <span class="font-semibold text-gray-900">"{{ $search }}"</span>
</p>
</div>
@endif
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-6">
@forelse($buku as $item)
@php
$habis = $item->eksemplar <= 0;
@endphp
<div
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 -->
<div class="relative w-full pt-[140%] overflow-hidden bg-gray-50 flex-shrink-0">
@if ($item->cover)
<img src="{{ asset('storage/' . $item->cover) }}" 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">
@else
<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">
<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>
@endif
@if ($habis)
<!-- Overlay Dipinjam Semua -->
<div
class="absolute inset-0 bg-red-900/30 backdrop-blur-[1px] flex items-center justify-center z-10">
<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">
TIDAK TERSEDIA
</div>
</div>
@endif
<!-- Badge BUKU BARU Dinamis (Buku terbit/masuk dalam 1 tahun terakhir) -->
@php
$isBaru = false;
$tahunSekarang = date('Y');
if (isset($item->tahun_terbit) && intval($item->tahun_terbit) >= $tahunSekarang - 1) {
$isBaru = true;
} elseif (isset($item->created_at)) {
$tanggalMasuk = \Carbon\Carbon::parse($item->created_at);
if ($tanggalMasuk->diffInDays(now()) <= 30) {
$isBaru = true;
}
}
@endphp
@if ($isBaru && !$habis)
<div class="absolute top-0 right-0 z-20">
<div
class="bg-gradient-to-r from-yellow-400 to-orange-500 text-white text-[9px] sm:text-[10px] font-extrabold px-3 py-1.5 shadow-lg rounded-bl-xl origin-top-right transform">
<i class="fas fa-sparkles mr-1"></i> BUKU BARU
</div>
</div>
@endif
<!-- Overlay Badges -->
<div class="absolute top-2 inset-x-2 flex justify-between items-start z-20">
<span
class="bg-white/90 backdrop-blur-md text-gray-800 text-[10px] sm:text-xs font-bold px-2 py-1 rounded shadow-sm">
{{ $item->nomor_panggil }}
</span>
@if (isset($item->similarity_score))
<span
class="bg-blue-600/90 backdrop-blur-md text-white text-[10px] sm:text-xs font-semibold px-2 py-1 rounded shadow-sm">
{{ $item->similarity_score >= 1 ? 'Exact' : 'Rel: ' . number_format($item->similarity_score, 1) }}
</span>
@endif
</div>
</div>
<!-- Content -->
<div class="p-4 flex-grow flex flex-col">
<h2 class="text-sm sm:text-base font-bold text-gray-900 mb-1 line-clamp-2 md:leading-snug {{ !$habis ? 'group-hover:text-blue-600 transition-colors' : '' }}"
title="{{ $item->judul }}">
{{ $item->judul }}
</h2>
<p class="text-blue-600 font-medium text-xs sm:text-sm mb-2 line-clamp-1">
{{ $item->pengarang }}
</p>
<div class="mt-auto pt-3 flex flex-col gap-2 border-t border-gray-50">
<div class="flex justify-between items-center text-[10px] sm:text-xs text-gray-500">
<span class="truncate pr-1">{{ $item->penerbit }}</span>
<span
class="font-medium bg-gray-100 px-1.5 py-0.5 rounded">{{ $item->tahun_terbit ?? '-' }}</span>
</div>
</div>
</div>
<!-- Action Area -->
<div class="px-4 pb-4 pt-0 mt-auto relative z-30">
@if ($habis)
<button disabled
class="w-full text-center bg-gray-100 text-gray-500 text-sm font-semibold py-2 px-3 rounded-xl border border-gray-200 cursor-not-allowed opacity-80 backdrop-blur-sm">
Habis Dipinjam
</button>
@else
<a href="{{ route('katalog.show', $item->id) }}"
class="block w-full text-center bg-gray-50 hover:bg-blue-600 text-gray-700 hover:text-white text-sm font-semibold py-2 px-3 rounded-xl border border-gray-200 hover:border-transparent transition-all duration-300">
Lihat Detail
</a>
@endif
</div>
</div>
</div>
<!-- Action Area -->
<div class="px-4 pb-4 pt-0 mt-auto relative z-30">
@if($habis)
<button disabled class="w-full text-center bg-gray-100 text-gray-500 text-sm font-semibold py-2 px-3 rounded-xl border border-gray-200 cursor-not-allowed opacity-80 backdrop-blur-sm">
Habis Dipinjam
</button>
@else
<a href="{{ route('katalog.show', $item->id_buku) }}" class="block w-full text-center bg-gray-50 hover:bg-blue-600 text-gray-700 hover:text-white text-sm font-semibold py-2 px-3 rounded-xl border border-gray-200 hover:border-transparent transition-all duration-300">
Lihat Detail
</a>
@endif
</div>
</div>
@empty
<div class="col-span-full py-20 bg-white rounded-3xl shadow-sm border border-gray-100 flex flex-col items-center justify-center text-center px-4">
<div class="w-20 h-20 sm:w-24 sm:h-24 bg-gray-50 rounded-full flex items-center justify-center mb-6">
<svg class="h-10 w-10 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<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" />
</svg>
</div>
<h3 class="text-xl sm:text-2xl font-bold text-gray-900 mb-2">Tidak Ada Koleksi</h3>
<p class="text-gray-500 max-w-md text-sm sm:text-base">Koleksi buku yang Anda cari belum tersedia saat ini. Silakan coba dengan kata kunci lain.</p>
</div>
@endforelse
</div>
<!-- Pagination -->
<div class="mt-12 flex justify-center">
{{ $buku->links() }}
</div>
<!-- Widget Buku Terpopuler -->
@if(isset($bukuPopuler) && $bukuPopuler->count() > 0)
<div class="mt-20 max-w-5xl mx-auto bg-white rounded-[2rem] shadow-sm border border-gray-100 p-6 sm:p-10">
<div class="flex items-center gap-3 mb-6 border-b border-gray-100 pb-4">
<div class="w-10 h-10 bg-gradient-to-br from-orange-400 to-red-500 rounded-xl flex items-center justify-center text-white shadow-lg shadow-orange-200">
<i class="fas fa-fire text-lg"></i>
</div>
<h3 class="text-2xl font-black text-gray-900 tracking-tight">Top 5 Buku Terpopuler</h3>
</div>
<ul class="divide-y divide-gray-50">
@foreach($bukuPopuler as $top)
<li class="py-4 flex flex-col sm:flex-row sm:justify-between sm:items-center gap-4 hover:bg-gray-50/80 -mx-4 px-4 rounded-2xl transition-colors group">
<div>
<a href="{{ route('katalog.show', $top->id_buku) }}" class="font-bold text-gray-900 text-base md:text-lg group-hover:text-blue-600 transition-colors block mb-1">
{{ $top->judul }}
</a>
<p class="text-sm text-gray-500">{{ $top->pengarang }}</p>
@empty
<div
class="col-span-full py-20 bg-white rounded-3xl shadow-sm border border-gray-100 flex flex-col items-center justify-center text-center px-4">
<div class="w-20 h-20 sm:w-24 sm:h-24 bg-gray-50 rounded-full flex items-center justify-center mb-6">
<svg class="h-10 w-10 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<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" />
</svg>
</div>
<h3 class="text-xl sm:text-2xl font-bold text-gray-900 mb-2">Tidak Ada Koleksi</h3>
<p class="text-gray-500 max-w-md text-sm sm:text-base">Koleksi buku yang Anda cari belum tersedia saat
ini. Silakan coba dengan kata kunci lain.</p>
</div>
<div class="self-start sm:self-auto">
<span class="inline-flex items-center gap-1.5 bg-gradient-to-r from-blue-50 to-indigo-50 text-blue-700 border border-blue-100 text-xs font-bold px-4 py-2 rounded-full whitespace-nowrap shadow-sm transition-all group-hover:shadow-md">
<i class="fas fa-chart-line text-blue-500"></i> {{ $top->peminjaman_count }} Peminjaman
</span>
@endforelse
</div>
<!-- Pagination -->
<div class="mt-12 flex justify-center">
{{ $buku->links() }}
</div>
<!-- Widget Buku Terpopuler -->
@if (isset($bukuPopuler) && $bukuPopuler->count() > 0)
<div class="mt-20 max-w-5xl mx-auto bg-white rounded-[2rem] shadow-sm border border-gray-100 p-6 sm:p-10">
<div class="flex items-center gap-3 mb-6 border-b border-gray-100 pb-4">
<div
class="w-10 h-10 bg-gradient-to-br from-orange-400 to-red-500 rounded-xl flex items-center justify-center text-white shadow-lg shadow-orange-200">
<i class="fas fa-fire text-lg"></i>
</div>
<h3 class="text-2xl font-black text-gray-900 tracking-tight">Top 5 Buku Terpopuler</h3>
</div>
</li>
@endforeach
</ul>
<ul class="divide-y divide-gray-50">
@foreach ($bukuPopuler as $top)
<li
class="py-4 flex flex-col sm:flex-row sm:justify-between sm:items-center gap-4 hover:bg-gray-50/80 -mx-4 px-4 rounded-2xl transition-colors group">
<div>
<a href="{{ route('katalog.show', $top->id) }}"
class="font-bold text-gray-900 text-base md:text-lg group-hover:text-blue-600 transition-colors block mb-1">
{{ $top->judul }}
</a>
<p class="text-sm text-gray-500">{{ $top->pengarang }}</p>
</div>
<div class="self-start sm:self-auto">
<span
class="inline-flex items-center gap-1.5 bg-gradient-to-r from-blue-50 to-indigo-50 text-blue-700 border border-blue-100 text-xs font-bold px-4 py-2 rounded-full whitespace-nowrap shadow-sm transition-all group-hover:shadow-md">
<i class="fas fa-chart-line text-blue-500"></i> {{ $top->peminjaman_count }} Peminjaman
</span>
</div>
</li>
@endforeach
</ul>
</div>
@endif
</div>
@endif
</div>
@endsection

View File

@ -1,247 +1,294 @@
@extends('layouts.guest')
@push('styles')
<style>
/* ===== Map Pin Visualization ===== */
.map-container {
position: relative;
width: 100%;
overflow: hidden;
border-radius: 0.75rem;
background: #E2E8F0;
}
.map-container img {
display: block;
width: 100%;
height: auto;
opacity: 0.95;
}
<style>
/* ===== Map Pin Visualization ===== */
.map-container {
position: relative;
width: 100%;
overflow: hidden;
border-radius: 0.75rem;
background: #E2E8F0;
}
/* Pin Pointer */
.map-pin {
position: absolute;
transform: translate(-50%, -100%);
z-index: 30;
cursor: pointer;
filter: drop-shadow(0 4px 8px rgba(0,0,0,0.25));
transition: filter 0.3s ease;
}
.map-pin:hover {
filter: drop-shadow(0 6px 14px rgba(227,38,54,0.5));
z-index: 40;
}
.map-pin.active {
animation: pinBounce 1.5s infinite;
}
.map-container img {
display: block;
width: 100%;
height: auto;
opacity: 0.95;
}
/* Pin Icon (red circle + triangle tail) */
.map-pin__icon {
display: flex;
flex-direction: column;
align-items: center;
}
.map-pin__circle {
width: 32px;
height: 32px;
background: linear-gradient(135deg, #E32636, #c0392b);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
border: 2.5px solid #fff;
box-shadow: 0 2px 8px rgba(227,38,54,0.4);
}
.map-pin__circle i {
color: #fff;
font-size: 13px;
}
.map-pin__tail {
width: 0;
height: 0;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-top: 10px solid #c0392b;
margin-top: -2px;
}
/* Pin Pointer */
.map-pin {
position: absolute;
transform: translate(-50%, -100%);
z-index: 30;
cursor: pointer;
filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.25));
transition: filter 0.3s ease;
}
/* Pin Label (tooltip di bawah) */
.map-pin__label {
position: absolute;
top: calc(100% + 6px);
left: 50%;
transform: translateX(-50%);
background: #0B5394;
color: #fff;
font-size: 9px;
font-weight: 800;
padding: 3px 8px;
border-radius: 4px;
white-space: nowrap;
box-shadow: 0 2px 6px rgba(11,83,148,0.4);
border: 1px solid rgba(96,165,250,0.4);
pointer-events: none;
opacity: 0;
transition: opacity 0.2s ease;
}
.map-pin:hover .map-pin__label,
.map-pin.active .map-pin__label {
opacity: 1;
}
.map-pin:hover {
filter: drop-shadow(0 6px 14px rgba(227, 38, 54, 0.5));
z-index: 40;
}
/* Pulse dot di dasar pin */
.map-pin__pulse {
position: absolute;
bottom: -4px;
left: 50%;
transform: translateX(-50%);
width: 10px;
height: 10px;
border-radius: 50%;
background: rgba(227,38,54,0.35);
z-index: -1;
}
.map-pin.active .map-pin__pulse {
animation: pinPulse 2s infinite;
}
.map-pin.active {
animation: pinBounce 1.5s infinite;
}
/* Overlay Not Found */
.map-overlay-notfound {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: rgba(255,255,255,0.85);
backdrop-filter: blur(6px);
z-index: 50;
border-radius: 0.75rem;
}
/* Pin Icon (red circle + triangle tail) */
.map-pin__icon {
display: flex;
flex-direction: column;
align-items: center;
}
@keyframes pinBounce {
0%, 100% { transform: translate(-50%, -100%); }
50% { transform: translate(-50%, calc(-100% - 8px)); }
}
@keyframes pinPulse {
0% { transform: translateX(-50%) scale(1); opacity: 0.6; }
100% { transform: translateX(-50%) scale(3.5); opacity: 0; }
}
/* Responsive adjustments */
@media (max-width: 640px) {
.map-pin__circle {
width: 24px;
height: 24px;
width: 32px;
height: 32px;
background: linear-gradient(135deg, #E32636, #c0392b);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
border: 2.5px solid #fff;
box-shadow: 0 2px 8px rgba(227, 38, 54, 0.4);
}
.map-pin__circle i {
font-size: 10px;
color: #fff;
font-size: 13px;
}
.map-pin__tail {
border-left-width: 5px;
border-right-width: 5px;
border-top-width: 7px;
width: 0;
height: 0;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-top: 10px solid #c0392b;
margin-top: -2px;
}
/* Pin Label (tooltip di bawah) */
.map-pin__label {
font-size: 8px;
padding: 2px 6px;
position: absolute;
top: calc(100% + 6px);
left: 50%;
transform: translateX(-50%);
background: #0B5394;
color: #fff;
font-size: 9px;
font-weight: 800;
padding: 3px 8px;
border-radius: 4px;
white-space: nowrap;
box-shadow: 0 2px 6px rgba(11, 83, 148, 0.4);
border: 1px solid rgba(96, 165, 250, 0.4);
pointer-events: none;
opacity: 0;
transition: opacity 0.2s ease;
}
}
</style>
.map-pin:hover .map-pin__label,
.map-pin.active .map-pin__label {
opacity: 1;
}
/* Pulse dot di dasar pin */
.map-pin__pulse {
position: absolute;
bottom: -4px;
left: 50%;
transform: translateX(-50%);
width: 10px;
height: 10px;
border-radius: 50%;
background: rgba(227, 38, 54, 0.35);
z-index: -1;
}
.map-pin.active .map-pin__pulse {
animation: pinPulse 2s infinite;
}
/* Overlay Not Found */
.map-overlay-notfound {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: rgba(255, 255, 255, 0.85);
backdrop-filter: blur(6px);
z-index: 50;
border-radius: 0.75rem;
}
@keyframes pinBounce {
0%,
100% {
transform: translate(-50%, -100%);
}
50% {
transform: translate(-50%, calc(-100% - 8px));
}
}
@keyframes pinPulse {
0% {
transform: translateX(-50%) scale(1);
opacity: 0.6;
}
100% {
transform: translateX(-50%) scale(3.5);
opacity: 0;
}
}
/* Responsive adjustments */
@media (max-width: 640px) {
.map-pin__circle {
width: 24px;
height: 24px;
}
.map-pin__circle i {
font-size: 10px;
}
.map-pin__tail {
border-left-width: 5px;
border-right-width: 5px;
border-top-width: 7px;
}
.map-pin__label {
font-size: 8px;
padding: 2px 6px;
}
}
</style>
@endpush
@section('content')
<div class="container mx-auto px-4 py-12 max-w-7xl">
<!-- Header: Back button & Search Bar -->
<div class="flex flex-col md:flex-row justify-between items-center mb-10 gap-6">
<a href="{{ route('katalog.index') }}" class="text-gray-500 hover:text-blue-600 font-bold flex items-center transition-colors px-4 py-2 bg-white rounded-full shadow-sm border border-gray-100 hover:shadow-md">
<i class="fas fa-arrow-left mr-2"></i> Kembali
</a>
<div class="container mx-auto px-4 py-12 max-w-7xl">
<!-- Header: Back button & Search Bar -->
<div class="flex flex-col md:flex-row justify-between items-center mb-10 gap-6">
<a href="{{ route('katalog.index') }}"
class="text-gray-500 hover:text-blue-600 font-bold flex items-center transition-colors px-4 py-2 bg-white rounded-full shadow-sm border border-gray-100 hover:shadow-md">
<i class="fas fa-arrow-left mr-2"></i> Kembali
</a>
<!-- Search Bar -->
<form action="{{ route('katalog.index') }}" method="GET" class="w-full md:w-80 relative group">
<input type="text" name="search" placeholder="Cari Buku..." class="w-full pl-5 pr-14 py-3 bg-white border border-gray-200 rounded-full shadow-sm focus:ring-4 focus:ring-blue-500/20 focus:border-blue-500 text-sm font-medium transition-all outline-none">
<button type="submit" class="absolute right-1 top-1 bottom-1 w-10 flex items-center justify-center bg-gray-100 text-gray-600 rounded-full hover:bg-blue-600 hover:text-white transition-colors">
<i class="fas fa-search"></i>
</button>
</form>
</div>
<!-- Search Bar -->
<form action="{{ route('katalog.index') }}" method="GET" class="w-full md:w-80 relative group">
<input type="text" name="search" placeholder="Cari Buku..."
class="w-full pl-5 pr-14 py-3 bg-white border border-gray-200 rounded-full shadow-sm focus:ring-4 focus:ring-blue-500/20 focus:border-blue-500 text-sm font-medium transition-all outline-none">
<button type="submit"
class="absolute right-1 top-1 bottom-1 w-10 flex items-center justify-center bg-gray-100 text-gray-600 rounded-full hover:bg-blue-600 hover:text-white transition-colors">
<i class="fas fa-search"></i>
</button>
</form>
</div>
<!-- Main Content Grid 3 Columns -->
<div class="grid grid-cols-1 md:grid-cols-12 gap-10 items-start">
<!-- Main Content Grid 3 Columns -->
<div class="grid grid-cols-1 md:grid-cols-12 gap-10 items-start">
<!-- Column 1: Book Cover Card -->
<div class="md:col-span-12 lg:col-span-3">
<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">
@if($buku->cover)
<img src="{{ asset('storage/' . $buku->cover) }}" alt="{{ $buku->judul }}" class="w-full aspect-[3/4] object-cover rounded-2xl mb-6 shadow-md border border-gray-100">
@else
<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">
<div class="absolute inset-0 opacity-40 bg-[url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGNpcmNsZSBjeD0iMiIgY3k9IjIiIHI9IjIiIGZpbGw9IiMzYjgyZjYiIGZpbGwtb3BhY2l0eT0iMC4wNSIvPjwvc3ZnPg==')]"></div>
<div class="relative z-10 flex flex-col items-center justify-center p-6 w-full h-full">
<div class="w-20 h-20 bg-white/80 backdrop-blur rounded-full flex items-center justify-center mb-4 shadow-sm text-blue-400">
<i class="fas fa-book-open text-3xl"></i>
<!-- Column 1: Book Cover Card -->
<div class="md:col-span-12 lg:col-span-3">
<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">
@if ($buku->cover)
<img src="{{ asset('storage/' . $buku->cover) }}" alt="{{ $buku->judul }}"
class="w-full aspect-[3/4] object-cover rounded-2xl mb-6 shadow-md border border-gray-100">
@else
<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">
<div
class="absolute inset-0 opacity-40 bg-[url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGNpcmNsZSBjeD0iMiIgY3k9IjIiIHI9IjIiIGZpbGw9IiMzYjgyZjYiIGZpbGwtb3BhY2l0eT0iMC4wNSIvPjwvc3ZnPg==')]">
</div>
<div class="relative z-10 flex flex-col items-center justify-center p-6 w-full h-full">
<div
class="w-20 h-20 bg-white/80 backdrop-blur rounded-full flex items-center justify-center mb-4 shadow-sm text-blue-400">
<i class="fas fa-book-open text-3xl"></i>
</div>
<h3
class="text-sm font-black text-blue-900 leading-snug break-words drop-shadow-sm uppercase line-clamp-4">
{{ $buku->judul }}</h3>
<div class="w-8 h-1 bg-blue-300/50 rounded-full my-3"></div>
<p class="text-[10px] text-blue-700 font-bold uppercase tracking-widest">
{{ $buku->pengarang }}</p>
</div>
<h3 class="text-sm font-black text-blue-900 leading-snug break-words drop-shadow-sm uppercase line-clamp-4">{{ $buku->judul }}</h3>
<div class="w-8 h-1 bg-blue-300/50 rounded-full my-3"></div>
<p class="text-[10px] text-blue-700 font-bold uppercase tracking-widest">{{ $buku->pengarang }}</p>
</div>
@endif
<h2 class="font-extrabold text-gray-900 uppercase tracking-widest text-xs leading-relaxed px-2 mb-2">
{{ $buku->judul }}</h2>
</div>
</div>
<!-- Column 2: Details Description -->
<div class="md:col-span-12 lg:col-span-5 flex flex-col gap-8 lg:px-4">
<div class="text-center lg:text-left">
<h2 class="text-3xl font-black text-gray-900 mb-2 tracking-tight">Deskripsi Buku</h2>
</div>
<div class="space-y-6">
<!-- Data Row -->
<div class="flex flex-col sm:flex-row gap-2 border-b border-gray-100 pb-5">
<span class="text-gray-500 font-semibold text-sm w-full sm:w-1/3 flex-shrink-0">Kode Buku:</span>
<span
class="text-gray-900 font-bold text-sm bg-gray-100 px-3 py-1 rounded w-fit">{{ $buku->nomor_panggil ?? '-' }}</span>
</div>
<!-- Data Row -->
<div class="flex flex-col sm:flex-row gap-2 border-b border-gray-100 pb-5">
<span class="text-gray-500 font-semibold text-sm w-full sm:w-1/3 flex-shrink-0">Judul Buku:</span>
<span class="text-gray-900 font-bold text-sm">{{ $buku->judul }}</span>
</div>
<!-- Data Row -->
<div class="flex flex-col sm:flex-row gap-2 border-b border-gray-100 pb-5">
<span class="text-gray-500 font-semibold text-sm w-full sm:w-1/3 flex-shrink-0">Nama Penulis:</span>
<span class="text-gray-900 font-bold text-sm">{{ $buku->pengarang }}</span>
</div>
<!-- Data Row -->
<div class="flex flex-col sm:flex-row gap-2 border-b border-gray-100 pb-5">
<span class="text-gray-500 font-semibold text-sm w-full sm:w-1/3 flex-shrink-0">Deskripsi
Fisik:</span>
<span
class="text-gray-700 font-medium text-sm leading-relaxed">{{ $buku->deskripsi_fisik ?: 'Tidak ada deskripsi fisik.' }}</span>
</div>
<!-- Data Row -->
<div class="flex flex-col sm:flex-row gap-2 border-b border-gray-100 pb-5">
<span class="text-gray-500 font-semibold text-sm w-full sm:w-1/3 flex-shrink-0">Nama
Kategori:</span>
<span
class="text-blue-600 font-bold text-sm">{{ $buku->kategori->nama_kategori ?? $lokasi['area'] }}</span>
</div>
<!-- Data Row -->
<div class="flex flex-col sm:flex-row gap-2 pb-5">
<span class="text-gray-500 font-semibold text-sm w-full sm:w-1/3 flex-shrink-0">Detail
Kategori:</span>
<span class="text-gray-900 font-bold text-sm">{{ $lokasi['area'] }} (Rak
{{ $lokasi['rak'] }})</span>
</div>
@endif
<h2 class="font-extrabold text-gray-900 uppercase tracking-widest text-xs leading-relaxed px-2 mb-2">{{ $buku->judul }}</h2>
</div>
</div>
<!-- Column 2: Details Description -->
<div class="md:col-span-12 lg:col-span-5 flex flex-col gap-8 lg:px-4">
<div class="text-center lg:text-left">
<h2 class="text-3xl font-black text-gray-900 mb-2 tracking-tight">Deskripsi Buku</h2>
</div>
<div class="space-y-6">
<!-- Data Row -->
<div class="flex flex-col sm:flex-row gap-2 border-b border-gray-100 pb-5">
<span class="text-gray-500 font-semibold text-sm w-full sm:w-1/3 flex-shrink-0">Kode Buku:</span>
<span class="text-gray-900 font-bold text-sm bg-gray-100 px-3 py-1 rounded w-fit">{{ $buku->nomor_panggil ?? '-' }}</span>
</div>
<!-- Data Row -->
<div class="flex flex-col sm:flex-row gap-2 border-b border-gray-100 pb-5">
<span class="text-gray-500 font-semibold text-sm w-full sm:w-1/3 flex-shrink-0">Judul Buku:</span>
<span class="text-gray-900 font-bold text-sm">{{ $buku->judul }}</span>
</div>
<!-- Data Row -->
<div class="flex flex-col sm:flex-row gap-2 border-b border-gray-100 pb-5">
<span class="text-gray-500 font-semibold text-sm w-full sm:w-1/3 flex-shrink-0">Nama Penulis:</span>
<span class="text-gray-900 font-bold text-sm">{{ $buku->pengarang }}</span>
</div>
<!-- Data Row -->
<div class="flex flex-col sm:flex-row gap-2 border-b border-gray-100 pb-5">
<span class="text-gray-500 font-semibold text-sm w-full sm:w-1/3 flex-shrink-0">Deskripsi Fisik:</span>
<span class="text-gray-700 font-medium text-sm leading-relaxed">{{ $buku->deskripsi_fisik ?: 'Tidak ada deskripsi fisik.' }}</span>
</div>
<!-- Data Row -->
<div class="flex flex-col sm:flex-row gap-2 border-b border-gray-100 pb-5">
<span class="text-gray-500 font-semibold text-sm w-full sm:w-1/3 flex-shrink-0">Nama Kategori:</span>
<span class="text-blue-600 font-bold text-sm">{{ $buku->kategori->nama_kategori ?? $lokasi['area'] }}</span>
</div>
<!-- Data Row -->
<div class="flex flex-col sm:flex-row gap-2 pb-5">
<span class="text-gray-500 font-semibold text-sm w-full sm:w-1/3 flex-shrink-0">Detail Kategori:</span>
<span class="text-gray-900 font-bold text-sm">{{ $lokasi['area'] }} (Rak {{ $lokasi['rak'] }})</span>
</div>
</div>
</div>
<div class="w-full lg:w-96 flex-shrink-0 flex flex-col gap-6 mx-auto relative">
<!-- MAP CONTAINER -->
<div class="map-container shadow-sm border-2 border-slate-300 select-none font-sans min-h-[300px]" id="mapContainer">
<div class="map-container shadow-sm border-2 border-slate-300 select-none font-sans min-h-[300px]"
id="mapContainer">
<!-- Background Image Map -->
<img src="{{ asset('img/img 2.png') }}" alt="Denah Perpustakaan" id="mapImage">
<!-- Pin Container (JavaScript akan merender pin di sini) -->
<div id="pinContainer"></div>
@if(!$buku->lokasi_x || !$buku->lokasi_y)
@if (!$buku->lokasi_x || !$buku->lokasi_y)
<!-- Overlay Not Found -->
<div class="map-overlay-notfound">
<i class="fas fa-exclamation-triangle text-red-500 text-3xl mb-2 animate-pulse"></i>
@ -252,171 +299,189 @@
</div>
<!-- Detail Mini location box directly below map -->
<div class="bg-blue-900 border border-blue-800 rounded-2xl p-5 text-center shadow-lg w-full relative z-20 transform transition hover:scale-[1.02]">
<span class="text-[10px] text-blue-300 font-bold uppercase tracking-widest block mb-2 opacity-80">Informasi Lokasi Fisik</span>
<div
class="bg-blue-900 border border-blue-800 rounded-2xl p-5 text-center shadow-lg w-full relative z-20 transform transition hover:scale-[1.02]">
<span
class="text-[10px] text-blue-300 font-bold uppercase tracking-widest block mb-2 opacity-80">Informasi
Lokasi Fisik</span>
<span class="text-2xl font-black text-white block mb-1 drop-shadow-sm">{{ $lokasi['rak'] }}</span>
<span class="text-sm font-semibold text-blue-200">{{ $lokasi['area'] }}</span>
</div>
</div>
</div>
<!-- Riwayat Peminjaman -->
<div class="mt-12 mb-8">
<h2 class="text-2xl font-extrabold text-gray-900 mb-6 border-b-2 border-blue-500 inline-block pb-2">Riwayat Peminjaman</h2>
<div class="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden">
@if($buku->peminjaman && $buku->peminjaman->count() > 0)
<div class="overflow-x-auto">
<table class="w-full text-left border-collapse">
<thead>
<tr class="bg-gray-50 border-b border-gray-200 text-gray-600 text-sm">
<th class="py-4 px-6 font-semibold">Nama Peminjam</th>
<th class="py-4 px-6 font-semibold">Tanggal Pinjam</th>
<th class="py-4 px-6 font-semibold">Tanggal Kembali</th>
<th class="py-4 px-6 font-semibold">Status</th>
</tr>
</thead>
<tbody class="text-gray-700 text-sm">
@foreach($buku->peminjaman->sortByDesc('tanggal_pinjam') as $history)
<tr class="border-b border-gray-100 hover:bg-gray-50 transition-colors">
<td class="py-4 px-6 font-medium text-gray-900">
@php
$nama = $history->user->name ?? 'Pengguna Tidak Diketahui';
$disensor = $nama !== 'Pengguna Tidak Diketahui' && strlen($nama) >= 3
? substr($nama, 0, 3) . '***'
: ($nama !== 'Pengguna Tidak Diketahui' ? substr($nama, 0, 1) . '***' : $nama);
@endphp
{{ $disensor }}
</td>
<td class="py-4 px-6">
{{ \Carbon\Carbon::parse($history->tanggal_pinjam)->translatedFormat('d F Y') }}
</td>
<td class="py-4 px-6">
@if($history->status_peminjaman === 'Dikembalikan' && $history->tanggal_dikembalikan)
<span class="text-green-600 font-medium">
{{ \Carbon\Carbon::parse($history->tanggal_dikembalikan)->translatedFormat('d F Y') }} (Dikembalikan)
</span>
@else
<span class="text-gray-600">
Batas: {{ \Carbon\Carbon::parse($history->tanggal_kembali)->translatedFormat('d F Y') }}
</span>
@endif
</td>
<td class="py-4 px-6">
@if($history->status_peminjaman === 'Dipinjam')
<span class="px-3 py-1 bg-yellow-100 text-yellow-700 font-bold rounded-full text-xs">Sedang Dipinjam</span>
@elseif($history->status_peminjaman === 'Dikembalikan')
<span class="px-3 py-1 bg-green-100 text-green-700 font-bold rounded-full text-xs">Selesai</span>
@else
<span class="px-3 py-1 bg-gray-100 text-gray-700 font-bold rounded-full text-xs">{{ $history->status_peminjaman }}</span>
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@else
<div class="p-8 text-center flex flex-col items-center justify-center bg-gray-50/50">
<div class="w-16 h-16 bg-blue-50 text-blue-300 rounded-full flex items-center justify-center mb-3">
<i class="fas fa-history text-2xl"></i>
</div>
<p class="text-gray-500 font-medium">Belum ada riwayat peminjaman untuk buku ini.</p>
</div>
@endif
</div>
</div>
@if($rekomendasi->count() > 0)
<div class="mt-12">
<h2 class="text-2xl font-extrabold text-gray-900 mb-6 border-b-2 border-blue-500 inline-block pb-2">Rekomendasi Buku Serupa</h2>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
@foreach($rekomendasi as $rek)
<div class="bg-white rounded-xl shadow-sm border border-gray-200 hover:shadow-md transition duration-300 flex flex-col overflow-hidden">
<div class="p-5 flex-grow">
<div class="flex justify-between items-start mb-2">
<span class="text-xs font-bold text-blue-600 bg-blue-50 px-2 py-1 rounded">{{ $rek->nomor_panggil }}</span>
<span class="text-xs font-semibold text-green-600">Skor: {{ number_format($rek->similarity_score, 1) }}</span>
<!-- Riwayat Peminjaman -->
<div class="mt-12 mb-8">
<h2 class="text-2xl font-extrabold text-gray-900 mb-6 border-b-2 border-blue-500 inline-block pb-2">Riwayat
Peminjaman</h2>
<div class="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden">
@if ($buku->peminjaman && $buku->peminjaman->count() > 0)
<div class="overflow-x-auto">
<table class="w-full text-left border-collapse">
<thead>
<tr class="bg-gray-50 border-b border-gray-200 text-gray-600 text-sm">
<th class="py-4 px-6 font-semibold">Nama Peminjam</th>
<th class="py-4 px-6 font-semibold">Tanggal Pinjam</th>
<th class="py-4 px-6 font-semibold">Tanggal Kembali</th>
<th class="py-4 px-6 font-semibold">Status</th>
</tr>
</thead>
<tbody class="text-gray-700 text-sm">
@foreach ($buku->peminjaman->sortByDesc('tanggal_pinjam') as $history)
<tr class="border-b border-gray-100 hover:bg-gray-50 transition-colors">
<td class="py-4 px-6 font-medium text-gray-900">
@php
$nama = $history->user->name ?? 'Pengguna Tidak Diketahui';
$disensor =
$nama !== 'Pengguna Tidak Diketahui' && strlen($nama) >= 3
? substr($nama, 0, 3) . '***'
: ($nama !== 'Pengguna Tidak Diketahui'
? substr($nama, 0, 1) . '***'
: $nama);
@endphp
{{ $disensor }}
</td>
<td class="py-4 px-6">
{{ \Carbon\Carbon::parse($history->tanggal_pinjam)->translatedFormat('d F Y') }}
</td>
<td class="py-4 px-6">
@if ($history->status_peminjaman === 'Dikembalikan' && $history->tanggal_dikembalikan)
<span class="text-green-600 font-medium">
{{ \Carbon\Carbon::parse($history->tanggal_dikembalikan)->translatedFormat('d F Y') }}
(Dikembalikan)
</span>
@else
<span class="text-gray-600">
Batas:
{{ \Carbon\Carbon::parse($history->tanggal_kembali)->translatedFormat('d F Y') }}
</span>
@endif
</td>
<td class="py-4 px-6">
@if ($history->status_peminjaman === 'Dipinjam')
<span
class="px-3 py-1 bg-yellow-100 text-yellow-700 font-bold rounded-full text-xs">Sedang
Dipinjam</span>
@elseif($history->status_peminjaman === 'Dikembalikan')
<span
class="px-3 py-1 bg-green-100 text-green-700 font-bold rounded-full text-xs">Selesai</span>
@else
<span
class="px-3 py-1 bg-gray-100 text-gray-700 font-bold rounded-full text-xs">{{ $history->status_peminjaman }}</span>
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<h3 class="text-lg font-bold text-gray-900 mb-1 line-clamp-2">{{ $rek->judul }}</h3>
<p class="text-sm text-gray-600 line-clamp-1">{{ $rek->pengarang }}</p>
</div>
<div class="px-5 py-3 bg-gray-50 border-t border-gray-100 mt-auto">
<a href="{{ route('katalog.show', $rek->id_buku) }}" class="text-sm font-semibold text-blue-600 hover:text-blue-800 flex items-center justify-center w-full">
Lihat Detail
</a>
@else
<div class="p-8 text-center flex flex-col items-center justify-center bg-gray-50/50">
<div class="w-16 h-16 bg-blue-50 text-blue-300 rounded-full flex items-center justify-center mb-3">
<i class="fas fa-history text-2xl"></i>
</div>
<p class="text-gray-500 font-medium">Belum ada riwayat peminjaman untuk buku ini.</p>
</div>
@endif
</div>
</div>
@if ($rekomendasi->count() > 0)
<div class="mt-12">
<h2 class="text-2xl font-extrabold text-gray-900 mb-6 border-b-2 border-blue-500 inline-block pb-2">
Rekomendasi Buku Serupa</h2>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
@foreach ($rekomendasi as $rek)
<div
class="bg-white rounded-xl shadow-sm border border-gray-200 hover:shadow-md transition duration-300 flex flex-col overflow-hidden">
<div class="p-5 flex-grow">
<div class="flex justify-between items-start mb-2">
<span
class="text-xs font-bold text-blue-600 bg-blue-50 px-2 py-1 rounded">{{ $rek->nomor_panggil }}</span>
<span class="text-xs font-semibold text-green-600">Skor:
{{ number_format($rek->similarity_score, 1) }}</span>
</div>
<h3 class="text-lg font-bold text-gray-900 mb-1 line-clamp-2">{{ $rek->judul }}</h3>
<p class="text-sm text-gray-600 line-clamp-1">{{ $rek->pengarang }}</p>
</div>
<div class="px-5 py-3 bg-gray-50 border-t border-gray-100 mt-auto">
<a href="{{ route('katalog.show', $rek->id) }}"
class="text-sm font-semibold text-blue-600 hover:text-blue-800 flex items-center justify-center w-full">
Lihat Detail
</a>
</div>
</div>
@endforeach
</div>
</div>
@endforeach
</div>
@endif
</div>
@endif
</div>
@endsection
@push('scripts')
@php
$pinDataJson = [
'x' => $buku->lokasi_x,
'y' => $buku->lokasi_y,
'label' => $lokasi['rak'] . ' — ' . $lokasi['area'],
];
@endphp
<script>
document.addEventListener('DOMContentLoaded', function () {
// Data koordinat dari Laravel
const pinData = @json($pinDataJson);
@php
$pinDataJson = [
'x' => $buku->lokasi_x,
'y' => $buku->lokasi_y,
'label' => $lokasi['rak'] . ' — ' . $lokasi['area'],
];
@endphp
<script>
document.addEventListener('DOMContentLoaded', function() {
// Data koordinat dari Laravel
const pinData = @json($pinDataJson);
const container = document.getElementById('pinContainer');
if (!container || !pinData.x || !pinData.y) return;
const container = document.getElementById('pinContainer');
if (!container || !pinData.x || !pinData.y) return;
/**
* Membuat elemen pin pointer dan menambahkannya ke container.
* @param {number} x - Posisi X dalam persentase (0-100)
* @param {number} y - Posisi Y dalam persentase (0-100)
* @param {string} label - Label teks untuk pin
* @param {boolean} isActive - Apakah pin ini aktif (bounce + label visible)
*/
function renderPin(x, y, label, isActive) {
// Wrapper pin
const pin = document.createElement('div');
pin.className = 'map-pin' + (isActive ? ' active' : '');
pin.style.left = x + '%';
pin.style.top = y + '%';
/**
* Membuat elemen pin pointer dan menambahkannya ke container.
* @param {number} x - Posisi X dalam persentase (0-100)
* @param {number} y - Posisi Y dalam persentase (0-100)
* @param {string} label - Label teks untuk pin
* @param {boolean} isActive - Apakah pin ini aktif (bounce + label visible)
*/
function renderPin(x, y, label, isActive) {
// Wrapper pin
const pin = document.createElement('div');
pin.className = 'map-pin' + (isActive ? ' active' : '');
pin.style.left = x + '%';
pin.style.top = y + '%';
// Ikon pin (circle + tail)
const icon = document.createElement('div');
icon.className = 'map-pin__icon';
// Ikon pin (circle + tail)
const icon = document.createElement('div');
icon.className = 'map-pin__icon';
const circle = document.createElement('div');
circle.className = 'map-pin__circle';
circle.innerHTML = '<i class="fas fa-map-marker-alt"></i>';
const circle = document.createElement('div');
circle.className = 'map-pin__circle';
circle.innerHTML = '<i class="fas fa-map-marker-alt"></i>';
const tail = document.createElement('div');
tail.className = 'map-pin__tail';
const tail = document.createElement('div');
tail.className = 'map-pin__tail';
icon.appendChild(circle);
icon.appendChild(tail);
pin.appendChild(icon);
icon.appendChild(circle);
icon.appendChild(tail);
pin.appendChild(icon);
// Pulse effect
const pulse = document.createElement('div');
pulse.className = 'map-pin__pulse';
pin.appendChild(pulse);
// Pulse effect
const pulse = document.createElement('div');
pulse.className = 'map-pin__pulse';
pin.appendChild(pulse);
// Label tooltip
if (label) {
const labelEl = document.createElement('span');
labelEl.className = 'map-pin__label';
labelEl.textContent = label;
pin.appendChild(labelEl);
}
// Label tooltip
if (label) {
const labelEl = document.createElement('span');
labelEl.className = 'map-pin__label';
labelEl.textContent = label;
pin.appendChild(labelEl);
}
container.appendChild(pin);
return pin;
}
container.appendChild(pin);
return pin;
}
// Render pin utama buku ini
renderPin(pinData.x, pinData.y, pinData.label, true);
});
</script>
// Render pin utama buku ini
renderPin(pinData.x, pinData.y, pinData.label, true);
});
</script>
@endpush

View File

@ -1,97 +1,116 @@
{{-- BUKU TERPOPULER SECTION --}}
<section id="populer" class="py-24 bg-gray-50 relative overflow-hidden border-b border-gray-100">
<div class="max-w-7xl mx-auto px-6 relative z-10">
@if(!empty($bukuPopuler) && $bukuPopuler->count())
<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">
<div class="w-full md:w-auto">
<div 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>
<span class="text-xs font-semibold text-blue-800 tracking-wide">Paling Laris</span>
@if (!empty($bukuPopuler) && $bukuPopuler->count())
<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">
<div class="w-full md:w-auto">
<div
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>
<span class="text-xs font-semibold text-blue-800 tracking-wide">Paling Laris</span>
</div>
<h2 class="text-3xl md:text-4xl font-black text-gray-900 tracking-tight">
Buku <span
class="text-transparent bg-clip-text bg-gradient-to-r from-blue-600 to-indigo-600">Terpopuler</span>
</h2>
<p class="text-gray-500 mt-2 max-w-md mx-auto md:mx-0">
Koleksi buku favorit yang paling banyak dipinjam oleh para pengunjung perpustakaan kami.
</p>
</div>
<h2 class="text-3xl md:text-4xl font-black text-gray-900 tracking-tight">
Buku <span class="text-transparent bg-clip-text bg-gradient-to-r from-blue-600 to-indigo-600">Terpopuler</span>
</h2>
<p class="text-gray-500 mt-2 max-w-md mx-auto md:mx-0">
Koleksi buku favorit yang paling banyak dipinjam oleh para pengunjung perpustakaan kami.
</p>
</div>
</div>
<div class="grid grid-cols-2 lg:grid-cols-5 md:grid-cols-3 gap-6">
@foreach($bukuPopuler as $item)
@php
$habis = ($item->eksemplar <= 0);
@endphp
<div 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 relative">
<div class="grid grid-cols-2 lg:grid-cols-5 md:grid-cols-3 gap-6">
@foreach ($bukuPopuler as $item)
@php
$habis = $item->eksemplar <= 0;
@endphp
<div
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 relative">
<!-- Peminjaman Count Badge -->
<div class="absolute top-2 left-2 z-20">
<span class="bg-blue-600/90 backdrop-blur-md text-white text-[10px] sm:text-xs font-bold px-2 py-1 rounded shadow-sm flex items-center gap-1">
<i class="fas fa-book-reader"></i> {{ $item->peminjaman_count }}x
</span>
</div>
<!-- Book Cover -->
<div class="relative w-full pt-[140%] overflow-hidden bg-gray-50 flex-shrink-0">
@if($item->cover ?? $item->sampul)
<img src="{{ asset('storage/' . ($item->cover ?? $item->sampul)) }}" 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">
@else
<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">
<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">No Cover</span>
<!-- Peminjaman Count Badge -->
<div class="absolute top-2 left-2 z-20">
<span
class="bg-blue-600/90 backdrop-blur-md text-white text-[10px] sm:text-xs font-bold px-2 py-1 rounded shadow-sm flex items-center gap-1">
<i class="fas fa-book-reader"></i> {{ $item->peminjaman_count }}x
</span>
</div>
@endif
@if($habis)
<!-- Overlay Dipinjam Semua -->
<div class="absolute inset-0 bg-red-900/30 backdrop-blur-[1px] flex items-center justify-center z-10">
<div class="bg-red-600/90 text-white font-black text-sm md:text-base px-2 py-2 border-y-2 border-white transform -rotate-12 shadow-2xl tracking-widest uppercase pointer-events-none text-center">
TIDAK TERSEDIA
<!-- Book Cover -->
<div class="relative w-full pt-[140%] overflow-hidden bg-gray-50 flex-shrink-0">
@if ($item->cover ?? $item->sampul)
<img src="{{ asset('storage/' . ($item->cover ?? $item->sampul)) }}"
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">
@else
<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">
<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">No Cover</span>
</div>
@endif
@if ($habis)
<!-- Overlay Dipinjam Semua -->
<div
class="absolute inset-0 bg-red-900/30 backdrop-blur-[1px] flex items-center justify-center z-10">
<div
class="bg-red-600/90 text-white font-black text-sm md:text-base px-2 py-2 border-y-2 border-white transform -rotate-12 shadow-2xl tracking-widest uppercase pointer-events-none text-center">
TIDAK TERSEDIA
</div>
</div>
@endif
<div class="absolute top-2 right-2 flex justify-between items-start z-10">
<span
class="bg-white/90 backdrop-blur-md text-gray-800 text-[10px] sm:text-xs font-bold px-2 py-1 rounded shadow-sm">
{{ $item->nomor_panggil ?? '-' }}
</span>
</div>
</div>
@endif
<div class="absolute top-2 right-2 flex justify-between items-start z-10">
<span class="bg-white/90 backdrop-blur-md text-gray-800 text-[10px] sm:text-xs font-bold px-2 py-1 rounded shadow-sm">
{{ $item->nomor_panggil ?? '-' }}
</span>
</div>
</div>
<!-- Content -->
<div class="p-4 flex-grow flex flex-col">
<h2 class="text-xs sm:text-sm font-bold text-gray-900 mb-1 line-clamp-2 {{ !$habis ? 'group-hover:text-blue-600 transition-colors' : '' }} leading-snug"
title="{{ $item->judul }}">
{{ $item->judul }}
</h2>
<p class="text-blue-600 font-medium text-[10px] sm:text-xs mb-2 line-clamp-1">
{{ $item->pengarang }}
</p>
<div class="mt-auto pt-3 flex flex-col gap-2 border-t border-gray-50">
<div class="flex justify-between items-center text-[10px] text-gray-500">
<span class="truncate pr-1">{{ $item->penerbit }}</span>
<span
class="font-medium bg-gray-100 px-1.5 py-0.5 rounded">{{ $item->tahun_terbit ?? '-' }}</span>
</div>
</div>
</div>
<!-- Content -->
<div class="p-4 flex-grow flex flex-col">
<h2 class="text-xs sm:text-sm font-bold text-gray-900 mb-1 line-clamp-2 {{ !$habis ? 'group-hover:text-blue-600 transition-colors' : '' }} leading-snug" title="{{ $item->judul }}">
{{ $item->judul }}
</h2>
<p class="text-blue-600 font-medium text-[10px] sm:text-xs mb-2 line-clamp-1">
{{ $item->pengarang }}
</p>
<div class="mt-auto pt-3 flex flex-col gap-2 border-t border-gray-50">
<div class="flex justify-between items-center text-[10px] text-gray-500">
<span class="truncate pr-1">{{ $item->penerbit }}</span>
<span class="font-medium bg-gray-100 px-1.5 py-0.5 rounded">{{ $item->tahun_terbit ?? '-' }}</span>
<!-- Action Area -->
<div class="px-4 pb-4 pt-0 mt-auto relative z-30">
@if ($habis)
<button disabled
class="w-full text-center bg-gray-100 text-gray-500 text-xs font-semibold py-2 px-3 rounded-xl border border-gray-200 cursor-not-allowed opacity-80 backdrop-blur-sm">
Habis Dipinjam
</button>
@else
<a href="{{ route('katalog.show', $item->id ?? 1) }}"
class="block w-full text-center bg-gray-50 hover:bg-blue-600 text-gray-700 hover:text-white text-xs font-semibold py-2 px-3 rounded-xl border border-gray-200 hover:border-transparent transition-all duration-300">
Lihat Detail
</a>
@endif
</div>
</div>
</div>
<!-- Action Area -->
<div class="px-4 pb-4 pt-0 mt-auto relative z-30">
@if($habis)
<button disabled class="w-full text-center bg-gray-100 text-gray-500 text-xs font-semibold py-2 px-3 rounded-xl border border-gray-200 cursor-not-allowed opacity-80 backdrop-blur-sm">
Habis Dipinjam
</button>
@else
<a href="{{ route('katalog.show', $item->id_buku ?? 1) }}" class="block w-full text-center bg-gray-50 hover:bg-blue-600 text-gray-700 hover:text-white text-xs font-semibold py-2 px-3 rounded-xl border border-gray-200 hover:border-transparent transition-all duration-300">
Lihat Detail
</a>
@endif
</div>
@endforeach
</div>
@endforeach
</div>
</div>
@endif
</div>
</section>

View File

@ -16,85 +16,102 @@
Buku-buku rilis baru dan penambahan paling anyar di perpustakaan kami.
</p>
</div>
<a href="{{ route('katalog.index') }}" class="px-6 py-3 bg-white text-primary-600 rounded-2xl font-semibold text-sm border border-primary-200 hover:bg-primary-50 transition-colors shadow-sm inline-flex items-center gap-2">
<a href="{{ route('katalog.index') }}"
class="px-6 py-3 bg-white text-primary-600 rounded-2xl font-semibold text-sm border border-primary-200 hover:bg-primary-50 transition-colors shadow-sm inline-flex items-center gap-2">
Lihat Semua Katalog <i class="fas fa-arrow-right text-xs"></i>
</a>
</div>
@if(!empty($bukuTerbaru) && $bukuTerbaru->count())
@if (!empty($bukuTerbaru) && $bukuTerbaru->count())
<div class="grid grid-cols-2 md:grid-cols-4 gap-6">
@foreach($bukuTerbaru as $item)
@php
$habis = ($item->eksemplar <= 0);
@endphp
<div 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 relative">
<!-- Badge BUKU BARU (Pojok Kanan Atas Kartu) -->
@if(!$habis)
<div class="absolute top-0 right-0 z-20">
<div class="bg-gradient-to-r from-yellow-400 to-orange-500 text-white text-[9px] sm:text-[10px] font-extrabold px-3 py-1.5 shadow-lg rounded-bl-xl origin-top-right transform">
<i class="fas fa-sparkles mr-1"></i> BUKU BARU
</div>
</div>
@endif
<!-- Book Cover -->
<div class="relative w-full pt-[140%] overflow-hidden bg-gray-50 flex-shrink-0">
@if($item->cover ?? $item->sampul)
<img src="{{ asset('storage/' . ($item->cover ?? $item->sampul)) }}" 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">
@else
<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">
<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>
@endif
@if($habis)
<!-- Overlay Dipinjam Semua -->
<div class="absolute inset-0 bg-red-900/30 backdrop-blur-[1px] flex items-center justify-center z-10">
<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">
TIDAK TERSEDIA
@foreach ($bukuTerbaru as $item)
@php
$habis = $item->eksemplar <= 0;
@endphp
<div
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 relative">
<!-- Badge BUKU BARU (Pojok Kanan Atas Kartu) -->
@if (!$habis)
<div class="absolute top-0 right-0 z-20">
<div
class="bg-gradient-to-r from-yellow-400 to-orange-500 text-white text-[9px] sm:text-[10px] font-extrabold px-3 py-1.5 shadow-lg rounded-bl-xl origin-top-right transform">
<i class="fas fa-sparkles mr-1"></i> BUKU BARU
</div>
</div>
@endif
<!-- Overlay Badges (Nomor Panggil) -->
<div class="absolute top-2 inset-x-2 flex justify-between items-start z-10">
<span class="bg-white/90 backdrop-blur-md text-gray-800 text-[10px] sm:text-xs font-bold px-2 py-1 rounded shadow-sm">
{{ $item->nomor_panggil ?? '-' }}
</span>
</div>
</div>
<!-- Book Cover -->
<div class="relative w-full pt-[140%] overflow-hidden bg-gray-50 flex-shrink-0">
@if ($item->cover ?? $item->sampul)
<img src="{{ asset('storage/' . ($item->cover ?? $item->sampul)) }}"
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">
@else
<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">
<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>
@endif
<!-- Content -->
<div class="p-4 flex-grow flex flex-col">
<h2 class="text-sm sm:text-base font-bold text-gray-900 mb-1 line-clamp-2 {{ !$habis ? 'group-hover:text-blue-600 transition-colors' : '' }} leading-snug" title="{{ $item->judul }}">
{{ $item->judul }}
</h2>
<p class="text-blue-600 font-medium text-xs sm:text-sm mb-2 line-clamp-1">
{{ $item->pengarang }}
</p>
<div class="mt-auto pt-3 flex flex-col gap-2 border-t border-gray-50">
<div class="flex justify-between items-center text-[10px] sm:text-xs text-gray-500">
<span class="truncate pr-1">{{ $item->penerbit }}</span>
<span class="font-medium bg-gray-100 px-1.5 py-0.5 rounded">{{ $item->tahun_terbit ?? '-' }}</span>
@if ($habis)
<!-- Overlay Dipinjam Semua -->
<div
class="absolute inset-0 bg-red-900/30 backdrop-blur-[1px] flex items-center justify-center z-10">
<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">
TIDAK TERSEDIA
</div>
</div>
@endif
<!-- Overlay Badges (Nomor Panggil) -->
<div class="absolute top-2 inset-x-2 flex justify-between items-start z-10">
<span
class="bg-white/90 backdrop-blur-md text-gray-800 text-[10px] sm:text-xs font-bold px-2 py-1 rounded shadow-sm">
{{ $item->nomor_panggil ?? '-' }}
</span>
</div>
</div>
</div>
<!-- Action Area -->
<div class="px-4 pb-4 pt-0 mt-auto relative z-30">
@if($habis)
<button disabled class="w-full text-center bg-gray-100 text-gray-500 text-sm font-semibold py-2 px-3 rounded-xl border border-gray-200 cursor-not-allowed opacity-80 backdrop-blur-sm">
Habis Dipinjam
</button>
@else
<a href="{{ route('katalog.show', $item->id_buku ?? 1) }}" class="block w-full text-center bg-gray-50 hover:bg-blue-600 text-gray-700 hover:text-white text-sm font-semibold py-2 px-3 rounded-xl border border-gray-200 hover:border-transparent transition-all duration-300">
Lihat Detail
</a>
@endif
<!-- Content -->
<div class="p-4 flex-grow flex flex-col">
<h2 class="text-sm sm:text-base font-bold text-gray-900 mb-1 line-clamp-2 {{ !$habis ? 'group-hover:text-blue-600 transition-colors' : '' }} leading-snug"
title="{{ $item->judul }}">
{{ $item->judul }}
</h2>
<p class="text-blue-600 font-medium text-xs sm:text-sm mb-2 line-clamp-1">
{{ $item->pengarang }}
</p>
<div class="mt-auto pt-3 flex flex-col gap-2 border-t border-gray-50">
<div class="flex justify-between items-center text-[10px] sm:text-xs text-gray-500">
<span class="truncate pr-1">{{ $item->penerbit }}</span>
<span
class="font-medium bg-gray-100 px-1.5 py-0.5 rounded">{{ $item->tahun_terbit ?? '-' }}</span>
</div>
</div>
</div>
<!-- Action Area -->
<div class="px-4 pb-4 pt-0 mt-auto relative z-30">
@if ($habis)
<button disabled
class="w-full text-center bg-gray-100 text-gray-500 text-sm font-semibold py-2 px-3 rounded-xl border border-gray-200 cursor-not-allowed opacity-80 backdrop-blur-sm">
Habis Dipinjam
</button>
@else
<a href="{{ route('katalog.show', $item->id ?? 1) }}"
class="block w-full text-center bg-gray-50 hover:bg-blue-600 text-gray-700 hover:text-white text-sm font-semibold py-2 px-3 rounded-xl border border-gray-200 hover:border-transparent transition-all duration-300">
Lihat Detail
</a>
@endif
</div>
</div>
</div>
@endforeach
</div>
@else