refactor: update book stock management, refine validation constraints, and adjust dashboard statistics and UI components.

This commit is contained in:
cukiprit 2026-04-14 00:19:26 +07:00
parent 0c3369262f
commit 78df5b3a72
15 changed files with 33 additions and 25 deletions

View File

@ -126,9 +126,10 @@ public function store(Request $request)
]);
// Update book status and decrement stock
$newStok = $book->stok - 1;
$book->update([
'status' => 'Dipinjam',
'stok' => $book->stok - 1,
'status' => $newStok <= 0 ? 'Dipinjam' : 'Tersedia',
'stok' => $newStok,
]);
}

View File

@ -61,7 +61,7 @@ public function store(Request $request)
'judul' => 'required|string|min:3|max:50',
'kategori' => 'required|string|min:3|max:50',
'youtube_link' => 'required|url',
'deskripsi' => 'required|string',
'deskripsi' => 'required|string|max:255',
]);
$validated['user_id'] = auth()->id();
@ -78,7 +78,7 @@ public function update(Request $request, $id)
'judul' => 'required|string|min:3|max:50',
'kategori' => 'required|string|min:3|max:50',
'youtube_link' => 'required|url',
'deskripsi' => 'required|string',
'deskripsi' => 'required|string|max:255',
]);
$rekomendasi->update($validated);

View File

@ -101,6 +101,8 @@ public function store(Request $request)
$validated['file_pdf'] = basename($path);
}
$validated['status'] = $validated['stok'] <= 0 ? 'Dipinjam' : 'Tersedia';
Book::create($validated);
return redirect()->route('admin.buku.index')->with('success', 'Buku berhasil ditambahkan.');
@ -132,6 +134,8 @@ public function update(Request $request, $id)
$validated['file_pdf'] = basename($path);
}
$validated['status'] = $validated['stok'] <= 0 ? 'Dipinjam' : 'Tersedia';
$buku->update($validated);
return redirect()->route('admin.buku.index')->with('success', 'Buku berhasil diperbarui.');

View File

@ -22,7 +22,7 @@ public function index()
['label' => 'Total Buku', 'value' => $allBooks, 'icon' => 'bi-journal-bookmark-fill', 'color' => 'primary'],
['label' => 'Total Anggota', 'value' => $allUsers, 'icon' => 'bi-people-fill', 'color' => 'success'],
['label' => 'Buku Dipinjam', 'value' => $bukuDipinjam, 'icon' => 'bi-arrow-up-right-circle-fill', 'color' => 'warning'],
['label' => 'Total Denda', 'value' => 'Rp ' . number_format(Loan::where('status', 'Terlambat')->sum('fine_overdue'), 0, ',', '.'), 'icon' => 'bi-cash-coin', 'color' => 'danger'],
['label' => 'Total Denda', 'value' => 'Rp ' . number_format(Loan::sum('fine_overdue') + Loan::sum('fine_damage'), 0, ',', '.'), 'icon' => 'bi-cash-coin', 'color' => 'danger'],
];
// Monthly stats (last 7 months)

View File

@ -47,7 +47,7 @@ public function store(Request $request)
{
$validated = $request->validate([
'title' => 'required|string|min:3|max:50',
'content' => 'required|string',
'content' => 'required|string|max:255',
'type' => 'required|in:info,warning,success,danger',
'icon' => 'nullable|string|max:50',
]);
@ -69,7 +69,7 @@ public function update(Request $request, $id)
$validated = $request->validate([
'title' => 'required|string|min:3|max:50',
'content' => 'required|string',
'content' => 'required|string|max:255',
'type' => 'required|in:info,warning,success,danger',
'icon' => 'nullable|string|max:50',
]);

View File

@ -45,7 +45,7 @@ public function index()
// Stats calculation
$stats = [
['label' => 'Buku yang dipinjam', 'value' => $loans->count(), 'icon' => 'bi-book-half', 'color' => 'primary'],
['label' => 'Tenggat Waktu', 'value' => $bukuPinjamOffline->where('sisa_hari', '<=', 3)->where('sisa_hari', '>=', 0)->count(), 'icon' => 'bi-clock-history', 'color' => 'danger'],
['label' => 'Tenggat Waktu', 'value' => $bukuPinjamOffline->where('sisa_hari', '<=', 2)->count(), 'icon' => 'bi-clock-history', 'color' => 'danger'],
['label' => 'Buku dikembalikan', 'value' => Loan::where('user_id', $user->id)->where('status', 'Dikembalikan')->count(), 'icon' => 'bi-check-circle', 'color' => 'success'],
['label' => 'History Baca', 'value' => Loan::where('user_id', $user->id)->count(), 'icon' => 'bi-hourglass-split', 'color' => 'warning'],
];

View File

@ -88,7 +88,7 @@ public function form($id)
$buku = Book::with('category')->findOrFail($id);
$semuaBuku = Book::whereJsonContains('tipe_akses', 'offline')
->where('status', 'Tersedia')
->where('stok', '>', 0)
->get();
return view('peminjaman.form', compact('user', 'buku', 'semuaBuku'));
@ -113,7 +113,7 @@ public function store(Request $request)
foreach ($bukuIds as $bukuId) {
$book = Book::lockForUpdate()->find($bukuId);
if ($book->status !== 'Tersedia') {
if ($book->stok <= 0) {
throw new \Exception("Buku '{$book->judul}' sudah tidak tersedia.");
}
@ -126,7 +126,11 @@ public function store(Request $request)
'status' => 'Dipinjam',
]);
$book->update(['status' => 'Dipinjam']);
$newStok = $book->stok - 1;
$book->update([
'stok' => $newStok,
'status' => $newStok <= 0 ? 'Dipinjam' : 'Tersedia'
]);
}
});

View File

@ -25,7 +25,7 @@ public function rules(): array
'max:255',
Rule::unique(User::class)->ignore($this->user()->id),
],
'phone' => ['required', 'numeric', 'digits_between:13,15'],
'phone' => ['required', 'string', 'min:13', 'max:16'],
];
}
}

View File

@ -37,7 +37,7 @@
</div>
<div class="mb-3">
<label for="content" class="form-label">Isi Pengumuman <span class="text-danger">*</span></label>
<textarea name="content" class="form-control @error('content') is-invalid @enderror" id="content" rows="5" placeholder="Tulis isi pengumuman di sini...">{{ old('content') }}</textarea>
<textarea name="content" class="form-control @error('content') is-invalid @enderror" id="content" rows="5" placeholder="Tulis isi pengumuman di sini..." maxlength="255">{{ old('content') }}</textarea>
@error('content')
<div class="invalid-feedback">{{ $message }}</div>
@enderror

View File

@ -38,7 +38,7 @@
</div>
<div class="mb-3">
<label for="content" class="form-label">Isi Pengumuman <span class="text-danger">*</span></label>
<textarea name="content" class="form-control @error('content') is-invalid @enderror" id="content" rows="5">{{ old('content', $pengumuman->content) }}</textarea>
<textarea name="content" class="form-control @error('content') is-invalid @enderror" id="content" rows="5" maxlength="255">{{ old('content', $pengumuman->content) }}</textarea>
@error('content')
<div class="invalid-feedback">{{ $message }}</div>
@enderror

View File

@ -40,7 +40,7 @@
</div>
<div class="mb-3">
<label class="form-label">Deskripsi <span class="text-danger">*</span></label>
<textarea name="deskripsi" id="editor" class="@error('deskripsi') is-invalid @enderror">{{ old('deskripsi') }}</textarea>
<textarea name="deskripsi" id="editor" class="@error('deskripsi') is-invalid @enderror" maxlength="255">{{ old('deskripsi') }}</textarea>
@error('deskripsi')
<div class="text-danger small mt-1">{{ $message }}</div>
@enderror

View File

@ -41,7 +41,7 @@
</div>
<div class="mb-3">
<label class="form-label">Deskripsi <span class="text-danger">*</span></label>
<textarea name="deskripsi" id="editor" class="@error('deskripsi') is-invalid @enderror">{{ old('deskripsi', $rekomendasi->deskripsi) }}</textarea>
<textarea name="deskripsi" id="editor" class="@error('deskripsi') is-invalid @enderror" maxlength="255">{{ old('deskripsi', $rekomendasi->deskripsi) }}</textarea>
@error('deskripsi')
<div class="text-danger small mt-1">{{ $message }}</div>
@enderror

View File

@ -76,7 +76,7 @@ class="badge fw-normal {{ $buku['status'] == 'Tersedia' ? 'bg-success-subtle tex
$isOnlineAccess =
$buku['tipe_akses'] === 'online' ||
(is_array($buku['tipe_akses']) && in_array('online', $buku['tipe_akses']));
$stokHabis = $buku['status'] == 'Dipinjam';
$stokHabis = $buku['stok'] <= 0;
@endphp
{{-- TOMBOL PINJAM (OFFLINE) --}}

View File

@ -59,8 +59,8 @@ class="form-control @error('email') is-invalid @enderror" value="{{ old('email',
<div class="mb-3">
<label for="phone" class="form-label">{{ __('Nomor Telepon (WA)') }}</label>
<input id="phone" name="phone" type="text" class="form-control @error('phone') is-invalid @enderror"
value="{{ old('phone', $user->phone) }}" required
minlength="13" maxlength="15" pattern="\d*">
value="{{ old('phone', $user->phone) }}"
maxlength="16" pattern="\+?[0-9]+" oninput="this.value = this.value.replace(/[^0-9+]/g, '')">
@error('phone')
<div class="invalid-feedback">{{ $message }}</div>
@enderror

View File

@ -19,7 +19,7 @@
</thead>
<tbody>
@php $counter = 1; @endphp
@forelse ($riwayatOnline as $transaksi)
@foreach ($riwayatOnline as $transaksi)
@foreach ($transaksi['books'] as $buku)
<tr>
<td>{{ $counter++ }}</td>
@ -38,11 +38,7 @@
</td>
</tr>
@endforeach
@empty
<tr>
<td colspan="6" class="text-center">Tidak ada riwayat baca buku online.</td>
</tr>
@endforelse
@endforeach
</tbody>
</table>
</div>
@ -82,6 +78,9 @@ class="bi bi-book-half me-2 text-primary"></i>Detail Riwayat</h5>
searching: false,
pageLength: 10,
order: [[0, 'asc']],
language: {
emptyTable: "Tidak ada riwayat baca buku online."
},
columnDefs: [
{ responsivePriority: 1, targets: 2 },
{ responsivePriority: 2, targets: 5 }