From 845d4edbd4bb8fc08020979660ab731aafd3ce2b Mon Sep 17 00:00:00 2001 From: Yurij Finiv Date: Sat, 10 Oct 2026 22:03:00 +0300 Subject: [PATCH] Split admin HTTP errors into customizable localized Blade views --- resources/lang/en/errors.php | 40 ++++++++++ resources/lang/uk/errors.php | 40 ++++++++++ resources/views/errors/401.blade.php | 7 ++ resources/views/errors/403.blade.php | 14 ++++ resources/views/errors/404.blade.php | 14 ++++ resources/views/errors/419.blade.php | 7 ++ resources/views/errors/429.blade.php | 7 ++ resources/views/errors/500.blade.php | 7 ++ resources/views/errors/503.blade.php | 7 ++ resources/views/errors/page.blade.php | 78 +------------------ .../errors/partials/admin-layout.blade.php | 31 ++++++++ .../errors/partials/standalone.blade.php | 58 ++++++++++++++ tests/Feature/AdminErrorPagesTest.php | 16 ++++ 13 files changed, 250 insertions(+), 76 deletions(-) create mode 100644 resources/lang/en/errors.php create mode 100644 resources/lang/uk/errors.php create mode 100644 resources/views/errors/401.blade.php create mode 100644 resources/views/errors/403.blade.php create mode 100644 resources/views/errors/404.blade.php create mode 100644 resources/views/errors/419.blade.php create mode 100644 resources/views/errors/429.blade.php create mode 100644 resources/views/errors/500.blade.php create mode 100644 resources/views/errors/503.blade.php create mode 100644 resources/views/errors/partials/admin-layout.blade.php create mode 100644 resources/views/errors/partials/standalone.blade.php diff --git a/resources/lang/en/errors.php b/resources/lang/en/errors.php new file mode 100644 index 0000000..d62bef6 --- /dev/null +++ b/resources/lang/en/errors.php @@ -0,0 +1,40 @@ + 'Back to dashboard', + 'try_again' => 'Try again', + '401' => [ + 'title' => 'Authentication required', + 'message' => 'Sign in to continue to the admin area.', + ], + '403' => [ + 'headline' => 'This section is restricted', + 'title' => 'Access denied', + 'message' => 'You do not have permission to access this section.', + 'hint' => 'If you need access, contact an administrator.', + 'eyebrow' => 'RESTRICTED ACCESS', + ], + '404' => [ + 'headline' => 'We couldn\'t find that page', + 'title' => 'Page not found', + 'message' => 'We could not find the admin page you requested.', + 'hint' => 'The address may be incorrect, or the page may have been moved.', + 'eyebrow' => 'PAGE UNAVAILABLE', + ], + '419' => [ + 'title' => 'Session expired', + 'message' => 'Your session has expired. Refresh the page and try again.', + ], + '429' => [ + 'title' => 'Too many requests', + 'message' => 'You have made too many requests. Please try again shortly.', + ], + '500' => [ + 'title' => 'Something went wrong', + 'message' => 'An unexpected error occurred. Please try again later.', + ], + '503' => [ + 'title' => 'Temporarily unavailable', + 'message' => 'The admin area is temporarily unavailable. Please try again soon.', + ], +]; diff --git a/resources/lang/uk/errors.php b/resources/lang/uk/errors.php new file mode 100644 index 0000000..936bca9 --- /dev/null +++ b/resources/lang/uk/errors.php @@ -0,0 +1,40 @@ + 'До панелі керування', + 'try_again' => 'Спробувати знову', + '401' => [ + 'title' => 'Потрібна авторизація', + 'message' => 'Увійдіть, щоб продовжити роботу з адмінпанеллю.', + ], + '403' => [ + 'headline' => 'Доступ до розділу обмежено', + 'title' => 'Доступ заборонено', + 'message' => 'У вас немає прав для перегляду цього розділу.', + 'hint' => 'Якщо вам потрібен доступ, зверніться до адміністратора.', + 'eyebrow' => 'ОБМЕЖЕНИЙ ДОСТУП', + ], + '404' => [ + 'headline' => 'Не вдалося знайти сторінку', + 'title' => 'Сторінку не знайдено', + 'message' => 'Запитану сторінку адмінпанелі не знайдено.', + 'hint' => 'Можливо, адреса неправильна або сторінку було переміщено.', + 'eyebrow' => 'СТОРІНКА НЕДОСТУПНА', + ], + '419' => [ + 'title' => 'Сесію завершено', + 'message' => 'Термін дії сесії минув. Оновіть сторінку та повторіть спробу.', + ], + '429' => [ + 'title' => 'Забагато запитів', + 'message' => 'Зачекайте трохи та повторіть спробу.', + ], + '500' => [ + 'title' => 'Внутрішня помилка', + 'message' => 'Сталася непередбачена помилка. Спробуйте пізніше.', + ], + '503' => [ + 'title' => 'Сервіс тимчасово недоступний', + 'message' => 'Адмінпанель тимчасово недоступна. Спробуйте пізніше.', + ], +]; diff --git a/resources/views/errors/401.blade.php b/resources/views/errors/401.blade.php new file mode 100644 index 0000000..2ea0898 --- /dev/null +++ b/resources/views/errors/401.blade.php @@ -0,0 +1,7 @@ +@php + $status = 401; + $title = __('lazy-admin::errors.401.title'); + $message = __('lazy-admin::errors.401.message'); + $icon = 'lock'; +@endphp +@include('lazy::errors.partials.standalone') diff --git a/resources/views/errors/403.blade.php b/resources/views/errors/403.blade.php new file mode 100644 index 0000000..b12dad8 --- /dev/null +++ b/resources/views/errors/403.blade.php @@ -0,0 +1,14 @@ +@php + $status = 403; + $title = __('lazy-admin::errors.403.title'); + $headline = __('lazy-admin::errors.403.headline'); + $message = __('lazy-admin::errors.403.message'); + $hint = __('lazy-admin::errors.403.hint'); + $eyebrow = __('lazy-admin::errors.403.eyebrow'); + $icon = 'shield'; +@endphp +@if($useAdminLayout) + @include('lazy::errors.partials.admin-layout') +@else + @include('lazy::errors.partials.standalone') +@endif diff --git a/resources/views/errors/404.blade.php b/resources/views/errors/404.blade.php new file mode 100644 index 0000000..f529f4c --- /dev/null +++ b/resources/views/errors/404.blade.php @@ -0,0 +1,14 @@ +@php + $status = 404; + $title = __('lazy-admin::errors.404.title'); + $headline = __('lazy-admin::errors.404.headline'); + $message = __('lazy-admin::errors.404.message'); + $hint = __('lazy-admin::errors.404.hint'); + $eyebrow = __('lazy-admin::errors.404.eyebrow'); + $icon = 'search'; +@endphp +@if($useAdminLayout) + @include('lazy::errors.partials.admin-layout') +@else + @include('lazy::errors.partials.standalone') +@endif diff --git a/resources/views/errors/419.blade.php b/resources/views/errors/419.blade.php new file mode 100644 index 0000000..234322f --- /dev/null +++ b/resources/views/errors/419.blade.php @@ -0,0 +1,7 @@ +@php + $status = 419; + $title = __('lazy-admin::errors.419.title'); + $message = __('lazy-admin::errors.419.message'); + $icon = 'clock'; +@endphp +@include('lazy::errors.partials.standalone') diff --git a/resources/views/errors/429.blade.php b/resources/views/errors/429.blade.php new file mode 100644 index 0000000..a1048d2 --- /dev/null +++ b/resources/views/errors/429.blade.php @@ -0,0 +1,7 @@ +@php + $status = 429; + $title = __('lazy-admin::errors.429.title'); + $message = __('lazy-admin::errors.429.message'); + $icon = 'clock'; +@endphp +@include('lazy::errors.partials.standalone') diff --git a/resources/views/errors/500.blade.php b/resources/views/errors/500.blade.php new file mode 100644 index 0000000..2577d05 --- /dev/null +++ b/resources/views/errors/500.blade.php @@ -0,0 +1,7 @@ +@php + $status = 500; + $title = __('lazy-admin::errors.500.title'); + $message = __('lazy-admin::errors.500.message'); + $icon = 'alert'; +@endphp +@include('lazy::errors.partials.standalone') diff --git a/resources/views/errors/503.blade.php b/resources/views/errors/503.blade.php new file mode 100644 index 0000000..2431a6b --- /dev/null +++ b/resources/views/errors/503.blade.php @@ -0,0 +1,7 @@ +@php + $status = 503; + $title = __('lazy-admin::errors.503.title'); + $message = __('lazy-admin::errors.503.message'); + $icon = 'alert'; +@endphp +@include('lazy::errors.partials.standalone') diff --git a/resources/views/errors/page.blade.php b/resources/views/errors/page.blade.php index f8e83e5..2b3411e 100644 --- a/resources/views/errors/page.blade.php +++ b/resources/views/errors/page.blade.php @@ -1,76 +1,2 @@ -{{-- Only authenticated 403/404 responses may render the full admin shell. --}} -@if(! $useAdminLayout) -@php - $pages = [ - 401 => ['title' => 'Authentication required', 'text' => 'Sign in to continue to the admin area.', 'icon' => 'lock'], - 403 => ['title' => 'Access denied', 'text' => 'You do not have permission to view this page.', 'icon' => 'shield'], - 404 => ['title' => 'Page not found', 'text' => 'This admin page may have moved, or the address may be incorrect.', 'icon' => 'search'], - 419 => ['title' => 'Session expired', 'text' => 'Your session has expired. Refresh the page and try again.', 'icon' => 'clock'], - 429 => ['title' => 'Too many requests', 'text' => 'You have made too many requests. Please try again shortly.', 'icon' => 'clock'], - 500 => ['title' => 'Something went wrong', 'text' => 'An unexpected error occurred. Please try again later.', 'icon' => 'alert'], - 503 => ['title' => 'Temporarily unavailable', 'text' => 'The admin area is temporarily unavailable. Please try again soon.', 'icon' => 'alert'], - ]; - $page = $pages[$status] ?? $pages[500]; -@endphp - - - - - - - {{ $status }} · {{ $page['title'] }} · {{ config('app.name', 'Lazy Admin') }} - - - -
{{ config('app.name', 'Lazy Admin') }}/ Admin
-
- -
{{ $status }}
-

{{ $page['title'] }}

-

{{ $page['text'] }}

-
- Back to dashboard - -
-
-
- - - - -@else - @include('lazy::errors.admin-shell') -@endif +{{-- Explicit per-status views are independently publishable and customizable. --}} +@include('lazy::errors.'.(string) $status) diff --git a/resources/views/errors/partials/admin-layout.blade.php b/resources/views/errors/partials/admin-layout.blade.php new file mode 100644 index 0000000..a5ab0ec --- /dev/null +++ b/resources/views/errors/partials/admin-layout.blade.php @@ -0,0 +1,31 @@ + +
+
+
+
+ + @if($status === 404) + + @else + + @endif + + {{ $eyebrow }} +
+

{{ $headline }}

+

{{ $message }}

+

{{ $hint }}

+
+ + +
+
+
+
+ +
+ {{ $status }} +
+
+
+
diff --git a/resources/views/errors/partials/standalone.blade.php b/resources/views/errors/partials/standalone.blade.php new file mode 100644 index 0000000..cb4aa65 --- /dev/null +++ b/resources/views/errors/partials/standalone.blade.php @@ -0,0 +1,58 @@ + + + + + + + {{ $status }} · {{ $title }} · {{ config('app.name', 'Lazy Admin') }} + + + +
{{ config('app.name', 'Lazy Admin') }}/ Admin
+
+ +
{{ $status }}
+

{{ $title }}

+

{{ $message }}

+
+ {{ __('lazy-admin::errors.back_to_dashboard') }} + +
+
+
+ + + diff --git a/tests/Feature/AdminErrorPagesTest.php b/tests/Feature/AdminErrorPagesTest.php index f5d2185..67981bf 100644 --- a/tests/Feature/AdminErrorPagesTest.php +++ b/tests/Feature/AdminErrorPagesTest.php @@ -80,3 +80,19 @@ ->and($route->gatherMiddleware())->toContain('web') ->and($route->gatherMiddleware())->toContain('auth:web'); }); + +it('provides a separate overridable template for each supported status', function (): void { + foreach ([401, 403, 404, 419, 429, 500, 503] as $status) { + expect(view()->exists("lazy::errors.{$status}"))->toBeTrue(); + } + + expect(view()->exists('lazy::errors.partials.admin-layout'))->toBeTrue() + ->and(view()->exists('lazy::errors.partials.standalone'))->toBeTrue(); +}); + +it('loads localized error titles and actions', function (): void { + app()->setLocale('uk'); + + expect(__('lazy-admin::errors.404.title'))->toBe('Сторінку не знайдено') + ->and(__('lazy-admin::errors.back_to_dashboard'))->toBe('До панелі керування'); +});