import React, { useState, useCallback } from 'react';
// --- Iconos simples de Lucide React para emular los de shadcn/ui ---
const CheckCircle = ({ className = "" }) => (
<svg className={className} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><path d="M9 11l3 3L22 4"/></svg>
);
const XCircle = ({ className = "" }) => (
<svg className={className} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><path d="M15 9l-6 6"/><path d="M9 9l6 6"/></svg>
);
// Componente: StatusDialog (Emulación de shadcn/ui Dialog/Alert)
const StatusDialog = ({ isOpen, status, message, onClose, onConfirmNavigation }) => {
if (!isOpen) return null;
const isSuccess = status === 'success';
const title = isSuccess ? 'Operación Exitosa' : 'Error al Guardar';
const icon = isSuccess ? <CheckCircle className="w-10 h-10 text-white" /> : <XCircle className="w-10 h-10 text-white" />;
const bgColor = isSuccess ? 'bg-green-600' : 'bg-red-600';
const handleConfirm = () => {
if (isSuccess) {
onConfirmNavigation(); // Navega solo si fue exitoso
} else {
onClose(); // Cierra el diálogo para permitir corrección
}
};
return (
// Overlay para oscurecer el fondo y asegurar que el modal esté encima del canvas
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50 p-4">
<div className={`w-full max-w-sm rounded-xl p-6 shadow-2xl ${bgColor} text-white transform transition-all duration-300 scale-100`}>
<div className="flex flex-col items-center justify-center text-center space-y-4">
<div className="rounded-full bg-white bg-opacity-20 p-3">
{icon}
</div>
<h3 className="text-xl font-bold">{title}</h3>
<p className="text-sm opacity-90">{message}</p>
<button
onClick={handleConfirm}
className="w-full mt-4 py-2 px-4 bg-white text-gray-800 font-semibold rounded-lg hover:bg-gray-100 transition-colors shadow-md"
>
{isSuccess ? 'Aceptar y Salir' : 'Cerrar'}
</button>
</div>
</div>
</div>
);
};
// Componente: OdontogramCanvas (Placeholder para el área de dibujo)
const OdontogramCanvas = () => {
return (
<div className="relative w-full h-[400px] md:h-[600px] border-4 border-gray-300 bg-white rounded-xl shadow-inner flex items-center justify-center">
{/* NOTA: Este es el área donde iría el canvas real.
El StatusDialog se posicionará por encima de este div
gracias al z-index del overlay fijo.
*/}
<p className="text-gray-500 text-lg font-mono">ODONTOGRAMA (Canvas de Dibujo)</p>
</div>
);
};
// Componente Principal de la Aplicación
export default function App() {
const [isProcessing, setIsProcessing] = useState(false);
const [dialogOpen, setDialogOpen] = useState(false);
const [dialogStatus, setDialogStatus] = useState(null); // 'success' o 'error'
const [dialogMessage, setDialogMessage] = useState('');
const [isSaved, setIsSaved] = useState(false); // Simula el estado del odontograma
const simulateSave = useCallback(async (shouldSucceed = true) => {
setIsProcessing(true);
// Simulación de una llamada POST asíncrona (AJAX)
try {
await new Promise(resolve => setTimeout(resolve, 1500)); // Simula latencia de red
if (shouldSucceed) {
// Éxito:
setDialogStatus('success');
setDialogMessage('¡El odontograma se ha guardado correctamente! Serás redirigido.');
setIsSaved(true);
// Simulación de regeneración de trabajo no guardado
setTimeout(()=>setIsSaved(false),5000);
} else {
// Error:
throw new Error('No se pudo establecer conexión con la base de datos de datos.');
}
} catch (error) {
setDialogStatus('error');
setDialogMessage(`Error: ${error.message || 'Ocurrió un error inesperado al guardar.'}`);
} finally {
setIsProcessing(false);
setDialogOpen(true);
}
}, []);
// 1. Lógica para navegar después de que el usuario acepta el éxito
const handleConfirmNavigation = () => {
setDialogOpen(false);
// Aquí iría la lógica de navegación real (usando un router o window.location)
console.log('NAVEGANDO FUERA DE LA PÁGINA...');
alert("Navegación simulada: Saliendo de la página del Odontograma.");
};
// 2. Lógica para cerrar el diálogo (solo si es error)
const handleCloseDialog = () => {
setDialogOpen(false);
setDialogStatus(null);
setDialogMessage('');
};
return (
<div className="min-h-screen bg-gray-50 p-4 md:p-8 font-sans antialiased">
<style>
{`
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap');
body { font-family: 'Inter', sans-serif; }
`}
</style>
<div className="max-w-4xl mx-auto space-y-8">
<header className="text-center">
<h1 className="text-3xl font-bold text-gray-800">Edición de Odontograma</h1>
<p className="text-gray-600">Guarda los cambios antes de salir.</p>
</header>
{/* Área del Odontograma (Canvas) */}
<OdontogramCanvas />
{/* Controles y Botones de Guardar */}
<div className="flex flex-col sm:flex-row justify-center space-y-4 sm:space-y-0 sm:space-x-4 p-4 bg-white border border-gray-200 rounded-xl shadow-md">
<button
onClick={() => simulateSave(true)}
disabled={isProcessing}
className="flex items-center justify-center px-6 py-3 text-lg font-semibold text-white bg-blue-600 rounded-lg hover:bg-blue-700 transition-all shadow-lg hover:shadow-xl disabled:bg-blue-400"
>
{isProcessing ? 'Guardando...' : 'Guardar Cambios (Éxito Simulado)'}
</button>
<button
onClick={() => simulateSave(false)}
disabled={isProcessing}
className="flex items-center justify-center px-6 py-3 text-lg font-semibold text-red-600 bg-white border-2 border-red-600 rounded-lg hover:bg-red-50 transition-all shadow-lg hover:shadow-xl disabled:opacity-50"
>
{isProcessing ? 'Guardando...' : 'Forzar Error de Guardado'}
</button>
</div>
</div>
{/* Diálogo de Estatus (Se muestra encima del canvas) */}
<StatusDialog
isOpen={dialogOpen}
status={dialogStatus}
message={dialogMessage}
onClose={handleCloseDialog}
onConfirmNavigation={handleConfirmNavigation}
/>
{/* Indicador de Estado para debugging */}
<div className="fixed bottom-4 right-4 bg-gray-800 text-white p-3 rounded-lg text-sm shadow-xl">
<p>Estado de guardado: <span className={`font-bold ${isSaved ? 'text-green-400' : 'text-yellow-400'}`}>{isSaved ? 'Guardado' : 'Pendiente'}</span></p>
</div>
</div>
);
}
No hay comentarios:
Publicar un comentario