diff --git a/.htaccess b/.htaccess
new file mode 100644
index 0000000..518f05e
--- /dev/null
+++ b/.htaccess
@@ -0,0 +1,26 @@
+
+ RewriteEngine On
+ RewriteBase /E31230887/
+
+ # 1. Handle Storage (Internal Rewrite)
+ # Mapping /storage/... ke /public/storage/... secara internal
+ RewriteRule ^storage/(.*)$ public/storage/$1 [L]
+
+ # 2. Handle Other Static Assets (img, build, images, favicon, robots.txt)
+ # Menghindari redirect R=302 agar URL tetap bersih tanpa /public/
+ RewriteCond %{REQUEST_URI} !^/E31230887/public/
+ RewriteRule ^(img|build|images|favicon\.ico|robots\.txt)(.*)$ public/$1$2 [L]
+
+ # 3. Handle Laravel Front Controller
+ # Jika file fisik tidak ada, lempar ke index.php
+ RewriteCond %{REQUEST_FILENAME} !-f
+ RewriteCond %{REQUEST_FILENAME} !-d
+ RewriteRule ^ index.php [L]
+
+
+Options -Indexes
+
+
+ Order allow,deny
+ Deny from all
+
diff --git a/app/Http/Controllers/AdminBukuController.php b/app/Http/Controllers/AdminBukuController.php
index 845181a..cf74ded 100644
--- a/app/Http/Controllers/AdminBukuController.php
+++ b/app/Http/Controllers/AdminBukuController.php
@@ -117,41 +117,41 @@ private function tentukanKoordinatRak($nomor_panggil)
return match (true) {
$kode_utama >= 0 && $kode_utama <= 99 => match (true) {
- $kode_utama <= 19 => ['x' => 13.00, 'y' => 22.00], // Rak 01
- $kode_utama <= 50 => ['x' => 18.00, 'y' => 22.00], // Rak 02
- default => ['x' => 25.00, 'y' => 22.00], // Rak 03-05
+ $kode_utama <= 19 => ['x' => 12.00, 'y' => 13.00], // Rak 01
+ $kode_utama <= 50 => ['x' => 17.00, 'y' => 13.00], // Rak 02
+ default => ['x' => 22.00, 'y' => 13.00], // Rak 03-05
},
$kode_utama >= 100 && $kode_utama <= 199 => match (true) {
- $kode_utama <= 150 => ['x' => 43.00, 'y' => 20.00], // Rak 06-10
- default => ['x' => 57.00, 'y' => 20.00], // Rak 11-14
+ $kode_utama <= 150 => ['x' => 35.00, 'y' => 13.00], // Rak 06-10
+ default => ['x' => 35.00, 'y' => 17.00], // Rak 11-14
},
$kode_utama >= 200 && $kode_utama <= 299 => match (true) {
- $kode_utama == 297 => ['x' => 25.00, 'y' => 38.00], // Rak 25-32 (Islam)
- default => ['x' => 13.00, 'y' => 38.00], // Rak 15-24
+ $kode_utama == 297 => ['x' => 14.00, 'y' => 38.00], // Rak 25-32 (Islam)
+ default => ['x' => 14.00, 'y' => 30.00], // Rak 15-24
},
$kode_utama >= 300 && $kode_utama <= 399 => match (true) {
- $kode_utama <= 330 => ['x' => 43.00, 'y' => 30.00], // Rak 33-36
- $kode_utama <= 360 => ['x' => 50.00, 'y' => 30.00], // Rak 37-40
- default => ['x' => 57.00, 'y' => 30.00], // Rak 41-44
+ $kode_utama <= 330 => ['x' => 38.00, 'y' => 23.00], // Rak 33-36
+ $kode_utama <= 360 => ['x' => 43.00, 'y' => 23.00], // Rak 37-40
+ default => ['x' => 48.00, 'y' => 23.00], // Rak 41-44
},
- $kode_utama >= 400 && $kode_utama <= 499 => ['x' => 18.00, 'y' => 62.00], // Rak 45
- $kode_utama >= 500 && $kode_utama <= 599 => ['x' => 50.00, 'y' => 74.00], // Rak 46-48
+ $kode_utama >= 400 && $kode_utama <= 499 => ['x' => 14.00, 'y' => 58.00], // Rak 45
+ $kode_utama >= 500 && $kode_utama <= 599 => ['x' => 38.00, 'y' => 72.00], // Rak 46-48
$kode_utama >= 600 && $kode_utama <= 699 => match (true) {
- $kode_utama <= 610 => ['x' => 35.00, 'y' => 85.00], // Rak 49-53
- $kode_utama <= 630 => ['x' => 45.00, 'y' => 85.00], // Rak 54-58
- $kode_utama <= 650 => ['x' => 55.00, 'y' => 85.00], // Rak 59-63
- default => ['x' => 65.00, 'y' => 85.00], // Rak 64-68
+ $kode_utama <= 610 => ['x' => 28.00, 'y' => 83.00], // Rak 49-53
+ $kode_utama <= 630 => ['x' => 36.00, 'y' => 83.00], // Rak 54-58
+ $kode_utama <= 650 => ['x' => 44.00, 'y' => 83.00], // Rak 59-63
+ default => ['x' => 52.00, 'y' => 83.00], // Rak 64-68
},
$kode_utama >= 700 && $kode_utama <= 799 => match (true) {
- $kode_utama <= 739 => ['x' => 77.00, 'y' => 22.00], // Rak 71
- $kode_utama <= 769 => ['x' => 82.00, 'y' => 22.00], // Rak 72
- $kode_utama <= 789 => ['x' => 87.00, 'y' => 22.00], // Rak 73
- default => ['x' => 82.00, 'y' => 22.00], // Rak 74
+ $kode_utama <= 739 => ['x' => 82.00, 'y' => 12.00], // Rak 71
+ $kode_utama <= 769 => ['x' => 86.00, 'y' => 12.00], // Rak 72
+ $kode_utama <= 789 => ['x' => 82.00, 'y' => 16.00], // Rak 73
+ default => ['x' => 86.00, 'y' => 16.00], // Rak 74
},
- $kode_utama >= 800 && $kode_utama <= 899 => ['x' => 82.00, 'y' => 32.00], // Rak 77-79
+ $kode_utama >= 800 && $kode_utama <= 899 => ['x' => 82.00, 'y' => 25.00], // Rak 77-79
$kode_utama >= 900 && $kode_utama <= 999 => match (true) {
- $kode_utama <= 919 => ['x' => 77.00, 'y' => 42.00], // Rak 69-70
- default => ['x' => 87.00, 'y' => 42.00], // Rak 80-84
+ $kode_utama <= 919 => ['x' => 82.00, 'y' => 30.00], // Rak 69-70
+ default => ['x' => 82.00, 'y' => 35.00], // Rak 80-84
},
default => ['x' => null, 'y' => null],
};
diff --git a/app/Http/Controllers/AdminPeminjamanController.php b/app/Http/Controllers/AdminPeminjamanController.php
index 702460a..9f2c8f5 100644
--- a/app/Http/Controllers/AdminPeminjamanController.php
+++ b/app/Http/Controllers/AdminPeminjamanController.php
@@ -58,84 +58,49 @@ public function store(Request $request)
$validated = $request->validate([
'id_anggota' => 'required|exists:anggotas,id',
'id_buku' => 'required|exists:buku,id_buku',
+ 'id_buku_2' => 'nullable|exists:buku,id_buku|different:id_buku',
'tanggal_pinjam' => 'required|date_format:Y-m-d|after_or_equal:2000-01-01|before_or_equal:2100-12-31',
'tanggal_kembali' => 'required|date_format:Y-m-d|after_or_equal:tanggal_pinjam|before_or_equal:2100-12-31',
]);
- $validated['status_peminjaman'] = 'Dipinjam';
+ $status = 'Dipinjam';
- // 2. Kurangi Stok Buku
- $buku = Buku::findOrFail($validated['id_buku']);
- $buku->decrement('eksemplar');
+ // 2. Kurangi Stok Buku Pertama & Simpan
+ $buku1 = Buku::findOrFail($validated['id_buku']);
+ $buku1->decrement('eksemplar');
- // 3. Simpan ke Database
- $peminjaman = Peminjaman::create($validated);
- $peminjaman->load(['buku', 'anggota']);
+ $peminjaman1 = Peminjaman::create([
+ 'id_anggota' => $validated['id_anggota'],
+ 'id_buku' => $validated['id_buku'],
+ 'tanggal_pinjam' => $validated['tanggal_pinjam'],
+ 'tanggal_kembali' => $validated['tanggal_kembali'],
+ 'status_peminjaman' => $status,
+ ]);
+ $peminjaman1->load(['buku', 'anggota']);
- $waSuccess = false;
+ $waSuccess = $this->kirimWaPeminjaman($peminjaman1, false);
- // 4. Proses Kirim WA (Format Struk Teks Resmi)
- try {
- $targetNum = $peminjaman->anggota->no_hp ?? '';
- $fonnteToken = 'vpzqxF2ZGgTGz9F5UbUS'; // Token Fonnte
+ // 3. Proses Buku Kedua (Opsional)
+ if (!empty($validated['id_buku_2'])) {
+ $buku2 = Buku::findOrFail($validated['id_buku_2']);
+ $buku2->decrement('eksemplar');
- // Standarisasi Format Nomor ke awalan 62
- if (!empty($targetNum)) {
- $targetNum = preg_replace('/^0/', '62', trim($targetNum));
+ $peminjaman2 = Peminjaman::create([
+ 'id_anggota' => $validated['id_anggota'],
+ 'id_buku' => $validated['id_buku_2'],
+ 'tanggal_pinjam' => $validated['tanggal_pinjam'],
+ 'tanggal_kembali' => $validated['tanggal_kembali'],
+ 'status_peminjaman' => $status,
+ ]);
+ $peminjaman2->load(['buku', 'anggota']);
+
+ $wa2Success = $this->kirimWaPeminjaman($peminjaman2, false);
+ if ($wa2Success) {
+ $waSuccess = true;
}
-
- if (!empty($targetNum) && !empty($fonnteToken)) {
- // Merangkai Teks Menyerupai Struk Kertas
- $pesanStruk = "🏢 *PERPUSTAKAAN DAERAH JEMBER*\n";
- $pesanStruk .= "Jl. Mastrip No. 1, Kabupaten Jember\n";
- $pesanStruk .= "===============================\n\n";
- $pesanStruk .= "📄 *BUKTI PEMINJAMAN BUKU*\n";
- $pesanStruk .= "No. Transaksi : PMJ-{$peminjaman->id_peminjaman}\n";
- $pesanStruk .= "Tanggal Cetak : " . \Carbon\Carbon::now()->format('d-m-Y H:i') . "\n\n";
- $pesanStruk .= "*DATA PEMINJAM*\n";
- $pesanStruk .= "Nama : {$peminjaman->anggota->nama}\n";
- $pesanStruk .= "No. HP : {$peminjaman->anggota->no_hp}\n\n";
- $pesanStruk .= "*DETAIL BUKU*\n";
- $pesanStruk .= "Judul : {$peminjaman->buku->judul}\n";
- $pesanStruk .= "Kode Pengembalian : {$peminjaman->buku->bibid}\n";
- $pesanStruk .= "Pinjam : " . \Carbon\Carbon::parse($peminjaman->tanggal_pinjam)->format('d F Y') . "\n";
- $pesanStruk .= "Kembali: *" . \Carbon\Carbon::parse($peminjaman->tanggal_kembali)->format('d F Y') . "*\n\n";
- $pesanStruk .= "===============================\n";
- $pesanStruk .= "⚠️ *Catatan:*\n";
- $pesanStruk .= "Tunjukkan Kode Pengembalian ke Admin saat pengembalian buku.\n";
- $pesanStruk .= "Harap kembalikan buku tepat waktu.\n";
- $pesanStruk .= "Denda keterlambatan: Rp 1.000/hari.\n\n";
- $pesanStruk .= "Terima kasih atas kunjungan Anda!\n";
- $pesanStruk .= "_Sistem Sarakata - TA 2026_";
-
- // Eksekusi Pengiriman via Http Laravel
- $response = \Illuminate\Support\Facades\Http::withoutVerifying()->timeout(15)->withHeaders([
- 'Authorization' => $fonnteToken,
- ])->post('https://api.fonnte.com/send', [
- 'target' => $targetNum,
- 'message' => $pesanStruk,
- ]);
-
- if ($response->successful() && ($response->json('status') == true)) {
- $waSuccess = true;
- } else {
- \Illuminate\Support\Facades\Log::warning("Fonnte Log: Gagal Terkirim", [
- 'target' => $targetNum,
- 'http_status' => $response->status(),
- 'body' => $response->body()
- ]);
- }
- } else {
- \Illuminate\Support\Facades\Log::warning('Fonnte Log: Token / No HP kosong', [
- 'target' => $targetNum ?? 'kosong',
- 'token_set' => !empty($fonnteToken),
- ]);
- }
- } catch (\Exception $e) {
- \Illuminate\Support\Facades\Log::error("Error WA Pengiriman: " . $e->getMessage());
}
- // 5. Notifikasi Kembali ke Layar Admin
+ // 4. Notifikasi Kembali ke Layar Admin
$msg = 'Transaksi peminjaman berhasil dicatat.';
if ($waSuccess) {
$msg .= ' Struk WA berhasil terkirim kepada Anggota.';
@@ -310,6 +275,16 @@ public function resendWa($id)
{
$peminjaman = Peminjaman::with(['buku', 'anggota'])->findOrFail($id);
+ $success = $this->kirimWaPeminjaman($peminjaman, true);
+ if ($success) {
+ return back()->with('success', 'Struk WhatsApp berhasil dikirim ulang ke nomor ' . $peminjaman->anggota->no_hp);
+ } else {
+ return back()->with('error', 'Gagal mengirim ulang WA. Silakan cek log Fonnte.');
+ }
+ }
+
+ private function kirimWaPeminjaman($peminjaman, $isSalinan = false)
+ {
try {
$targetNum = $peminjaman->anggota->no_hp ?? '';
$fonnteToken = env('FONNTE_TOKEN', 'vpzqxF2ZGgTGz9F5UbUS');
@@ -319,10 +294,12 @@ public function resendWa($id)
}
if (!empty($targetNum) && !empty($fonnteToken)) {
+ $tipeStruk = $isSalinan ? "SALINAN BUKTI PEMINJAMAN" : "BUKTI PEMINJAMAN BUKU";
+
$pesanStruk = "🏢 *PERPUSTAKAAN DAERAH JEMBER*\n";
$pesanStruk .= "Jl. Mastrip No. 1, Kabupaten Jember\n";
$pesanStruk .= "===============================\n\n";
- $pesanStruk .= "📄 *SALINAN BUKTI PEMINJAMAN*\n";
+ $pesanStruk .= "📄 *{$tipeStruk}*\n";
$pesanStruk .= "No. Transaksi : PMJ-{$peminjaman->id_peminjaman}\n";
$pesanStruk .= "Tanggal Cetak : " . \Carbon\Carbon::now()->format('d-m-Y H:i') . "\n\n";
$pesanStruk .= "*DATA PEMINJAM*\n";
@@ -330,12 +307,12 @@ public function resendWa($id)
$pesanStruk .= "No. HP : {$peminjaman->anggota->no_hp}\n\n";
$pesanStruk .= "*DETAIL BUKU*\n";
$pesanStruk .= "Judul : {$peminjaman->buku->judul}\n";
- $pesanStruk .= "Kode Panggil : {$peminjaman->buku->bibid}\n";
+ $pesanStruk .= "Kode Pengembalian : {$peminjaman->buku->bibid}\n";
$pesanStruk .= "Pinjam : " . \Carbon\Carbon::parse($peminjaman->tanggal_pinjam)->format('d F Y') . "\n";
$pesanStruk .= "Kembali: *" . \Carbon\Carbon::parse($peminjaman->tanggal_kembali)->format('d F Y') . "*\n\n";
$pesanStruk .= "===============================\n";
$pesanStruk .= "⚠️ *Catatan:*\n";
- $pesanStruk .= "Tunjukkan Kode Panggil ke Admin saat pengembalian buku.\n";
+ $pesanStruk .= "Tunjukkan Kode Pengembalian ke Admin saat pengembalian buku.\n";
$pesanStruk .= "Harap kembalikan buku tepat waktu.\n";
$pesanStruk .= "Denda keterlambatan: Rp 1.000/hari.\n\n";
$pesanStruk .= "Terima kasih atas kunjungan Anda!\n";
@@ -349,17 +326,18 @@ public function resendWa($id)
]);
if ($response->successful() && ($response->json('status') == true)) {
- return back()->with('success', 'Struk WhatsApp berhasil dikirim ulang ke nomor ' . $targetNum);
+ return true;
} else {
- \Illuminate\Support\Facades\Log::warning("Fonnte Log: Gagal Terkirim Ulang", ['body' => $response->body()]);
- return back()->with('error', 'Gagal mengirim ulang WA. API Fonnte menolak koneksi (Status: '.$response->status().').');
+ \Illuminate\Support\Facades\Log::warning("Fonnte Log: Gagal Terkirim", [
+ 'target' => $targetNum,
+ 'http_status' => $response->status(),
+ 'body' => $response->body()
+ ]);
}
- } else {
- return back()->with('error', 'Nomor HP anggota kosong atau Token Fonnte belum dikonfigurasi.');
}
} catch (\Exception $e) {
- \Illuminate\Support\Facades\Log::error("Error WA Pengiriman Ulang: " . $e->getMessage());
- return back()->with('error', 'Terjadi kesalahan sistem saat menghubungi server WhatsApp.');
+ \Illuminate\Support\Facades\Log::error("Error WA Pengiriman: " . $e->getMessage());
}
+ return false;
}
}
diff --git a/app/Http/Controllers/LaporanController.php b/app/Http/Controllers/LaporanController.php
index 27e56da..fb04f2d 100644
--- a/app/Http/Controllers/LaporanController.php
+++ b/app/Http/Controllers/LaporanController.php
@@ -8,23 +8,85 @@
class LaporanController extends Controller
{
- public function kehadiran()
+ public function kehadiran(Request $request)
{
- $bukuTamu = BukuTamu::with('user')
- ->orderBy('tanggal_kunjungan', 'desc')
- ->get();
+ $query = BukuTamu::with('user')->orderBy('tanggal_kunjungan', 'desc');
+
+ // Filter Bulan & Tahun
+ if ($request->filled('bulan')) {
+ $query->whereMonth('tanggal_kunjungan', $request->input('bulan'));
+ }
+ if ($request->filled('tahun')) {
+ $query->whereYear('tanggal_kunjungan', $request->input('tahun'));
+ }
+
+ $bukuTamu = $query->get();
+
+ // Slice data berdasarkan rentang baris (Limit Cetak)
+ if ($request->filled('limit_start') || $request->filled('limit_end')) {
+ $start = $request->filled('limit_start') ? (int)$request->input('limit_start') : 1;
+ $offset = max(0, $start - 1);
+ if ($request->filled('limit_end')) {
+ $end = (int)$request->input('limit_end');
+ $length = max(0, $end - $offset);
+ $bukuTamu = $bukuTamu->slice($offset, $length);
+ } else {
+ $bukuTamu = $bukuTamu->slice($offset);
+ }
+ }
return view('laporan.kehadiran', compact('bukuTamu'));
}
public function peminjaman(Request $request)
{
- $query = Peminjaman::with(['anggota', 'user', 'buku'])->orderBy('tanggal_pinjam', 'desc');
+ $query = Peminjaman::with(['anggota', 'user', 'buku.kategori'])->orderBy('tanggal_pinjam', 'desc');
- // Optional filtering by month/year if needed (can be added later)
+ // 1. Filter Bulan & Tahun
+ if ($request->filled('bulan')) {
+ $query->whereMonth('tanggal_pinjam', $request->input('bulan'));
+ }
+ if ($request->filled('tahun')) {
+ $query->whereYear('tanggal_pinjam', $request->input('tahun'));
+ }
+
+ // 2. Filter Kategori Buku (Berdasarkan DDC / Nomor Panggil)
+ if ($request->filled('id_kategori')) {
+ $classDigit = $request->input('id_kategori'); // '0', '1', ..., '9'
+ $query->whereHas('buku', function ($q) use ($classDigit) {
+ $q->where('nomor_panggil', 'like', "{$classDigit}%");
+ });
+ }
$peminjaman = $query->get();
- return view('laporan.peminjaman', compact('peminjaman'));
+ // Slice data berdasarkan rentang baris (Limit Cetak)
+ if ($request->filled('limit_start') || $request->filled('limit_end')) {
+ $start = $request->filled('limit_start') ? (int)$request->input('limit_start') : 1;
+ $offset = max(0, $start - 1);
+ if ($request->filled('limit_end')) {
+ $end = (int)$request->input('limit_end');
+ $length = max(0, $end - $offset);
+ $peminjaman = $peminjaman->slice($offset, $length);
+ } else {
+ $peminjaman = $peminjaman->slice($offset);
+ }
+ }
+
+ // Kategori berdasarkan DDC & Lokasi Rak sesuai permintaan user
+ $categories = [
+ '0' => '000-099 : Karya Umum (Rak 01-05)',
+ '1' => '100-199 : Filsafat & Psikologi (Rak 06-14)',
+ '2' => '200-299 : Agama (Rak 15-32)',
+ '3' => '300-399 : Ilmu Sosial (Rak 33-44)',
+ '4' => '400-499 : Bahasa (Rak 45)',
+ '5' => '500-599 : Ilmu Murni / Sains (Rak 46-48)',
+ '6' => '600-699 : Ilmu Terapan (Rak 49-68)',
+ '7' => '700-799 : Kesenian & Olahraga (Rak 71-74)',
+ '8' => '800-899 : Sastra (Rak 77-79)',
+ '9' => '900-999 : Geografi & Sejarah (Rak 69-70, Rak 80-84)'
+ ];
+
+ return view('laporan.peminjaman', compact('peminjaman', 'categories'));
}
}
diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php
index 13b704d..1bcb398 100644
--- a/app/Providers/AppServiceProvider.php
+++ b/app/Providers/AppServiceProvider.php
@@ -7,20 +7,19 @@
class AppServiceProvider extends ServiceProvider
{
- /**
- * Register any application services.
- */
public function register(): void
{
//
}
- /**
- * Bootstrap any application services.
- */
public function boot(): void
{
Paginator::useTailwind();
- }
+ // Paksa URL Utama & HTTPS di Production untuk menjamin asset() & route() konsisten
+ if (config('app.env') !== 'local') {
+ \Illuminate\Support\Facades\URL::forceRootUrl(config('app.url'));
+ \Illuminate\Support\Facades\URL::forceScheme('https');
+ }
+ }
}
diff --git a/buat_link.php b/buat_link.php
new file mode 100644
index 0000000..4e2df68
--- /dev/null
+++ b/buat_link.php
@@ -0,0 +1,31 @@
+🔧 Memperbaiki Jembatan Storage (Symlink)";
+echo "
Target: $target
";
+echo "Link: $link
";
+
+if (file_exists($link)) {
+ echo "⚠️ Menghapus link/folder storage lama...
";
+ if (is_link($link)) {
+ unlink($link);
+ } else {
+ // Jika ternyata folder biasa (bukan link), kita amankan dengan ganti nama
+ rename($link, $link . '_backup_' . time());
+ }
+}
+
+if (symlink($target, $link)) {
+ echo "✅ Jembatan Storage Berhasil Dibuat!
";
+ echo "Sekarang gambar buku Anda seharusnya sudah muncul di website.
";
+ echo "Kembali ke Website";
+} else {
+ echo "❌ Gagal membuat jembatan symlink.
";
+ echo "Beberapa hosting membatasi fungsi symlink(). Jika ini terjadi, beri tahu asisten AI Anda untuk menggunakan metode .htaccess redirect.
";
+}
diff --git a/check_link.php b/check_link.php
new file mode 100644
index 0000000..baf174b
--- /dev/null
+++ b/check_link.php
@@ -0,0 +1,8 @@
+id();
- $table->string('bibid')->nullable();
- $table->string('judul');
- $table->string('edisi')->nullable();
- $table->string('pengarang');
- $table->string('penerbit');
- $table->year('tahun_terbit')->nullable();
- $table->text('deskripsi_fisik')->nullable();
- $table->string('nomor_panggil')->nullable();
- $table->string('konten_digital')->nullable();
- $table->integer('eksemplar')->default(1);
- $table->unsignedBigInteger('id_kategori')->nullable();
- $table->string('cover')->nullable();
- $table->float('lokasi_x')->nullable();
- $table->float('lokasi_y')->nullable();
- $table->timestamps();
- });
- }
-
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('bukus');
- }
-};
diff --git a/debug.php b/debug.php
new file mode 100644
index 0000000..ff0d8ac
--- /dev/null
+++ b/debug.php
@@ -0,0 +1,13 @@
+";
+echo "DOCUMENT_ROOT: " . $_SERVER['DOCUMENT_ROOT'] . "\n";
+echo "REQUEST_URI: " . $_SERVER['REQUEST_URI'] . "\n";
+echo "SCRIPT_FILENAME: " . $_SERVER['SCRIPT_FILENAME'] . "\n";
+echo "__DIR__: " . __DIR__ . "\n";
+echo "\n--- Cek keberadaan file ---\n";
+echo "img/denah.webp via __DIR__: " . (file_exists(__DIR__ . '/img/denah.webp') ? '✅ ADA' : '❌ TIDAK ADA') . "\n";
+echo "public/img/denah.webp via __DIR__: " . (file_exists(__DIR__ . '/public/img/denah.webp') ? '✅ ADA' : '❌ TIDAK ADA') . "\n";
+echo "DOCUMENT_ROOT/img/denah.webp: " . (file_exists($_SERVER['DOCUMENT_ROOT'] . '/img/denah.webp') ? '✅ ADA' : '❌ TIDAK ADA') . "\n";
+echo "DOCUMENT_ROOT/E31230887/img/denah.webp: " . (file_exists($_SERVER['DOCUMENT_ROOT'] . '/E31230887/img/denah.webp') ? '✅ ADA' : '❌ TIDAK ADA') . "\n";
+echo "";
diff --git a/index.php b/index.php
new file mode 100644
index 0000000..ffdc62c
--- /dev/null
+++ b/index.php
@@ -0,0 +1,4 @@
+
+
+
+
+
+
+
+
@@ -34,18 +59,29 @@ class="w-full border-gray-300 rounded-lg shadow-sm focus:border-blue-500 focus:r
-
-
-
+
+
+
+
+
+
+
+
+
@@ -83,5 +119,131 @@ class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-8 rounded-lg s
btn.innerHTML = 'Memproses...';
btn.classList.add('opacity-50', 'cursor-not-allowed');
});
+
+ let scanBuffer = "";
+ let lastKeyTime = Date.now();
+
+ // Global barcode scan detection
+ document.addEventListener('keypress', function(e) {
+ const target = e.target;
+
+ if (target.tagName === 'INPUT' && target.type !== 'submit' && target.type !== 'button' && target.type !== 'checkbox' && target.type !== 'radio') {
+ if (!target.classList.contains('ts-control') && !target.closest('.ts-wrapper')) {
+ return;
+ }
+ }
+ if (target.tagName === 'TEXTAREA' || target.tagName === 'SELECT') {
+ return;
+ }
+
+ const currentTime = Date.now();
+
+ if (currentTime - lastKeyTime > 100) {
+ scanBuffer = "";
+ }
+
+ lastKeyTime = currentTime;
+
+ if (e.key === 'Enter') {
+ if (scanBuffer.length >= 2) {
+ e.preventDefault();
+ const cleanCode = scanBuffer.trim();
+ handleGlobalScan(cleanCode);
+ scanBuffer = "";
+ }
+ } else {
+ if (e.key.length === 1) {
+ scanBuffer += e.key;
+ }
+ }
+ });
+
+ function handleGlobalScan(bibid) {
+ const select1 = document.getElementById('select-buku-peminjaman');
+ const select2 = document.getElementById('select-buku-peminjaman-2');
+
+ if (!select1) return;
+
+ function findVal(selectEl) {
+ const options = selectEl.options;
+ for (let i = 0; i < options.length; i++) {
+ if (options[i].getAttribute('data-bibid') === bibid) {
+ return { value: options[i].value, text: options[i].text };
+ }
+ }
+ return null;
+ }
+
+ const item = findVal(select1);
+ if (!item) {
+ Swal.fire({
+ icon: 'error',
+ title: 'Buku Tidak Ditemukan',
+ text: 'Kode buku "' + bibid + '" tidak terdaftar atau tidak tersedia.',
+ timer: 2000,
+ showConfirmButton: false,
+ toast: true,
+ position: 'top-end'
+ });
+ return;
+ }
+
+ let targetSelect = null;
+ if (select1.tomselect && !select1.tomselect.getValue()) {
+ targetSelect = select1;
+ } else if (select2 && select2.tomselect && !select2.tomselect.getValue()) {
+ targetSelect = select2;
+ } else {
+ targetSelect = select1;
+ }
+
+ if (targetSelect && targetSelect.tomselect) {
+ const otherSelect = (targetSelect === select1) ? select2 : select1;
+ if (otherSelect && otherSelect.tomselect && otherSelect.tomselect.getValue() === item.value) {
+ Swal.fire({
+ icon: 'warning',
+ title: 'Buku Sudah Dipilih',
+ text: 'Buku ini sudah dipilih pada slot lainnya.',
+ timer: 2000,
+ showConfirmButton: false,
+ toast: true,
+ position: 'top-end'
+ });
+ return;
+ }
+
+ targetSelect.tomselect.setValue(item.value);
+ Swal.fire({
+ icon: 'success',
+ title: 'Buku Berhasil Dipilih',
+ text: item.text,
+ timer: 1500,
+ showConfirmButton: false,
+ toast: true,
+ position: 'top-end'
+ });
+ }
+ }
+
+ document.addEventListener('DOMContentLoaded', function() {
+ // Initialize TomSelect for books
+ const ts1 = new TomSelect('#select-buku-peminjaman', { maxOptions: null });
+ const ts2 = new TomSelect('#select-buku-peminjaman-2', { maxOptions: null });
+
+ // Focus on first book dropdown
+ setTimeout(() => {
+ ts1.focus();
+ }, 100);
+
+ // Prevent Enter key from submitting form on text/select inputs
+ const forms = document.querySelectorAll('form');
+ forms.forEach(form => {
+ form.addEventListener('keydown', function(e) {
+ if (e.key === 'Enter' && e.target.tagName !== 'BUTTON' && e.target.type !== 'submit') {
+ e.preventDefault();
+ }
+ });
+ });
+ });
@endsection
diff --git a/resources/views/admin/peminjaman/index.blade.php b/resources/views/admin/peminjaman/index.blade.php
index acfb7e2..0587932 100644
--- a/resources/views/admin/peminjaman/index.blade.php
+++ b/resources/views/admin/peminjaman/index.blade.php
@@ -16,6 +16,16 @@
tanggal_pinjam: '{{ old('tanggal_pinjam') ?? '' }}',
tanggal_kembali: '{{ old('tanggal_kembali') ?? '' }}'
},
+ init() {
+ this.$watch('isModalPeminjamanOpen', value => {
+ if (value) {
+ setTimeout(() => {
+ const ts1 = document.getElementById('select-buku-peminjaman');
+ if (ts1 && ts1.tomselect) ts1.tomselect.focus();
+ }, 200);
+ }
+ });
+ },
openEditModal(id, anggotaId, buku, pinjam, kembali) {
this.editData = { id: id, id_anggota: anggotaId, id_buku: buku, tanggal_pinjam: pinjam, tanggal_kembali: kembali };
this.isModalEditOpen = true;
@@ -252,19 +262,34 @@ class="mt-1 block w-full border-gray-200 focus:border-indigo-500 focus:ring-indi
-
-
-
+
+
+
+
+
+
+
+
+
@@ -376,7 +401,7 @@ class="bg-green-50 text-green-700 p-3 rounded-lg text-center font-bold text-xs m
-