Memperbarui fitur Buku Tamu dan form Tambah Buku

This commit is contained in:
wardhatul1765 2026-05-05 02:42:52 +07:00
parent 70a420ae47
commit 077e2746f6
17 changed files with 286 additions and 148 deletions

View File

@ -20,11 +20,11 @@ public function store(Request $request)
'bibid' => 'required|string|max:30|unique:buku,bibid', 'bibid' => 'required|string|max:30|unique:buku,bibid',
'judul' => 'required|string', 'judul' => 'required|string',
'pengarang' => 'required|string|max:100', 'pengarang' => 'required|string|max:100',
'penerbit' => 'nullable|string', 'penerbit' => 'required|string',
'tahun_terbit' => 'nullable|digits:4', 'tahun_terbit' => 'required|digits:4',
'edisi' => 'nullable|string|max:50', 'edisi' => 'required|digits:4',
'deskripsi_fisik' => 'nullable|string|max:100', 'deskripsi_fisik' => 'required|string|max:100',
'nomor_panggil' => 'required|string|max:50', 'nomor_panggil' => 'required|string|max:50|unique:buku,nomor_panggil',
'eksemplar' => 'required|integer|min:1', 'eksemplar' => 'required|integer|min:1',
'id_kategori' => 'required|exists:kategori,id_kategori', 'id_kategori' => 'required|exists:kategori,id_kategori',
'cover' => 'image|mimes:jpeg,png,jpg,webp|max:2048', 'cover' => 'image|mimes:jpeg,png,jpg,webp|max:2048',
@ -71,11 +71,11 @@ public function update(Request $request, $id)
'bibid' => 'required|string|max:30|unique:buku,bibid,' . $id . ',id_buku', 'bibid' => 'required|string|max:30|unique:buku,bibid,' . $id . ',id_buku',
'judul' => 'required|string', 'judul' => 'required|string',
'pengarang' => 'required|string|max:100', 'pengarang' => 'required|string|max:100',
'penerbit' => 'nullable|string', 'penerbit' => 'required|string',
'tahun_terbit' => 'nullable|digits:4', 'tahun_terbit' => 'required|digits:4',
'edisi' => 'nullable|string|max:50', 'edisi' => 'required|digits:4',
'deskripsi_fisik' => 'nullable|string|max:100', 'deskripsi_fisik' => 'required|string|max:100',
'nomor_panggil' => 'required|string|max:50', 'nomor_panggil' => 'required|string|max:50|unique:buku,nomor_panggil,' . $id . ',id_buku',
'eksemplar' => 'required|integer|min:1', 'eksemplar' => 'required|integer|min:1',
'id_kategori' => 'required|exists:kategori,id_kategori', 'id_kategori' => 'required|exists:kategori,id_kategori',
'cover' => 'image|mimes:jpeg,png,jpg,webp|max:2048' 'cover' => 'image|mimes:jpeg,png,jpg,webp|max:2048'

View File

@ -58,8 +58,8 @@ public function store(Request $request)
$validated = $request->validate([ $validated = $request->validate([
'id_anggota' => 'required|exists:anggotas,id', 'id_anggota' => 'required|exists:anggotas,id',
'id_buku' => 'required|exists:buku,id_buku', 'id_buku' => 'required|exists:buku,id_buku',
'tanggal_pinjam' => 'required|date', 'tanggal_pinjam' => 'required|date_format:Y-m-d|after_or_equal:2000-01-01|before_or_equal:2100-12-31',
'tanggal_kembali' => 'required|date|after_or_equal:tanggal_pinjam', 'tanggal_kembali' => 'required|date_format:Y-m-d|after_or_equal:tanggal_pinjam|before_or_equal:2100-12-31',
]); ]);
$validated['status_peminjaman'] = 'Dipinjam'; $validated['status_peminjaman'] = 'Dipinjam';
@ -240,8 +240,8 @@ public function update(Request $request, $id)
$validated = $request->validate([ $validated = $request->validate([
'id_anggota' => 'required|exists:anggotas,id', 'id_anggota' => 'required|exists:anggotas,id',
'id_buku' => 'required|exists:buku,id_buku', 'id_buku' => 'required|exists:buku,id_buku',
'tanggal_pinjam' => 'required|date', 'tanggal_pinjam' => 'required|date_format:Y-m-d|after_or_equal:2000-01-01|before_or_equal:2100-12-31',
'tanggal_kembali' => 'required|date|after_or_equal:tanggal_pinjam', 'tanggal_kembali' => 'required|date_format:Y-m-d|after_or_equal:tanggal_pinjam|before_or_equal:2100-12-31',
]); ]);
$peminjaman = Peminjaman::findOrFail($id); $peminjaman = Peminjaman::findOrFail($id);

View File

@ -33,12 +33,12 @@ public function store(Request $request)
'nama' => 'required|string|max:255', 'nama' => 'required|string|max:255',
'jenis_anggota' => 'required|in:Mahasiswa,Siswa,Dosen,Umum', 'jenis_anggota' => 'required|in:Mahasiswa,Siswa,Dosen,Umum',
'no_identitas' => 'required|unique:anggotas,no_identitas', 'no_identitas' => 'required|unique:anggotas,no_identitas',
'no_ktp' => 'nullable|numeric|digits_between:1,16', 'no_ktp' => 'required|numeric|digits_between:1,16|unique:anggotas,no_ktp',
'prodi' => 'nullable|string|max:255', 'prodi' => 'required_unless:jenis_anggota,Umum|nullable|string|max:255',
'no_hp' => 'required|string|max:20', 'no_hp' => 'required|numeric|digits_between:10,13',
'alamat' => 'required|string', 'alamat' => 'required|string',
'nama_wali' => 'required|string|max:255', 'nama_wali' => 'required|string|max:255',
'no_hp_wali' => 'required|string|max:20', 'no_hp_wali' => 'required|numeric|digits_between:10,13',
'hubungan_wali' => 'required|in:Orang Tua,Saudara,Dosen Wali,Lainnya', 'hubungan_wali' => 'required|in:Orang Tua,Saudara,Dosen Wali,Lainnya',
]); ]);
@ -60,12 +60,12 @@ public function update(Request $request, Anggota $member)
'nama' => 'required|string|max:255', 'nama' => 'required|string|max:255',
'jenis_anggota' => 'required|in:Mahasiswa,Siswa,Dosen,Umum', 'jenis_anggota' => 'required|in:Mahasiswa,Siswa,Dosen,Umum',
'no_identitas' => 'required|unique:anggotas,no_identitas,' . $member->id, 'no_identitas' => 'required|unique:anggotas,no_identitas,' . $member->id,
'no_ktp' => 'nullable|numeric|digits_between:1,16', 'no_ktp' => 'required|numeric|digits_between:1,16|unique:anggotas,no_ktp,' . $member->id,
'prodi' => 'nullable|string|max:255', 'prodi' => 'required_unless:jenis_anggota,Umum|nullable|string|max:255',
'no_hp' => 'required|string|max:20', 'no_hp' => 'required|numeric|digits_between:10,13',
'alamat' => 'required|string', 'alamat' => 'required|string',
'nama_wali' => 'required|string|max:255', 'nama_wali' => 'required|string|max:255',
'no_hp_wali' => 'required|string|max:20', 'no_hp_wali' => 'required|numeric|digits_between:10,13',
'hubungan_wali' => 'required|in:Orang Tua,Saudara,Dosen Wali,Lainnya', 'hubungan_wali' => 'required|in:Orang Tua,Saudara,Dosen Wali,Lainnya',
]); ]);

View File

@ -23,10 +23,10 @@ public function store(Request $request)
'keperluan' => 'required', 'keperluan' => 'required',
]); ]);
$anggota = Anggota::where('no_identitas', $request->no_anggota)->first(); $anggota = Anggota::where('no_ktp', $request->no_anggota)->orWhere('no_identitas', $request->no_anggota)->first();
if (!$anggota) { if (!$anggota) {
return back()->withErrors(['no_anggota' => 'Nomor Anggota tidak ditemukan dalam sistem kami.'])->withInput(); return back()->withErrors(['no_anggota' => 'Nomor KTP / NIK tidak ditemukan dalam sistem kami.'])->withInput();
} }
// Cari user terkait untuk id_user // Cari user terkait untuk id_user
@ -47,10 +47,10 @@ public function store(Request $request)
// Jalur tamu: isi manual // Jalur tamu: isi manual
$request->validate([ $request->validate([
'nama_tamu' => 'required|string|max:255', 'nama_tamu' => 'required|string|max:255',
'email' => 'nullable|email|max:255', 'email' => 'required|email|max:255',
'no_hp' => 'nullable|string|max:20', 'no_hp' => 'required|digits_between:10,13',
'asal_instansi' => 'required|string|max:255', 'asal_instansi' => 'required|string|max:255',
'status' => 'nullable|string|max:255', 'status' => 'required|string|max:255',
'keperluan' => 'required', 'keperluan' => 'required',
]); ]);

View File

@ -10,6 +10,7 @@ class BukuTamu extends Model
use HasFactory; use HasFactory;
protected $table = 'buku_tamu'; protected $table = 'buku_tamu';
protected $primaryKey = 'id_tamu';
public $timestamps = false; public $timestamps = false;
protected $fillable = [ protected $fillable = [

View File

@ -0,0 +1,24 @@
<?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
{
\Illuminate\Support\Facades\DB::statement('ALTER TABLE buku_tamu MODIFY id_tamu INT UNSIGNED NOT NULL AUTO_INCREMENT');
}
/**
* Reverse the migrations.
*/
public function down(): void
{
\Illuminate\Support\Facades\DB::statement('ALTER TABLE buku_tamu MODIFY id_tamu INT UNSIGNED NOT NULL');
}
};

View File

@ -35,7 +35,7 @@
</div> </div>
<div> <div>
<x-input-label for="id_kategori" value="Kategori" /> <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="border border-gray-200 bg-gray-50 text-gray-900 text-sm rounded-xl focus:ring-blue-500 focus:border-blue-500 block w-full p-3 shadow-sm hover:bg-white transition-all duration-200 outline-none">
<option value="">Pilih Kategori</option> <option value="">Pilih Kategori</option>
@foreach($kategori as $kat) @foreach($kategori as $kat)
<option value="{{ $kat->id_kategori }}" {{ old('id_kategori') == $kat->id_kategori ? 'selected' : '' }}> <option value="{{ $kat->id_kategori }}" {{ old('id_kategori') == $kat->id_kategori ? 'selected' : '' }}>
@ -65,26 +65,26 @@
<div class="grid grid-cols-1 md:grid-cols-3 gap-6"> <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div> <div>
<x-input-label for="penerbit" value="Penerbit" /> <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')" /> <x-text-input id="penerbit" name="penerbit" type="text" class="mt-1 block w-full" :value="old('penerbit')" required />
</div> </div>
<div> <div>
<x-input-label for="tahun_terbit" value="Tahun Terbit" /> <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')" /> <x-text-input id="tahun_terbit" name="tahun_terbit" type="number" class="mt-1 block w-full" :value="old('tahun_terbit')" required />
</div> </div>
<div> <div>
<x-input-label for="edisi" value="Edisi" /> <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')" /> <x-text-input id="edisi" name="edisi" type="number" class="mt-1 block w-full" :value="old('edisi')" required />
</div> </div>
</div> </div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6"> <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div> <div>
<x-input-label for="deskripsi_fisik" value="Deskripsi Fisik" /> <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')" /> <x-text-input id="deskripsi_fisik" name="deskripsi_fisik" type="text" class="mt-1 block w-full" :value="old('deskripsi_fisik')" required />
</div> </div>
<div> <div>
<x-input-label for="eksemplar" value="Jumlah Eksemplar" /> <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')" /> <x-text-input id="eksemplar" name="eksemplar" type="number" class="mt-1 block w-full" :value="old('eksemplar')" required />
</div> </div>
</div> </div>

View File

@ -32,7 +32,7 @@ class="p-6 space-y-6">
<div> <div>
<x-input-label for="id_kategori" value="Kategori" /> <x-input-label for="id_kategori" value="Kategori" />
<select id="id_kategori" name="id_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"> class="border border-gray-200 bg-gray-50 text-gray-900 text-sm rounded-xl focus:ring-blue-500 focus:border-blue-500 block w-full p-3 shadow-sm hover:bg-white transition-all duration-200 outline-none">
<option value="">Pilih Kategori</option> <option value="">Pilih Kategori</option>
@foreach ($kategori as $kat) @foreach ($kategori as $kat)
<option value="{{ $kat->id_kategori }}" <option value="{{ $kat->id_kategori }}"
@ -66,17 +66,17 @@ class="mt-1 block w-full border-gray-300 focus:border-indigo-500 focus:ring-indi
<div> <div>
<x-input-label for="penerbit" value="Penerbit" /> <x-input-label for="penerbit" value="Penerbit" />
<x-text-input id="penerbit" name="penerbit" type="text" class="mt-1 block w-full" <x-text-input id="penerbit" name="penerbit" type="text" class="mt-1 block w-full"
:value="old('penerbit', $buku->penerbit)" /> :value="old('penerbit', $buku->penerbit)" required />
</div> </div>
<div> <div>
<x-input-label for="tahun_terbit" value="Tahun Terbit" /> <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" <x-text-input id="tahun_terbit" name="tahun_terbit" type="number" class="mt-1 block w-full"
:value="old('tahun_terbit', $buku->tahun_terbit)" /> :value="old('tahun_terbit', $buku->tahun_terbit)" required />
</div> </div>
<div> <div>
<x-input-label for="edisi" value="Edisi" /> <x-input-label for="edisi" value="Edisi" />
<x-text-input id="edisi" name="edisi" type="text" class="mt-1 block w-full" <x-text-input id="edisi" name="edisi" type="number" class="mt-1 block w-full"
:value="old('edisi', $buku->edisi)" /> :value="old('edisi', $buku->edisi)" required />
</div> </div>
</div> </div>
@ -84,12 +84,12 @@ class="mt-1 block w-full border-gray-300 focus:border-indigo-500 focus:ring-indi
<div> <div>
<x-input-label for="deskripsi_fisik" value="Deskripsi Fisik" /> <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" <x-text-input id="deskripsi_fisik" name="deskripsi_fisik" type="text" class="mt-1 block w-full"
:value="old('deskripsi_fisik', $buku->deskripsi_fisik)" /> :value="old('deskripsi_fisik', $buku->deskripsi_fisik)" required />
</div> </div>
<div> <div>
<x-input-label for="eksemplar" value="Jumlah Eksemplar" /> <x-input-label for="eksemplar" value="Jumlah Eksemplar" />
<x-text-input id="eksemplar" name="eksemplar" type="number" class="mt-1 block w-full" <x-text-input id="eksemplar" name="eksemplar" type="number" class="mt-1 block w-full"
:value="old('eksemplar', $buku->eksemplar)" /> :value="old('eksemplar', $buku->eksemplar)" required />
</div> </div>
</div> </div>

View File

@ -133,7 +133,7 @@ class="mt-1 block w-full bg-gray-50/50" :value="old('bibid')" required />
<div> <div>
<x-input-label for="id_kategori" value="Kategori" /> <x-input-label for="id_kategori" value="Kategori" />
<select id="id_kategori" name="id_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" class="border border-gray-200 bg-gray-50 text-gray-900 text-sm rounded-xl focus:ring-blue-500 focus:border-blue-500 block w-full p-3 shadow-sm hover:bg-white transition-all duration-200 outline-none"
required> required>
<option value="">Pilih Kategori</option> <option value="">Pilih Kategori</option>
@foreach ($kategori as $kat) @foreach ($kategori as $kat)
@ -169,17 +169,17 @@ class="mt-1 block w-full bg-gray-50/50" :value="old('nomor_panggil')" required /
<div> <div>
<x-input-label for="penerbit" value="Penerbit" /> <x-input-label for="penerbit" value="Penerbit" />
<x-text-input id="penerbit" name="penerbit" type="text" <x-text-input id="penerbit" name="penerbit" type="text"
class="mt-1 block w-full bg-gray-50/50" :value="old('penerbit')" /> class="mt-1 block w-full bg-gray-50/50" :value="old('penerbit')" required />
</div> </div>
<div> <div>
<x-input-label for="tahun_terbit" value="Tahun Terbit" /> <x-input-label for="tahun_terbit" value="Tahun Terbit" />
<x-text-input id="tahun_terbit" name="tahun_terbit" type="number" <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')" /> class="mt-1 block w-full bg-gray-50/50" :value="old('tahun_terbit')" required />
</div> </div>
<div> <div>
<x-input-label for="edisi" value="Edisi" /> <x-input-label for="edisi" value="Edisi" />
<x-text-input id="edisi" name="edisi" type="text" <x-text-input id="edisi" name="edisi" type="number"
class="mt-1 block w-full bg-gray-50/50" :value="old('edisi')" /> class="mt-1 block w-full bg-gray-50/50" :value="old('edisi')" required />
</div> </div>
</div> </div>
@ -187,7 +187,7 @@ class="mt-1 block w-full bg-gray-50/50" :value="old('edisi')" />
<div> <div>
<x-input-label for="deskripsi_fisik" value="Deskripsi Fisik" /> <x-input-label for="deskripsi_fisik" value="Deskripsi Fisik" />
<x-text-input id="deskripsi_fisik" name="deskripsi_fisik" type="text" <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')" /> class="mt-1 block w-full bg-gray-50/50" :value="old('deskripsi_fisik')" required />
</div> </div>
<div> <div>
<x-input-label for="eksemplar" value="Jumlah Eksemplar" /> <x-input-label for="eksemplar" value="Jumlah Eksemplar" />

View File

@ -52,12 +52,14 @@ class="w-full border-gray-300 rounded-lg shadow-sm focus:border-blue-500 focus:r
<div> <div>
<label class="block text-sm font-medium text-gray-700 mb-2">Tanggal Pinjam</label> <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')) }}" <input type="date" name="tanggal_pinjam" value="{{ old('tanggal_pinjam', date('Y-m-d')) }}"
min="2000-01-01" max="2100-12-31"
class="w-full border-gray-300 rounded-lg shadow-sm focus:border-blue-500 focus:ring-blue-500"> class="w-full border-gray-300 rounded-lg shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div> </div>
<div> <div>
<label class="block text-sm font-medium text-gray-700 mb-2">Tanggal Kembali (Tenggat)</label> <label class="block text-sm font-medium text-gray-700 mb-2">Tanggal Kembali (Tenggat)</label>
<input type="date" name="tanggal_kembali" <input type="date" name="tanggal_kembali"
value="{{ old('tanggal_kembali', date('Y-m-d', strtotime('+7 days'))) }}" value="{{ old('tanggal_kembali', date('Y-m-d', strtotime('+7 days'))) }}"
min="2000-01-01" max="2100-12-31"
class="w-full border-gray-300 rounded-lg shadow-sm focus:border-blue-500 focus:ring-blue-500"> class="w-full border-gray-300 rounded-lg shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div> </div>
</div> </div>

View File

@ -240,7 +240,7 @@ class="w-10 h-10 rounded-full bg-gray-50 hover:bg-red-50 text-gray-400 hover:tex
<div> <div>
<x-input-label value="Pilih Anggota / Member" /> <x-input-label value="Pilih Anggota / Member" />
<select name="id_anggota" x-init="new TomSelect($el, { maxOptions: null })" <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" class="mt-1 block w-full border-gray-200 focus:border-indigo-500 focus:ring-indigo-500 rounded-xl shadow-sm bg-gray-50/50 p-3"
required> required>
<option value="">-- Pilih Member --</option> <option value="">-- Pilih Member --</option>
@foreach ($anggota as $a) @foreach ($anggota as $a)
@ -255,7 +255,7 @@ class="mt-1 block w-full border-gray-300 focus:border-indigo-500 focus:ring-indi
<div> <div>
<x-input-label value="Pilih Buku (Hanya yang tersedia)" /> <x-input-label value="Pilih Buku (Hanya yang tersedia)" />
<select name="id_buku" x-init="new TomSelect($el, { maxOptions: null })" <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" class="mt-1 block w-full border-gray-200 focus:border-indigo-500 focus:ring-indigo-500 rounded-xl shadow-sm bg-gray-50/50 p-3"
required> required>
<option value="">-- Pilih Buku --</option> <option value="">-- Pilih Buku --</option>
@foreach ($buku as $b) @foreach ($buku as $b)
@ -272,12 +272,14 @@ class="mt-1 block w-full border-gray-300 focus:border-indigo-500 focus:ring-indi
<x-input-label value="Tanggal Pinjam" /> <x-input-label value="Tanggal Pinjam" />
<x-text-input type="date" name="tanggal_pinjam" <x-text-input type="date" name="tanggal_pinjam"
value="{{ old('tanggal_pinjam', date('Y-m-d')) }}" value="{{ old('tanggal_pinjam', date('Y-m-d')) }}"
min="2000-01-01" max="2100-12-31"
class="mt-1 block w-full bg-gray-50/50" required /> class="mt-1 block w-full bg-gray-50/50" required />
</div> </div>
<div> <div>
<x-input-label value="Tanggal Kembali (Tenggat)" /> <x-input-label value="Tanggal Kembali (Tenggat)" />
<x-text-input type="date" name="tanggal_kembali" <x-text-input type="date" name="tanggal_kembali"
value="{{ old('tanggal_kembali', date('Y-m-d', strtotime('+7 days'))) }}" value="{{ old('tanggal_kembali', date('Y-m-d', strtotime('+7 days'))) }}"
min="2000-01-01" max="2100-12-31"
class="mt-1 block w-full bg-gray-50/50" required /> class="mt-1 block w-full bg-gray-50/50" required />
</div> </div>
</div> </div>
@ -431,7 +433,7 @@ class="w-10 h-10 rounded-full bg-gray-50 hover:bg-red-50 text-gray-400 hover:tex
<x-input-label value="Pilih Anggota / Member" /> <x-input-label value="Pilih Anggota / Member" />
<select name="id_anggota" x-model="editData.id_anggota" x-init="let tsA = null; <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) })" $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" class="mt-1 block w-full border-gray-200 focus:border-indigo-500 focus:ring-indigo-500 rounded-xl shadow-sm bg-gray-50/50 p-3"
required> required>
<option value="">-- Pilih Member --</option> <option value="">-- Pilih Member --</option>
@foreach ($anggota as $a) @foreach ($anggota as $a)
@ -445,7 +447,7 @@ class="mt-1 block w-full border-gray-300 focus:border-indigo-500 focus:ring-indi
<x-input-label value="Pilih Buku" /> <x-input-label value="Pilih Buku" />
<select name="id_buku" x-model="editData.id_buku" x-init="let tsB = null; <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) })" $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" class="mt-1 block w-full border-gray-200 focus:border-indigo-500 focus:ring-indigo-500 rounded-xl shadow-sm bg-gray-50/50 p-3"
required> required>
<option value="">-- Pilih Buku --</option> <option value="">-- Pilih Buku --</option>
@foreach ($buku as $b) @foreach ($buku as $b)
@ -459,11 +461,13 @@ class="mt-1 block w-full border-gray-300 focus:border-indigo-500 focus:ring-indi
<div> <div>
<x-input-label value="Tanggal Pinjam" /> <x-input-label value="Tanggal Pinjam" />
<x-text-input type="date" name="tanggal_pinjam" x-model="editData.tanggal_pinjam" <x-text-input type="date" name="tanggal_pinjam" x-model="editData.tanggal_pinjam"
min="2000-01-01" max="2100-12-31"
class="mt-1 block w-full bg-gray-50/50" required /> class="mt-1 block w-full bg-gray-50/50" required />
</div> </div>
<div> <div>
<x-input-label value="Tanggal Kembali (Tenggat)" /> <x-input-label value="Tanggal Kembali (Tenggat)" />
<x-text-input type="date" name="tanggal_kembali" x-model="editData.tanggal_kembali" <x-text-input type="date" name="tanggal_kembali" x-model="editData.tanggal_kembali"
min="2000-01-01" max="2100-12-31"
class="mt-1 block w-full bg-gray-50/50" required /> class="mt-1 block w-full bg-gray-50/50" required />
</div> </div>
</div> </div>

View File

@ -64,7 +64,7 @@
<div class="grid grid-cols-1 md:grid-cols-2 gap-4"> <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<x-input-label for="no_hp" value="No. HP" /> <x-input-label for="no_hp" value="No. HP" />
<x-text-input id="no_hp" name="no_hp" type="text" class="mt-1 block w-full" :value="old('no_hp', $anggota->no_hp)" required /> <x-text-input id="no_hp" name="no_hp" type="number" class="mt-1 block w-full" :value="old('no_hp', $anggota->no_hp)" required />
<x-input-error class="mt-2" :messages="$errors->get('no_hp')" /> <x-input-error class="mt-2" :messages="$errors->get('no_hp')" />
</div> </div>
@ -92,7 +92,7 @@
<div> <div>
<x-input-label for="no_hp_wali" value="No. HP Wali" /> <x-input-label for="no_hp_wali" value="No. HP Wali" />
<x-text-input id="no_hp_wali" name="no_hp_wali" type="text" class="mt-1 block w-full" :value="old('no_hp_wali', $anggota->no_hp_wali)" required /> <x-text-input id="no_hp_wali" name="no_hp_wali" type="number" class="mt-1 block w-full" :value="old('no_hp_wali', $anggota->no_hp_wali)" required />
<x-input-error class="mt-2" :messages="$errors->get('no_hp_wali')" /> <x-input-error class="mt-2" :messages="$errors->get('no_hp_wali')" />
</div> </div>
@ -131,8 +131,10 @@ function toggleProdi() {
if (jenis === 'Umum') { if (jenis === 'Umum') {
prodiField.style.display = 'none'; prodiField.style.display = 'none';
document.getElementById('prodi').value = ''; document.getElementById('prodi').value = '';
document.getElementById('prodi').removeAttribute('required');
} else { } else {
prodiField.style.display = 'block'; prodiField.style.display = 'block';
document.getElementById('prodi').setAttribute('required', 'required');
} }
// Logika Dynamic Form untuk Identitas Siswa / Pelajar // Logika Dynamic Form untuk Identitas Siswa / Pelajar

View File

@ -6,7 +6,7 @@
<div x-data="{ isModalAnggotaOpen: {{ ($errors->any() || request('add') == 'true') ? 'true' : 'false' }} }"> <div x-data="{ isModalAnggotaOpen: {{ ($errors->any() || request('add') == 'true') ? 'true' : 'false' }} }">
<x-page-header title="Data Anggota"> <x-page-header title="Data Anggota">
<x-slot name="actions"> <x-slot name="actions">
<button @click="isModalAnggotaOpen = true" class="bg-gradient-to-r from-emerald-600 to-teal-600 hover:from-emerald-700 hover:to-teal-700 text-white px-5 py-2.5 rounded-xl shadow-lg shadow-emerald-500/30 transition-all font-semibold flex items-center gap-2 transform hover:scale-105"> <button @click="isModalAnggotaOpen = 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-user-plus"></i> Tambah Anggota <i class="fas fa-user-plus"></i> Tambah Anggota
</button> </button>
</x-slot> </x-slot>
@ -185,7 +185,7 @@ class="inline-block px-4 pt-5 pb-4 overflow-hidden text-left align-bottom transi
<div x-show="jenisAnggota !== 'Umum'" x-transition> <div x-show="jenisAnggota !== 'Umum'" x-transition>
<x-input-label for="prodi" value="Program Studi / Jurusan" /> <x-input-label for="prodi" value="Program Studi / Jurusan" />
<x-text-input id="prodi" name="prodi" type="text" class="mt-1 block w-full bg-gray-50/50" :value="old('prodi')" placeholder="Contoh: Teknik Informatika" /> <x-text-input id="prodi" name="prodi" type="text" class="mt-1 block w-full bg-gray-50/50" :value="old('prodi')" placeholder="Contoh: Teknik Informatika" x-bind:required="jenisAnggota !== 'Umum'" />
</div> </div>
</div> </div>
</div> </div>
@ -199,7 +199,7 @@ class="inline-block px-4 pt-5 pb-4 overflow-hidden text-left align-bottom transi
<div class="grid grid-cols-1 md:grid-cols-2 gap-6"> <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div> <div>
<x-input-label for="no_hp" value="No. HP" /> <x-input-label for="no_hp" value="No. HP" />
<x-text-input id="no_hp" name="no_hp" type="text" class="mt-1 block w-full bg-gray-50/50" :value="old('no_hp')" placeholder="08xxxxxxxxx" required /> <x-text-input id="no_hp" name="no_hp" type="number" class="mt-1 block w-full bg-gray-50/50" :value="old('no_hp')" placeholder="08xxxxxxxxx" required />
</div> </div>
<div class="md:col-span-2"> <div class="md:col-span-2">
@ -224,7 +224,7 @@ class="inline-block px-4 pt-5 pb-4 overflow-hidden text-left align-bottom transi
<div> <div>
<x-input-label for="no_hp_wali" value="No. HP Wali" /> <x-input-label for="no_hp_wali" value="No. HP Wali" />
<x-text-input id="no_hp_wali" name="no_hp_wali" type="text" class="mt-1 block w-full bg-gray-50/50" :value="old('no_hp_wali')" placeholder="08xxxxxxxxx" required /> <x-text-input id="no_hp_wali" name="no_hp_wali" type="number" class="mt-1 block w-full bg-gray-50/50" :value="old('no_hp_wali')" placeholder="08xxxxxxxxx" required />
</div> </div>
<div> <div>
@ -244,7 +244,7 @@ class="inline-block px-4 pt-5 pb-4 overflow-hidden text-left align-bottom transi
<button type="button" @click="isModalAnggotaOpen = 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"> <button type="button" @click="isModalAnggotaOpen = 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 Batal
</button> </button>
<button type="submit" class="bg-gradient-to-r from-emerald-600 to-teal-600 hover:from-emerald-700 hover:to-teal-700 text-white px-6 py-2.5 rounded-xl font-bold shadow-lg shadow-emerald-500/30 transition-all transform hover:scale-105"> <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 Anggota <i class="fas fa-save mr-2"></i> Simpan Anggota
</button> </button>
</div> </div>

View File

@ -26,6 +26,31 @@
@keyframes blob { 0% { transform: translate(0,0) scale(1); } 33% { transform: translate(30px,-50px) scale(1.1); } 66% { transform: translate(-20px,20px) scale(0.9); } 100% { transform: translate(0,0) scale(1); } } @keyframes blob { 0% { transform: translate(0,0) scale(1); } 33% { transform: translate(30px,-50px) scale(1.1); } 66% { transform: translate(-20px,20px) scale(0.9); } 100% { transform: translate(0,0) scale(1); } }
.animate-blob { animation: blob 7s infinite; } .animate-blob { animation: blob 7s infinite; }
.animation-delay-2000 { animation-delay: 2s; } .animation-delay-2000 { animation-delay: 2s; }
/* Hide spin buttons for number input */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type=number] {
-moz-appearance: textfield;
}
/* Custom Scrollbar */
::-webkit-scrollbar {
width: 6px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.15);
border-radius: 10px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.3);
}
</style> </style>
</head> </head>
@ -79,8 +104,12 @@
{{-- RIGHT PANEL (Form) --}} {{-- RIGHT PANEL (Form) --}}
<div class="w-full md:w-7/12 bg-gradient-to-br from-primary-900 via-primary-800 to-primary-900 relative flex flex-col p-8 md:p-12"> <div class="w-full md:w-7/12 bg-gradient-to-br from-primary-900 via-primary-800 to-primary-900 relative flex flex-col p-8 md:p-12">
<div class="mb-6 pb-4"> @php $activeTipe = old('tipe', request('tipe', 'member')); @endphp
<h2 class="text-2xl font-bold text-white tracking-wide mb-2">Buku Tamu</h2>
<div class="mb-5 pb-3">
<h2 id="form-title" class="text-2xl font-bold text-white tracking-wide mb-1">
{{ $activeTipe == 'member' ? 'Buku Tamu Anggota' : 'Buku Tamu Pengunjung Umum' }}
</h2>
<p class="text-primary-300/60 text-sm">Isi data kunjungan Anda hari ini.</p> <p class="text-primary-300/60 text-sm">Isi data kunjungan Anda hari ini.</p>
</div> </div>
@ -96,65 +125,73 @@
</div> </div>
@endif @endif
{{-- Toggle --}} {{-- Toggle --}}
<div class="flex gap-3 mb-6"> <div class="flex gap-3 mb-6">
<label class="toggle-option flex-1 flex items-center gap-3 p-4 rounded-xl border border-white/10 active" id="toggle-member" onclick="switchMode('member')"> <label class="toggle-option flex-1 flex items-center gap-3 p-4 rounded-xl border border-white/10 {{ $activeTipe == 'member' ? 'active' : '' }}" id="toggle-member" onclick="switchMode('member')">
<input type="radio" name="mode_toggle" value="member" checked class="hidden"> <input type="radio" name="mode_toggle" value="member" {{ $activeTipe == 'member' ? 'checked' : '' }} class="hidden">
<div class="w-5 h-5 rounded-full border-2 border-white/40 flex items-center justify-center" id="radio-member"> <div class="w-5 h-5 rounded-full border-2 border-white/40 flex items-center justify-center" id="radio-member">
@if($activeTipe == 'member')
<div class="w-3 h-3 rounded-full bg-primary-400"></div> <div class="w-3 h-3 rounded-full bg-primary-400"></div>
@endif
</div> </div>
<div> <div>
<p class="text-white text-sm font-semibold">Anggota</p> <p class="text-white text-sm font-semibold">Anggota</p>
<p class="text-primary-300/50 text-[10px]">Sudah punya No. Anggota</p> <p class="text-primary-300/50 text-[10px]">Punya NIK / No. Anggota</p>
</div> </div>
</label> </label>
<label class="toggle-option flex-1 flex items-center gap-3 p-4 rounded-xl border border-white/10" id="toggle-tamu" onclick="switchMode('tamu')"> <label class="toggle-option flex-1 flex items-center gap-3 p-4 rounded-xl border border-white/10 {{ $activeTipe == 'tamu' ? 'active' : '' }}" id="toggle-tamu" onclick="switchMode('tamu')">
<input type="radio" name="mode_toggle" value="tamu" class="hidden"> <input type="radio" name="mode_toggle" value="tamu" {{ $activeTipe == 'tamu' ? 'checked' : '' }} class="hidden">
<div class="w-5 h-5 rounded-full border-2 border-white/40 flex items-center justify-center" id="radio-tamu"></div> <div class="w-5 h-5 rounded-full border-2 border-white/40 flex items-center justify-center" id="radio-tamu">
@if($activeTipe == 'tamu')
<div class="w-3 h-3 rounded-full bg-primary-400"></div>
@endif
</div>
<div> <div>
<p class="text-white text-sm font-semibold">Pengunjung</p> <p class="text-white text-sm font-semibold">Pengunjung</p>
<p class="text-primary-300/50 text-[10px]">Belum punya No. Anggota</p> <p class="text-primary-300/50 text-[10px]">Belum punya NIK / Anggota</p>
</div> </div>
</label> </label>
</div> </div>
<form method="POST" action="{{ route('buku_tamu.store') }}" class="space-y-6" id="buku-tamu-form"> <form method="POST" action="{{ route('buku_tamu.store') }}" class="space-y-6" id="buku-tamu-form">
@csrf @csrf
<input type="hidden" name="tipe" id="tipe-input" value="member"> <input type="hidden" name="tipe" id="tipe-input" value="{{ $activeTipe }}">
<div id="form-member" class="space-y-5"> <div id="form-member" class="space-y-5" style="{{ $activeTipe == 'member' ? '' : 'display: none;' }}">
<div> <div>
<label class="block text-xs font-semibold text-primary-200/70 mb-2 ml-1 uppercase tracking-wider">No. Anggota</label> <label class="block text-xs font-semibold text-primary-200/70 mb-2 ml-1 uppercase tracking-wider">NIK / No. KTP / No. Anggota</label>
<input type="text" name="no_anggota" placeholder="Masukkan Nomor Anggota" <input type="text" name="no_anggota" placeholder="Masukkan 16 digit NIK atau Nomor Anggota"
class="w-full glass-input rounded-xl px-5 py-4 text-sm" value="{{ old('no_anggota') }}"> class="w-full glass-input rounded-xl px-5 py-4 text-sm" value="{{ old('no_anggota') }}" {{ $activeTipe == 'member' ? 'required' : '' }}>
</div> </div>
</div> </div>
<div id="form-tamu" class="space-y-5" style="display: none;"> <div id="form-tamu" class="space-y-5" style="{{ $activeTipe == 'tamu' ? '' : 'display: none;' }}">
<div> <div>
<label class="block text-xs font-semibold text-primary-200/70 mb-2 ml-1 uppercase tracking-wider">Nama Lengkap</label> <label class="block text-xs font-semibold text-primary-200/70 mb-2 ml-1 uppercase tracking-wider">Nama Lengkap</label>
<input type="text" name="nama_tamu" placeholder="Isi nama lengkap anda" <input type="text" name="nama_tamu" placeholder="Isi nama lengkap anda"
class="w-full glass-input rounded-xl px-5 py-4 text-sm" value="{{ old('nama_tamu') }}"> class="w-full glass-input rounded-xl px-5 py-4 text-sm" value="{{ old('nama_tamu') }}" {{ $activeTipe == 'tamu' ? 'required' : '' }}>
</div> </div>
<div> <div>
<label class="block text-xs font-semibold text-primary-200/70 mb-2 ml-1 uppercase tracking-wider">Email</label> <label class="block text-xs font-semibold text-primary-200/70 mb-2 ml-1 uppercase tracking-wider">Email</label>
<input type="email" name="email" placeholder="Isi email anda" <input type="email" name="email" placeholder="Isi email anda"
class="w-full glass-input rounded-xl px-5 py-4 text-sm" value="{{ old('email') }}"> class="w-full glass-input rounded-xl px-5 py-4 text-sm" value="{{ old('email') }}" {{ $activeTipe == 'tamu' ? 'required' : '' }}>
</div> </div>
<div> <div>
<label class="block text-xs font-semibold text-primary-200/70 mb-2 ml-1 uppercase tracking-wider">No HP</label> <label class="block text-xs font-semibold text-primary-200/70 mb-2 ml-1 uppercase tracking-wider">No HP</label>
<input type="text" name="no_hp" placeholder="+62" <input type="number" name="no_hp" placeholder="08..."
class="w-full glass-input rounded-xl px-5 py-4 text-sm" value="{{ old('no_hp') }}"> class="w-full glass-input rounded-xl px-5 py-4 text-sm" value="{{ old('no_hp') }}" {{ $activeTipe == 'tamu' ? 'required' : '' }} oninput="if(this.value.length > 13) this.value = this.value.slice(0, 13);">
</div> </div>
<div> <div>
<label class="block text-xs font-semibold text-primary-200/70 mb-2 ml-1 uppercase tracking-wider">Asal Instansi/ Sekolah / Kampus</label> <label class="block text-xs font-semibold text-primary-200/70 mb-2 ml-1 uppercase tracking-wider">Asal Instansi/ Sekolah / Kampus</label>
<input type="text" name="asal_instansi" placeholder="Politeknik Negeri Jember" <input type="text" name="asal_instansi" placeholder="Politeknik Negeri Jember"
class="w-full glass-input rounded-xl px-5 py-4 text-sm" value="{{ old('asal_instansi') }}"> class="w-full glass-input rounded-xl px-5 py-4 text-sm" value="{{ old('asal_instansi') }}" {{ $activeTipe == 'tamu' ? 'required' : '' }}>
</div> </div>
<div> <div>
<label class="block text-xs font-semibold text-primary-200/70 mb-2 ml-1 uppercase tracking-wider">Status</label> <label class="block text-xs font-semibold text-primary-200/70 mb-2 ml-1 uppercase tracking-wider">Status</label>
<div class="relative"> <div class="relative">
<select name="status" class="w-full glass-input rounded-xl px-5 py-4 text-sm appearance-none cursor-pointer"> <select name="status" class="w-full glass-input rounded-xl px-5 py-4 text-sm appearance-none cursor-pointer" {{ $activeTipe == 'tamu' ? 'required' : '' }}>
<option value="" disabled selected>Pilih Status</option> <option value="" disabled selected>Pilih Status</option>
<option value="Siswa" {{ old('status') == 'Siswa' ? 'selected' : '' }}>Siswa</option> <option value="Siswa" {{ old('status') == 'Siswa' ? 'selected' : '' }}>Siswa</option>
<option value="Mahasiswa" {{ old('status') == 'Mahasiswa' ? 'selected' : '' }}>Mahasiswa</option> <option value="Mahasiswa" {{ old('status') == 'Mahasiswa' ? 'selected' : '' }}>Mahasiswa</option>
@ -204,14 +241,7 @@ class="group w-full py-4 bg-gradient-to-r from-primary-400 to-primary-500 hover:
</button> </button>
</div> </div>
<div class="text-center pt-2">
<p class="text-sm text-primary-200/40">
Belum punya akun anggota?
<a href="{{ route('register') }}" class="text-white font-semibold hover:text-primary-300 transition underline decoration-primary-400/30 underline-offset-4">
Daftar Sekarang
</a>
</p>
</div>
</form> </form>
</div> </div>
</div> </div>
@ -226,6 +256,10 @@ function switchMode(mode) {
const radioMember = document.getElementById('radio-member'); const radioMember = document.getElementById('radio-member');
const radioTamu = document.getElementById('radio-tamu'); const radioTamu = document.getElementById('radio-tamu');
const tipeInput = document.getElementById('tipe-input'); const tipeInput = document.getElementById('tipe-input');
const formTitle = document.getElementById('form-title');
const reqMember = formMember.querySelectorAll('input, select');
const reqTamu = formTamu.querySelectorAll('input, select');
if (mode === 'member') { if (mode === 'member') {
formMember.style.display = 'block'; formMember.style.display = 'block';
@ -235,6 +269,10 @@ function switchMode(mode) {
radioMember.innerHTML = '<div class="w-3 h-3 rounded-full bg-primary-400"></div>'; radioMember.innerHTML = '<div class="w-3 h-3 rounded-full bg-primary-400"></div>';
radioTamu.innerHTML = ''; radioTamu.innerHTML = '';
tipeInput.value = 'member'; tipeInput.value = 'member';
if(formTitle) formTitle.innerText = 'Buku Tamu Anggota';
reqMember.forEach(el => el.setAttribute('required', 'required'));
reqTamu.forEach(el => el.removeAttribute('required'));
} else { } else {
formMember.style.display = 'none'; formMember.style.display = 'none';
formTamu.style.display = 'block'; formTamu.style.display = 'block';
@ -243,6 +281,10 @@ function switchMode(mode) {
radioMember.innerHTML = ''; radioMember.innerHTML = '';
radioTamu.innerHTML = '<div class="w-3 h-3 rounded-full bg-primary-400"></div>'; radioTamu.innerHTML = '<div class="w-3 h-3 rounded-full bg-primary-400"></div>';
tipeInput.value = 'tamu'; tipeInput.value = 'tamu';
if(formTitle) formTitle.innerText = 'Buku Tamu Pengunjung Umum';
reqMember.forEach(el => el.removeAttribute('required'));
reqTamu.forEach(el => el.setAttribute('required', 'required'));
} }
} }
</script> </script>

View File

@ -24,6 +24,23 @@
</script> </script>
<style> <style>
.gradient-text { background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 50%, #2563eb 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } .gradient-text { background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 50%, #2563eb 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; }
/* TomSelect Custom Styling */
.ts-control {
border: 1px solid #e5e7eb !important;
background-color: #f9fafb !important;
border-radius: 0.75rem !important;
padding: 0.75rem 1rem !important;
font-size: 0.875rem !important;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05) !important;
}
.ts-control.focus {
border-color: #6366f1 !important;
box-shadow: 0 0 0 1px #6366f1 !important;
}
.ts-control input {
font-size: 0.875rem !important;
}
</style> </style>
</head> </head>
<body class="bg-gray-50 font-sans antialiased flex flex-col h-screen overflow-hidden" x-data="{ sidebarOpen: false }"> <body class="bg-gray-50 font-sans antialiased flex flex-col h-screen overflow-hidden" x-data="{ sidebarOpen: false }">
@ -152,5 +169,52 @@ class="flex items-center gap-3 px-4 py-3 rounded-xl transition-all duration-300
</main> </main>
</div> </div>
{{-- SweetAlert2 for Global Delete Confirmation --}}
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
// Intercept all forms that have a confirm() in their onsubmit attribute
const deleteForms = document.querySelectorAll('form[onsubmit*="return confirm"]');
deleteForms.forEach(form => {
// Extract the message from the confirm('Message') call
const originalOnsubmit = form.getAttribute('onsubmit');
const messageMatch = originalOnsubmit.match(/confirm\(['"](.*?)['"]\)/);
const message = messageMatch ? messageMatch[1] : 'Apakah Anda yakin ingin menghapus data ini?';
// Remove the default onsubmit to prevent browser confirm
form.removeAttribute('onsubmit');
// Add the custom SweetAlert event listener
form.addEventListener('submit', function (e) {
e.preventDefault();
Swal.fire({
title: 'Konfirmasi Hapus',
text: message,
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#ef4444',
cancelButtonColor: '#6b7280',
confirmButtonText: '<i class="fas fa-trash-alt mr-2"></i> Ya, Hapus',
cancelButtonText: 'Batal',
reverseButtons: true,
customClass: {
popup: 'rounded-3xl shadow-2xl',
title: 'text-2xl font-bold text-gray-800',
htmlContainer: 'text-gray-500',
confirmButton: 'rounded-xl px-6 py-2.5 font-bold shadow-lg shadow-red-500/30 transition-all ml-3',
cancelButton: 'rounded-xl px-6 py-2.5 font-bold bg-gray-100 text-gray-600 hover:bg-gray-200 transition-all'
},
buttonsStyling: false
}).then((result) => {
if (result.isConfirmed) {
form.submit();
}
});
});
});
});
</script>
@stack('scripts')
</body> </body>
</html> </html>

View File

@ -139,13 +139,13 @@ class="relative transition-colors {{ request()->routeIs('home') ? 'text-primary-
class="relative transition-colors {{ request()->routeIs('katalog.*') ? 'text-primary-600 font-semibold' : 'text-gray-600 hover:text-primary-600' }} after:absolute after:bottom-[-4px] after:left-0 {{ request()->routeIs('katalog.*') ? 'after:w-full' : 'after:w-0 hover:after:w-full' }} after:h-0.5 after:bg-primary-500 after:transition-all">Katalog class="relative transition-colors {{ request()->routeIs('katalog.*') ? 'text-primary-600 font-semibold' : 'text-gray-600 hover:text-primary-600' }} after:absolute after:bottom-[-4px] after:left-0 {{ request()->routeIs('katalog.*') ? 'after:w-full' : 'after:w-0 hover:after:w-full' }} after:h-0.5 after:bg-primary-500 after:transition-all">Katalog
Buku</a> Buku</a>
<a href="{{ route('home') }}#fitur" <a href="{{ route('home') }}#fitur"
class="relative transition-colors {{ request()->routeIs('home') && request()->getQueryString() == '' ? 'text-primary-600 font-semibold' : 'text-gray-600 hover:text-primary-600' }} after:absolute after:bottom-[-4px] after:left-0 after:w-0 after:h-0.5 after:bg-primary-500 after:transition-all hover:after:w-full">Fitur</a> class="relative transition-colors text-gray-600 hover:text-primary-600 after:absolute after:bottom-[-4px] after:left-0 after:w-0 after:h-0.5 after:bg-primary-500 after:transition-all hover:after:w-full">Fitur</a>
<a href="{{ route('home') }}#rekomendasi" <a href="{{ route('home') }}#rekomendasi"
class="relative transition-colors {{ request()->routeIs('home') && request()->getQueryString() == '' ? 'text-primary-600 font-semibold' : 'text-gray-600 hover:text-primary-600' }} after:absolute after:bottom-[-4px] after:left-0 after:w-0 after:h-0.5 after:bg-primary-500 after:transition-all hover:after:w-full">Koleksi</a> class="relative transition-colors text-gray-600 hover:text-primary-600 after:absolute after:bottom-[-4px] after:left-0 after:w-0 after:h-0.5 after:bg-primary-500 after:transition-all hover:after:w-full">Koleksi</a>
@guest @guest
<button onclick="openGuestModal()" <button onclick="openGuestModal()"
class="px-5 py-2.5 bg-primary-50 text-primary-600 rounded-xl font-semibold hover:bg-primary-100 transition-colors cursor-pointer"> class="px-5 py-2.5 bg-primary-50 text-primary-600 rounded-xl font-semibold hover:bg-primary-100 transition-colors cursor-pointer flex items-center justify-center">
<i class="fas fa-book-reader mr-1.5"></i> Buku Tamu <i class="fas fa-book-reader mr-1.5"></i> Buku Tamu
</button> </button>
<a href="{{ route('login') }}" <a href="{{ route('login') }}"
@ -179,7 +179,7 @@ class="px-5 py-2.5 bg-gradient-to-r from-green-600 to-green-700 text-white round
<div class="flex flex-col gap-3 mt-4"> <div class="flex flex-col gap-3 mt-4">
@guest @guest
<button onclick="openGuestModal()" class="w-full px-5 py-3 bg-primary-50 text-primary-600 rounded-xl font-bold hover:bg-primary-100 transition-colors text-center"> <button onclick="openGuestModal()" class="w-full px-5 py-3 bg-primary-50 text-primary-600 rounded-xl font-bold hover:bg-primary-100 transition-colors text-center flex items-center justify-center">
<i class="fas fa-book-reader mr-1.5"></i> Buku Tamu <i class="fas fa-book-reader mr-1.5"></i> Buku Tamu
</button> </button>
<a href="{{ route('login') }}" class="w-full px-5 py-3 bg-gradient-to-r from-primary-600 to-primary-700 text-white rounded-xl font-bold shadow-lg shadow-primary-200 text-center"> <a href="{{ route('login') }}" class="w-full px-5 py-3 bg-gradient-to-r from-primary-600 to-primary-700 text-white rounded-xl font-bold shadow-lg shadow-primary-200 text-center">
@ -275,6 +275,52 @@ class="fab fa-twitter text-sm"></i></a>
</div> </div>
</footer> </footer>
<!-- Global Guest Modal -->
<div id="guestModal" class="fixed inset-0 bg-gray-900/60 backdrop-blur-sm hidden z-[100] flex items-center justify-center p-4 transition-opacity duration-300">
<div class="bg-white rounded-[2rem] shadow-2xl max-w-md w-full overflow-hidden transform transition-all">
<div class="p-8 text-center relative">
<!-- Close Button -->
<button onclick="closeGuestModal()" class="absolute top-4 right-4 text-gray-400 hover:text-gray-600 transition-colors w-8 h-8 rounded-full hover:bg-gray-100 flex items-center justify-center">
<i class="fas fa-times"></i>
</button>
<!-- Icon Box -->
<div class="w-16 h-16 bg-gradient-to-br from-primary-500 to-primary-600 text-white rounded-2xl flex items-center justify-center mx-auto mb-5 text-2xl shadow-lg shadow-primary-200">
<i class="fas fa-user-check"></i>
</div>
<h3 class="text-2xl font-black text-gray-900 tracking-tight">Selamat Datang!</h3>
<p class="text-gray-500 text-sm mt-2 leading-relaxed">Apakah Anda sudah terdaftar sebagai anggota Sarakata?</p>
<div class="grid grid-cols-1 gap-3 mt-8">
<!-- Member Option -->
<a href="{{ route('buku_tamu.index') }}" class="flex items-center gap-4 p-4 border-2 border-primary-100 rounded-2xl hover:border-primary-300 hover:bg-primary-50/50 transition-all group cursor-pointer shadow-sm hover:shadow-md">
<div class="w-12 h-12 bg-primary-100 rounded-xl flex items-center justify-center text-primary-600 group-hover:bg-gradient-to-br group-hover:from-primary-500 group-hover:to-primary-600 group-hover:text-white transition-all shadow-sm group-hover:shadow-primary-300">
<i class="fas fa-id-card"></i>
</div>
<div class="text-left flex-1 border-gray-100">
<div class="font-bold text-gray-900 text-sm">Saya Anggota</div>
<div class="text-xs text-gray-400">Punya No. Anggota</div>
</div>
<i class="fas fa-chevron-right text-primary-300 group-hover:text-primary-500 transition-colors"></i>
</a>
<!-- Visitor Option -->
<a href="{{ route('buku_tamu.index', ['tipe' => 'tamu']) }}" class="flex items-center gap-4 p-4 border-2 border-gray-100 rounded-2xl hover:border-gray-300 hover:bg-gray-50 transition-all group cursor-pointer shadow-sm hover:shadow-md">
<div class="w-12 h-12 bg-gray-100 rounded-xl flex items-center justify-center text-gray-500 group-hover:bg-gray-800 group-hover:text-white transition-all shadow-sm">
<i class="fas fa-user-friends"></i>
</div>
<div class="text-left flex-1 border-gray-100">
<div class="font-bold text-gray-900 text-sm">Pengunjung Umum</div>
<div class="text-xs text-gray-400">Belum punya member</div>
</div>
<i class="fas fa-chevron-right text-gray-300 group-hover:text-gray-600 transition-colors"></i>
</a>
</div>
</div>
</div>
</div>
@stack('scripts') @stack('scripts')
<script> <script>
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
@ -296,6 +342,16 @@ class="fab fa-twitter text-sm"></i></a>
} }
}); });
}); });
// Global Modal Scripts
function openGuestModal() {
document.getElementById('guestModal').classList.remove('hidden');
document.body.style.overflow = 'hidden';
}
function closeGuestModal() {
document.getElementById('guestModal').classList.add('hidden');
document.body.style.overflow = 'auto';
}
</script> </script>
</body> </body>

View File

@ -11,61 +11,4 @@
@include('welcome.rekomendasi') @include('welcome.rekomendasi')
</section> </section>
<div id="guestModal" class="fixed inset-0 bg-gray-900/60 backdrop-blur-sm hidden z-[100] flex items-center justify-center p-4 transition-opacity duration-300"> @endsection
<div class="bg-white rounded-[2rem] shadow-2xl max-w-md w-full overflow-hidden transform transition-all">
<div class="p-8 text-center relative">
<!-- Close Button -->
<button onclick="closeGuestModal()" class="absolute top-4 right-4 text-gray-400 hover:text-gray-600 transition-colors w-8 h-8 rounded-full hover:bg-gray-100 flex items-center justify-center">
<i class="fas fa-times"></i>
</button>
<!-- Icon Box -->
<div class="w-16 h-16 bg-gradient-to-br from-primary-500 to-primary-600 text-white rounded-2xl flex items-center justify-center mx-auto mb-5 text-2xl shadow-lg shadow-primary-200">
<i class="fas fa-user-check"></i>
</div>
<h3 class="text-2xl font-black text-gray-900 tracking-tight">Selamat Datang!</h3>
<p class="text-gray-500 text-sm mt-2 leading-relaxed">Apakah Anda sudah terdaftar sebagai anggota Sarakata?</p>
<div class="grid grid-cols-1 gap-3 mt-8">
<!-- Member Option -->
<a href="{{ route('buku_tamu.index') }}" class="flex items-center gap-4 p-4 border-2 border-primary-100 rounded-2xl hover:border-primary-300 hover:bg-primary-50/50 transition-all group cursor-pointer shadow-sm hover:shadow-md">
<div class="w-12 h-12 bg-primary-100 rounded-xl flex items-center justify-center text-primary-600 group-hover:bg-gradient-to-br group-hover:from-primary-500 group-hover:to-primary-600 group-hover:text-white transition-all shadow-sm group-hover:shadow-primary-300">
<i class="fas fa-id-card"></i>
</div>
<div class="text-left flex-1 border-gray-100">
<div class="font-bold text-gray-900 text-sm">Saya Anggota</div>
<div class="text-xs text-gray-400">Punya No. Anggota</div>
</div>
<i class="fas fa-chevron-right text-primary-300 group-hover:text-primary-500 transition-colors"></i>
</a>
<!-- Visitor Option -->
<a href="{{ route('buku_tamu.index') }}" class="flex items-center gap-4 p-4 border-2 border-gray-100 rounded-2xl hover:border-gray-300 hover:bg-gray-50 transition-all group cursor-pointer shadow-sm hover:shadow-md">
<div class="w-12 h-12 bg-gray-100 rounded-xl flex items-center justify-center text-gray-500 group-hover:bg-gray-800 group-hover:text-white transition-all shadow-sm">
<i class="fas fa-user-friends"></i>
</div>
<div class="text-left flex-1 border-gray-100">
<div class="font-bold text-gray-900 text-sm">Pengunjung Umum</div>
<div class="text-xs text-gray-400">Belum punya member</div>
</div>
<i class="fas fa-chevron-right text-gray-300 group-hover:text-gray-600 transition-colors"></i>
</a>
</div>
</div>
</div>
</div>
@endsection
@push('scripts')
<script>
function openGuestModal() {
document.getElementById('guestModal').classList.remove('hidden');
document.body.style.overflow = 'hidden';
}
function closeGuestModal() {
document.getElementById('guestModal').classList.add('hidden');
document.body.style.overflow = 'auto';
}
</script>
@endpush