88 lines
3.4 KiB
TypeScript
88 lines
3.4 KiB
TypeScript
'use client';
|
|
|
|
import React, { useEffect } from 'react';
|
|
import Link from 'next/link';
|
|
import { RefreshCw, Home, ShoppingBag, Sparkles } from 'lucide-react';
|
|
|
|
export default function GlobalAppError({
|
|
error,
|
|
reset,
|
|
}: {
|
|
error: Error & { digest?: string };
|
|
reset: () => void;
|
|
}) {
|
|
useEffect(() => {
|
|
console.error('[AppError Boundary]:', error);
|
|
|
|
const isChunkError =
|
|
error.message?.includes('Loading chunk') ||
|
|
error.message?.includes('ChunkLoadError') ||
|
|
error.message?.includes('Failed to fetch dynamically imported module');
|
|
|
|
if (isChunkError) {
|
|
const lastReload = sessionStorage.getItem('dripzone_root_error_reload');
|
|
const now = Date.now();
|
|
if (!lastReload || now - parseInt(lastReload, 10) > 10000) {
|
|
sessionStorage.setItem('dripzone_root_error_reload', now.toString());
|
|
window.location.reload();
|
|
}
|
|
}
|
|
}, [error]);
|
|
|
|
const handleHardReload = () => {
|
|
try {
|
|
sessionStorage.removeItem('dripzone_root_error_reload');
|
|
window.location.href = window.location.pathname + '?v=' + Date.now();
|
|
} catch (_) {
|
|
window.location.reload();
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen bg-neutral-950 text-white flex flex-col items-center justify-center p-4">
|
|
<div className="max-w-md w-full bg-neutral-900/90 border border-purple-500/30 rounded-3xl p-8 text-center space-y-6 shadow-2xl backdrop-blur-xl relative overflow-hidden">
|
|
<div className="absolute top-0 right-0 w-48 h-48 bg-purple-600/10 rounded-full blur-3xl pointer-events-none" />
|
|
|
|
<div className="w-16 h-16 rounded-2xl bg-purple-500/15 border border-purple-500/40 text-purple-400 flex items-center justify-center mx-auto shadow-inner">
|
|
<Sparkles className="w-8 h-8 text-purple-400 animate-pulse" />
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<h2 className="text-xl font-black tracking-tight text-white">DripZone Luxury Store</h2>
|
|
<p className="text-xs text-neutral-400 leading-relaxed">
|
|
Hemos actualizado la vitrina con nuevos lanzamientos exclusivos.
|
|
Recarga para ver la versión más reciente del catálogo.
|
|
</p>
|
|
</div>
|
|
|
|
<div className="space-y-2.5 pt-2">
|
|
<button
|
|
onClick={handleHardReload}
|
|
className="w-full bg-gradient-to-r from-purple-600 to-fuchsia-600 hover:from-purple-500 hover:to-fuchsia-500 text-white font-black text-xs py-3.5 px-4 rounded-xl flex items-center justify-center gap-2 shadow-lg shadow-purple-900/40 cursor-pointer transition-all active:scale-98"
|
|
>
|
|
<RefreshCw className="w-4 h-4" />
|
|
<span>Recargar Catálogo</span>
|
|
</button>
|
|
|
|
<div className="grid grid-cols-2 gap-2">
|
|
<button
|
|
onClick={() => reset()}
|
|
className="bg-neutral-800 hover:bg-neutral-700 text-neutral-200 font-bold text-xs py-2.5 px-3 rounded-xl flex items-center justify-center gap-1.5 cursor-pointer transition-all"
|
|
>
|
|
<span>Reintentar</span>
|
|
</button>
|
|
|
|
<Link
|
|
href="/"
|
|
className="bg-neutral-800 hover:bg-neutral-700 text-neutral-200 font-bold text-xs py-2.5 px-3 rounded-xl flex items-center justify-center gap-1.5 cursor-pointer transition-all"
|
|
>
|
|
<Home className="w-3.5 h-3.5 text-neutral-400" />
|
|
<span>Inicio</span>
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|