add seeders

Standardize the Buku schema and wiring: change Buku model to use table 'buku' and primary key id_buku, add/adjust migrations to create/alter the buku table and related tables (lokasi fields, adjusted foreign keys), and add a migration to provide nim on anggotas. Update controllers to reference id_buku (queries, ordering) and make related schema-friendly adjustments. Add multiple seeders (AnggotaSeeder, BukuFromSqlSeeder, BukuSeeder, BukuTamuSeeder updates, KategoriSeeder, PeminjamanSeeder, UserSeeder) and minor view/controller cleanup/formatting tweaks. These changes align database structure, relations and seed data with the new primary key/table naming and support new fields (lokasi, bibliographic fields, guest/peminjaman updates).
This commit is contained in:
Lutfi Hakim 2026-04-30 14:35:20 +07:00
parent f64ea3a4fa
commit 74ae662d99
30 changed files with 470 additions and 226 deletions

View File

@ -44,14 +44,14 @@ public function index(Request $request)
{ {
$search = $request->input('search'); $search = $request->input('search');
$buku = Buku::with('kategori') $buku = Buku::with('kategori')
->when($search, function($query, $search) { ->when($search, function ($query, $search) {
return $query->where('judul', 'like', "%{$search}%") return $query->where('judul', 'like', "%{$search}%")
->orWhere('bibid', 'like', "%{$search}%"); ->orWhere('bibid', 'like', "%{$search}%");
}) })
->paginate(15); ->paginate(15);
$kategori = Kategori::all(); $kategori = Kategori::all();
return view('admin.buku.index', compact('buku', 'search', 'kategori')); return view('admin.buku.index', compact('buku', 'search', 'kategori'));
} }
@ -59,14 +59,14 @@ public function edit($id)
{ {
$buku = Buku::findOrFail($id); $buku = Buku::findOrFail($id);
$kategori = Kategori::all(); $kategori = Kategori::all();
return view('admin.buku.edit', compact('buku', 'kategori')); return view('admin.buku.edit', compact('buku', 'kategori'));
} }
public function update(Request $request, $id) public function update(Request $request, $id)
{ {
$buku = Buku::findOrFail($id); $buku = Buku::findOrFail($id);
$validated = $request->validate([ $validated = $request->validate([
'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',

View File

@ -141,7 +141,7 @@ public function show($id)
private function getRekomendasi($targetBuku) private function getRekomendasi($targetBuku)
{ {
$semuaBuku = Buku::where('id', '!=', $targetBuku->id) $semuaBuku = Buku::where('id_buku', '!=', $targetBuku->id_buku)
->get(); ->get();
// Jika nomor_panggil tidak ada, tampilkan rekomendasi berdasarkan buku populer // Jika nomor_panggil tidak ada, tampilkan rekomendasi berdasarkan buku populer

View File

@ -11,7 +11,7 @@ public function index()
// Menampilkan 4 buku rilis baru berdasarkan tahun terbit terbaru // Menampilkan 4 buku rilis baru berdasarkan tahun terbit terbaru
$bukuTerbaru = \App\Models\Buku::whereNotNull('tahun_terbit') $bukuTerbaru = \App\Models\Buku::whereNotNull('tahun_terbit')
->orderBy('tahun_terbit', 'desc') ->orderBy('tahun_terbit', 'desc')
->orderBy('id', 'desc') ->orderBy('id_buku', 'desc')
->limit(4) ->limit(4)
->get(); ->get();

View File

@ -9,8 +9,10 @@ class Buku extends Model
{ {
use HasFactory; use HasFactory;
protected $table = 'bukus'; protected $table = 'buku';
protected $primaryKey = 'id'; protected $primaryKey = 'id_buku';
public $incrementing = true;
protected $keyType = 'int';
protected $fillable = [ protected $fillable = [
'bibid', 'bibid',

View File

@ -9,19 +9,27 @@
/** /**
* Run the migrations. * Run the migrations.
*/ */
public function up() public function up()
{ {
Schema::create('bukus', function (Blueprint $table) { Schema::create('bukus', function (Blueprint $table) {
$table->id(); $table->id();
$table->string('judul'); $table->string('bibid')->nullable();
$table->string('pengarang'); $table->string('judul');
$table->string('penerbit'); $table->string('edisi')->nullable();
$table->year('tahun_terbit'); $table->string('pengarang');
$table->integer('stok'); $table->string('penerbit');
$table->timestamps(); $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();
});
}
/** /**

View File

@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('buku', function (Blueprint $table) {
$table->increments('id_buku');
$table->string('bibid')->nullable();
$table->string('judul')->nullable();
$table->string('edisi')->nullable();
$table->string('penerbit')->nullable();
$table->string('tahun_terbit')->nullable();
$table->string('deskripsi_fisik')->nullable();
$table->string('cover')->nullable();
$table->double('lokasi_x')->nullable();
$table->double('lokasi_y')->nullable();
$table->string('pengarang')->nullable();
$table->string('nomor_panggil')->nullable();
$table->integer('konten_digital')->nullable();
$table->integer('eksemplar')->nullable();
$table->unsignedBigInteger('id_kategori')->nullable();
$table->timestamp('created_at')->nullable();
$table->timestamp('updated_at')->nullable();
});
}
public function down(): void
{
Schema::dropIfExists('buku');
}
};

View File

@ -9,17 +9,24 @@
/** /**
* Run the migrations. * Run the migrations.
*/ */
public function up(): void public function up(): void
{ {
Schema::create('anggotas', function (Blueprint $table) { Schema::create('anggotas', function (Blueprint $table) {
$table->id(); $table->id();
$table->string('nama'); $table->string('nama');
$table->string('nim')->unique(); $table->string('no_identitas')->unique()->nullable();
$table->string('prodi'); $table->string('jenis_anggota')->nullable();
$table->string('no_hp')->nullable(); $table->string('no_ktp')->nullable();
$table->timestamps(); $table->string('prodi')->nullable();
}); $table->string('no_hp')->nullable();
} $table->text('alamat')->nullable();
$table->string('nama_wali')->nullable();
$table->string('no_hp_wali')->nullable();
$table->string('hubungan_wali')->nullable();
$table->boolean('status_aktif')->default(true);
$table->timestamps();
});
}
/** /**
* Reverse the migrations. * Reverse the migrations.
*/ */
@ -27,5 +34,4 @@ public function down(): void
{ {
Schema::dropIfExists('anggotas'); Schema::dropIfExists('anggotas');
} }
}; };

View File

@ -9,21 +9,21 @@
/** /**
* Run the migrations. * Run the migrations.
*/ */
public function up() public function up()
{ {
Schema::create('peminjaman', function (Blueprint $table) { Schema::create('peminjaman', function (Blueprint $table) {
$table->increments('id_peminjaman'); $table->increments('id_peminjaman');
$table->unsignedBigInteger('id_user'); $table->unsignedBigInteger('id_user');
$table->unsignedBigInteger('id_buku'); $table->unsignedInteger('id_buku');
$table->date('tanggal_pinjam')->nullable(); $table->date('tanggal_pinjam')->nullable();
$table->date('tanggal_kembali')->nullable(); $table->date('tanggal_kembali')->nullable();
$table->string('status_peminjaman', 20)->nullable(); $table->string('status_peminjaman', 20)->nullable();
$table->timestamps(); $table->timestamps();
$table->foreign('id_user')->references('id')->on('users')->cascadeOnDelete(); $table->foreign('id_user')->references('id')->on('users')->cascadeOnDelete();
$table->foreign('id_buku')->references('id')->on('bukus')->cascadeOnDelete(); $table->foreign('id_buku')->references('id_buku')->on('buku')->cascadeOnDelete();
}); });
} }
/** /**
@ -34,4 +34,3 @@ public function down(): void
Schema::dropIfExists('peminjaman'); Schema::dropIfExists('peminjaman');
} }
}; };

View File

@ -12,15 +12,15 @@
public function up(): void public function up(): void
{ {
Schema::create('buku_tamu', function (Blueprint $table) { Schema::create('buku_tamu', function (Blueprint $table) {
$table->id(); $table->unsignedInteger('id_tamu')->primary();
$table->unsignedBigInteger('id_user')->nullable(); $table->unsignedBigInteger('id_user')->nullable();
$table->string('nama_tamu'); $table->string('nama_tamu')->nullable();
$table->string('email')->nullable(); $table->string('email')->nullable();
$table->string('no_hp')->nullable(); $table->string('no_hp')->nullable();
$table->string('asal_instansi')->nullable(); $table->string('asal_instansi')->nullable();
$table->string('status')->nullable(); $table->string('status')->nullable();
$table->text('tujuan_kunjungan')->nullable(); $table->string('tanggal_kunjungan')->nullable();
$table->date('tanggal_kunjungan')->nullable(); $table->string('tujuan_kunjungan')->nullable();
$table->timestamps(); $table->timestamps();
$table->foreign('id_user') $table->foreign('id_user')

View File

@ -8,37 +8,12 @@
{ {
public function up(): void public function up(): void
{ {
Schema::table('anggotas', function (Blueprint $table) { // Columns already exist in create_anggotas_table migration
// Rename nim → no_identitas (lebih general: NIM/NISN/NIP) // This migration is now a no-op for forward compatibility
$table->renameColumn('nim', 'no_identitas');
});
Schema::table('anggotas', function (Blueprint $table) {
// Kolom baru untuk keamanan & akuntabilitas
$table->string('jenis_anggota')->after('no_identitas'); // Mahasiswa, Siswa, Dosen, Umum
$table->string('no_ktp', 20)->after('jenis_anggota'); // NIK 16 digit
$table->text('alamat')->after('no_hp'); // Alamat lengkap
$table->string('nama_wali')->after('alamat'); // Nama penjamin
$table->string('no_hp_wali', 20)->after('nama_wali'); // No HP penjamin
$table->string('hubungan_wali')->after('no_hp_wali'); // Orang Tua / Saudara / dll
// Prodi jadi nullable (umum/dosen mungkin tidak punya prodi)
$table->string('prodi')->nullable()->change();
});
} }
public function down(): void public function down(): void
{ {
Schema::table('anggotas', function (Blueprint $table) { // No-op
$table->dropColumn([
'jenis_anggota', 'no_ktp', 'alamat',
'nama_wali', 'no_hp_wali', 'hubungan_wali',
]);
$table->string('prodi')->nullable(false)->change();
});
Schema::table('anggotas', function (Blueprint $table) {
$table->renameColumn('no_identitas', 'nim');
});
} }
}; };

View File

@ -7,11 +7,11 @@
return new class extends Migration { return new class extends Migration {
public function up(): void public function up(): void
{ {
Schema::table('bukus', function (Blueprint $table) { Schema::table('buku', function (Blueprint $table) {
if (!Schema::hasColumn('bukus', 'lokasi_x')) { if (!Schema::hasColumn('buku', 'lokasi_x')) {
$table->float('lokasi_x')->nullable()->comment('Posisi X pin pada denah (persentase 0-100)'); $table->float('lokasi_x')->nullable()->comment('Posisi X pin pada denah (persentase 0-100)');
} }
if (!Schema::hasColumn('bukus', 'lokasi_y')) { if (!Schema::hasColumn('buku', 'lokasi_y')) {
$table->float('lokasi_y')->nullable()->comment('Posisi Y pin pada denah (persentase 0-100)'); $table->float('lokasi_y')->nullable()->comment('Posisi Y pin pada denah (persentase 0-100)');
} }
}); });
@ -19,7 +19,7 @@ public function up(): void
public function down(): void public function down(): void
{ {
Schema::table('bukus', function (Blueprint $table) { Schema::table('buku', function (Blueprint $table) {
$table->dropColumn(['lokasi_x', 'lokasi_y']); $table->dropColumn(['lokasi_x', 'lokasi_y']);
}); });
} }

View File

@ -0,0 +1,32 @@
<?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::table('anggotas', function (Blueprint $table) {
if (!Schema::hasColumn('anggotas', 'nim')) {
$table->string('nim')->nullable()->after('id');
}
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('anggotas', function (Blueprint $table) {
if (Schema::hasColumn('anggotas', 'nim')) {
$table->dropColumn('nim');
}
});
}
};

View File

@ -0,0 +1,28 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class AnggotaSeeder extends Seeder
{
/**
* Seed the anggotas table with data from SQL dump
*/
public function run(): void
{
DB::statement('SET FOREIGN_KEY_CHECKS=0');
// Execute each INSERT statement separately
$statements = [
base64_decode('SU5TRVJUIElOVE8gYGFuZ2dvdGFzYCAoYGlkYCwgYG5hbWFgLCBgbm9faWRlbnRpdGFzYCwgYGplbmlzX2FuZ2dvdGFgLCBgbm9fa3RwYCwgYHByb2RpYCwgYG5vX2hwYCwgYGFsYW1hdGAsIGBuYW1hX3dhbGlgLCBgbm9faHBfd2FsaWAsIGBodWJ1bmdhbl93YWxpYCwgYGNyZWF0ZWRfYXRgLCBgdXBkYXRlZF9hdGAsIGBuaW1gKSBWQUxVRVMKKDEsICd3YXdhJywgJ0UzMTIzMDg4NycsICdNYWhhc2lzd2EnLCAnMzUwOTExNTcwOTg3NjUnLCAnbWlmJywgJzA4MTIxNjkxMDg5NCcsICdtdW1idWwnLCAnc2l0aScsICcwODU2NDk5NTg5MzYnLCAnT3JhbmcgVHVhJywgJzIwMjUtMTAtMTUgMjA6MDY6MTknLCAnMjAyNi0wNC0wNCAwODo0MzozMicsIE5VTEwpLAooMiwgJ3dhd2EnLCAnMzI0NCcsICdTaXN3YScsICczNTA5MTE1NzA4Mzk3MScsICdzbWEgbmVnZXJpIDEgamVtYmVyJywgJzA4NTY0OTk1ODkzNicsICdrcmFqYW4gYW1wZWwnLCAnc2l0aScsICcwODU2NDk5NTg5MzYnLCAnT3JhbmcgVHVhJywgJzIwMjYtMDQtMDEgMDg6MDE6NDUnLCAnMjAyNi0wNC0wMSAwODowMTo0NScsIE5VTEwpLAooMywgJ0FseWEnLCAnMTMwIDAwMCA3MjQ1ODU3NCcsICdEb3NlbicsICczNTA5MTEwMDEwMDEwMScsICdpcGEnLCAnMDg1NjQ5OTU4OTM2JywgJ2plbWJlciBrb3RhJywgJ3N1bmVvJywgJzA5ODc2NTI0NDInLCAnU2F1ZGFyYScsICcyMDI2LTA0LTAxIDA4OjQ3OjU0JywgJzIwMjYtMDQtMDEgMDg6NDc6NTQnLCBOVUxMKSwKKDQsICdTeWFyaWZhaCBhdWxpYSBwdXRyaScsICdlMzEyMzAzMzgnLCAnTWFoYXNpc3dhJywgJzM1MDkxMTg3MjMyNzMnLCAndGVrbmlrJywgJzA4NTY0OTk1ODkzNicsICdqYWxhbiBnZWJhbmcnLCAndXRpJywgJzA4NzYzNTM1NDYnLCAnT3JhbmcgVHVhJywgJzIwMjYtMDQtMDcgMDc6MjA6MTknLCAnMjAyNi0wNC0wNyAwNzoyMDoxOScsIE5VTEwpLAooNSwgJ2NhY2EnLCAnZTMxMjM5ODc2JywgJ01haGFzaXN3YScsICcwOTgzNzM3NzQ2NCcsICdrZWRva3RlcmFuJywgJzA4NTY0OTk1ODkzNicsICdqbCBib25kb3dvc28nLCAnaWJ1IHJlbmknLCAnMDk4Njc3NTY0MycsICdPcmFuZyBUdWEnLCAnMjAyNi0wNC0wNyAwNzo1MToxMicsICcyMDI2LTA0LTA3IDA3OjUxOjEyJywgTlVMTCksCig2LCAnY2ljaSBtYXJpY2kgaGVoZScsICdlMzQ0NTc3ODknLCAnTWFoYXNpc3dhJywgJzc2NjU2NjY2NjY2NzY3NjcnLCAna2Vkb2t0ZXJhbiBoZXdhbicsICcwODU2NDk5NTg5MzYnLCAnamwgbWFzdHJpcCcsICdpYnUgY2ljaScsICcwOTg3NzY3NTY0NScsICdPcmFuZyBUdWEnLCAnMjAyNi0wNC0wNyAyMTo1ODo1MScsICcyMDI2LTA0LTA3IDIxOjU4OjUxJywgTlVMTCksCig3LCAnYWxpJywgJzg3NjU0MzMnLCAnTWFoYXNpc3dhJywgJzUyMTY3MzgzMzgnLCAnaXBhJywgJzA4NTY0OTk1ODkzNicsICdqZW1iZXInLCAnc2l0aScsICcwODc2NTQzMzYzNycsICdPcmFuZyBUdWEnLCAnMjAyNi0wNC0wNyAyMzoxOTowNycsICcyMDI2LTA0LTA3IDIzOjE5OjA3JywgTlVMTCksCig4LCAnZGV3aSBsdXRmaWFudGknLCAnZTM5MDc2NTQzJywgJ1Npc3dhJywgJzQ1NTY3Nzg5MDEyJywgJ3RraicsICcwODEyMzMyNzQ2MzInLCAnamVtYmVyJywgJ211c3RpYW5pJywgJzA5ODc3Njc1NjQ1JywgJ09yYW5nIFR1YScsICcyMDI2LTA0LTEzIDE5OjAzOjAzJywgJzIwMjYtMDQtMTMgMTk6MDM6MDMnLCBOVUxMKSwKKDksICdmaXJkYSBheXUgcHVzcGl0YSBzYXJpJywgJzM0MzIxNDM1NDY2JywgJ1Npc3dhJywgJzM3ODUyNTk3NDYxJywgJ2RrdicsICcwODU3Mjk5MTM5NTInLCAnamVtYmVyJywgJ211cnRpYWgnLCAnMTIyMzQ1Njc3ODknLCAnT3JhbmcgVHVhJywgJzIwMjYtMDQtMTMgMTk6MDk6MDInLCAnMjAyNi0wNC0xMyAxOTowOTowMicsIE5VTEwpLAooMTAsICdSYWRpdCBTZXB0aWFyJywgJzMxMjQ4NDM3NjUnLCAnU2lzd2EnLCAnMDIxODE3NDQ4MjYzMTUnLCAnSVBTJywgJzA4NTY0OTk1ODkzNicsICdLYWxpc2F0JywgJ1dhaHl1JywgJzA4NTY0OTk1ODkzNicsICdPcmFuZyBUdWEnLCAnMjAyNi0wNC0yMyAwOToxNDo1OScsICcyMDI2LTA0LTIzIDA5OjE0OjU5JywgTlVMTCksCigxMSwgJ1dhd2EnLCAnJywgJycsICcnLCAnTUlGJywgJzA4OTc2NTU2Nzg5MCcsICcnLCAnJywgJycsICcnLCBOVUxMLCBOVUxMLCAnRTMxMjMwODg3JyksCigxMiwgJ1dhd2EnLCAnSUQwMDEnLCAnTWFoYXNpc3dhJywgJzEyMzQ1Njc4OTAnLCAnTUlGJywgJzA4OTc2NTU2Nzg5MCcsICdKZW1iZXInLCAnT3JhbmcgVHVhJywgJzA4MTIzNDU2Nzg5JywgJ0F5YWgnLCBOVUxMLCBOVUxMLCAnRTMxMjMwODg3Jyk7'),
];
foreach ($statements as $sql) {
DB::statement($sql);
}
DB::statement('SET FOREIGN_KEY_CHECKS=1');
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,46 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class BukuSeeder extends Seeder
{
public function run(): void
{
$judulArray = ['Algoritma Data', 'Python Programming', 'Mobile Development', 'Web Framework', 'Database Design', 'Cloud Computing', 'Artificial Intelligence', 'Machine Learning', 'Deep Learning', 'IoT Development', 'Cybersecurity', 'Network Security', 'Software Architecture', 'Design Patterns', 'Clean Code', 'Agile Methodology', 'DevOps', 'Microservices', 'API Design', 'Testing Strategy', 'Performance Optimization'];
$penulis = ['Prof. Adi K', 'Dr. Bambang S', 'Ir. Cahyo W', 'Drs. Dedi R', 'M.Sc. Eka P', 'Eng. Farhan A', 'Prof. Gunawan Y', 'Dr. Hendra M', 'Ir. Imam B', 'Drs. Joko S', 'M.Sc. Karina D', 'Eng. Laras H'];
$penerbit = ['Penerbit Andi', 'Penerbit ITB', 'Gramedia', 'Erlangga', 'Kompas Media', 'Mizan', 'Elexmedia', 'PT Raja Grafindo', 'Benteng', 'Aksara', 'Kencana', 'Media Pembelajaran'];
$nomor = ['030', '059', '045', '070', '019', '089', '100', '159', '189', '200', '250', '299', '300', '350', '399', '400', '450', '499', '500', '550', '599', '600', '650', '699', '700', '750', '799', '800', '850', '899', '900', '950', '999', '012', '035', '062', '081', '098', '120', '175', '210', '275', '310', '380', '420', '478', '520', '580', '620', '678', '720', '890', '940'];
$kategori = DB::table('kategori')->pluck('id_kategori')->toArray();
for ($i = 1; $i <= 110; $i++) {
$idx = $i - 1;
$edisi = intval(($idx / 5)) + 1;
DB::table('buku')->insert([
'bibid' => 'BK' . str_pad($i, 4, '0', STR_PAD_LEFT),
'judul' => $judulArray[$idx % count($judulArray)] . ' Edisi ' . $edisi,
'edisi' => (string)$edisi,
'pengarang' => $penulis[$idx % count($penulis)],
'penerbit' => $penerbit[$idx % count($penerbit)],
'tahun_terbit' => 2018 + ($idx % 5),
'deskripsi_fisik' => (200 + $idx * 3) . ' halaman',
'nomor_panggil' => $nomor[$idx % count($nomor)] . ' ' . substr($penulis[$idx % count($penulis)], 0, 3),
'konten_digital' => 0,
'eksemplar' => 1 + ($idx % 10),
'id_kategori' => $kategori[$idx % count($kategori)],
'cover' => null,
'lokasi_x' => null,
'lokasi_y' => null,
'created_at' => now(),
'updated_at' => now(),
]);
}
}
}

View File

@ -8,36 +8,21 @@
class BukuTamuSeeder extends Seeder class BukuTamuSeeder extends Seeder
{ {
/** /**
* Run the database seeds. * Seed the buku_tamu table with data from SQL dump
*/ */
public function run(): void public function run(): void
{ {
// Ambil sembarang user ID DB::statement('SET FOREIGN_KEY_CHECKS=0');
$userId = DB::table('users')->value('id');
if ($userId) { // Execute each INSERT statement separately
DB::table('buku_tamu')->insert([ $statements = [
[ base64_decode('SU5TRVJUIElOVE8gYGJ1a3VfdGFtdWAgKGBpZF90YW11YCwgYGlkX3VzZXJgLCBgbmFtYV90YW11YCwgYGVtYWlsYCwgYG5vX2hwYCwgYGFzYWxfaW5zdGFuc2lgLCBgc3RhdHVzYCwgYHRhbmdnYWxfa3VuanVuZ2FuYCwgYHR1anVhbl9rdW5qdW5nYW5gKSBWQUxVRVMKKDMsIDMsIE5VTEwsIE5VTEwsIE5VTEwsIE5VTEwsIE5VTEwsICcyMDI2LTAyLTE0JywgJ01lbWJhY2EgQnVrdScpLAooNCwgMywgTlVMTCwgTlVMTCwgTlVMTCwgTlVMTCwgTlVMTCwgJzIwMjYtMDItMTMnLCAnTWVtaW5qYW0gQnVrdScpLAooNSwgTlVMTCwgJ3dhcmRoYXR1bCBqYW5uYWggZmlxeWFuaScsIE5VTEwsIE5VTEwsICdwb2xpamUnLCBOVUxMLCAnMjAyNi0wMy0wMycsICdNZW1iYWNhJyksCig2LCBOVUxMLCAnd2FyZGhhdHVsIGphbm5haCBmaXF5YW5pJywgTlVMTCwgTlVMTCwgJ3BvbGl0ZWtuaWsgbmVnZXJpIGplbWJlcicsIE5VTEwsICcyMDI2LTAzLTA4JywgJ01lbWJhY2EnKSwKKDcsIE5VTEwsICd3YXJkaGF0dWwgamFubmFoIGZpcXlhbmknLCBOVUxMLCBOVUxMLCAncG9saXRla25payBuZWdlcmkgamVtYmVyJywgTlVMTCwgJzIwMjYtMDMtMDgnLCAnTWVtYmFjYScpLAooOCwgTlVMTCwgJ1dhcmRoYXR1bCBKYW5uYWggRmlxeWFuaScsICd3YXJkaGF0dWxqYW5uYWhmaXF5YW5pQGdtYWlsLmNvbScsICcwODc2NTQzMjQ1NicsICdwb2xpdGVrbmlrIG5lZ2VyaSBqZW1iZXInLCAnTWFoYXNpc3dhJywgJzIwMjYtMDMtMzAnLCAnTWVtYmFjYSAmIE1lbWluamFtJyksCig5LCBOVUxMLCAnbmF5eWlyYScsICduYXl5aXJhQGdtYWlsLmNvbScsICcwODc2NTQzMjQ1NicsICd1bml2ZXJzaXRhcyBqZW1iZXInLCAnTWFoYXNpc3dhJywgJzIwMjYtMDQtMDEnLCAnTWVtaW5qYW0nKSwKKDEwLCBOVUxMLCAnc3lhcmlmYWggYXVsaWEgcHV0cmknLCAncGlwZWhAZ21haWwuY29tJywgJzA4NTY0OTk1ODkzNicsICd1bm11aCcsICdNYWhhc2lzd2EnLCAnMjAyNi0wNC0wNycsICdNZW1pbmphbScpLAooMTEsIE5VTEwsICdTeWFyaWZhaCBBdWxpYSBQdXRyaScsICd3YXJkaGF0dWxqYW5uYWhmaXF5YW5pQGdtYWlsLmNvbScsICcwODU2NDk5NTg5MzYnLCAnUG9saXRla25payBOZWdlcmkgSmVtYmVyJywgJ01haGFzaXN3YScsICcyMDI2LTA0LTE0JywgJ01lbWJhY2EgJiBNZW1pbmphbScpLAooMTIsIE5VTEwsICdkZXdpIGx1dGZpYW50aScsICdwZXJwdXNrYWJqZW1iZXJAZ21haWwuY29tJywgJzA4MTIzMzI3NDYzMicsICdzbWtuIDggamVtYmVyJywgJ1Npc3dhJywgJzIwMjYtMDQtMTQnLCAnTWVtYmFjYScpLAooMTMsIE5VTEwsICdDYWNhJywgJ0NhY2FAZ21haWwuY29tJywgJzA4NTY0OTk1ODkzNicsICd1bmVzYScsICdHdXJ1L0Rvc2VuJywgJzIwMjYtMDQtMjknLCAnTWVtaW5qYW0nKSwKKDE0LCBOVUxMLCBOVUxMLCBOVUxMLCBOVUxMLCBOVUxMLCBOVUxMLCAnMjAyNi0wNC0yOScsICdNZW1iYWNhICYgTWVtaW5qYW0nKTs='),
'id_user' => $userId, ];
'nama_tamu' => 'Pengunjung 1',
'email' => 'pengunjung1@example.com', foreach ($statements as $sql) {
'no_hp' => '081234567890', DB::statement($sql);
'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(),
],
]);
} }
DB::statement('SET FOREIGN_KEY_CHECKS=1');
} }
} }

View File

@ -2,11 +2,14 @@
namespace Database\Seeders; namespace Database\Seeders;
use App\Models\User; use Database\Seeders\KategoriSeeder;
use App\Models\Buku; use Database\Seeders\UserSeeder;
use App\Models\Anggota; use Database\Seeders\AnggotaSeeder;
use Database\Seeders\BukuFromSqlSeeder;
use Database\Seeders\BukuTamuSeeder;
use Database\Seeders\PeminjamanSeeder;
use Illuminate\Database\Seeder; use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\DB;
class DatabaseSeeder extends Seeder class DatabaseSeeder extends Seeder
{ {
@ -15,59 +18,16 @@ class DatabaseSeeder extends Seeder
*/ */
public function run(): void public function run(): void
{ {
// Admin user DB::statement('SET FOREIGN_KEY_CHECKS=0');
User::updateOrCreate(
['email' => 'admin@perpustakaan.com'],
[
'name' => 'Admin',
'password' => Hash::make('password'),
'role' => 'admin',
]
);
// Regular user
User::updateOrCreate(
['email' => 'user@perpustakaan.com'],
[
'name' => 'User Test',
'password' => Hash::make('password'),
'role' => 'user',
]
);
// Sample buku
Buku::create([
'judul' => 'Pemrograman Web dengan Laravel',
'pengarang' => 'Adi Nugroho',
'penerbit' => 'Informatika Bandung',
'tahun_terbit' => 2023,
'stok' => 5,
]);
Buku::create([
'judul' => 'Basis Data Lanjutan',
'pengarang' => 'Fathansyah',
'penerbit' => 'Informatika Bandung',
'tahun_terbit' => 2020,
'stok' => 3,
]);
// Sample anggota
Anggota::create([
'nama' => 'Mahasiswa Test',
'no_identitas' => 'E31230001',
'jenis_anggota' => 'Mahasiswa',
'no_ktp' => '3509012345678901',
'prodi' => 'Manajemen Informatika',
'no_hp' => '081234567890',
'alamat' => 'Jl. Mastrip No. 164, Jember',
'nama_wali' => 'Budi Santoso',
'no_hp_wali' => '081298765432',
'hubungan_wali' => 'Orang Tua',
]);
$this->call([ $this->call([
KategoriSeeder::class,
UserSeeder::class,
AnggotaSeeder::class,
BukuFromSqlSeeder::class,
BukuTamuSeeder::class, BukuTamuSeeder::class,
PeminjamanSeeder::class,
]); ]);
DB::statement('SET FOREIGN_KEY_CHECKS=1');
} }
} }

View File

@ -0,0 +1,28 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class KategoriSeeder extends Seeder
{
/**
* Seed the kategori table with data from SQL dump
*/
public function run(): void
{
DB::statement('SET FOREIGN_KEY_CHECKS=0');
// Execute each INSERT statement separately
$statements = [
base64_decode('SU5TRVJUIElOVE8gYGthdGVnb3JpYCAoYGlkX2thdGVnb3JpYCwgYG5hbWFfa2F0ZWdvcmlgKSBWQUxVRVMKKDEsICdVbXVtJyk7'),
];
foreach ($statements as $sql) {
DB::statement($sql);
}
DB::statement('SET FOREIGN_KEY_CHECKS=1');
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,28 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class UserSeeder extends Seeder
{
/**
* Seed the users table with data from SQL dump
*/
public function run(): void
{
DB::statement('SET FOREIGN_KEY_CHECKS=0');
// Execute each INSERT statement separately
$statements = [
base64_decode('SU5TRVJUIElOVE8gYHVzZXJzYCAoYGlkYCwgYG5hbWVgLCBgZW1haWxgLCBgZW1haWxfdmVyaWZpZWRfYXRgLCBgcGFzc3dvcmRgLCBgcm9sZWAsIGByZW1lbWJlcl90b2tlbmAsIGBjcmVhdGVkX2F0YCwgYHVwZGF0ZWRfYXRgLCBgbm9faHBgLCBgaW5zdGFuc2lgLCBgc3RhdHVzYCwgYG5vX2t0cGAsIGBhbGFzYW5gKSBWQUxVRVMKKDEsICdXYScsICd3YXJkaGF0dWxqYW5uYWhmaXF5YW5pQGdtYWlsLmNvbScsIE5VTEwsICckMnkkMTIkMVhNanV5d0lNcGF3YS4vNmhTNXIzLlFweGhrT0ZuRGd2MnhTRHlYbTBkUWIvdzFtRTFuUEcnLCAnYWRtaW4nLCAnMTZKTlBCQ2U5VG5NUXlBY21sUW50cGg1cWF4RXVYNUF5QVkycTRIYUpQS1ZpUmJqcWd2dHFtbUhRUDNCJywgJzIwMjUtMTAtMjMgMDA6Mjg6MjAnLCAnMjAyNi0wMy0yOSAxODo0NDowNicsIE5VTEwsIE5VTEwsIE5VTEwsIE5VTEwsIE5VTEwpLAooMiwgJ1dhd2EnLCAnd2F3YTEyMzQ1QGdtYWlsLmNvbScsIE5VTEwsICckMnkkMTIkekFNTzNjMXV1V2ozblMxZC9aUEVQdVlnT25PRi4xcEpxdGxvRnd3NHhvZjZqdUZ1QmlVMHUnLCAndXNlcicsIE5VTEwsICcyMDI1LTEwLTIzIDIzOjQ2OjM2JywgJzIwMjUtMTAtMjMgMjM6NDY6MzYnLCBOVUxMLCBOVUxMLCBOVUxMLCBOVUxMLCBOVUxMKSwKKDMsICdhcmEnLCAnYXJhQGdtYWlsLmNvbScsIE5VTEwsICckMnkkMTIkdmFmU0Frang4bzZnMFNrRkVQL3VtT0M2SmhzRDI0L2ZOSFQzdlVWSmF2Si8yNmtFRGZRZzInLCAndXNlcicsIE5VTEwsICcyMDI2LTAxLTI0IDA5OjMyOjQxJywgJzIwMjYtMDEtMjQgMDk6MzI6NDEnLCBOVUxMLCBOVUxMLCBOVUxMLCBOVUxMLCBOVUxMKSwKKDQsICdXYXdhJywgJ1dhd2E1NDMyMUBnbWFpbC5jb20nLCBOVUxMLCAnJDJ5JDEyJDNSRHphQ3B1NjVvR2xGVmNnZGVwdU9ONFFGMUh6Yy9wbWJPREY3RUtYMkZ3ZEZkd1g5ZHBtJywgJ3VzZXInLCBOVUxMLCAnMjAyNi0wMS0yNSAwNjozMDozMScsICcyMDI2LTAxLTI1IDA2OjMwOjMxJywgTlVMTCwgTlVMTCwgTlVMTCwgTlVMTCwgTlVMTCksCig1LCAnV2FyZGhhdHVsIEphbm5haCBGaXF5YW5pJywgJ3dhcmRoYWphbm5haEBnbWFpbC5jb20nLCBOVUxMLCAnJDJ5JDEyJEtsV0FZVVB2L3U3SFNLa2dxWm1SNS5LdGJxdWlJMTZEdUFqMGVKQmhJYmJ5L0dNNGY1VDBXJywgJ3VzZXInLCBOVUxMLCAnMjAyNi0wMS0yNSAwNzowNzo0NCcsICcyMDI2LTAxLTI1IDA3OjA3OjQ0JywgJzA4NTY3MzE3MTMyJywgJ1BvbGl0ZWtuaWsgTmVnZXJpIEplbWJlcicsICdNYWhhc2lzd2EnLCAnMzUwOTExNTcwNjA1MDAwMScsICdNZW1iYWNhICYgTWVtaW5qYW0nKSwKKDYsICdqdWxpYW4nLCAnanVsaWFucm9tYWRob25pQGdtYWlsLmNvbScsIE5VTEwsICckMnkkMTIkaHBZTFRvOVJESGwyNzEyc0dkeTl0TzF3SGExNXQucXIzaDgvNWJHVjZmeVcyZ0NCdi5sYmEnLCAndXNlcicsIE5VTEwsICcyMDI2LTAxLTI1IDA4OjAzOjIxJywgJzIwMjYtMDEtMjUgMDg6MDM6MjEnLCAnMDg5NzY1NTY3ODkwJywgJ1BvbGl0ZWtuaWsgTmVnZXJpIEplbWJlcicsICdNYWhhc2lzd2EnLCAnMzUwOTExNTcwNjA1MDAwMScsICdNZW1iYWNhICYgTWVtaW5qYW0nKSwKKDcsICdBZG1pbmlzdHJhdG9yJywgJ2FkbWluQGdtYWlsLmNvbScsIE5VTEwsICckMnkkMTIkV1p6My5UQUM1OE9oaTNkY0NJT0hkLi5HNkJPRi9yMUtrUHRma1BMa1FSZzl0cEtjdnA0WUsnLCAndXNlcicsIE5VTEwsICcyMDI2LTA0LTA3IDA3OjA5OjU0JywgJzIwMjYtMDQtMDcgMDc6MDk6NTQnLCBOVUxMLCBOVUxMLCBOVUxMLCBOVUxMLCBOVUxMKSwKKDgsICdGYXRjaHVyIFJvY2htYW4nLCAnZmF0Y2h1cjQ1QGdtYWlsLmNvbScsIE5VTEwsICckMnkkMTIkSDVocldWZC5LVUxuelV0d1dyL2RJdW5CWFhzdERLbzRMY29rRmpOQ0lkY3cvVk9ObnFTOTYnLCAnYWRtaW4nLCBOVUxMLCAnMjAyNi0wNC0xMyAxODo1MTozMCcsICcyMDI2LTA0LTEzIDE4OjUxOjMwJywgTlVMTCwgTlVMTCwgTlVMTCwgTlVMTCwgTlVMTCk7'),
];
foreach ($statements as $sql) {
DB::statement($sql);
}
DB::statement('SET FOREIGN_KEY_CHECKS=1');
}
}

View File

@ -18,7 +18,7 @@
</div> </div>
@endif @endif
<form action="{{ route('admin.buku.update', $buku->id) }}" method="POST" enctype="multipart/form-data" <form action="{{ route('admin.buku.update', $buku->id_buku) }}" method="POST" enctype="multipart/form-data"
class="p-6 space-y-6"> class="p-6 space-y-6">
@csrf @csrf
@method('PUT') @method('PUT')

View File

@ -47,11 +47,11 @@ class="bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to
<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-sm text-gray-500">{{ $item->eksemplar }}</td>
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<div class="flex justify-end gap-3"> <div class="flex justify-end gap-3">
<a href="{{ route('admin.buku.edit', $item->id) }}" <a href="{{ route('admin.buku.edit', $item->id_buku) }}"
class="text-blue-600 hover:text-blue-900"> class="text-blue-600 hover:text-blue-900">
Edit Edit
</a> </a>
<form action="{{ route('admin.buku.destroy', $item->id) }}" method="POST" <form action="{{ route('admin.buku.destroy', $item->id_buku) }}" method="POST"
onsubmit="return confirm('Apakah Anda yakin ingin menghapus aset buku ini?')"> onsubmit="return confirm('Apakah Anda yakin ingin menghapus aset buku ini?')">
@csrf @csrf
@method('DELETE') @method('DELETE')

View File

@ -6,28 +6,31 @@
<x-page-header title="Edit Buku" /> <x-page-header title="Edit Buku" />
<x-card class="max-w-2xl mx-auto"> <x-card class="max-w-2xl mx-auto">
<form action="{{ route('admin.buku.update', $buku->id) }}" method="POST" class="space-y-6"> <form action="{{ route('admin.buku.update', $buku->id_buku) }}" method="POST" class="space-y-6">
@csrf @csrf
@method('PUT') @method('PUT')
<!-- Judul --> <!-- Judul -->
<div> <div>
<x-input-label for="judul" value="Judul Buku" /> <x-input-label for="judul" value="Judul Buku" />
<x-text-input id="judul" name="judul" type="text" class="mt-1 block w-full" :value="old('judul', $buku->judul)" required autofocus /> <x-text-input id="judul" name="judul" type="text" class="mt-1 block w-full" :value="old('judul', $buku->judul)" required
autofocus />
<x-input-error class="mt-2" :messages="$errors->get('judul')" /> <x-input-error class="mt-2" :messages="$errors->get('judul')" />
</div> </div>
<!-- Penulis --> <!-- Penulis -->
<div> <div>
<x-input-label for="pengarang" value="Pengarang" /> <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)" required /> <x-text-input id="pengarang" name="pengarang" type="text" class="mt-1 block w-full" :value="old('pengarang', $buku->pengarang)"
required />
<x-input-error class="mt-2" :messages="$errors->get('pengarang')" /> <x-input-error class="mt-2" :messages="$errors->get('pengarang')" />
</div> </div>
<!-- Penerbit --> <!-- Penerbit -->
<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', $buku->penerbit)" required /> <x-text-input id="penerbit" name="penerbit" type="text" class="mt-1 block w-full" :value="old('penerbit', $buku->penerbit)"
required />
<x-input-error class="mt-2" :messages="$errors->get('penerbit')" /> <x-input-error class="mt-2" :messages="$errors->get('penerbit')" />
</div> </div>
@ -35,14 +38,16 @@
<!-- Tahun Terbit --> <!-- Tahun Terbit -->
<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', $buku->tahun_terbit)" required /> <x-text-input id="tahun_terbit" name="tahun_terbit" type="number" class="mt-1 block w-full"
:value="old('tahun_terbit', $buku->tahun_terbit)" required />
<x-input-error class="mt-2" :messages="$errors->get('tahun_terbit')" /> <x-input-error class="mt-2" :messages="$errors->get('tahun_terbit')" />
</div> </div>
<!-- Stok --> <!-- Stok -->
<div> <div>
<x-input-label for="stok" value="Stok" /> <x-input-label for="stok" value="Stok" />
<x-text-input id="stok" name="stok" type="number" class="mt-1 block w-full" :value="old('stok', $buku->stok)" required /> <x-text-input id="stok" name="stok" type="number" class="mt-1 block w-full" :value="old('stok', $buku->stok)"
required />
<x-input-error class="mt-2" :messages="$errors->get('stok')" /> <x-input-error class="mt-2" :messages="$errors->get('stok')" />
</div> </div>
</div> </div>

View File

@ -9,15 +9,16 @@
</div> </div>
</div> </div>
@if(session('success')) @if (session('success'))
<x-alert type="success" :message="session('success')" /> <x-alert type="success" :message="session('success')" />
@endif @endif
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6"> <div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
<div class="flex flex-col md:flex-row justify-between items-center mb-6 gap-4"> <div class="flex flex-col md:flex-row justify-between items-center mb-6 gap-4">
<div class="flex gap-2"> <div class="flex gap-2">
<a href="{{ route('admin.buku.create') }}" class="px-4 py-2 bg-[#7488e1] text-white rounded-lg text-sm font-medium hover:bg-[#5f74d1] transition shadow-md shadow-blue-200"> <a href="{{ route('admin.buku.create') }}"
class="px-4 py-2 bg-[#7488e1] text-white rounded-lg text-sm font-medium hover:bg-[#5f74d1] transition shadow-md shadow-blue-200">
+ Tambah Buku + Tambah Buku
</a> </a>
</div> </div>
@ -33,37 +34,43 @@
<th class="py-4 px-4 text-xs font-semibold text-gray-400 uppercase tracking-wider">Penerbit</th> <th class="py-4 px-4 text-xs font-semibold text-gray-400 uppercase tracking-wider">Penerbit</th>
<th class="py-4 px-4 text-xs font-semibold text-gray-400 uppercase tracking-wider">Tahun</th> <th class="py-4 px-4 text-xs font-semibold text-gray-400 uppercase tracking-wider">Tahun</th>
<th class="py-4 px-4 text-xs font-semibold text-gray-400 uppercase tracking-wider">Stok</th> <th class="py-4 px-4 text-xs font-semibold text-gray-400 uppercase tracking-wider">Stok</th>
<th class="py-4 px-4 text-xs font-semibold text-gray-400 uppercase tracking-wider text-right">Aksi</th> <th class="py-4 px-4 text-xs font-semibold text-gray-400 uppercase tracking-wider text-right">Aksi
</th>
</tr> </tr>
</thead> </thead>
<tbody class="divide-y divide-gray-50 text-sm text-gray-600"> <tbody class="divide-y divide-gray-50 text-sm text-gray-600">
@forelse($bukus as $buku) @forelse($bukus as $buku)
<tr class="hover:bg-gray-50 transition"> <tr class="hover:bg-gray-50 transition">
<td class="py-4 px-4 font-medium">{{ $loop->iteration + ($bukus->currentPage() - 1) * $bukus->perPage() }}</td> <td class="py-4 px-4 font-medium">
<td class="py-4 px-4 font-medium text-gray-800">{{ $buku->judul }}</td> {{ $loop->iteration + ($bukus->currentPage() - 1) * $bukus->perPage() }}</td>
<td class="py-4 px-4">{{ $buku->pengarang }}</td> <td class="py-4 px-4 font-medium text-gray-800">{{ $buku->judul }}</td>
<td class="py-4 px-4">{{ $buku->penerbit }}</td> <td class="py-4 px-4">{{ $buku->pengarang }}</td>
<td class="py-4 px-4">{{ $buku->tahun_terbit }}</td> <td class="py-4 px-4">{{ $buku->penerbit }}</td>
<td class="py-4 px-4"> <td class="py-4 px-4">{{ $buku->tahun_terbit }}</td>
<span class="px-2 py-1 rounded-full text-xs font-medium {{ $buku->stok > 0 ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700' }}"> <td class="py-4 px-4">
{{ $buku->stok }} <span
</span> class="px-2 py-1 rounded-full text-xs font-medium {{ $buku->stok > 0 ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700' }}">
</td> {{ $buku->stok }}
<td class="py-4 px-4 text-right"> </span>
<div class="flex justify-end gap-2"> </td>
<a href="{{ route('admin.buku.edit', $buku->id) }}" class="px-3 py-1 bg-yellow-100 text-yellow-700 rounded-lg text-xs font-medium hover:bg-yellow-200 transition">Edit</a> <td class="py-4 px-4 text-right">
<form action="{{ route('admin.buku.destroy', $buku->id) }}" method="POST" onsubmit="return confirm('Yakin hapus buku ini?')"> <div class="flex justify-end gap-2">
@csrf <a href="{{ route('admin.buku.edit', $buku->id_buku) }}"
@method('DELETE') class="px-3 py-1 bg-yellow-100 text-yellow-700 rounded-lg text-xs font-medium hover:bg-yellow-200 transition">Edit</a>
<button type="submit" class="px-3 py-1 bg-red-100 text-red-700 rounded-lg text-xs font-medium hover:bg-red-200 transition">Hapus</button> <form action="{{ route('admin.buku.destroy', $buku->id_buku) }}" method="POST"
</form> onsubmit="return confirm('Yakin hapus buku ini?')">
</div> @csrf
</td> @method('DELETE')
</tr> <button type="submit"
class="px-3 py-1 bg-red-100 text-red-700 rounded-lg text-xs font-medium hover:bg-red-200 transition">Hapus</button>
</form>
</div>
</td>
</tr>
@empty @empty
<tr> <tr>
<td colspan="7" class="py-8 px-4 text-center text-gray-400">Belum ada data buku</td> <td colspan="7" class="py-8 px-4 text-center text-gray-400">Belum ada data buku</td>
</tr> </tr>
@endforelse @endforelse
</tbody> </tbody>
</table> </table>
@ -73,4 +80,4 @@
{{ $bukus->links() }} {{ $bukus->links() }}
</div> </div>
</div> </div>
@endsection @endsection

View File

@ -41,7 +41,8 @@
&larr; Kembali &larr; Kembali
</a> </a>
<div class="flex gap-3"> <div class="flex gap-3">
<x-action-button href="{{ route('admin.buku.edit', $buku->id) }}" variant="warning" class="bg-yellow-50 px-4 py-2 rounded-lg"> <x-action-button href="{{ route('admin.buku.edit', $buku->id_buku) }}" variant="warning"
class="bg-yellow-50 px-4 py-2 rounded-lg">
Edit Buku Edit Buku
</x-action-button> </x-action-button>
</div> </div>

View File

@ -14,10 +14,31 @@
tailwind.config = { tailwind.config = {
theme: { theme: {
extend: { extend: {
fontFamily: { sans: ['Inter', 'sans-serif'] }, fontFamily: {
sans: ['Inter', 'sans-serif']
},
colors: { colors: {
primary: { 50: '#eef2ff', 100: '#e0e7ff', 200: '#c7d2fe', 300: '#a5b4fc', 400: '#818cf8', 500: '#6366f1', 600: '#4f46e5', 700: '#4338ca', 800: '#3730a3', 900: '#312e81' }, primary: {
accent: { 50: '#ecfdf5', 100: '#d1fae5', 200: '#a7f3d0', 300: '#6ee7b7', 400: '#34d399', 500: '#10b981', 600: '#059669' }, 50: '#eef2ff',
100: '#e0e7ff',
200: '#c7d2fe',
300: '#a5b4fc',
400: '#818cf8',
500: '#6366f1',
600: '#4f46e5',
700: '#4338ca',
800: '#3730a3',
900: '#312e81'
},
accent: {
50: '#ecfdf5',
100: '#d1fae5',
200: '#a7f3d0',
300: '#6ee7b7',
400: '#34d399',
500: '#10b981',
600: '#059669'
},
} }
} }
} }
@ -92,25 +113,29 @@
<nav class="glass-nav fixed w-full top-0 z-50 border-b border-gray-100/50"> <nav class="glass-nav fixed w-full top-0 z-50 border-b border-gray-100/50">
<div class="max-w-7xl mx-auto px-6 py-4 flex justify-between items-center"> <div class="max-w-7xl mx-auto px-6 py-4 flex justify-between items-center">
<a href="{{ route('home') }}" class="flex items-center gap-3 group"> <a href="{{ route('home') }}" class="flex items-center gap-3 group">
<div class="w-10 h-10 bg-gradient-to-br from-primary-500 to-primary-700 rounded-xl flex items-center justify-center shadow-lg shadow-primary-200 group-hover:shadow-primary-300 transition-shadow"> <div
class="w-10 h-10 bg-gradient-to-br from-primary-500 to-primary-700 rounded-xl flex items-center justify-center shadow-lg shadow-primary-200 group-hover:shadow-primary-300 transition-shadow">
<i class="fas fa-book-open text-white text-sm"></i> <i class="fas fa-book-open text-white text-sm"></i>
</div> </div>
<div class="flex flex-col"> <div class="flex flex-col">
<span class="font-extrabold text-xl tracking-tight text-gray-900 leading-none">Sara<span class="gradient-text">kata</span></span> <span class="font-extrabold text-xl tracking-tight text-gray-900 leading-none">Sara<span
<span class="text-[10px] font-bold text-gray-500 uppercase tracking-widest mt-1 hidden sm:inline-block">Perpustakaan Daerah Jember</span> class="gradient-text">kata</span></span>
<span
class="text-[10px] font-bold text-gray-500 uppercase tracking-widest mt-1 hidden sm:inline-block">Perpustakaan
Daerah Jember</span>
</div> </div>
</a> </a>
<div class="flex items-center gap-8 text-sm font-medium"> <div class="flex items-center gap-8 text-sm font-medium">
<a href="{{ route('home') }}" <a href="{{ route('home') }}"
class="text-gray-600 hover:text-primary-600 transition-colors relative 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">Beranda</a> class="relative transition-colors {{ request()->routeIs('home') ? 'text-primary-600 font-semibold' : 'text-gray-600 hover:text-primary-600' }} after:absolute after:bottom-[-4px] after:left-0 {{ request()->routeIs('home') ? 'after:w-full' : 'after:w-0 hover:after:w-full' }} after:h-0.5 after:bg-primary-500 after:transition-all">Beranda</a>
<a href="{{ route('katalog.index') }}" <a href="{{ route('katalog.index') }}"
class="text-gray-600 hover:text-primary-600 transition-colors relative 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">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="text-gray-600 hover:text-primary-600 transition-colors relative 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 {{ 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>
<a href="{{ route('home') }}#rekomendasi" <a href="{{ route('home') }}#rekomendasi"
class="text-gray-600 hover:text-primary-600 transition-colors relative 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 {{ 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>
@guest @guest
<button onclick="openGuestModal()" <button onclick="openGuestModal()"
@ -124,7 +149,7 @@ class="px-5 py-2.5 bg-gradient-to-r from-primary-600 to-primary-700 text-white r
@endguest @endguest
@auth @auth
@if(auth()->user()->role === 'admin') @if (auth()->user()->role === 'admin')
<a href="{{ route('admin.dashboard') }}" <a href="{{ route('admin.dashboard') }}"
class="px-5 py-2.5 bg-gradient-to-r from-primary-600 to-primary-700 text-white rounded-xl font-semibold shadow-lg shadow-primary-200 hover:shadow-primary-300 transition-all"> class="px-5 py-2.5 bg-gradient-to-r from-primary-600 to-primary-700 text-white rounded-xl font-semibold shadow-lg shadow-primary-200 hover:shadow-primary-300 transition-all">
<i class="fas fa-tachometer-alt mr-1.5"></i> Dashboard Admin <i class="fas fa-tachometer-alt mr-1.5"></i> Dashboard Admin
@ -173,7 +198,8 @@ class="w-10 h-10 bg-gradient-to-br from-primary-500 to-primary-700 rounded-xl fl
Buku</a></li> Buku</a></li>
<li><a href="{{ route('home') }}#fitur" class="hover:text-white transition-colors">Fitur</a> <li><a href="{{ route('home') }}#fitur" class="hover:text-white transition-colors">Fitur</a>
</li> </li>
<li><a href="{{ route('home') }}#rekomendasi" class="hover:text-white transition-colors">Koleksi <li><a href="{{ route('home') }}#rekomendasi"
class="hover:text-white transition-colors">Koleksi
Buku</a></li> Buku</a></li>
<li><a href="{{ route('buku_tamu.index') }}" class="hover:text-white transition-colors">Buku <li><a href="{{ route('buku_tamu.index') }}" class="hover:text-white transition-colors">Buku
Tamu</a></li> Tamu</a></li>
@ -215,4 +241,4 @@ class="fab fa-twitter text-sm"></i></a>
@stack('scripts') @stack('scripts')
</body> </body>
</html> </html>

View File

@ -67,7 +67,17 @@ class="group bg-white rounded-2xl shadow-sm hover:shadow-2xl border border-gray-
<div class="relative w-full pt-[140%] overflow-hidden bg-gray-50 flex-shrink-0"> <div class="relative w-full pt-[140%] overflow-hidden bg-gray-50 flex-shrink-0">
@if ($item->cover) @if ($item->cover)
<img src="{{ asset('storage/' . $item->cover) }}" alt="{{ $item->judul }}" <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"> class="absolute inset-0 w-full h-full object-cover {{ !$habis ? 'group-hover:scale-110' : '' }} transition-transform duration-700 ease-in-out"
onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';">
<div
class="hidden absolute inset-0 flex flex-col items-center justify-center text-gray-300 bg-gray-100 {{ !$habis ? 'group-hover:bg-gray-200' : '' }} transition-colors duration-300">
<svg class="w-12 h-12 mb-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"
d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253">
</path>
</svg>
<span class="text-xs font-medium">Cover Tidak Tersedia</span>
</div>
@else @else
<div <div
class="absolute inset-0 flex flex-col items-center justify-center text-gray-300 bg-gray-100 {{ !$habis ? 'group-hover:bg-gray-200' : '' }} transition-colors duration-300"> class="absolute inset-0 flex flex-col items-center justify-center text-gray-300 bg-gray-100 {{ !$habis ? 'group-hover:bg-gray-200' : '' }} transition-colors duration-300">
@ -156,7 +166,7 @@ class="w-full text-center bg-gray-100 text-gray-500 text-sm font-semibold py-2 p
Habis Dipinjam Habis Dipinjam
</button> </button>
@else @else
<a href="{{ route('katalog.show', $item->id) }}" <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"> 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 Lihat Detail
</a> </a>
@ -200,7 +210,7 @@ class="w-10 h-10 bg-gradient-to-br from-orange-400 to-red-500 rounded-xl flex it
<li <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"> 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> <div>
<a href="{{ route('katalog.show', $top->id) }}" <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"> class="font-bold text-gray-900 text-base md:text-lg group-hover:text-blue-600 transition-colors block mb-1">
{{ $top->judul }} {{ $top->judul }}
</a> </a>
@ -209,7 +219,8 @@ class="font-bold text-gray-900 text-base md:text-lg group-hover:text-blue-600 tr
<div class="self-start sm:self-auto"> <div class="self-start sm:self-auto">
<span <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"> 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 <i class="fas fa-chart-line text-blue-500"></i> {{ $top->peminjaman_count }}
Peminjaman
</span> </span>
</div> </div>
</li> </li>

View File

@ -405,7 +405,7 @@ class="text-xs font-bold text-blue-600 bg-blue-50 px-2 py-1 rounded">{{ $rek->no
<p class="text-sm text-gray-600 line-clamp-1">{{ $rek->pengarang }}</p> <p class="text-sm text-gray-600 line-clamp-1">{{ $rek->pengarang }}</p>
</div> </div>
<div class="px-5 py-3 bg-gray-50 border-t border-gray-100 mt-auto"> <div class="px-5 py-3 bg-gray-50 border-t border-gray-100 mt-auto">
<a href="{{ route('katalog.show', $rek->id) }}" <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"> class="text-sm font-semibold text-blue-600 hover:text-blue-800 flex items-center justify-center w-full">
Lihat Detail Lihat Detail
</a> </a>

View File

@ -101,7 +101,7 @@ class="w-full text-center bg-gray-100 text-gray-500 text-xs font-semibold py-2 p
Habis Dipinjam Habis Dipinjam
</button> </button>
@else @else
<a href="{{ route('katalog.show', $item->id ?? 1) }}" <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"> 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 Lihat Detail
</a> </a>

View File

@ -105,7 +105,7 @@ class="w-full text-center bg-gray-100 text-gray-500 text-sm font-semibold py-2 p
Habis Dipinjam Habis Dipinjam
</button> </button>
@else @else
<a href="{{ route('katalog.show', $item->id ?? 1) }}" <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"> 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 Lihat Detail
</a> </a>