Add custom error and global-error pages matching site design

Adds app/error.tsx (client error boundary, reuses Header/Footer/Button)
and app/global-error.tsx (root layout crash fallback with self-contained
html/body and manually replicated styling), both bilingual (ES/EN) and
matching the brand's colors, fonts, and tone.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Michilis
2026-07-01 06:06:22 +00:00
co-authored by Claude Sonnet 5
parent cacc52ec24
commit 09bfb17f03
2 changed files with 133 additions and 0 deletions
+54
View File
@@ -0,0 +1,54 @@
'use client';
import { useEffect } from 'react';
import Link from 'next/link';
import Header from '@/components/layout/Header';
import Footer from '@/components/layout/Footer';
import Button from '@/components/ui/Button';
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
if (process.env.NODE_ENV === 'development') {
console.error(error);
}
}, [error]);
return (
<div className="min-h-screen flex flex-col">
<Header />
<main className="flex-1 flex items-center justify-center bg-secondary-gray px-4 py-16">
<div className="text-center max-w-md mx-auto">
<div className="text-6xl mb-4">😅</div>
<h1 className="text-3xl font-semibold text-primary-dark mb-2">
¡Ups! Algo salió mal
</h1>
<p className="text-lg text-gray-700 mb-6">
Oops, something went wrong
</p>
<p className="text-gray-600 mb-8">
No fue tu culpa, fue un error de nuestro lado. Prueba de nuevo o vuelve al inicio mientras lo revisamos.
<br />
It was not your fault, something broke on our end. Try again or head back home while we take a look.
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<Button onClick={reset} size="lg">
Intentar de nuevo · Try again
</Button>
<Link href="/">
<Button variant="outline" size="lg" className="w-full sm:w-auto">
Ir al inicio · Go home
</Button>
</Link>
</div>
</div>
</main>
<Footer />
</div>
);
}
+79
View File
@@ -0,0 +1,79 @@
'use client';
import { useEffect } from 'react';
import { Poppins } from 'next/font/google';
import './globals.css';
const poppins = Poppins({
subsets: ['latin'],
display: 'swap',
variable: '--font-poppins',
weight: ['400', '500', '600', '700'],
});
export default function GlobalError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
if (process.env.NODE_ENV === 'development') {
console.error(error);
}
}, [error]);
return (
<html lang="en" className={poppins.variable}>
<body className={poppins.className}>
<div className="min-h-screen flex flex-col bg-secondary-gray">
<header className="bg-white shadow-sm">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-16 flex items-center">
<span className="text-xl font-semibold" style={{ color: '#002F44' }}>
Spanglish
</span>
</div>
</header>
<main className="flex-1 flex items-center justify-center px-4 py-16">
<div className="text-center max-w-md mx-auto bg-white rounded-card shadow-card p-8">
<div className="text-6xl mb-4">😵</div>
<h1 className="text-2xl font-semibold text-primary-dark mb-2">
¡Ups! Algo salió mal
</h1>
<p className="text-lg text-gray-700 mb-4">
Oops, something went wrong
</p>
<p className="text-gray-600 mb-8">
Toda la página tuvo un problema al cargar. Prueba de nuevo o vuelve al inicio.
<br />
The whole page had trouble loading. Try again or head back home.
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<button
onClick={reset}
className="inline-flex items-center justify-center px-7 py-3 text-lg font-medium rounded-btn bg-primary-yellow text-primary-dark hover:bg-yellow-400 transition-colors"
>
Intentar de nuevo · Try again
</button>
<a
href="/"
className="inline-flex items-center justify-center px-7 py-3 text-lg font-medium rounded-btn border-2 border-primary-dark text-primary-dark hover:bg-gray-50 transition-colors"
>
Ir al inicio · Go home
</a>
</div>
</div>
</main>
<footer className="border-t border-secondary-light-gray py-6">
<p className="text-center text-sm" style={{ color: '#002F44' }}>
© {new Date().getFullYear()} Spanglish
</p>
</footer>
</div>
</body>
</html>
);
}