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

215 lines
6.9 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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>
);
}