refactor: update book stock management, refine validation constraints, and adjust dashboard statistics and UI components.
This commit is contained in:
parent
0c3369262f
commit
78df5b3a72
|
|
@ -126,9 +126,10 @@ public function store(Request $request)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Update book status and decrement stock
|
// Update book status and decrement stock
|
||||||
|
$newStok = $book->stok - 1;
|
||||||
$book->update([
|
$book->update([
|
||||||
'status' => 'Dipinjam',
|
'status' => $newStok <= 0 ? 'Dipinjam' : 'Tersedia',
|
||||||
'stok' => $book->stok - 1,
|
'stok' => $newStok,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ public function store(Request $request)
|
||||||
'judul' => 'required|string|min:3|max:50',
|
'judul' => 'required|string|min:3|max:50',
|
||||||
'kategori' => 'required|string|min:3|max:50',
|
'kategori' => 'required|string|min:3|max:50',
|
||||||
'youtube_link' => 'required|url',
|
'youtube_link' => 'required|url',
|
||||||
'deskripsi' => 'required|string',
|
'deskripsi' => 'required|string|max:255',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$validated['user_id'] = auth()->id();
|
$validated['user_id'] = auth()->id();
|
||||||
|
|
@ -78,7 +78,7 @@ public function update(Request $request, $id)
|
||||||
'judul' => 'required|string|min:3|max:50',
|
'judul' => 'required|string|min:3|max:50',
|
||||||
'kategori' => 'required|string|min:3|max:50',
|
'kategori' => 'required|string|min:3|max:50',
|
||||||
'youtube_link' => 'required|url',
|
'youtube_link' => 'required|url',
|
||||||
'deskripsi' => 'required|string',
|
'deskripsi' => 'required|string|max:255',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$rekomendasi->update($validated);
|
$rekomendasi->update($validated);
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,8 @@ public function store(Request $request)
|
||||||
$validated['file_pdf'] = basename($path);
|
$validated['file_pdf'] = basename($path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$validated['status'] = $validated['stok'] <= 0 ? 'Dipinjam' : 'Tersedia';
|
||||||
|
|
||||||
Book::create($validated);
|
Book::create($validated);
|
||||||
|
|
||||||
return redirect()->route('admin.buku.index')->with('success', 'Buku berhasil ditambahkan.');
|
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['file_pdf'] = basename($path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$validated['status'] = $validated['stok'] <= 0 ? 'Dipinjam' : 'Tersedia';
|
||||||
|
|
||||||
$buku->update($validated);
|
$buku->update($validated);
|
||||||
|
|
||||||
return redirect()->route('admin.buku.index')->with('success', 'Buku berhasil diperbarui.');
|
return redirect()->route('admin.buku.index')->with('success', 'Buku berhasil diperbarui.');
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ public function index()
|
||||||
['label' => 'Total Buku', 'value' => $allBooks, 'icon' => 'bi-journal-bookmark-fill', 'color' => 'primary'],
|
['label' => 'Total Buku', 'value' => $allBooks, 'icon' => 'bi-journal-bookmark-fill', 'color' => 'primary'],
|
||||||
['label' => 'Total Anggota', 'value' => $allUsers, 'icon' => 'bi-people-fill', 'color' => 'success'],
|
['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' => '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)
|
// Monthly stats (last 7 months)
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ public function store(Request $request)
|
||||||
{
|
{
|
||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
'title' => 'required|string|min:3|max:50',
|
'title' => 'required|string|min:3|max:50',
|
||||||
'content' => 'required|string',
|
'content' => 'required|string|max:255',
|
||||||
'type' => 'required|in:info,warning,success,danger',
|
'type' => 'required|in:info,warning,success,danger',
|
||||||
'icon' => 'nullable|string|max:50',
|
'icon' => 'nullable|string|max:50',
|
||||||
]);
|
]);
|
||||||
|
|
@ -69,7 +69,7 @@ public function update(Request $request, $id)
|
||||||
|
|
||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
'title' => 'required|string|min:3|max:50',
|
'title' => 'required|string|min:3|max:50',
|
||||||
'content' => 'required|string',
|
'content' => 'required|string|max:255',
|
||||||
'type' => 'required|in:info,warning,success,danger',
|
'type' => 'required|in:info,warning,success,danger',
|
||||||
'icon' => 'nullable|string|max:50',
|
'icon' => 'nullable|string|max:50',
|
||||||
]);
|
]);
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ public function index()
|
||||||
// Stats calculation
|
// Stats calculation
|
||||||
$stats = [
|
$stats = [
|
||||||
['label' => 'Buku yang dipinjam', 'value' => $loans->count(), 'icon' => 'bi-book-half', 'color' => 'primary'],
|
['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' => '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'],
|
['label' => 'History Baca', 'value' => Loan::where('user_id', $user->id)->count(), 'icon' => 'bi-hourglass-split', 'color' => 'warning'],
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ public function form($id)
|
||||||
$buku = Book::with('category')->findOrFail($id);
|
$buku = Book::with('category')->findOrFail($id);
|
||||||
|
|
||||||
$semuaBuku = Book::whereJsonContains('tipe_akses', 'offline')
|
$semuaBuku = Book::whereJsonContains('tipe_akses', 'offline')
|
||||||
->where('status', 'Tersedia')
|
->where('stok', '>', 0)
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
return view('peminjaman.form', compact('user', 'buku', 'semuaBuku'));
|
return view('peminjaman.form', compact('user', 'buku', 'semuaBuku'));
|
||||||
|
|
@ -113,7 +113,7 @@ public function store(Request $request)
|
||||||
foreach ($bukuIds as $bukuId) {
|
foreach ($bukuIds as $bukuId) {
|
||||||
$book = Book::lockForUpdate()->find($bukuId);
|
$book = Book::lockForUpdate()->find($bukuId);
|
||||||
|
|
||||||
if ($book->status !== 'Tersedia') {
|
if ($book->stok <= 0) {
|
||||||
throw new \Exception("Buku '{$book->judul}' sudah tidak tersedia.");
|
throw new \Exception("Buku '{$book->judul}' sudah tidak tersedia.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -126,7 +126,11 @@ public function store(Request $request)
|
||||||
'status' => 'Dipinjam',
|
'status' => 'Dipinjam',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$book->update(['status' => 'Dipinjam']);
|
$newStok = $book->stok - 1;
|
||||||
|
$book->update([
|
||||||
|
'stok' => $newStok,
|
||||||
|
'status' => $newStok <= 0 ? 'Dipinjam' : 'Tersedia'
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ public function rules(): array
|
||||||
'max:255',
|
'max:255',
|
||||||
Rule::unique(User::class)->ignore($this->user()->id),
|
Rule::unique(User::class)->ignore($this->user()->id),
|
||||||
],
|
],
|
||||||
'phone' => ['required', 'numeric', 'digits_between:13,15'],
|
'phone' => ['required', 'string', 'min:13', 'max:16'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="content" class="form-label">Isi Pengumuman <span class="text-danger">*</span></label>
|
<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')
|
@error('content')
|
||||||
<div class="invalid-feedback">{{ $message }}</div>
|
<div class="invalid-feedback">{{ $message }}</div>
|
||||||
@enderror
|
@enderror
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="content" class="form-label">Isi Pengumuman <span class="text-danger">*</span></label>
|
<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')
|
@error('content')
|
||||||
<div class="invalid-feedback">{{ $message }}</div>
|
<div class="invalid-feedback">{{ $message }}</div>
|
||||||
@enderror
|
@enderror
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">Deskripsi <span class="text-danger">*</span></label>
|
<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')
|
@error('deskripsi')
|
||||||
<div class="text-danger small mt-1">{{ $message }}</div>
|
<div class="text-danger small mt-1">{{ $message }}</div>
|
||||||
@enderror
|
@enderror
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">Deskripsi <span class="text-danger">*</span></label>
|
<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')
|
@error('deskripsi')
|
||||||
<div class="text-danger small mt-1">{{ $message }}</div>
|
<div class="text-danger small mt-1">{{ $message }}</div>
|
||||||
@enderror
|
@enderror
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ class="badge fw-normal {{ $buku['status'] == 'Tersedia' ? 'bg-success-subtle tex
|
||||||
$isOnlineAccess =
|
$isOnlineAccess =
|
||||||
$buku['tipe_akses'] === 'online' ||
|
$buku['tipe_akses'] === 'online' ||
|
||||||
(is_array($buku['tipe_akses']) && in_array('online', $buku['tipe_akses']));
|
(is_array($buku['tipe_akses']) && in_array('online', $buku['tipe_akses']));
|
||||||
$stokHabis = $buku['status'] == 'Dipinjam';
|
$stokHabis = $buku['stok'] <= 0;
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
{{-- TOMBOL PINJAM (OFFLINE) --}}
|
{{-- TOMBOL PINJAM (OFFLINE) --}}
|
||||||
|
|
|
||||||
|
|
@ -59,8 +59,8 @@ class="form-control @error('email') is-invalid @enderror" value="{{ old('email',
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="phone" class="form-label">{{ __('Nomor Telepon (WA)') }}</label>
|
<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"
|
<input id="phone" name="phone" type="text" class="form-control @error('phone') is-invalid @enderror"
|
||||||
value="{{ old('phone', $user->phone) }}" required
|
value="{{ old('phone', $user->phone) }}"
|
||||||
minlength="13" maxlength="15" pattern="\d*">
|
maxlength="16" pattern="\+?[0-9]+" oninput="this.value = this.value.replace(/[^0-9+]/g, '')">
|
||||||
@error('phone')
|
@error('phone')
|
||||||
<div class="invalid-feedback">{{ $message }}</div>
|
<div class="invalid-feedback">{{ $message }}</div>
|
||||||
@enderror
|
@enderror
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@php $counter = 1; @endphp
|
@php $counter = 1; @endphp
|
||||||
@forelse ($riwayatOnline as $transaksi)
|
@foreach ($riwayatOnline as $transaksi)
|
||||||
@foreach ($transaksi['books'] as $buku)
|
@foreach ($transaksi['books'] as $buku)
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ $counter++ }}</td>
|
<td>{{ $counter++ }}</td>
|
||||||
|
|
@ -38,11 +38,7 @@
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
@empty
|
@endforeach
|
||||||
<tr>
|
|
||||||
<td colspan="6" class="text-center">Tidak ada riwayat baca buku online.</td>
|
|
||||||
</tr>
|
|
||||||
@endforelse
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -82,6 +78,9 @@ class="bi bi-book-half me-2 text-primary"></i>Detail Riwayat</h5>
|
||||||
searching: false,
|
searching: false,
|
||||||
pageLength: 10,
|
pageLength: 10,
|
||||||
order: [[0, 'asc']],
|
order: [[0, 'asc']],
|
||||||
|
language: {
|
||||||
|
emptyTable: "Tidak ada riwayat baca buku online."
|
||||||
|
},
|
||||||
columnDefs: [
|
columnDefs: [
|
||||||
{ responsivePriority: 1, targets: 2 },
|
{ responsivePriority: 1, targets: 2 },
|
||||||
{ responsivePriority: 2, targets: 5 }
|
{ responsivePriority: 2, targets: 5 }
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue