feat: Baca Buku Online
This commit is contained in:
parent
78ba8a0772
commit
542153ad8a
|
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Services\DummyDataService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\View\View;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
|
||||
class BacaOnlineController extends Controller
|
||||
{
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$filters = $request->only(['search', 'kategori', 'tahun', 'penulis']);
|
||||
$filters['tipe_akses'] = 'online';
|
||||
$semuaBuku = DummyDataService::getKatalogBuku($filters);
|
||||
$filterOptions = DummyDataService::getFilterOptions();
|
||||
|
||||
return view('katalog.index', [
|
||||
'semuaBuku' => $semuaBuku,
|
||||
'filterOptions' => $filterOptions,
|
||||
'input' => $request->query(),
|
||||
'pageTitle' => 'Baca Buku Online',
|
||||
'mode' => 'online',
|
||||
]);
|
||||
}
|
||||
|
||||
public function ringkasan(int $id): View
|
||||
{
|
||||
$book = $this->getBookOrFail($id);
|
||||
|
||||
return view('katalog.ringkasan', [
|
||||
'buku' => $book,
|
||||
'pageTitle' => 'Ringkasan Buku',
|
||||
'actionRoute' => 'baca.request_code',
|
||||
'actionButtonText' => 'Baca Sekarang',
|
||||
'actionButtonIcon' => 'bi-book-half',
|
||||
]);
|
||||
}
|
||||
|
||||
public function showCodeRequestPage(int $id): View
|
||||
{
|
||||
$book = $this->getBookOrFail($id);
|
||||
$sessionKey = 'access_code_for_book_' . $id;
|
||||
|
||||
if (session()->has($sessionKey)) {
|
||||
$accessCode = session($sessionKey);
|
||||
} else {
|
||||
$accessCode = 'BCO-' . date('Ymd') . '-' . $book['id'] . '-' . Str::upper(Str::random(4));
|
||||
session([$sessionKey => $accessCode]);
|
||||
}
|
||||
|
||||
session(['book_verified_' . $id => false]);
|
||||
|
||||
return view('baca.request_code', [
|
||||
'book' => $book,
|
||||
'accessCode' => $accessCode
|
||||
]);
|
||||
}
|
||||
|
||||
public function verifyCode(Request $request, int $id): RedirectResponse
|
||||
{
|
||||
$request->validate(['kode_akses' => 'required|string']);
|
||||
$correctCode = session('access_code_for_book_' . $id);
|
||||
|
||||
if ($request->input('kode_akses') === $correctCode) {
|
||||
session(['book_verified_' . $id => true]);
|
||||
session()->forget('access_code_for_book_' . $id);
|
||||
return redirect()->route('baca.view_book', ['id' => $id]);
|
||||
}
|
||||
|
||||
return back()->with('error', 'Kode akses yang Anda masukkan salah!');
|
||||
}
|
||||
|
||||
public function viewBook(int $id): View|RedirectResponse
|
||||
{
|
||||
if (!session('book_verified_' . $id, false)) {
|
||||
return redirect()->route('baca.request_code', ['id' => $id])
|
||||
->with('error', 'Silakan masukkan kode akses terlebih dahulu.');
|
||||
}
|
||||
$book = $this->getBookOrFail($id);
|
||||
return view('baca.view_book', ['book' => $book]);
|
||||
}
|
||||
|
||||
public function streamPdf(int $id): BinaryFileResponse|Response
|
||||
{
|
||||
if (!session('book_verified_' . $id, false)) {
|
||||
abort(403, 'Akses Ditolak.');
|
||||
}
|
||||
$book = $this->getBookOrFail($id);
|
||||
$filePath = 'books/' . $book['file_pdf'];
|
||||
$absolutePath = storage_path('app/' . $filePath);
|
||||
|
||||
if (!file_exists($absolutePath)) {
|
||||
abort(404, 'GAGAL - PHP tidak dapat menemukan file di: ' . $absolutePath);
|
||||
}
|
||||
|
||||
return response()->file($absolutePath);
|
||||
}
|
||||
|
||||
private function getBookOrFail(int $id): array
|
||||
{
|
||||
$book = DummyDataService::getKatalogBuku()->firstWhere('id', $id);
|
||||
if (!$book) {
|
||||
abort(404, 'Buku tidak ditemukan.');
|
||||
}
|
||||
return $book;
|
||||
}
|
||||
}
|
||||
|
|
@ -7,25 +7,19 @@
|
|||
|
||||
class KatalogController extends Controller
|
||||
{
|
||||
public function index(Request $request, $tipe = null)
|
||||
public function index(Request $request)
|
||||
{
|
||||
$filters = [
|
||||
'search' => $request->query('search'),
|
||||
'kategori' => $request->query('kategori'),
|
||||
'tahun' => $request->query('tahun'),
|
||||
'penulis' => $request->query('penulis'),
|
||||
];
|
||||
|
||||
$filters = $request->only(['search', 'kategori', 'tahun', 'penulis']);
|
||||
|
||||
$semuaBuku = DummyDataService::getKatalogBuku($filters);
|
||||
|
||||
$filterOptions = DummyDataService::getFilterOptions();
|
||||
|
||||
return view('katalog', [
|
||||
return view('katalog.index', [
|
||||
'semuaBuku' => $semuaBuku,
|
||||
'filterOptions' => $filterOptions,
|
||||
'input' => $filters,
|
||||
'pageTitle' => 'Katalog Buku',
|
||||
'mode' => 'umum',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,78 +4,65 @@
|
|||
|
||||
use App\Services\DummyDataService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class PeminjamanController extends Controller
|
||||
{
|
||||
/**
|
||||
* Menampilkan daftar buku yang bisa dipinjam offline,
|
||||
* dengan memanfaatkan filter dari getKatalogBuku.
|
||||
*/
|
||||
public function index(Request $request)
|
||||
public function index(Request $request)
|
||||
{
|
||||
$filters = $request->only(['search', 'kategori', 'tahun', 'penulis']);
|
||||
$filters['tipe_akses'] = 'offline';
|
||||
$semuaBuku = DummyDataService::getKatalogBuku($filters);
|
||||
$filterOptions = DummyDataService::getFilterOptions();
|
||||
|
||||
return view('peminjaman.index', [
|
||||
return view('katalog.index', [
|
||||
'semuaBuku' => $semuaBuku,
|
||||
'filterOptions' => $filterOptions,
|
||||
'input' => $request->query(),
|
||||
'input' => $request->query(),
|
||||
'pageTitle' => 'Peminjaman Buku Offline',
|
||||
'mode' => 'offline',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Menampilkan halaman ringkasan buku sebelum meminjam.
|
||||
*/
|
||||
public function ringkasan($id)
|
||||
{
|
||||
// Untuk simulasi, kita anggap user sudah login
|
||||
// $user = Auth::user();
|
||||
$user = DummyDataService::getAllSiswa()[0];
|
||||
|
||||
$user = Auth::user();
|
||||
$buku = DummyDataService::getKatalogBuku()->firstWhere('id', $id);
|
||||
|
||||
return view('peminjaman.ringkasan', compact('user', 'buku'));
|
||||
return view('katalog.ringkasan', [
|
||||
'user' => $user,
|
||||
'buku' => $buku,
|
||||
'pageTitle' => 'Ringkasan Buku',
|
||||
'actionRoute' => 'peminjaman.form',
|
||||
'actionButtonText' => 'Lanjutkan ke Form Peminjaman',
|
||||
'actionButtonIcon' => 'bi-file-earmark-text-fill',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Menampilkan form peminjaman dengan semua buku offline untuk pilihan tambahan.
|
||||
*/
|
||||
|
||||
public function form($id)
|
||||
{
|
||||
// $user = Auth::user();
|
||||
$user = DummyDataService::getAllSiswa()[0];
|
||||
|
||||
// Buku yang dipilih pertama kali
|
||||
$user = Auth::user();
|
||||
$buku = DummyDataService::getKatalogBuku()->firstWhere('id', $id);
|
||||
|
||||
// Semua buku offline untuk pilihan tambahan
|
||||
$filters = ['tipe_akses' => 'offline'];
|
||||
$semuaBuku = DummyDataService::getKatalogBuku($filters);
|
||||
|
||||
return view('peminjaman.form', compact('user', 'buku', 'semuaBuku'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Proses pengiriman form peminjaman multi buku
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
// Validasi input
|
||||
$request->validate([
|
||||
'buku_ids' => 'required|array|min:1|max:3',
|
||||
'buku_ids.*' => 'integer|exists:books,id' // Sesuaikan dengan tabel yang ada
|
||||
'buku_ids.*' => 'integer'
|
||||
]);
|
||||
|
||||
// Logic untuk menyimpan peminjaman multiple books
|
||||
$bukuIds = $request->input('buku_ids');
|
||||
|
||||
// Contoh logic penyimpanan:
|
||||
|
||||
foreach ($bukuIds as $bukuId) {
|
||||
// Simpan ke database peminjaman
|
||||
// Di backend nanti kayak gini
|
||||
// Peminjaman::create([
|
||||
// 'user_id' => auth()->id(),
|
||||
// 'user_id' => auth()->id(),
|
||||
// 'book_id' => $bukuId,
|
||||
// 'tanggal_pinjam' => now(),
|
||||
// 'tanggal_kembali' => now()->addDays(7),
|
||||
|
|
@ -86,4 +73,4 @@ public function store(Request $request)
|
|||
return redirect()->route('dashboard')
|
||||
->with('success', 'Berhasil meminjam ' . count($bukuIds) . ' buku!');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,8 +145,10 @@ private static function getAllBooks()
|
|||
'tahun' => 2022,
|
||||
'status' => 'Tersedia',
|
||||
'is_new' => true,
|
||||
'tipe_akses' => 'online',
|
||||
'tipe_akses' => ['online','offline'],
|
||||
'file_pdf'=>'ipas.pdf',
|
||||
'progress' => 75,
|
||||
'sisa_hari' => 14,
|
||||
'user_id' => 1,
|
||||
],
|
||||
[
|
||||
|
|
@ -158,7 +160,8 @@ private static function getAllBooks()
|
|||
'tahun' => 2023,
|
||||
'status' => 'Tersedia',
|
||||
'is_new' => false,
|
||||
'tipe_akses' => ['online', 'offline'],
|
||||
'tipe_akses' => 'offline',
|
||||
'sisa_hari' => 3,
|
||||
'progress' => 100,
|
||||
'user_id' => [3, 1],
|
||||
],
|
||||
|
|
@ -210,7 +213,9 @@ private static function getAllBooks()
|
|||
'tahun' => 2023,
|
||||
'status' => 'Tersedia',
|
||||
'is_new' => true,
|
||||
'tipe_akses' => 'online',
|
||||
'tipe_akses' => ['online','offline'],
|
||||
'file_pdf'=>'mtk.pdf',
|
||||
'sisa_hari' => 7,
|
||||
'progress' => 40,
|
||||
'user_id' => [1, 4, 5],
|
||||
],
|
||||
|
|
@ -223,22 +228,54 @@ private static function getAllBooks()
|
|||
'tahun' => 2024,
|
||||
'status' => 'Tersedia',
|
||||
'is_new' => true,
|
||||
'tipe_akses' => 'online',
|
||||
'tipe_akses' => 'offline',
|
||||
'sisa_hari' => 4,
|
||||
'progress' => 0,
|
||||
'user_id' => [3, 1]
|
||||
],
|
||||
[
|
||||
'id' => 8,
|
||||
'judul' => 'Buku Offline Tanpa Peminjam',
|
||||
'penulis' => 'Penulis Misteri',
|
||||
'cover' => 'images/covers/sosiologi.jpg',
|
||||
'kategori' => 'Misteri',
|
||||
'tahun' => 2020,
|
||||
'judul' => 'Ayah',
|
||||
'penulis' => 'Andrea Hirata',
|
||||
'cover' => 'images/covers/ayah.png',
|
||||
'kategori' => 'Novel',
|
||||
'tahun' => 2015,
|
||||
'status' => 'Tersedia',
|
||||
'is_new' => false,
|
||||
'tipe_akses' => 'offline',
|
||||
'sisa_hari' => null
|
||||
'is_new' => true,
|
||||
'tipe_akses' => 'online',
|
||||
'file_pdf' => 'ayah.pdf',
|
||||
'progress' => 0,
|
||||
'user_id' => [1, 2, 3],
|
||||
],
|
||||
[
|
||||
'id' => 9,
|
||||
'judul' => 'Senja, Hujan, & Cerita yang Telah Usai',
|
||||
'penulis' => 'Boy Candra',
|
||||
'cover' => 'images/covers/senja.png',
|
||||
'kategori' => 'Novel',
|
||||
'tahun' => 2015,
|
||||
'status' => 'Tersedia',
|
||||
'is_new' => true,
|
||||
'tipe_akses' => ['online','offline'],
|
||||
'file_pdf' => 'senja.pdf',
|
||||
'progress' => 0,
|
||||
'sisa_hari' => 14,
|
||||
'user_id' => [1, 3],
|
||||
],
|
||||
[
|
||||
'id' => 10,
|
||||
'judul' => 'Hijrah itu Cinta',
|
||||
'penulis' => 'Abay Adhitya',
|
||||
'cover' => 'images/covers/hijrah.png',
|
||||
'kategori' => 'Religi',
|
||||
'tahun' => 2018,
|
||||
'status' => 'Tersedia',
|
||||
'is_new' => true,
|
||||
'tipe_akses' => 'online',
|
||||
'file_pdf' => 'hijrah.pdf',
|
||||
'progress' => 0,
|
||||
'user_id' => [2, 3],
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -297,36 +334,36 @@ public static function getBacaBukuOnline($user): array
|
|||
*/
|
||||
// app/Services/DummyDataService.php
|
||||
|
||||
public static function getKatalogBuku(array $filters = []): \Illuminate\Support\Collection
|
||||
{
|
||||
$buku = self::getAllBooks();
|
||||
public static function getKatalogBuku(array $filters = []): \Illuminate\Support\Collection
|
||||
{
|
||||
$buku = self::getAllBooks();
|
||||
|
||||
$buku = $buku->when($filters['search'] ?? null, function ($query, $search) {
|
||||
return $query->filter(fn($item) => str_contains(strtolower($item['judul']), strtolower($search)));
|
||||
})->when($filters['kategori'] ?? null, function ($query, $kategori) {
|
||||
return $query->where('kategori', $kategori);
|
||||
})->when($filters['tahun'] ?? null, function ($query, $tahun) {
|
||||
return $query->where('tahun', $tahun);
|
||||
})->when($filters['penulis'] ?? null, function ($query, $penulis) {
|
||||
return $query->where('penulis', $penulis);
|
||||
})
|
||||
->when($filters['tipe_akses'] ?? null, function ($query, $tipe) {
|
||||
if ($tipe === 'offline') {
|
||||
return $query->filter(function ($buku) {
|
||||
return $buku['tipe_akses'] === 'offline' || (is_array($buku['tipe_akses']) && in_array('offline', $buku['tipe_akses']));
|
||||
});
|
||||
}
|
||||
if ($tipe === 'online') {
|
||||
return $query->filter(function ($buku) {
|
||||
return $buku['tipe_akses'] === 'online' || (is_array($buku['tipe_akses']) && in_array('online', $buku['tipe_akses']));
|
||||
});
|
||||
}
|
||||
return $query;
|
||||
})
|
||||
->sortByDesc('status');
|
||||
$buku = $buku->when($filters['search'] ?? null, function ($query, $search) {
|
||||
return $query->filter(fn($item) => str_contains(strtolower($item['judul']), strtolower($search)));
|
||||
})->when($filters['kategori'] ?? null, function ($query, $kategori) {
|
||||
return $query->where('kategori', $kategori);
|
||||
})->when($filters['tahun'] ?? null, function ($query, $tahun) {
|
||||
return $query->where('tahun', $tahun);
|
||||
})->when($filters['penulis'] ?? null, function ($query, $penulis) {
|
||||
return $query->where('penulis', $penulis);
|
||||
})
|
||||
->when($filters['tipe_akses'] ?? null, function ($query, $tipe) {
|
||||
if ($tipe === 'offline') {
|
||||
return $query->filter(function ($buku) {
|
||||
return $buku['tipe_akses'] === 'offline' || (is_array($buku['tipe_akses']) && in_array('offline', $buku['tipe_akses']));
|
||||
});
|
||||
}
|
||||
if ($tipe === 'online') {
|
||||
return $query->filter(function ($buku) {
|
||||
return $buku['tipe_akses'] === 'online' || (is_array($buku['tipe_akses']) && in_array('online', $buku['tipe_akses']));
|
||||
});
|
||||
}
|
||||
return $query;
|
||||
})
|
||||
->sortByDesc('status');
|
||||
|
||||
return $buku;
|
||||
}
|
||||
return $buku;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method baru untuk mengambil daftar unik untuk dropdown filter
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 542 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 378 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 238 KiB |
|
|
@ -1,13 +1,12 @@
|
|||
@section('page-title', 'Peminjaman Buku')
|
||||
@section('page-title', 'Baca Buku Online')
|
||||
<x-app-layout>
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">Daftar Buku Peminjaman Offline</h1>
|
||||
<h1 class="h2">Daftar Buku Baca Online</h1>
|
||||
</div>
|
||||
|
||||
<!-- Filter & Pencarian -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<form action="{{ route('peminjaman.index') }}" method="GET">
|
||||
<form action="{{ route('baca.index') }}" method="GET">
|
||||
<div class="row g-3 align-items-center">
|
||||
<div class="col-md-4">
|
||||
<input type="text" name="search" class="form-control"
|
||||
|
|
@ -51,10 +50,8 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<p class="fw-bold">Daftar buku yang tersedia secara offline dan dapat diambil di perpustakaan dengan mengisi form
|
||||
yang tersedia.</p>
|
||||
<p class="fw-bold">Berikut adalah daftar buku yang tersedia untuk dibaca secara online melalui platform ini.</p>
|
||||
|
||||
<!-- Daftar Buku -->
|
||||
<div class="row row-cols-2 row-cols-md-3 row-cols-lg-5 g-4">
|
||||
@forelse ($semuaBuku as $buku)
|
||||
<div class="col">
|
||||
|
|
@ -75,9 +72,9 @@ class="badge fw-normal {{ $buku['status'] == 'Tersedia' ? 'bg-success-subtle tex
|
|||
|
||||
<div class="d-grid mt-auto">
|
||||
@if ($buku['status'] == 'Tersedia')
|
||||
<a href="{{ route('peminjaman.ringkasan', $buku['id']) }}"
|
||||
<a href="{{ route('baca.request_code', $buku['id']) }}"
|
||||
class="btn btn-outline-primary btn-sm">
|
||||
<i class="bi bi-arrow-down-up me-1"></i> Pinjam Offline
|
||||
<i class="bi bi-book-half me-1"></i> Baca Sekarang
|
||||
</a>
|
||||
@else
|
||||
<button class="btn btn-secondary btn-sm" disabled><i class="bi bi-x-circle me-1"></i>
|
||||
|
|
@ -93,9 +90,9 @@ class="btn btn-outline-primary btn-sm">
|
|||
<h4 class="alert-heading">Tidak Ada Hasil</h4>
|
||||
<p>Tidak ada buku yang cocok dengan kriteria filter Anda. Coba reset atau ubah filter.</p>
|
||||
<hr>
|
||||
<a href="{{ route('peminjaman') }}" class="btn btn-primary">Reset Filter</a>
|
||||
<a href="{{ route('baca.index') }}" class="btn btn-primary">Reset Filter</a>
|
||||
</div>
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</x-app-layout>
|
||||
</x-app-layout>
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
@section('page-title', 'Kode Akses Buku')
|
||||
<x-app-layout>
|
||||
<div class="container text-center py-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8 col-lg-6">
|
||||
|
||||
<h2 class="fw-bold">KODE AKSES BUKU ANDA</h2>
|
||||
<p class="text-muted">Kode unik telah diberikan secara otomatis. Perhatikan kode dibawah ini:</p>
|
||||
|
||||
<div class="my-4 p-4 rounded" style="border: 2px dashed #0d6efd; background-color: #f8f9fa; display: inline-block;">
|
||||
<h3 class="fw-bold" style="font-family: monospace; letter-spacing: 2px;">{{ $accessCode }}</h3>
|
||||
</div>
|
||||
|
||||
<p class="text-muted">Jangan bagikan kepada orang lain.</p>
|
||||
<p>Masukkan kode akses ini pada kolom dibawah ini:</p>
|
||||
|
||||
@if(session('error'))
|
||||
<div class="alert alert-danger">
|
||||
{{ session('error') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form action="{{ route('baca.verify_code', ['id' => $book['id']]) }}" method="POST" class="mt-3">
|
||||
@csrf
|
||||
<div class="form-group" style="max-width: 400px; margin-left: auto; margin-right: auto;">
|
||||
<label for="kode_akses" class="form-label fw-bold">Kode Akses Buku:</label>
|
||||
<input type="text" name="kode_akses" id="kode_akses" class="form-control form-control-lg text-center" placeholder="Masukkan kode akses..." required autofocus>
|
||||
</div>
|
||||
<div class="d-grid gap-2" style="max-width: 400px; margin-left: auto; margin-right: auto;">
|
||||
<button type="submit" class="btn btn-primary btn-lg mt-3">Akses Buku</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-app-layout>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
@section('page-title', 'Membaca: ' . $book['judul'])
|
||||
<x-app-layout>
|
||||
<div class="container-fluid vh-100 d-flex flex-column p-3">
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2 text-truncate">{{ $book['judul'] }}</h1>
|
||||
<a href="{{ route('baca.index') }}" class="btn btn-outline-secondary flex-shrink-0">
|
||||
<i class="bi bi-x-lg me-1"></i>
|
||||
Tutup
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="flex-grow-1">
|
||||
{{-- src memanggil route streamPdf yang aman, bukan direct link ke file PDF --}}
|
||||
<iframe src="{{ route('baca.stream_pdf', ['id' => $book['id']]) }}" width="100%" height="100%"
|
||||
class="rounded border" style="border: none;">
|
||||
Browser Anda tidak mendukung iframe untuk menampilkan PDF.
|
||||
</iframe>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</x-app-layout>
|
||||
|
||||
{{-- Override CSS agar layout <main> bisa memenuhi lebar container-fluid --}}
|
||||
@push('styles')
|
||||
<style>
|
||||
main.container-fluid {
|
||||
max-width: none !important;
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
@section('page-title', $pageTitle)
|
||||
<x-app-layout>
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">{{ $pageTitle }}</h1>
|
||||
</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<form action="{{ route(request()->route()->getName()) }}" method="GET">
|
||||
<div class="row g-3 align-items-center">
|
||||
<div class="col-md-4">
|
||||
<input type="text" name="search" class="form-control"
|
||||
placeholder="Cari buku berdasarkan judul..." value="{{ $input['search'] ?? '' }}">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<select name="kategori" class="form-select">
|
||||
<option value="">Semua Kategori</option>
|
||||
@foreach ($filterOptions['kategori'] as $kategori)
|
||||
<option value="{{ $kategori }}"
|
||||
{{ ($input['kategori'] ?? '') == $kategori ? 'selected' : '' }}>{{ $kategori }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<select name="tahun" class="form-select">
|
||||
<option value="">Semua Tahun</option>
|
||||
@foreach ($filterOptions['tahun'] as $tahun)
|
||||
<option value="{{ $tahun }}"
|
||||
{{ ($input['tahun'] ?? '') == $tahun ? 'selected' : '' }}>{{ $tahun }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<select name="penulis" class="form-select">
|
||||
<option value="">Semua Penulis</option>
|
||||
@foreach ($filterOptions['penulis'] as $penulis)
|
||||
<option value="{{ $penulis }}"
|
||||
{{ ($input['penulis'] ?? '') == $penulis ? 'selected' : '' }}>{{ $penulis }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2 d-grid">
|
||||
<button type="submit" class="btn btn-primary">Filter</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row row-cols-2 row-cols-md-3 row-cols-lg-5 g-4">
|
||||
@forelse ($semuaBuku as $buku)
|
||||
<div class="col">
|
||||
<div class="card h-100 shadow-sm border-0">
|
||||
<img src="{{ asset($buku['cover']) }}" class="card-img-top rounded-2 object-fit-cover"
|
||||
style="height: 310px;" alt="Cover {{ $buku['judul'] }}">
|
||||
|
||||
<div class="card-body d-flex flex-column p-3">
|
||||
<div class="flex-grow-1">
|
||||
<div class="mb-2">
|
||||
<span class="badge fw-normal text-primary border me-1">{{ $buku['kategori'] }}</span>
|
||||
<span
|
||||
class="badge fw-normal {{ $buku['status'] == 'Tersedia' ? 'bg-success-subtle text-success-emphasis' : 'bg-warning-subtle text-warning-emphasis' }} border">{{ $buku['status'] }}</span>
|
||||
</div>
|
||||
<h6 class="card-title fw-bold line-clamp-2">{{ $buku['judul'] }}</h6>
|
||||
<p class="card-text small text-muted mb-2">{{ $buku['penulis'] }}</p>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2 mt-auto pt-2 border-top">
|
||||
@php
|
||||
$bisaPinjam =
|
||||
(is_array($buku['tipe_akses']) && in_array('offline', $buku['tipe_akses'])) ||
|
||||
$buku['tipe_akses'] === 'offline';
|
||||
$bisaBaca =
|
||||
(is_array($buku['tipe_akses']) && in_array('online', $buku['tipe_akses'])) ||
|
||||
$buku['tipe_akses'] === 'online';
|
||||
@endphp
|
||||
|
||||
@if ($mode === 'offline')
|
||||
{{-- Mode Peminjaman: hanya tampilkan tombol Pinjam --}}
|
||||
<a href="{{ route('peminjaman.ringkasan', $buku['id']) }}"
|
||||
class="btn btn-sm btn-outline-primary w-100">
|
||||
<i class="bi bi-arrow-left-right me-1"></i> Pinjam Buku
|
||||
</a>
|
||||
@elseif($mode === 'online')
|
||||
{{-- Mode Baca Online: hanya tampilkan tombol Baca Buku --}}
|
||||
<a href="{{ route('baca.ringkasan', $buku['id']) }}"
|
||||
class="btn btn-sm btn-primary w-100">
|
||||
<i class="bi bi-search me-1"></i> Baca Buku
|
||||
</a>
|
||||
@else
|
||||
{{-- Mode 'umum' atau default --}}
|
||||
{{-- Mode Katalog Umum: Tampilkan kedua tombol (aktif/nonaktif) --}}
|
||||
@if ($bisaPinjam && $buku['status'] == 'Tersedia')
|
||||
<a href="{{ route('peminjaman.ringkasan', $buku['id']) }}"
|
||||
class="btn btn-sm btn-outline-primary w-100"><i
|
||||
class="bi bi-arrow-left-right me-1"></i> Pinjam</a>
|
||||
@else
|
||||
<button class="btn btn-sm btn-outline-secondary w-100" disabled><i
|
||||
class="bi bi-arrow-left-right me-1"></i> Pinjam</button>
|
||||
@endif
|
||||
|
||||
@if ($bisaBaca && $buku['status'] == 'Tersedia')
|
||||
<a href="{{ route('baca.ringkasan', $buku['id']) }}"
|
||||
class="btn btn-sm btn-primary w-100"><i class="bi bi-book-half me-1"></i>
|
||||
Baca</a>
|
||||
@else
|
||||
<button class="btn btn-sm btn-secondary w-100" disabled><i
|
||||
class="bi bi-book-half me-1"></i> Baca</button>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<div class="col-12">
|
||||
<div class="alert alert-warning text-center">
|
||||
<h4 class="alert-heading">Tidak Ada Hasil</h4>
|
||||
<p>Tidak ada buku yang cocok dengan kriteria filter Anda. Coba reset atau ubah filter.</p>
|
||||
<hr>
|
||||
<a href="{{ route(request()->route()->getName()) }}" class="btn btn-primary">Reset Filter</a>
|
||||
</div>
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</x-app-layout>
|
||||
|
|
@ -1,27 +1,23 @@
|
|||
@section('page-title', 'Ringkasan Buku')
|
||||
@section('page-title', $pageTitle)
|
||||
<x-app-layout>
|
||||
<div class="d-flex flex-column" style="min-height: calc(100vh - 110px);">
|
||||
|
||||
{{-- Header --}}
|
||||
<div class="d-flex align-items-center mb-4">
|
||||
<a href="{{ route('peminjaman.index')}}" class="btn btn-outline-secondary me-3">
|
||||
<a href="{{ url()->previous() }}" class="btn btn-outline-secondary me-3">
|
||||
<i class="bi bi-arrow-left"></i>
|
||||
</a>
|
||||
<h1 class="h2 mb-0">Ringkasan Buku</h1>
|
||||
</div>
|
||||
|
||||
{{-- Wrapper main content --}}
|
||||
<main class="flex-grow-1 d-flex align-items-center justify-content-center">
|
||||
<div class="container-fluid">
|
||||
<div class="row g-5 align-items-center">
|
||||
|
||||
{{-- Kolom Kiri untuk Cover Buku --}}
|
||||
<div class="col-lg-4 text-center">
|
||||
<img src="{{ asset($buku['cover']) }}" class="img-fluid rounded-3 shadow-lg"
|
||||
style="max-height: 450px; max-width: 300px; object-fit: cover;" alt="Cover {{ $buku['judul'] }}">
|
||||
</div>
|
||||
|
||||
{{-- Kolom Kanan untuk Detail & Button --}}
|
||||
<div class="col-lg-8">
|
||||
<h1 class="display-5 fw-bold mb-2">{{ $buku['judul'] }}</h1>
|
||||
<p class="h5 text-muted mb-4">oleh {{ $buku['penulis'] }}</p>
|
||||
|
|
@ -34,9 +30,9 @@
|
|||
</p>
|
||||
|
||||
<div class="mt-5">
|
||||
<a href="{{ route('peminjaman.form', $buku['id']) }}" class="btn btn-primary btn-lg rounded-pill px-5 py-3">
|
||||
<i class="bi bi-file-earmark-text-fill me-2"></i>
|
||||
Lanjutkan ke Form Peminjaman
|
||||
<a href="{{ route($actionRoute, $buku['id']) }}" class="btn btn-primary btn-lg rounded-pill px-5 py-3">
|
||||
<i class="{{ $actionButtonIcon }} me-2"></i>
|
||||
{{ $actionButtonText }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -5,7 +5,8 @@
|
|||
|
||||
<div class="d-flex align-items-center mt-md-2" style="gap: 0.75rem;">
|
||||
<div class="vr bg-primary sidebar-title" style="width: 2px;"></div>
|
||||
<img src="{{ asset('images/logo/name.svg') }}" alt="Perpus" style="height: 32px;" class="sidebar-title">
|
||||
<img src="{{ asset('images/logo/name.svg') }}" alt="Perpus" style="height: 32px;"
|
||||
class="sidebar-title">
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
|
@ -55,7 +56,7 @@ class="nav-link {{ request()->routeIs('peminjaman.*') ? 'active' : '' }}">
|
|||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#" class="nav-link">
|
||||
<a href="{{ route('baca.index') }}" class="nav-link {{ request()->routeIs('baca.*') ? 'active' : '' }}">
|
||||
<i class="bi bi-globe "></i>
|
||||
<span class="nav-text ms-2">Baca Buku Online</span>
|
||||
</a>
|
||||
|
|
|
|||
|
|
@ -136,7 +136,6 @@ class="rounded me-3 form-book-cover">
|
|||
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
||||
<div class="modal-content border-0 shadow-lg rounded-3">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="modal-header bg-light">
|
||||
<h5 class="modal-title fw-bold" id="pilihBukuModalLabel">
|
||||
<i class="bi bi-book-half me-2 text-primary"></i>Pilih Buku Tambahan
|
||||
|
|
@ -144,17 +143,13 @@ class="rounded me-3 form-book-cover">
|
|||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
<!-- Body -->
|
||||
<div class="modal-body">
|
||||
|
||||
<!-- Alert Info -->
|
||||
<div class="alert alert-info border-0 bg-info-subtle mb-4 d-flex align-items-center">
|
||||
<i class="bi bi-info-circle-fill me-2"></i>
|
||||
<span>Anda dapat memilih maksimal <strong><span id="sisaSlot">2</span> buku</strong> lagi.
|
||||
Total maksimal 3 buku.</span>
|
||||
</div>
|
||||
|
||||
<!-- Search Box -->
|
||||
<div class="mb-3">
|
||||
<div class="input-group shadow-sm">
|
||||
<span class="input-group-text bg-white"><i class="bi bi-search"></i></span>
|
||||
|
|
@ -177,7 +172,6 @@ class="rounded me-3 form-book-cover">
|
|||
<div class="card-body p-3">
|
||||
<div class="d-flex align-items-start">
|
||||
|
||||
<!-- Cover Buku -->
|
||||
<img src="{{ asset($bukuItem['cover']) }}" alt="Cover"
|
||||
class="rounded me-3 form-book-cover"
|
||||
style="width: 60px; height: 80px; object-fit: cover;">
|
||||
|
|
@ -197,7 +191,6 @@ class="bi bi-star-fill me-1"></i>Buku Utama</span>
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Checkbox -->
|
||||
<div class="form-check ms-2">
|
||||
<input class="form-check-input book-checkbox" type="checkbox"
|
||||
value="{{ $bukuItem['id'] }}" id="book{{ $bukuItem['id'] }}"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
use App\Http\Controllers\BacaOnlineController;
|
||||
use App\Http\Controllers\DashboardController;
|
||||
use App\Http\Controllers\KatalogController;
|
||||
use App\Http\Controllers\PeminjamanController;
|
||||
|
|
@ -10,23 +11,36 @@
|
|||
return view('welcome');
|
||||
});
|
||||
|
||||
Route::middleware(['auth'])->group(function () {
|
||||
Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
|
||||
Route::get('/katalog', [KatalogController::class, 'index'])->name('katalog');
|
||||
|
||||
Route::get('/dashboard', [DashboardController::class, 'index'])
|
||||
->middleware(['auth'])->name('dashboard');
|
||||
Route::get('/katalog', [KatalogController::class, 'index'])
|
||||
->middleware('auth')->name('katalog');
|
||||
// --- Fitur Peminjaman Buku Offline ---
|
||||
Route::prefix('peminjaman-offline')->name('peminjaman.')->group(function () {
|
||||
Route::get('/', [PeminjamanController::class, 'index'])->name('index');
|
||||
Route::get('/{id}/ringkasan', [PeminjamanController::class, 'ringkasan'])->name('ringkasan');
|
||||
Route::get('/{id}/form', [PeminjamanController::class, 'form'])->name('form');
|
||||
Route::post('/store', [PeminjamanController::class, 'store'])->name('store');
|
||||
});
|
||||
|
||||
// Route untuk peminjaman offline
|
||||
Route::get('/peminjaman-offline', [PeminjamanController::class, 'index'])->name('peminjaman.index');
|
||||
Route::get('/peminjaman-offline/{id}/ringkasan', [PeminjamanController::class, 'ringkasan'])->name('peminjaman.ringkasan');
|
||||
Route::get('/peminjaman-offline/{id}/form', [PeminjamanController::class, 'form'])->name('peminjaman.form');
|
||||
Route::post('/peminjaman/store', [PeminjamanController::class, 'store'])->name('peminjaman.store');
|
||||
// --- Fitur Baca Buku Online ---
|
||||
Route::prefix('baca-online')->name('baca.')->group(function () {
|
||||
Route::get('/', [BacaOnlineController::class, 'index'])->name('index');
|
||||
Route::get('/{id}/ringkasan', [BacaOnlineController::class, 'ringkasan'])->name('ringkasan'); // Rute baru
|
||||
Route::get('/{id}/request', [BacaOnlineController::class, 'showCodeRequestPage'])->name('request_code');
|
||||
Route::post('/{id}/verify', [BacaOnlineController::class, 'verifyCode'])->name('verify_code');
|
||||
Route::get('/{id}/view', [BacaOnlineController::class, 'viewBook'])->name('view_book');
|
||||
});
|
||||
|
||||
Route::middleware('auth')->group(function () {
|
||||
Route::get('/profile', [ProfileController::class, 'index'])->name('profile.index');
|
||||
Route::get('/profile/edit', [ProfileController::class, 'edit'])->name('profile.edit');
|
||||
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
|
||||
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
|
||||
Route::get('/secure-pdf/{id}', [BacaOnlineController::class, 'streamPdf'])->name('baca.stream_pdf');
|
||||
|
||||
// --- Manajemen Profil Pengguna ---
|
||||
Route::prefix('profile')->name('profile.')->group(function () {
|
||||
Route::get('/', [ProfileController::class, 'index'])->name('index');
|
||||
Route::get('/edit', [ProfileController::class, 'edit'])->name('edit');
|
||||
Route::patch('/', [ProfileController::class, 'update'])->name('update');
|
||||
Route::delete('/', [ProfileController::class, 'destroy'])->name('destroy');
|
||||
});
|
||||
});
|
||||
|
||||
require __DIR__ . '/auth.php';
|
||||
require __DIR__ . '/auth.php';
|
||||
Loading…
Reference in New Issue