feat: add custom error page handler and improve permission check safety in sidebar navigation
This commit is contained in:
parent
1368ed0b54
commit
eb13532b0b
@ -7,6 +7,7 @@
|
||||
use Illuminate\Foundation\Configuration\Exceptions;
|
||||
use Illuminate\Foundation\Configuration\Middleware;
|
||||
use Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets;
|
||||
use Inertia\Inertia;
|
||||
|
||||
return Application::configure(basePath: dirname(__DIR__))
|
||||
->withRouting(
|
||||
@ -27,5 +28,13 @@
|
||||
$schedule->command('payroll:generate')->monthlyOn(1, '00:00');
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions): void {
|
||||
//
|
||||
$exceptions->respond(function ($response) {
|
||||
if (in_array($response->getStatusCode(), [500, 503, 404, 403])) {
|
||||
return Inertia::render('error', ['status' => $response->getStatusCode()])
|
||||
->toResponse(request())
|
||||
->setStatusCode($response->getStatusCode());
|
||||
}
|
||||
|
||||
return $response;
|
||||
});
|
||||
})->create();
|
||||
|
||||
@ -14,7 +14,7 @@ createInertiaApp({
|
||||
title: (title) => (title ? `${title} - ${appName}` : appName),
|
||||
layout: (name) => {
|
||||
switch (true) {
|
||||
case name === 'welcome' || name === 'homepage':
|
||||
case name === 'welcome' || name === 'homepage' || name === 'error':
|
||||
return null;
|
||||
case name.startsWith('auth/'):
|
||||
return AuthLayout;
|
||||
|
||||
@ -137,7 +137,7 @@ export function AppSidebar() {
|
||||
const filterNavItems = (items: NavItem[]) => {
|
||||
return items.filter((item) => {
|
||||
if (!item.permission) return true;
|
||||
return auth.permissions.includes(item.permission);
|
||||
return auth?.permissions?.includes(item.permission) ?? false;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
89
resources/js/pages/error.tsx
Normal file
89
resources/js/pages/error.tsx
Normal file
@ -0,0 +1,89 @@
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { homepage } from '@/routes';
|
||||
import { Head, Link } from '@inertiajs/react';
|
||||
import { AlertCircle, ArrowLeft, Home, Search } from 'lucide-react';
|
||||
|
||||
export default function ErrorPage({ status }: { status: number }) {
|
||||
const title =
|
||||
{
|
||||
503: '503: Service Unavailable',
|
||||
500: '500: Server Error',
|
||||
404: '404: Page Not Found',
|
||||
403: '403: Forbidden',
|
||||
}[status] || 'Error';
|
||||
|
||||
const description =
|
||||
{
|
||||
503: 'Maaf, kami sedang melakukan pemeliharaan rutin untuk meningkatkan layanan. Silakan kembali lagi nanti.',
|
||||
500: 'Ups, terjadi kesalahan sistem yang tidak terduga. Tim teknis kami telah diberitahu.',
|
||||
404: 'Halaman yang Anda cari tidak dapat ditemukan atau telah dipindahkan ke alamat lain.',
|
||||
403: 'Maaf, Anda tidak memiliki akses untuk melihat konten di halaman ini.',
|
||||
}[status] || 'Terjadi kesalahan pada aplikasi.';
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head title={title} />
|
||||
<div className="relative flex min-h-screen flex-col items-center justify-center overflow-hidden bg-slate-50 p-6 dark:bg-slate-950">
|
||||
{/* Abstract Background Elements */}
|
||||
<div className="absolute -top-[10%] -left-[10%] h-[40%] w-[40%] rounded-full bg-primary/5 blur-3xl" />
|
||||
<div className="absolute -right-[10%] -bottom-[10%] h-[40%] w-[40%] rounded-full bg-primary/10 blur-3xl" />
|
||||
|
||||
<div className="relative z-10 flex w-full max-w-2xl flex-col items-center text-center">
|
||||
{/* Big Error Number with Gradient */}
|
||||
<div className="animate-in duration-700 fade-in zoom-in">
|
||||
<h1 className="text-[12rem] leading-none font-black tracking-tighter text-slate-200/50 select-none sm:text-[18rem] dark:text-slate-800/50">
|
||||
{status}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
{/* Content Card */}
|
||||
<div className="mt-[-4rem] flex flex-col items-center space-y-8 sm:mt-[-8rem]">
|
||||
<div className="relative">
|
||||
<div className="absolute -inset-1 rounded-full bg-gradient-to-r from-primary to-primary-foreground opacity-20 blur" />
|
||||
<div className="relative flex h-24 w-24 items-center justify-center rounded-full bg-white shadow-2xl dark:bg-slate-900">
|
||||
{status === 404 ? (
|
||||
<Search className="h-10 w-10 animate-pulse text-primary" />
|
||||
) : (
|
||||
<AlertCircle className="h-10 w-10 animate-bounce text-destructive" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3 px-4">
|
||||
<h2 className="text-3xl font-bold tracking-tight text-slate-900 sm:text-4xl dark:text-slate-50">
|
||||
{title}
|
||||
</h2>
|
||||
<p className="mx-auto max-w-md text-lg text-slate-600 dark:text-slate-400">
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-3 sm:flex-row sm:items-center">
|
||||
<Button
|
||||
asChild
|
||||
size="lg"
|
||||
className="h-12 gap-2 px-8 shadow-lg shadow-primary/20 transition-all hover:scale-105 active:scale-95"
|
||||
>
|
||||
<Link href={homepage().url}>
|
||||
<Home className="h-4 w-4" />
|
||||
Beranda
|
||||
</Link>
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="lg"
|
||||
onClick={() => window.history.back()}
|
||||
className="h-12 gap-2 bg-white/50 backdrop-blur-sm transition-all hover:bg-white dark:bg-slate-900/50 dark:hover:bg-slate-900"
|
||||
>
|
||||
<ArrowLeft className="h-4 w-4" />
|
||||
Kembali
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
ErrorPage.layout = null;
|
||||
Loading…
Reference in New Issue
Block a user