feat(app): Build complete UI for Siswa, Guru, and Admin roles with refactored auth
This commit is contained in:
parent
98679fec62
commit
187bb9d9af
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\Auth\LoginRequest;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\View\View;
|
||||||
|
|
||||||
|
class AdminLoginController extends Controller
|
||||||
|
{
|
||||||
|
// Menampilkan form login admin
|
||||||
|
public function create(): View
|
||||||
|
{
|
||||||
|
return view('auth.admin-login');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memproses login admin
|
||||||
|
public function store(LoginRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$request->authenticate(); // Menjalankan logika ketat di LoginRequest
|
||||||
|
$request->session()->regenerate();
|
||||||
|
return redirect()->route('admin.dashboard');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,9 +14,14 @@ class AuthenticatedSessionController extends Controller
|
||||||
/**
|
/**
|
||||||
* Display the login view.
|
* Display the login view.
|
||||||
*/
|
*/
|
||||||
public function create(): View
|
public function create(Request $request): View
|
||||||
{
|
{
|
||||||
return view('auth.login');
|
// Ambil 'role' dari URL, jika tidak ada, defaultnya 'siswa'
|
||||||
|
$role = $request->query('role', 'siswa');
|
||||||
|
|
||||||
|
return view('auth.login', [
|
||||||
|
'role' => $role
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -24,22 +29,12 @@ public function create(): View
|
||||||
*/
|
*/
|
||||||
public function store(LoginRequest $request): RedirectResponse
|
public function store(LoginRequest $request): RedirectResponse
|
||||||
{
|
{
|
||||||
$request->authenticate();
|
$request->authenticate(); // Menjalankan logika di LoginRequest
|
||||||
|
|
||||||
$request->session()->regenerate();
|
$request->session()->regenerate();
|
||||||
|
|
||||||
// Ambil data user dari session
|
// Karena login sudah dijamin benar, cukup arahkan ke dashboard umum
|
||||||
$userData = session('user_data');
|
return redirect()->intended(route('dashboard'));
|
||||||
|
|
||||||
// Cek role dan redirect sesuai role
|
|
||||||
if ($userData && isset($userData['role']) && $userData['role'] === 'penjaga perpus') {
|
|
||||||
return redirect()->route('admin.dashboard');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default redirect ke dashboard siswa
|
|
||||||
return redirect()->route('dashboard');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy an authenticated session.
|
* Destroy an authenticated session.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace App\Http\Middleware;
|
|
||||||
|
|
||||||
use App\Models\User;
|
|
||||||
use Closure;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
|
||||||
|
|
||||||
class AuthenticateFromSessionData
|
|
||||||
{
|
|
||||||
public function handle(Request $request, Closure $next): Response
|
|
||||||
{
|
|
||||||
if (session()->has('user_data') && !Auth::check()) {
|
|
||||||
$userArray = session('user_data');
|
|
||||||
$userArray['name'] = $userArray['nama_lengkap'];
|
|
||||||
|
|
||||||
$userModel = new User();
|
|
||||||
$userModel->forceFill($userArray);
|
|
||||||
|
|
||||||
Auth::login($userModel);
|
|
||||||
}
|
|
||||||
return $next($request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,25 +4,16 @@
|
||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
class CheckRole
|
class CheckRole
|
||||||
{
|
{
|
||||||
/**
|
public function handle(Request $request, Closure $next, ...$roles): Response
|
||||||
* Handle an incoming request.
|
|
||||||
*/
|
|
||||||
public function handle(Request $request, Closure $next, string $role): Response
|
|
||||||
{
|
{
|
||||||
$userData = session('user_data');
|
if (!Auth::check() || !in_array(Auth::user()->role, $roles)) {
|
||||||
|
return redirect()->route('login')
|
||||||
// Cek apakah user sudah login
|
->with('error', 'Akses ditolak. Anda tidak memiliki izin untuk mengakses halaman tersebut.');
|
||||||
if (!$userData) {
|
|
||||||
return redirect()->route('login');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cek apakah role sesuai
|
|
||||||
if (!isset($userData['role']) || $userData['role'] !== $role) {
|
|
||||||
abort(403, 'Akses ditolak. Anda tidak memiliki izin untuk mengakses halaman ini.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
|
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
|
||||||
|
|
||||||
use Closure;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
|
||||||
|
|
||||||
class SessionAuthMiddleware
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Handle an incoming request.
|
|
||||||
*/
|
|
||||||
public function handle(Request $request, Closure $next): Response
|
|
||||||
{
|
|
||||||
// Cek apakah user_data ada di session
|
|
||||||
if (!session()->has('user_data')) {
|
|
||||||
return redirect()->route('login');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $next($request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,71 +2,133 @@
|
||||||
|
|
||||||
namespace App\Http\Requests\Auth;
|
namespace App\Http\Requests\Auth;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
use App\Services\DummyDataService;
|
use App\Services\DummyDataService;
|
||||||
use Illuminate\Auth\Events\Lockout;
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\RateLimiter;
|
use Illuminate\Support\Facades\RateLimiter;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
|
use Illuminate\Auth\Events\Lockout;
|
||||||
|
|
||||||
class LoginRequest extends FormRequest
|
class LoginRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Determine if the user is authorized to make this request.
|
* Menentukan apakah pengguna diizinkan untuk membuat request ini.
|
||||||
|
* Selalu true karena semua orang boleh mencoba login.
|
||||||
*/
|
*/
|
||||||
public function authorize(): bool
|
public function authorize(): bool
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mendapatkan aturan validasi yang berlaku untuk request ini.
|
||||||
|
* Aturan ini dinamis, berubah tergantung pada 'role' yang dikirim dari form.
|
||||||
|
*/
|
||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
|
// Jika form mengirim 'role' dengan nilai 'siswa'...
|
||||||
|
if ($this->input('role') === 'siswa') {
|
||||||
|
// ...maka validasi input 'nisn' dan 'password'.
|
||||||
|
return [
|
||||||
|
'nisn' => ['required', 'string'],
|
||||||
|
'password' => ['required', 'string'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jika tidak (untuk 'guru' dan 'penjaga perpus'), validasi 'email' dan 'password'.
|
||||||
return [
|
return [
|
||||||
'nisn' => ['required', 'string'],
|
'email' => ['required', 'string', 'email'],
|
||||||
'password' => ['required', 'string'],
|
'password' => ['required', 'string'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mencoba untuk mengautentikasi kredensial dari request.
|
||||||
|
* Ini adalah "otak" dari proses login yang berisi logika paling penting.
|
||||||
|
*
|
||||||
|
* @throws \Illuminate\Validation\ValidationException
|
||||||
|
*/
|
||||||
public function authenticate(): void
|
public function authenticate(): void
|
||||||
{
|
{
|
||||||
|
// Langkah 1: Pastikan pengguna tidak mencoba login terlalu sering (mencegah brute-force).
|
||||||
$this->ensureIsNotRateLimited();
|
$this->ensureIsNotRateLimited();
|
||||||
|
|
||||||
$allSiswa = DummyDataService::getAllSiswa();
|
// Ambil data yang dikirim dari form login.
|
||||||
$inputNisn = $this->input('nisn');
|
$roleDariForm = $this->input('role');
|
||||||
|
$allUsers = DummyDataService::getAllSiswa();
|
||||||
$inputPassword = $this->input('password');
|
$inputPassword = $this->input('password');
|
||||||
|
$userArray = null;
|
||||||
|
|
||||||
$userArray = collect($allSiswa)->firstWhere('nisn', $inputNisn);
|
// Tentukan field mana yang akan menerima pesan error jika gagal (nisn atau email).
|
||||||
|
$errorField = $this->filled('nisn') ? 'nisn' : 'email';
|
||||||
|
|
||||||
if ($userArray && $userArray['password'] === $inputPassword) {
|
// Langkah 2: Cari data pengguna berdasarkan input yang diberikan.
|
||||||
// Simpan ke session
|
if ($this->filled('nisn')) {
|
||||||
session(['user_data' => $userArray]);
|
// Jika form diisi dengan 'nisn', cari pengguna berdasarkan 'nisn'.
|
||||||
|
$userArray = collect($allUsers)->firstWhere('nisn', $this->input('nisn'));
|
||||||
// Set redirect intention berdasarkan role
|
} else {
|
||||||
if (isset($userArray['role']) && $userArray['role'] === 'penjaga perpus') {
|
// Jika tidak, cari pengguna berdasarkan 'email'.
|
||||||
session()->put('url.intended', route('admin.dashboard'));
|
$userArray = collect($allUsers)->firstWhere('email', $this->input('email'));
|
||||||
}
|
|
||||||
|
|
||||||
RateLimiter::clear($this->throttleKey());
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Langkah 3: Lakukan Pengecekan Kredensial dan Role.
|
||||||
|
// Cek #1: Apakah pengguna ditemukan DAN password yang dimasukkan cocok?
|
||||||
|
if ($userArray && $userArray['password'] === $inputPassword) {
|
||||||
|
|
||||||
|
// Cek #2: Jika kredensial benar, apakah role pengguna sesuai dengan form yang digunakan?
|
||||||
|
if (isset($userArray['role']) && $userArray['role'] === $roleDariForm) {
|
||||||
|
|
||||||
|
// --- SEMUA SYARAT TERPENUHI ---
|
||||||
|
// Buat objek User dari data dummy.
|
||||||
|
$userModel = new User();
|
||||||
|
$userArray['name'] = $userArray['nama_lengkap'];
|
||||||
|
$userModel->forceFill($userArray);
|
||||||
|
|
||||||
|
// Loginkan pengguna secara resmi ke dalam sistem.
|
||||||
|
Auth::login($userModel);
|
||||||
|
|
||||||
|
// Reset hitungan percobaan login yang gagal.
|
||||||
|
RateLimiter::clear($this->throttleKey());
|
||||||
|
return; // Proses autentikasi berhasil.
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// --- KASUS GAGAL: KREDENSIAL BENAR, TAPI ROLE SALAH ---
|
||||||
|
// Tambah hitungan percobaan login yang gagal.
|
||||||
|
RateLimiter::hit($this->throttleKey());
|
||||||
|
|
||||||
|
// Ambil nama role asli pengguna untuk ditampilkan di pesan error.
|
||||||
|
$actualRole = Str::title($userArray['role'] ?? 'Tidak Dikenal');
|
||||||
|
|
||||||
|
// Lemparkan error validasi khusus 'forbidden' dengan pesan yang jelas.
|
||||||
|
throw ValidationException::withMessages([
|
||||||
|
'forbidden' => "Akses ditolak. Akun ini terdaftar sebagai {$actualRole}.",
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- KASUS GAGAL: KREDENSIAL TIDAK COCOK ---
|
||||||
|
// Jika pengguna tidak ditemukan atau password salah.
|
||||||
RateLimiter::hit($this->throttleKey());
|
RateLimiter::hit($this->throttleKey());
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'nisn' => trans('auth.failed'),
|
$errorField => trans('auth.failed'), // Pesan error umum "These credentials do not match...".
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Memastikan request login tidak dibatasi karena terlalu banyak percobaan.
|
||||||
|
*/
|
||||||
public function ensureIsNotRateLimited(): void
|
public function ensureIsNotRateLimited(): void
|
||||||
{
|
{
|
||||||
if (! RateLimiter::tooManyAttempts($this->throttleKey(), 5)) {
|
// Jika percobaan belum melebihi 5 kali, lanjutkan.
|
||||||
|
if (!RateLimiter::tooManyAttempts($this->throttleKey(), 5)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Jika sudah lebih dari 5 kali, lemparkan error 'throttle'.
|
||||||
event(new Lockout($this));
|
event(new Lockout($this));
|
||||||
|
|
||||||
$seconds = RateLimiter::availableIn($this->throttleKey());
|
$seconds = RateLimiter::availableIn($this->throttleKey());
|
||||||
|
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'email' => trans('auth.throttle', [
|
'email' => trans('auth.throttle', [
|
||||||
'seconds' => $seconds,
|
'seconds' => $seconds,
|
||||||
|
|
@ -76,10 +138,13 @@ public function ensureIsNotRateLimited(): void
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the rate limiting throttle key for the request.
|
* Mendapatkan kunci throttle untuk request ini.
|
||||||
|
* Kunci ini unik untuk setiap pengguna (berdasarkan nisn/email) dan alamat IP.
|
||||||
*/
|
*/
|
||||||
public function throttleKey(): string
|
public function throttleKey(): string
|
||||||
{
|
{
|
||||||
return Str::transliterate(Str::lower($this->string('nisn')).'|'.$this->ip());
|
// Gunakan 'nisn' jika ada, jika tidak, gunakan 'email' sebagai identitas.
|
||||||
|
$loginIdentifier = $this->input('nisn') ?: $this->input('email');
|
||||||
|
return Str::transliterate(Str::lower($loginIdentifier) . '|' . $this->ip());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -23,10 +23,8 @@ public static function getAllSiswa(): array
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 2,
|
'id' => 2,
|
||||||
'nisn' => '1122334455',
|
|
||||||
'nama_lengkap' => 'Budi Santoso',
|
'nama_lengkap' => 'Budi Santoso',
|
||||||
'email' => 'budi.santoso@smkn1perpus.sch.id',
|
'email' => 'budi.santoso@smkn1perpus.sch.id',
|
||||||
'nomor_hp' => '081122334455',
|
|
||||||
'password' => 'password',
|
'password' => 'password',
|
||||||
'role' => 'penjaga perpus',
|
'role' => 'penjaga perpus',
|
||||||
],
|
],
|
||||||
|
|
@ -54,10 +52,8 @@ public static function getAllSiswa(): array
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 5,
|
'id' => 5,
|
||||||
'nisn' => '2233445566',
|
|
||||||
'nama_lengkap' => 'Rina Marlina',
|
'nama_lengkap' => 'Rina Marlina',
|
||||||
'email' => 'rina.marlina@smkn1perpus.sch.id',
|
'email' => 'rina.marlina@smkn1perpus.sch.id',
|
||||||
'nomor_hp' => '081223344556',
|
|
||||||
'password' => 'password',
|
'password' => 'password',
|
||||||
'role' => 'guru',
|
'role' => 'guru',
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -11,14 +11,10 @@
|
||||||
health: '/up',
|
health: '/up',
|
||||||
)
|
)
|
||||||
->withMiddleware(function (Middleware $middleware) {
|
->withMiddleware(function (Middleware $middleware) {
|
||||||
$middleware->web(append: [
|
$middleware->alias([
|
||||||
\App\Http\Middleware\AuthenticateFromSessionData::class,
|
'role' => \App\Http\Middleware\CheckRole::class,
|
||||||
]);
|
]);
|
||||||
$middleware->alias([
|
})
|
||||||
'session.auth' => \App\Http\Middleware\SessionAuthMiddleware::class,
|
|
||||||
'role' => \App\Http\Middleware\CheckRole::class,
|
|
||||||
]);
|
|
||||||
})
|
|
||||||
->withProviders([
|
->withProviders([
|
||||||
App\Providers\AuthServiceProvider::class,
|
App\Providers\AuthServiceProvider::class,
|
||||||
])
|
])
|
||||||
|
|
|
||||||
|
|
@ -317,3 +317,29 @@ $transition: all 0.3s ease;
|
||||||
.book-option[style*="display: none"] {
|
.book-option[style*="display: none"] {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===================================
|
||||||
|
// WELCOME PAGE & Login Page Styles
|
||||||
|
// ===================================
|
||||||
|
|
||||||
|
.hero-gradient {
|
||||||
|
background: linear-gradient(135deg, map-get($theme-colors, "primary") 0%, color.adjust(map-get($theme-colors, "primary"), $lightness: 10%) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.role-card {
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
.card {
|
||||||
|
transition: $transition;
|
||||||
|
border-radius: 20px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
box-shadow: $shadow-md;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-panel {
|
||||||
|
background: linear-gradient(135deg, map-get($theme-colors, "primary") 0%, color.adjust(map-get($theme-colors, "primary"), $lightness: 10%) 100%);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
<x-guest-layout>
|
||||||
|
@if ($errors->has('forbidden'))
|
||||||
|
<div class="alert alert-danger d-flex align-items-center" role="alert">
|
||||||
|
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
||||||
|
<div>{{ $errors->first('forbidden') }}</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<x-auth-session-status class="mb-4" :status="session('status')" />
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('admin.login.store') }}">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<input type="hidden" name="role" value="penjaga perpus">
|
||||||
|
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<i class="bi bi-shield-lock-fill text-primary fs-1 mb-3"></i>
|
||||||
|
<h3 class="fw-bold text-primary">Login Petugas</h3>
|
||||||
|
<p class="text-muted">Halaman ini khusus untuk Penjaga Perpustakaan.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="email" class="form-label">Alamat Email</label>
|
||||||
|
<input id="email" class="form-control" type="email" name="email" required autofocus />
|
||||||
|
<x-input-error :messages="$errors->get('email')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="password" class="form-label">Kata Sandi</label>
|
||||||
|
<input id="password" class="form-control" type="password" name="password" required />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-grid mt-4">
|
||||||
|
<button type="submit" class="btn btn-primary btn-lg">Masuk</button>
|
||||||
|
</div>
|
||||||
|
<p class="mt-4 text-center text-muted small">
|
||||||
|
Kembali ke <a href="/" class="fw-semibold text-decoration-none">halaman utama</a>.
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</x-guest-layout>
|
||||||
|
|
@ -1,75 +1,53 @@
|
||||||
<x-guest-layout>
|
<x-guest-layout>
|
||||||
<x-auth-session-status class="mb-4" :status="session('status')" />
|
@if ($errors->has('forbidden'))
|
||||||
|
<div class="alert alert-danger d-flex align-items-center" role="alert">
|
||||||
|
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
||||||
|
<div>{{ $errors->first('forbidden') }}</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
<form method="POST" action="{{ route('login') }}">
|
<form method="POST" action="{{ route('login') }}">
|
||||||
@csrf
|
@csrf
|
||||||
|
<input type="hidden" name="role" value="{{ $role }}">
|
||||||
|
|
||||||
<div class="text-center mb-4">
|
<div class="text-center mb-4">
|
||||||
<h3 class="fw-bold text-primary">Login Siswa</h3>
|
{{-- Judul dinamis --}}
|
||||||
<p class="text-muted">Masukan NISN dan kata sandi Anda.</p>
|
<h3 class="fw-bold text-primary">Login {{ Str::title($role) }}</h3>
|
||||||
|
<p class="text-muted">
|
||||||
|
@if ($role == 'siswa')
|
||||||
|
Masukan NISN dan kata sandi Anda.
|
||||||
|
@else
|
||||||
|
Masukan Email dan kata sandi Anda.
|
||||||
|
@endif
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
{{-- Form dinamis --}}
|
||||||
<label for="nisn" class="form-label">Nomor Induk Siswa Nasional (NISN)</label>
|
@if($role == 'siswa')
|
||||||
<input id="nisn" class="form-control bg-body-tertiary @error('nisn') is-invalid @enderror"
|
<div class="mb-3">
|
||||||
type="text" name="nisn" value="{{ old('nisn') }}" required autofocus autocomplete="username" />
|
<label for="nisn" class="form-label">Nomor Induk Siswa Nasional (NISN)</label>
|
||||||
@error('nisn')
|
<input id="nisn" class="form-control" type="text" name="nisn" required autofocus />
|
||||||
<div class="invalid-feedback">{{ $message }}</div>
|
<x-input-error :messages="$errors->get('nisn')" class="mt-2" /> {{-- <-- Pastikan ini ada --}}
|
||||||
@enderror
|
</div>
|
||||||
</div>
|
@else
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="email" class="form-label">Alamat Email</label>
|
||||||
|
<input id="email" class="form-control" type="email" name="email" required autofocus />
|
||||||
|
<x-input-error :messages="$errors->get('email')" class="mt-2" /> {{-- <-- Pastikan ini ada --}}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="password" class="form-label">Kata Sandi</label>
|
<label for="password" class="form-label">Kata Sandi</label>
|
||||||
<div class="input-group">
|
<input id="password" class="form-control" type="password" name="password" required />
|
||||||
<input id="password" class="form-control bg-body-tertiary @error('password') is-invalid @enderror"
|
|
||||||
type="password" name="password" required autocomplete="current-password" />
|
|
||||||
<span class="input-group-text bg-body-tertiary" id="togglePassword" style="cursor: pointer;">
|
|
||||||
<i class="bi bi-eye-slash-fill"></i>
|
|
||||||
</span>
|
|
||||||
@error('password')
|
|
||||||
<div class="invalid-feedback">{{ $message }}</div>
|
|
||||||
@enderror
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="d-flex justify-content-end align-items-center mb-3">
|
<div class="d-grid mt-4">
|
||||||
@if (Route::has('password.request'))
|
<button type="submit" class="btn btn-primary btn-lg">Masuk</button>
|
||||||
<a class="text-decoration-none small" href="{{ route('password.request') }}">
|
|
||||||
Lupa password?
|
|
||||||
</a>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="d-grid">
|
|
||||||
<button type="submit" class="btn btn-primary btn-lg">
|
|
||||||
Masuk
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="mt-4 text-center text-muted small">
|
<p class="mt-4 text-center text-muted small">
|
||||||
Belum punya akun?
|
Kembali ke <a href="/" class="fw-semibold text-decoration-none">halaman utama</a>.
|
||||||
<a href="{{ route('register') }}" class="fw-semibold text-decoration-none">Daftar sekarang</a>
|
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
|
|
||||||
const togglePassword = document.querySelector('#togglePassword');
|
|
||||||
const passwordInput = document.querySelector('#password');
|
|
||||||
const icon = togglePassword.querySelector('i');
|
|
||||||
|
|
||||||
togglePassword.addEventListener('click', function() {
|
|
||||||
const type = passwordInput.getAttribute('type') === 'password' ? 'text' : 'password';
|
|
||||||
passwordInput.setAttribute('type', type);
|
|
||||||
|
|
||||||
if (type === 'password') {
|
|
||||||
icon.classList.remove('bi-eye-fill');
|
|
||||||
icon.classList.add('bi-eye-slash-fill');
|
|
||||||
} else {
|
|
||||||
icon.classList.remove('bi-eye-slash-fill');
|
|
||||||
icon.classList.add('bi-eye-fill');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</x-guest-layout>
|
</x-guest-layout>
|
||||||
|
|
|
||||||
|
|
@ -7,36 +7,63 @@
|
||||||
<title>{{ config('app.name', 'Laravel') }}</title>
|
<title>{{ config('app.name', 'Laravel') }}</title>
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||||
@vite(['resources/scss/app.scss', 'resources/js/app.js'])
|
@vite(['resources/scss/app.scss', 'resources/js/app.js'])
|
||||||
|
|
||||||
<style>
|
|
||||||
.info-panel {
|
|
||||||
background-color: var(--bs-primary);
|
|
||||||
}
|
|
||||||
.info-svg {
|
|
||||||
max-width: 400px;
|
|
||||||
width: 80%;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row min-vh-100">
|
<div class="row min-vh-100">
|
||||||
|
<!-- Left Panel - Info -->
|
||||||
<div class="col-lg-7 d-none d-lg-flex flex-column justify-content-center align-items-center info-panel text-white p-5">
|
<div class="col-lg-7 d-none d-lg-flex flex-column justify-content-center align-items-center info-panel text-white p-5">
|
||||||
<div class="text-center">
|
<div class="text-center" style="max-width: 500px;">
|
||||||
<i class="bi bi-book-half" style="font-size: 4rem;"></i>
|
<!-- Logo -->
|
||||||
<h1 class="display-4 fw-bold mt-3">Perpus Digital</h1>
|
<div class="icon-circle bg-white bg-opacity-10 mx-auto mb-4" style="width: 100px; height: 100px; border-radius: 30px;">
|
||||||
<p class="lead mt-3">Gerbang Anda menuju dunia pengetahuan. Jelajahi ribuan koleksi buku digital, pinjam dengan mudah, dan lacak progres membaca Anda.</p>
|
<i class="bi bi-book-half" style="font-size: 3rem;"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 class="display-4 fw-bold mb-3">DIGIPUS.GO</h1>
|
||||||
|
<p class="lead opacity-90 mb-4">
|
||||||
|
Gerbang Anda menuju dunia pengetahuan. Jelajahi ribuan koleksi buku digital, pinjam dengan mudah, dan lacak progres membaca Anda.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- Features -->
|
||||||
|
<div class="row g-3 mt-4">
|
||||||
|
<div class="col-6">
|
||||||
|
<div class="p-3 bg-white bg-opacity-10 rounded-4">
|
||||||
|
<i class="bi bi-book fs-3 mb-2 d-block"></i>
|
||||||
|
<div class="fw-semibold">Ribuan Buku</div>
|
||||||
|
<small class="opacity-75">Koleksi lengkap</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-6">
|
||||||
|
<div class="p-3 bg-white bg-opacity-10 rounded-4">
|
||||||
|
<i class="bi bi-clock-history fs-3 mb-2 d-block"></i>
|
||||||
|
<div class="fw-semibold">Mudah & Cepat</div>
|
||||||
|
<small class="opacity-75">Proses instant</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Right Panel - Auth Form -->
|
||||||
<div class="col-lg-5 d-flex flex-column justify-content-center align-items-center bg-light p-4">
|
<div class="col-lg-5 d-flex flex-column justify-content-center align-items-center bg-light p-4">
|
||||||
<div class="card shadow-lg border-0 p-4 p-md-5" style="max-width: 450px; width: 100%;">
|
<div class="w-100" style="max-width: 450px;">
|
||||||
{{ $slot }}
|
<!-- Mobile Logo -->
|
||||||
|
<div class="d-lg-none text-center mb-4">
|
||||||
|
<div class="icon-circle bg-primary-soft mx-auto mb-3" style="width: 70px; height: 70px; border-radius: 22px;">
|
||||||
|
<i class="bi bi-book-half text-primary" style="font-size: 2rem;"></i>
|
||||||
|
</div>
|
||||||
|
<h4 class="fw-bold">DIGIPUS.GO</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Auth Card -->
|
||||||
|
<div class="card shadow-lg border-0" style="border-radius: 28px;">
|
||||||
|
<div class="card-body p-4 p-md-5">
|
||||||
|
{{ $slot }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -4,59 +4,150 @@
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>Selamat Datang di {{ config('app.name', 'Perpus Digital') }}</title>
|
<title>Selamat Datang di {{ config('app.name', 'Perpus Digital') }}</title>
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||||
@vite(['resources/scss/app.scss', 'resources/js/app.js'])
|
@vite(['resources/scss/app.scss', 'resources/js/app.js'])
|
||||||
|
|
||||||
<style>
|
|
||||||
.info-panel {
|
|
||||||
background-color: var(--bs-primary);
|
|
||||||
}
|
|
||||||
.info-svg {
|
|
||||||
max-width: 400px;
|
|
||||||
width: 80%;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<!-- Hero Section -->
|
||||||
|
<div class="hero-gradient min-vh-100 d-flex align-items-center">
|
||||||
|
<div class="container py-5">
|
||||||
|
<div class="row align-items-center g-5">
|
||||||
|
<!-- Left Content -->
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<div class="text-white mb-4 mb-lg-0">
|
||||||
|
<div class="badge bg-white text-primary px-3 py-2 mb-3" style="border-radius: 50px;">
|
||||||
|
<i class="bi bi-stars me-1"></i> Perpustakaan Digital
|
||||||
|
</div>
|
||||||
|
<h1 class="display-4 fw-bold mb-3">DIGIPUS.GO</h1>
|
||||||
|
<p class="fs-5 mb-4 opacity-75">
|
||||||
|
Gerbang menuju dunia pengetahuan tanpa batas. Akses ribuan koleksi buku digital dengan mudah.
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="row g-3 mt-4">
|
||||||
<div class="row min-vh-100">
|
<div class="col-sm-6">
|
||||||
|
<div class="d-flex align-items-center gap-3">
|
||||||
<div class="col-lg-7 d-none d-lg-flex flex-column justify-content-center align-items-center info-panel text-white p-5">
|
<div class="icon-box bg-white bg-opacity-10 text-white" style="border-radius: 16px;">
|
||||||
<div class="text-center">
|
<i class="bi bi-book"></i>
|
||||||
<i class="bi bi-book-half" style="font-size: 4rem;"></i>
|
</div>
|
||||||
<h1 class="display-4 fw-bold mt-3">Perpus Digital</h1>
|
<div>
|
||||||
<p class="lead mt-3">Gerbang Anda menuju dunia pengetahuan. Jelajahi ribuan koleksi buku digital, pinjam dengan mudah, dan lacak progres membaca Anda.</p>
|
<div class="fw-semibold">Ribuan Buku</div>
|
||||||
|
<small class="opacity-75">Koleksi lengkap</small>
|
||||||
<svg class="info-svg mt-4" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
|
</div>
|
||||||
<path fill="#FFFFFF" d="M37.3,-45.1C51.2,-36.8,67.3,-26.1,72.4,-11.3C77.5,3.6,71.6,22.6,61,35.1C50.4,47.6,35.1,53.6,19.9,56.9C4.8,60.2,-10.2,60.8,-25.1,55.9C-40,51,-54.8,40.6,-64.3,26.3C-73.8,12,-78,-6.2,-73,-21.2C-68,-36.2,-53.8,-48.1,-39.3,-56.3C-24.8,-64.5,-10,-69,5.7,-68.1C21.4,-67.2,42.8,-60.9,37.3,-45.1" transform="translate(100 100)" style="opacity: 0.1;"></path>
|
</div>
|
||||||
</svg>
|
</div>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<div class="d-flex align-items-center gap-3">
|
||||||
|
<div class="icon-box bg-white bg-opacity-10 text-white" style="border-radius: 16px;">
|
||||||
|
<i class="bi bi-clock"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="fw-semibold">Akses 24/7</div>
|
||||||
|
<small class="opacity-75">Kapan saja</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<div class="d-flex align-items-center gap-3">
|
||||||
|
<div class="icon-box bg-white bg-opacity-10 text-white" style="border-radius: 16px;">
|
||||||
|
<i class="bi bi-phone"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="fw-semibold">Responsive</div>
|
||||||
|
<small class="opacity-75">Semua perangkat</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<div class="d-flex align-items-center gap-3">
|
||||||
|
<div class="icon-box bg-white bg-opacity-10 text-white" style="border-radius: 16px;">
|
||||||
|
<i class="bi bi-shield-check"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="fw-semibold">Aman</div>
|
||||||
|
<small class="opacity-75">Data terlindungi</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-lg-5 d-flex flex-column justify-content-center align-items-center bg-light p-4">
|
<!-- Right Content - Login Card -->
|
||||||
<div class="card shadow-lg border-0 p-4 p-md-5" style="max-width: 450px; width: 100%;">
|
<div class="col-lg-5 offset-lg-1">
|
||||||
<div class="text-center mb-4">
|
<div class="card border-0 shadow-lg" style="border-radius: 32px;">
|
||||||
<h3 class="fw-bold text-primary">Selamat Datang</h3>
|
<div class="card-body p-5">
|
||||||
<p class="text-muted">Silakan pilih peran Anda untuk masuk.</p>
|
<!-- Logo -->
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<div class="icon-circle bg-primary-soft mx-auto mb-3" style="width: 90px; height: 90px; border-radius: 28px;">
|
||||||
|
<i class="bi bi-book-half text-primary" style="font-size: 2.5rem;"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="fw-bold mb-2">Selamat Datang</h3>
|
||||||
|
<p class="text-muted mb-0">Pilih peran Anda untuk melanjutkan</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Role Options -->
|
||||||
|
<div class="d-grid gap-3 mb-4">
|
||||||
|
<!-- Siswa -->
|
||||||
|
<a href="{{ route('login', ['role' => 'siswa']) }}" class="role-card text-decoration-none">
|
||||||
|
<div class="card h-100 border-0 bg-light">
|
||||||
|
<div class="card-body p-4">
|
||||||
|
<div class="d-flex align-items-center gap-3">
|
||||||
|
<div class="icon-circle bg-primary text-white flex-shrink-0" style="border-radius: 20px;">
|
||||||
|
<i class="bi bi-person-badge fs-4"></i>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<h5 class="mb-1 fw-bold">Siswa</h5>
|
||||||
|
<p class="mb-0 text-muted small">Pinjam dan baca buku digital</p>
|
||||||
|
</div>
|
||||||
|
<i class="bi bi-arrow-right-circle fs-3 text-primary"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Guru -->
|
||||||
|
<a href="{{ route('login', ['role' => 'guru']) }}" class="role-card text-decoration-none">
|
||||||
|
<div class="card h-100 border-0 bg-light">
|
||||||
|
<div class="card-body p-4">
|
||||||
|
<div class="d-flex align-items-center gap-3">
|
||||||
|
<div class="icon-circle bg-success text-white flex-shrink-0" style="border-radius: 20px;">
|
||||||
|
<i class="bi bi-person-workspace fs-4"></i>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<h5 class="mb-1 fw-bold">Guru</h5>
|
||||||
|
<p class="mb-0 text-muted small">Kelola dan rekomendasikan buku</p>
|
||||||
|
</div>
|
||||||
|
<i class="bi bi-arrow-right-circle fs-3 text-success"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Divider -->
|
||||||
|
<div class="text-center mb-3">
|
||||||
|
<span class="text-muted small">atau</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Admin Link -->
|
||||||
|
<div class="text-center">
|
||||||
|
<a href="{{ route('admin.login') }}" class="btn btn-outline-secondary" style="border-radius: 16px;">
|
||||||
|
<i class="bi bi-shield-lock me-2"></i>Login sebagai Petugas
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="d-grid gap-3">
|
<!-- Footer Info -->
|
||||||
<a href="{{ route('login') }}" class="btn btn-primary btn-lg">
|
<div class="text-center mt-3">
|
||||||
<i class="bi bi-person-badge me-2"></i> Login sebagai Murid
|
<small class="text-white opacity-75">
|
||||||
</a>
|
<i class="bi bi-info-circle me-1"></i>
|
||||||
<a href="{{ route('login') }}" class="btn btn-success btn-lg">
|
Butuh bantuan? Hubungi petugas perpustakaan
|
||||||
<i class="bi bi-person-workspace me-2"></i> Login sebagai Guru
|
</small>
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -1,24 +1,42 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
|
// General Controllers
|
||||||
use App\Http\Controllers\DashboardController;
|
use App\Http\Controllers\DashboardController;
|
||||||
use App\Http\Controllers\KatalogController;
|
use App\Http\Controllers\KatalogController;
|
||||||
use App\Http\Controllers\PeminjamanController;
|
use App\Http\Controllers\PeminjamanController;
|
||||||
use App\Http\Controllers\BacaOnlineController;
|
use App\Http\Controllers\BacaOnlineController;
|
||||||
use App\Http\Controllers\RiwayatController;
|
use App\Http\Controllers\RiwayatController;
|
||||||
use App\Http\Controllers\ProfileController;
|
use App\Http\Controllers\ProfileController;
|
||||||
|
|
||||||
|
// Admin Controllers
|
||||||
use App\Http\Controllers\Admin\DashboardController as AdminDashboardController;
|
use App\Http\Controllers\Admin\DashboardController as AdminDashboardController;
|
||||||
use App\Http\Controllers\Admin\BookController as AdminBookController;
|
use App\Http\Controllers\Admin\BookController as AdminBookController;
|
||||||
use App\Http\Controllers\Admin\PengumumanController;
|
|
||||||
use App\Http\Controllers\Admin\UserController as AdminUserController;
|
use App\Http\Controllers\Admin\UserController as AdminUserController;
|
||||||
|
use App\Http\Controllers\Admin\PengumumanController as AdminPengumumanController;
|
||||||
|
|
||||||
|
// Guru Controller
|
||||||
use App\Http\Controllers\Guru\LaporanController;
|
use App\Http\Controllers\Guru\LaporanController;
|
||||||
|
|
||||||
|
// Auth Controllers
|
||||||
|
use App\Http\Controllers\Auth\AdminLoginController;
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Web Routes
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
// RUTE PUBLIK (Bisa diakses tanpa login)
|
||||||
Route::get('/', function () {
|
Route::get('/', function () {
|
||||||
return view('welcome');
|
return view('welcome');
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- RUTE UNTUK PENGGUNA TERAUTENTIKASI (SISWA & PENJAGA PERPUS) ---
|
// --- RUTE UNTUK PENGGUNA TERAUTENTIKASI (SISWA, GURU, & PENJAGA PERPUS) ---
|
||||||
Route::middleware(['session.auth'])->group(function () {
|
Route::middleware(['auth'])->group(function () {
|
||||||
|
|
||||||
|
// Rute Umum untuk Siswa & Guru
|
||||||
Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
|
Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
|
||||||
Route::get('/katalog', [KatalogController::class, 'index'])->name('katalog.index');
|
Route::get('/katalog', [KatalogController::class, 'index'])->name('katalog.index');
|
||||||
|
|
||||||
|
|
@ -35,39 +53,48 @@
|
||||||
Route::get('/{id}/request', [BacaOnlineController::class, 'showCodeRequestPage'])->name('request_code');
|
Route::get('/{id}/request', [BacaOnlineController::class, 'showCodeRequestPage'])->name('request_code');
|
||||||
Route::post('/{id}/verify', [BacaOnlineController::class, 'verifyCode'])->name('verify_code');
|
Route::post('/{id}/verify', [BacaOnlineController::class, 'verifyCode'])->name('verify_code');
|
||||||
Route::get('/{id}/view', [BacaOnlineController::class, 'viewBook'])->name('view_book');
|
Route::get('/{id}/view', [BacaOnlineController::class, 'viewBook'])->name('view_book');
|
||||||
|
Route::get('/secure-pdf/{id}', [BacaOnlineController::class, 'streamPdf'])->name('stream_pdf');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::get('/riwayat/offline', [RiwayatController::class, 'offlineIndex'])->name('riwayat.offline');
|
Route::prefix('riwayat')->name('riwayat.')->group(function () {
|
||||||
Route::get('/riwayat/online', [RiwayatController::class, 'onlineIndex'])->name('riwayat.online');
|
Route::get('/offline', [RiwayatController::class, 'offlineIndex'])->name('offline');
|
||||||
|
Route::get('/online', [RiwayatController::class, 'onlineIndex'])->name('online');
|
||||||
|
});
|
||||||
|
|
||||||
Route::get('/secure-pdf/{id}', [BacaOnlineController::class, 'streamPdf'])->name('baca.stream_pdf');
|
|
||||||
|
|
||||||
// --- Manajemen Profil Pengguna ---
|
|
||||||
Route::prefix('profile')->name('profile.')->group(function () {
|
Route::prefix('profile')->name('profile.')->group(function () {
|
||||||
Route::get('/', [ProfileController::class, 'index'])->name('index');
|
Route::get('/', [ProfileController::class, 'index'])->name('index');
|
||||||
Route::get('/edit', [ProfileController::class, 'edit'])->name('edit');
|
Route::get('/edit', [ProfileController::class, 'edit'])->name('edit');
|
||||||
Route::patch('/', [ProfileController::class, 'update'])->name('update');
|
Route::patch('/', [ProfileController::class, 'update'])->name('update');
|
||||||
Route::delete('/', [ProfileController::class, 'destroy'])->name('destroy');
|
Route::delete('/', [ProfileController::class, 'destroy'])->name('destroy');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// --- GRUP RUTE KHUSUS UNTUK GURU ---
|
||||||
|
Route::middleware(['role:guru'])->prefix('guru')->name('guru.')->group(function () {
|
||||||
|
Route::get('/laporan-minat-baca', [LaporanController::class, 'index'])->name('laporan.index');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- GRUP RUTE KHUSUS UNTUK ADMIN / PENJAGA PERPUSTAKAAN ---
|
// --- GRUP RUTE KHUSUS UNTUK ADMIN / PENJAGA PERPUSTAKAAN ---
|
||||||
Route::middleware(['session.auth', 'role:penjaga perpus'])->prefix('admin')->name('admin.')->group(function () {
|
Route::middleware(['auth', 'role:penjaga perpus'])->prefix('admin')->name('admin.')->group(function () {
|
||||||
Route::get('/dashboard', [AdminDashboardController::class, 'index'])->name('dashboard');
|
Route::get('/dashboard', [AdminDashboardController::class, 'index'])->name('dashboard');
|
||||||
|
|
||||||
Route::get('/buku', [AdminBookController::class, 'index'])->name('buku.index');
|
Route::get('/buku', [AdminBookController::class, 'index'])->name('buku.index');
|
||||||
Route::get('/buku/{id}/edit', [AdminBookController::class, 'edit'])->name('buku.edit');
|
|
||||||
Route::get('/buku/tambah', [AdminBookController::class, 'create'])->name('buku.create');
|
Route::get('/buku/tambah', [AdminBookController::class, 'create'])->name('buku.create');
|
||||||
|
Route::get('/buku/{id}/edit', [AdminBookController::class, 'edit'])->name('buku.edit');
|
||||||
|
|
||||||
Route::get('/pengguna', [AdminUserController::class, 'index'])->name('pengguna.index');
|
Route::get('/pengguna', [AdminUserController::class, 'index'])->name('pengguna.index');
|
||||||
Route::get('/pengumuman', [PengumumanController::class, 'index'])->name('pengumuman.index');
|
|
||||||
Route::get('/pengumuman/tambah', [PengumumanController::class, 'create'])->name('pengumuman.create');
|
|
||||||
Route::get('/pengumuman/{id}/edit', [PengumumanController::class, 'edit'])->name('pengumuman.edit');
|
|
||||||
Route::get('/pengguna/tambah', [AdminUserController::class, 'create'])->name('pengguna.create');
|
Route::get('/pengguna/tambah', [AdminUserController::class, 'create'])->name('pengguna.create');
|
||||||
Route::get('/pengguna/{id}/edit', [AdminUserController::class, 'edit'])->name('pengguna.edit');
|
Route::get('/pengguna/{id}/edit', [AdminUserController::class, 'edit'])->name('pengguna.edit');
|
||||||
|
|
||||||
|
Route::get('/pengumuman', [AdminPengumumanController::class, 'index'])->name('pengumuman.index');
|
||||||
|
Route::get('/pengumuman/tambah', [AdminPengumumanController::class, 'create'])->name('pengumuman.create');
|
||||||
|
Route::get('/pengumuman/{id}/edit', [AdminPengumumanController::class, 'edit'])->name('pengumuman.edit');
|
||||||
});
|
});
|
||||||
|
|
||||||
// GRUP RUTE KHUSUS UNTUK GURU
|
// --- RUTE LOGIN KHUSUS ADMIN ---
|
||||||
Route::middleware(['role:guru'])->prefix('guru')->name('guru.')->group(function () {
|
Route::middleware('guest')->group(function() {
|
||||||
Route::get('/laporan-minat-baca', [LaporanController::class, 'index'])->name('laporan.index');
|
Route::get('/admin/login', [AdminLoginController::class, 'create'])->name('admin.login');
|
||||||
|
Route::post('/admin/login', [AdminLoginController::class, 'store'])->name('admin.login.store');
|
||||||
});
|
});
|
||||||
|
|
||||||
require __DIR__ . '/auth.php';
|
require __DIR__ . '/auth.php';
|
||||||
Loading…
Reference in New Issue