FactuGES_ERP/apps/web/src/components/error-fallbacks.tsx

215 lines
6.9 KiB
TypeScript
Raw Normal View History

2025-08-24 10:14:20 +00:00
import { Button } from "@repo/shadcn-ui/components";
import * as React from "react";
import { FallbackProps } from "react-error-boundary";
/**
* 1) Fallback simple
*/
export function SimpleFallback({ error, resetErrorBoundary }: FallbackProps) {
return (
<div role='alert' className='p-4 rounded-md border bg-red-50 text-red-700'>
<p className='font-medium'>⚠️ Algo salió mal</p>
<pre className='mt-2 text-sm whitespace-pre-wrap'>{error?.message}</pre>
<Button
onClick={resetErrorBoundary}
className='mt-3 px-3 py-1.5 rounded-md bg-red-600 text-white'
>
Reintentar
</Button>
</div>
);
}
/**
* 2) Fallback de sección (tarjeta compacta)
*/
export function SectionCardFallback({ error, resetErrorBoundary }: FallbackProps) {
return (
<div role='alert' className='rounded-2xl border shadow-sm p-5 bg-white'>
<div className='flex items-start gap-3'>
<div className='shrink-0 rounded-full p-2 bg-red-100'>❗</div>
<div className='grow'>
<h3 className='font-semibold text-gray-900'>No se pudo cargar esta sección</h3>
<p className='mt-1 text-sm text-gray-600'>{error?.message}</p>
<div className='mt-3 flex gap-2'>
<Button
onClick={resetErrorBoundary}
className='px-3 py-1.5 rounded-md bg-gray-900 text-white'
>
Reintentar
</Button>
<Button
onClick={() => window.location.reload()}
className='px-3 py-1.5 rounded-md border'
>
Refrescar página
</Button>
</div>
</div>
</div>
</div>
);
}
/**
* 3) Fallback pantalla completa
*/
export function FullPageFallback({ error }: FallbackProps) {
return (
<div className='min-h-screen flex flex-col items-center justify-center px-6 bg-gray-50 text-center'>
<div className='text-5xl'>😵</div>
<h1 className='mt-4 text-2xl font-bold text-gray-900'>Ocurrió un error inesperado</h1>
<p className='mt-2 text-gray-600'>{error?.message}</p>
<div className='mt-6 flex flex-wrap items-center justify-center gap-3'>
<a href='/' className='px-4 py-2 rounded-md bg-blue-600 text-white'>
Volver al inicio
</a>
<Button onClick={() => window.location.reload()} className='px-4 py-2 rounded-md border'>
Recargar
</Button>
</div>
</div>
);
}
/**
* 4) Fallback para listas
*/
export function ListFallback({ error, resetErrorBoundary }: FallbackProps) {
return (
<div role='alert' className='p-4 rounded-md border bg-amber-50'>
<div className='flex items-start gap-3'>
<span className='text-xl'>🗂️</span>
<div>
<p className='font-medium text-amber-900'>No pudimos cargar la lista.</p>
<p className='text-sm text-amber-800 mt-1'>{error?.message}</p>
<div className='mt-3 flex gap-2'>
<Button
onClick={resetErrorBoundary}
className='px-3 py-1.5 rounded-md bg-amber-700 text-white'
>
Reintentar
</Button>
<Button
onClick={() => window.location.reload()}
className='px-3 py-1.5 rounded-md border'
>
Recargar
</Button>
</div>
</div>
</div>
</div>
);
}
/**
* 5) Fallback para formularios
*/
export function FormFallback({ error, resetErrorBoundary }: FallbackProps) {
return (
<div role='alert' className='rounded-md border p-4 bg-red-50'>
<h4 className='font-semibold text-red-800'>No se pudo mostrar el formulario</h4>
<p className='mt-1 text-sm text-red-700'>{error?.message}</p>
<div className='mt-3 flex gap-2'>
<Button
onClick={resetErrorBoundary}
className='px-3 py-1.5 rounded-md bg-red-600 text-white'
>
Reintentar
</Button>
<Button onClick={() => history.back()} className='px-3 py-1.5 rounded-md border'>
Volver atrás
</Button>
</div>
</div>
);
}
/**
* 6) Fallback para problemas de red
*/
export function NetworkFallback({ error, resetErrorBoundary }: FallbackProps) {
const note = navigator.onLine
? "La conexión parece estar activa."
: "Estás sin conexión. Revisa tu red y reintenta.";
return (
<div role='alert' className='rounded-md border p-4 bg-blue-50 text-blue-900'>
<div className='font-medium'>No pudimos obtener los datos</div>
<p className='mt-1 text-sm'>{error?.message}</p>
<p className='mt-1 text-xs opacity-80'>{note}</p>
<div className='mt-3 flex gap-2'>
<Button
onClick={resetErrorBoundary}
className='px-3 py-1.5 rounded-md bg-blue-700 text-white'
>
Reintentar
</Button>
<Button onClick={() => window.location.reload()} className='px-3 py-1.5 rounded-md border'>
Recargar
</Button>
</div>
</div>
);
}
/**
* 7) Fallback modo desarrollador (detalle de stack)
*/
export function DevDetailsFallback({ error, resetErrorBoundary }: FallbackProps) {
const [open, setOpen] = React.useState(false);
return (
<div role='alert' className='rounded-md border p-4 bg-gray-50'>
<div className='flex items-center justify-between'>
<p className='font-medium text-gray-900'>Algo falló</p>
<div className='flex gap-2'>
<Button
onClick={resetErrorBoundary}
className='px-3 py-1.5 rounded-md bg-gray-900 text-white'
>
Reintentar
</Button>
<Button onClick={() => setOpen((v) => !v)} className='px-3 py-1.5 rounded-md border'>
{open ? "Ocultar detalles" : "Ver detalles"}
</Button>
</div>
</div>
{open && (
<pre className='mt-3 text-xs whitespace-pre-wrap bg-white p-3 rounded-md border overflow-auto'>
{error?.stack || error?.message}
</pre>
)}
</div>
);
}
/**
* 8) Fallback con soporte (link a ayuda)
*/
export function SupportFallback({ error, resetErrorBoundary }: FallbackProps) {
return (
<div role='alert' className='rounded-md border p-4 bg-white'>
<h4 className='font-semibold text-gray-900'>No pudimos completar la acción</h4>
<p className='mt-1 text-gray-700'>{error?.message}</p>
<div className='mt-3 flex flex-wrap gap-2'>
<Button
onClick={resetErrorBoundary}
className='px-3 py-1.5 rounded-md bg-gray-900 text-white'
>
Intentar de nuevo
</Button>
<a href='/ayuda' className='px-3 py-1.5 rounded-md border'>
Ir a Ayuda
</a>
<a
href='mailto:soporte@tuapp.com?subject=Error%20en%20la%20aplicaci%C3%B3n'
className='px-3 py-1.5 rounded-md border'
>
Contactar soporte
</a>
</div>
</div>
);
}