import React, { useState, useEffect, createContext, useContext } from 'react'; import { initializeApp } from 'firebase/app'; import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged } from 'firebase/auth'; import { getFirestore, doc, getDoc, setDoc, updateDoc, onSnapshot, collection, query, addDoc, deleteDoc } from 'firebase/firestore'; // Iconos de Lucide React import { Home, Pill, MessageSquare, AlertCircle, User, Plus, Camera, Send, History, Check, X, Bell, Clock, Stethoscope } from 'lucide-react'; // Contexto para la aplicación (Firebase, Auth, Firestore, UserID, CurrentProfileId) const AppContext = createContext(null); // Proveedor del contexto de la aplicación function AppProvider({ children }) { const [app, setApp] = useState(null); const [db, setDb] = useState(null); const [auth, setAuth] = useState(null); const [userId, setUserId] = useState(null); const [currentProfileId, setCurrentProfileId] = useState(null); const [profiles, setProfiles] = useState([]); // Todos los perfiles gestionados por el usuario actual const [isAuthReady, setIsAuthReady] = useState(false); // Para asegurar que la autenticación está lista useEffect(() => { // Inicializar Firebase const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; const firebaseConfig = typeof __firebase_config !== 'undefined' ? JSON.parse(__firebase_config) : {}; try { const firebaseApp = initializeApp(firebaseConfig); const firestoreDb = getFirestore(firebaseApp); const firebaseAuth = getAuth(firebaseApp); setApp(firebaseApp); setDb(firestoreDb); setAuth(firebaseAuth); // Manejar la autenticación const unsubscribe = onAuthStateChanged(firebaseAuth, async (user) => { if (user) { setUserId(user.uid); console.log("Usuario autenticado:", user.uid); } else { // Si no hay token inicial, iniciar sesión anónimamente if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) { try { await signInWithCustomToken(firebaseAuth, __initial_auth_token); console.log("Sesión iniciada con token personalizado."); } catch (error) { console.error("Error al iniciar sesión con token personalizado:", error); await signInAnonymously(firebaseAuth); console.log("Sesión iniciada anónimamente debido a error con token."); } } else { await signInAnonymously(firebaseAuth); console.log("Sesión iniciada anónimamente."); } } setIsAuthReady(true); // La autenticación ha sido procesada }); return () => unsubscribe(); // Limpiar el listener al desmontar } catch (error) { console.error("Error al inicializar Firebase:", error); } }, []); // Cargar perfiles y establecer el perfil actual una vez que la autenticación esté lista useEffect(() => { if (db && userId && isAuthReady) { const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; const profilesColRef = collection(db, `artifacts/${appId}/users/${userId}/profiles`); const unsubscribe = onSnapshot(profilesColRef, (snapshot) => { const fetchedProfiles = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); setProfiles(fetchedProfiles); // Si no hay perfil actual o el perfil actual ya no existe, establecer el primero como predeterminado if (!currentProfileId || !fetchedProfiles.some(p => p.id === currentProfileId)) { if (fetchedProfiles.length > 0) { setCurrentProfileId(fetchedProfiles[0].id); } else { // Si no hay perfiles, crear uno por defecto para el usuario const createDefaultProfile = async () => { const defaultProfile = { name: "Mi Perfil", allergies: "Ninguna", emergencyContact: "N/A", bloodType: "", // Nuevo campo age: "", // Nuevo campo sex: "", // Nuevo campo rut: "" // Nuevo campo }; try { const newProfileRef = await addDoc(profilesColRef, defaultProfile); setCurrentProfileId(newProfileRef.id); console.log("Perfil predeterminado creado:", newProfileRef.id); } catch (error) { console.error("Error al crear perfil predeterminado:", error); } }; createDefaultProfile(); } } }, (error) => { console.error("Error al escuchar perfiles:", error); }); return () => unsubscribe(); } }, [db, userId, isAuthReady, currentProfileId]); // Dependencias para re-ejecutar cuando cambian return ( {children} ); } // Hook personalizado para usar el contexto de la aplicación function useAppContext() { return useContext(AppContext); } // Componente para mostrar mensajes modales (reemplazo de alert/confirm) function Modal({ title, message, onClose, onConfirm, showCancel = false }) { return (

{title}

{message}

{showCancel && ( )}
); } // Componente de navegación inferior function Navbar({ onNavigate, currentPage }) { const navItems = [ { name: "Inicio", icon: Home, page: "home" }, { name: "Medicamentos", icon: Pill, page: "add-medication" }, { name: "Doctor Virtual", icon: MessageSquare, page: "virtual-doctor" }, { name: "Asistente", icon: Stethoscope, page: "medication-assistant" }, { name: "Perfil", icon: User, page: "profile" }, ]; return ( ); } // Pantalla de Inicio function HomeScreen({ onNavigate }) { const { db, userId, currentProfileId, isAuthReady } = useAppContext(); const [medications, setMedications] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [showModal, setShowModal] = useState(false); const [modalContent, setModalContent] = useState({ title: '', message: '' }); useEffect(() => { if (db && userId && currentProfileId && isAuthReady) { setLoading(true); setError(null); const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; const medsColRef = collection(db, `artifacts/${appId}/users/${userId}/profiles/${currentProfileId}/medications`); const unsubscribe = onSnapshot(medsColRef, (snapshot) => { const fetchedMeds = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); setMedications(fetchedMeds); setLoading(false); }, (err) => { console.error("Error al cargar medicamentos:", err); setError("Error al cargar medicamentos. Inténtalo de nuevo."); setLoading(false); }); return () => unsubscribe(); } }, [db, userId, currentProfileId, isAuthReady]); const handleTakeMedication = async (medId) => { if (!db || !userId || !currentProfileId) return; const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; const medDocRef = doc(db, `artifacts/${appId}/users/${userId}/profiles/${currentProfileId}/medications`, medId); try { await updateDoc(medDocRef, { lastTaken: new Date().toISOString(), history: [...(medications.find(m => m.id === medId)?.history || []), { type: 'taken', timestamp: new Date().toISOString() }] }); setModalContent({ title: "Medicamento Tomado", message: "¡Has registrado la toma de tu medicamento!" }); setShowModal(true); } catch (e) { console.error("Error al registrar toma:", e); setModalContent({ title: "Error", message: "No se pudo registrar la toma. Inténtalo de nuevo." }); setShowModal(true); } }; const handleSkipMedication = async (medId) => { if (!db || !userId || !currentProfileId) return; const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; const medDocRef = doc(db, `artifacts/${appId}/users/${userId}/profiles/${currentProfileId}/medications`, medId); try { await updateDoc(medDocRef, { history: [...(medications.find(m => m.id === medId)?.history || []), { type: 'skipped', timestamp: new Date().toISOString() }] }); setModalContent({ title: "Medicamento Omitido", message: "Has marcado el medicamento como omitido." }); setShowModal(true); } catch (e) { console.error("Error al registrar omisión:", e); setModalContent({ title: "Error", message: "No se pudo registrar la omisión. Inténtalo de nuevo." }); setShowModal(true); } }; const getNextReminder = (medication) => { // En una app real, esta lógica sería mucho más sofisticada para calcular el próximo recordatorio // basándose en la última toma, frecuencia y horarios específicos. if (medication.frequency && typeof medication.frequency === 'object') { if (medication.frequency.type === "Personalizado") { return medication.frequency.value; } if (medication.frequency.type === "Horarios Específicos" && medication.frequency.times && medication.frequency.times.length > 0) { return `Horarios: ${medication.frequency.times.join(', ')}`; } return "N/A"; } // Para frecuencias antiguas o simples strings if (medication.frequency === "Diario") return "Hoy, " + new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); if (medication.frequency.startsWith("Cada ")) { const hoursMatch = medication.frequency.match(/Cada (\d+) horas/); if (hoursMatch && hoursMatch[1]) { return `Cada ${hoursMatch[1]} horas`; } } return "N/A"; }; return (

Saludify

Próximos Recordatorios

{loading ? (
Cargando recordatorios...
) : error ? (
{error}
) : medications.length === 0 ? (
No hay medicamentos registrados. ¡Agrega uno!
) : (
{medications.map((med) => (

{med.name}

{med.dosage} - {getNextReminder(med)}

{/* Muestra la frecuencia ya procesada */}

Última toma: {med.lastTaken ? new Date(med.lastTaken).toLocaleString() : 'Nunca'}

))}
)}

Historial Reciente

{loading ? (
Cargando historial...
) : medications.length === 0 ? (
Historial de cumplimiento aparecerá aquí.
) : (
{medications.flatMap(med => (med.history || []).slice(-5).sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp)).map((item, index) => ( // Mostrar las últimas 5 entradas y ordenar por fecha
{med.name} {item.type === 'taken' ? 'Tomada' : 'Omitida'}
{new Date(item.timestamp).toLocaleString()}
)) )} {medications.every(med => !med.history || med.history.length === 0) && (
Historial de cumplimiento aparecerá aquí.
)}
)} {/* Placeholder para visualización de cumplimiento más avanzada */}

Próxima mejora: Visualización de cumplimiento.

Aquí se mostrarán gráficos interactivos para que puedas ver tu adherencia a los medicamentos a lo largo del tiempo.

{showModal && ( setShowModal(false)} /> )}
); } // Pantalla para Agregar Medicamento function AddMedicationScreen() { const { db, userId, currentProfileId, isAuthReady } = useAppContext(); const [name, setName] = useState(''); const [dosage, setDosage] = useState(''); const [frequencyType, setFrequencyType] = useState('Diario'); // 'Diario', 'Cada X horas', 'Personalizado', 'Horarios Específicos' const [customFrequencyValue, setCustomFrequencyValue] = useState(''); // Para "Personalizado" const [specificTimes, setSpecificTimes] = useState(['09:00']); // Para "Horarios Específicos" const [isScanning, setIsScanning] = useState(false); const [loading, setLoading] = useState(false); const [showModal, setShowModal] = useState(false); const [modalContent, setModalContent] = useState({ title: '', message: '' }); const handleAddSpecificTime = () => { setSpecificTimes([...specificTimes, '']); // Añadir un nuevo campo de hora vacío }; const handleRemoveSpecificTime = (index) => { const newTimes = specificTimes.filter((_, i) => i !== index); setSpecificTimes(newTimes); }; const handleSpecificTimeChange = (index, value) => { const newTimes = [...specificTimes]; newTimes[index] = value; setSpecificTimes(newTimes); }; const handleAddMedication = async (e) => { e.preventDefault(); if (!db || !userId || !currentProfileId || !isAuthReady) { setModalContent({ title: "Error", message: "La aplicación no está lista. Inténtalo de nuevo." }); setShowModal(true); return; } let finalFrequencyData; if (frequencyType === "Personalizado") { if (!customFrequencyValue.trim()) { setModalContent({ title: "Campos Incompletos", message: "Por favor, especifica la frecuencia personalizada (ej: Cada 3 horas)." }); setShowModal(true); return; } finalFrequencyData = { type: "Personalizado", value: customFrequencyValue.trim() }; } else if (frequencyType === "Horarios Específicos") { const validTimes = specificTimes.filter(t => t.trim() !== ''); if (validTimes.length === 0) { setModalContent({ title: "Campos Incompletos", message: "Por favor, agrega al menos un horario específico." }); setShowModal(true); return; } finalFrequencyData = { type: "Horarios Específicos", times: validTimes }; } else { finalFrequencyData = { type: frequencyType }; // Para "Diario", "Cada 8 horas", etc. } if (!name || !dosage) { setModalContent({ title: "Campos Incompletos", message: "Por favor, completa el nombre y la dosis." }); setShowModal(true); return; } setLoading(true); const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; const medsColRef = collection(db, `artifacts/${appId}/users/${userId}/profiles/${currentProfileId}/medications`); try { await addDoc(medsColRef, { name, dosage, frequency: finalFrequencyData, // Usar la estructura de frecuencia final lastTaken: null, history: [], createdAt: new Date().toISOString() }); setName(''); setDosage(''); setFrequencyType('Diario'); setCustomFrequencyValue(''); setSpecificTimes(['09:00']); // Resetear a un valor por defecto setModalContent({ title: "Éxito", message: "Medicamento agregado correctamente." }); setShowModal(true); } catch (e) { console.error("Error al agregar medicamento:", e); setModalContent({ title: "Error", message: "No se pudo agregar el medicamento. Inténtalo de nuevo." }); setShowModal(true); } finally { setLoading(false); } }; const handleScanMedication = () => { setIsScanning(true); setModalContent({ title: "Escaneo de Medicamento (IA)", message: "Esta función de escaneo con IA está en desarrollo. En una versión futura, podrás escanear la caja o pastilla para reconocer el medicamento automáticamente.", onConfirm: () => setIsScanning(false) }); setShowModal(true); }; return (

Agregar Medicamento

Ingreso Manual

setName(e.target.value)} required />
setDosage(e.target.value)} required />
{frequencyType === "Personalizado" && ( setCustomFrequencyValue(e.target.value)} required /> )} {frequencyType === "Horarios Específicos" && (

Define los horarios exactos:

{specificTimes.map((time, index) => (
handleSpecificTimeChange(index, e.target.value)} required /> {specificTimes.length > 1 && ( )}
))}
)}

Escaneo con Cámara (IA)

Próximamente: Escanea la caja o pastilla de tu medicamento para reconocerlo automáticamente.

{/* Placeholder para la base de datos de medicamentos con IA */}

Próxima mejora: Base de datos de medicamentos con IA.

Aquí podrás buscar medicamentos y obtener información detallada automáticamente, o usar la cámara para identificarlos.

{showModal && ( setShowModal(false)} onConfirm={modalContent.onConfirm} /> )}
); } // Pantalla del Doctor Virtual (IA) function VirtualDoctorScreen() { const [messages, setMessages] = useState([]); const [input, setInput] = useState(''); const [loading, setLoading] = useState(false); const [showModal, setShowModal] = useState(false); const [modalContent, setModalContent] = useState({ title: '', message: '' }); const callGeminiAPI = async (prompt) => { setLoading(true); try { let chatHistory = []; chatHistory.push({ role: "user", parts: [{ text: prompt }] }); const payload = { contents: chatHistory }; const apiKey = ""; // La clave API será proporcionada por el entorno de Canvas const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${apiKey}`; const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const result = await response.json(); if (result.candidates && result.candidates.length > 0 && result.candidates[0].content && result.candidates[0].content.parts && result.candidates[0].content.parts.length > 0) { const text = result.candidates[0].content.parts[0].text; return text.replace(/\*/g, ''); // Eliminar asteriscos } else { console.error("Respuesta inesperada de la API de Gemini:", result); return "Lo siento, no pude obtener una respuesta en este momento. Inténtalo de nuevo más tarde."; } } catch (error) { console.error("Error al llamar a la API de Gemini:", error); return "Hubo un error al conectar con el Doctor Virtual. Por favor, verifica tu conexión."; } finally { setLoading(false); } }; const handleSendMessage = async () => { if (input.trim() === '') return; const newUserMessage = { sender: 'user', text: input }; setMessages((prevMessages) => [...prevMessages, newUserMessage]); setInput(''); setLoading(true); const aiResponse = await callGeminiAPI(input); const newAiMessage = { sender: 'ai', text: aiResponse }; setMessages((prevMessages) => [...prevMessages, newAiMessage]); setLoading(false); }; return (

Doctor Virtual

Disclaimer Legal:

La información proporcionada por el Doctor Virtual es solo para fines educativos e informativos. No sustituye la consulta, diagnóstico o tratamiento médico profesional. Siempre busca el consejo de un médico u otro proveedor de salud calificado para cualquier pregunta que puedas tener sobre una condición médica.

{messages.length === 0 && (
¡Hola! Pregúntame sobre tus medicamentos.
Ej: "¿Para qué sirve el paracetamol?"
)} {messages.map((msg, index) => (
{msg.text}
))} {loading && (
Pensando...
)}
setInput(e.target.value)} onKeyPress={(e) => { if (e.key === 'Enter') handleSendMessage(); }} disabled={loading} />
{showModal && ( setShowModal(false)} /> )}
); } // Nueva Pantalla: Asistente de Medicamentos (IA) function MedicationAssistantScreen() { const [medicationName, setMedicationName] = useState(''); const [queryType, setQueryType] = useState('sideEffects'); // 'sideEffects' o 'interactions' const [response, setResponse] = useState(''); const [loading, setLoading] = useState(false); const [showModal, setShowModal] = useState(false); const [modalContent, setModalContent] = useState({ title: '', message: '' }); const callGeminiAPI = async (prompt) => { setLoading(true); try { let chatHistory = []; chatHistory.push({ role: "user", parts: [{ text: prompt }] }); const payload = { contents: chatHistory }; const apiKey = ""; // La clave API será proporcionada por el entorno de Canvas const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${apiKey}`; const res = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const result = await res.json(); if (result.candidates && result.candidates.length > 0 && result.candidates[0].content && result.candidates[0].content.parts && result.candidates[0].content.parts.length > 0) { const text = result.candidates[0].content.parts[0].text; return text.replace(/\*/g, ''); // Eliminar asteriscos } else { console.error("Respuesta inesperada de la API de Gemini:", result); return "Lo siento, no pude obtener información en este momento. Inténtalo de nuevo más tarde."; } } catch (error) { console.error("Error al llamar a la API de Gemini:", error); return "Hubo un error al conectar con el Asistente. Por favor, verifica tu conexión."; } finally { setLoading(false); } }; const handleGetInfo = async () => { if (!medicationName.trim()) { setModalContent({ title: "Medicamento Requerido", message: "Por favor, ingresa el nombre del medicamento." }); setShowModal(true); return; } let prompt = ""; if (queryType === "sideEffects") { prompt = `Dame una lista concisa de los efectos secundarios comunes del medicamento ${medicationName}. Si no conoces el medicamento, indícalo.`; } else { // interactions prompt = `Enumera las posibles interacciones del medicamento ${medicationName} con otros medicamentos o sustancias comunes (alcohol, alimentos). Si no conoces el medicamento, indícalo.`; } setResponse("Buscando información..."); const aiResponse = await callGeminiAPI(prompt); setResponse(aiResponse); }; return (

Asistente de Medicamentos ✨

Disclaimer Legal:

La información proporcionada por el Asistente de Medicamentos es solo para fines educativos e informativos. No sustituye la consulta, diagnóstico o tratamiento médico profesional. Siempre busca el consejo de un médico u otro proveedor de salud calificado para cualquier pregunta que puedas tener sobre una condición médica.

Obtener Información

setMedicationName(e.target.value)} required />
{response && (

Resultado:

{response}

)} {showModal && ( setShowModal(false)} /> )}
); } // Pantalla SOS Medicamentos function SOSScreen() { const [contact, setContact] = useState(''); const [message, setMessage] = useState(''); const [showModal, setShowModal] = useState(false); const [modalContent, setModalContent] = useState({ title: '', message: '' }); const handleSendSOS = () => { if (!contact.trim()) { setModalContent({ title: "Contacto Requerido", message: "Por favor, ingresa un número de contacto o nombre." }); setShowModal(true); return; } // Simulación de envío de SMS/Notificación setModalContent({ title: "Alerta Enviada", message: `Se ha enviado una alerta a ${contact}. En una aplicación real, esto enviaría un SMS o notificación push.`, }); setShowModal(true); setMessage(''); setContact(''); }; return (

SOS Medicamentos

Envía una alerta rápida a un familiar o contacto de emergencia si necesitas ayuda o te quedas sin medicamentos.

setContact(e.target.value)} />
{showModal && ( setShowModal(false)} /> )}
); } // Pantalla de Emergencia Médica (Lock Screen accesible) function EmergencyScreen({ onNavigate }) { const { db, userId, currentProfileId, profiles, isAuthReady } = useAppContext(); const [currentProfile, setCurrentProfile] = useState(null); const [medications, setMedications] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { if (db && userId && currentProfileId && isAuthReady) { setLoading(true); setError(null); const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; // Fetch current profile details const profileDocRef = doc(db, `artifacts/${appId}/users/${userId}/profiles`, currentProfileId); const unsubscribeProfile = onSnapshot(profileDocRef, (docSnap) => { if (docSnap.exists()) { setCurrentProfile({ id: docSnap.id, ...docSnap.data() }); } else { console.warn("Perfil actual no encontrado para emergencia."); setCurrentProfile(null); } }, (err) => { console.error("Error al cargar perfil para emergencia:", err); setError("Error al cargar datos de emergencia."); }); // Fetch medications for the current profile const medsColRef = collection(db, `artifacts/${appId}/users/${userId}/profiles/${currentProfileId}/medications`); const unsubscribeMeds = onSnapshot(medsColRef, (snapshot) => { const fetchedMeds = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); setMedications(fetchedMeds); setLoading(false); }, (err) => { console.error("Error al cargar medicamentos para emergencia:", err); setError("Error al cargar medicamentos de emergencia."); setLoading(false); }); return () => { unsubscribeProfile(); unsubscribeMeds(); }; } }, [db, userId, currentProfileId, isAuthReady]); if (loading) { return (
Cargando información de emergencia...
); } if (error) { return (
{error}
Por favor, regresa más tarde.
); } return (

¡EMERGENCIA MÉDICA!

Información Vital para Personal de Salud

Datos del Paciente

Nombre: {currentProfile?.name || 'No especificado'}

Edad: {currentProfile?.age || 'No especificado'}

Sexo: {currentProfile?.sex || 'No especificado'}

Tipo de Sangre: {currentProfile?.bloodType || 'No especificado'}

RUT: {currentProfile?.rut || 'No especificado'}

Alergias Conocidas: {currentProfile?.allergies || 'Ninguna conocida'}

Contacto de Emergencia: {currentProfile?.emergencyContact || 'No especificado'}

Medicamentos Actuales

{medications.length > 0 ? ( ) : (

No hay medicamentos registrados.

)}
); } // Pantalla de Perfil y Configuración function ProfileScreen() { const { db, userId, currentProfileId, setCurrentProfileId, profiles, isAuthReady } = useAppContext(); const [currentProfile, setCurrentProfile] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [showModal, setShowModal] = useState(false); const [modalContent, setModalContent] = useState({ title: '', message: '' }); const [editMode, setEditMode] = useState(false); const [tempProfile, setTempProfile] = useState({ name: '', allergies: '', emergencyContact: '', bloodType: '', // Nuevo age: '', // Nuevo sex: '', // Nuevo rut: '' // Nuevo }); useEffect(() => { if (db && userId && currentProfileId && isAuthReady) { setLoading(true); setError(null); const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; const profileDocRef = doc(db, `artifacts/${appId}/users/${userId}/profiles`, currentProfileId); const unsubscribe = onSnapshot(profileDocRef, (docSnap) => { if (docSnap.exists()) { const data = { id: docSnap.id, ...docSnap.data() }; setCurrentProfile(data); // Asegurarse de que tempProfile se inicialice con todos los campos, incluso si son nulos en Firestore setTempProfile({ name: data.name || '', allergies: data.allergies || '', emergencyContact: data.emergencyContact || '', bloodType: data.bloodType || '', age: data.age || '', sex: data.sex || '', rut: data.rut || '' }); } else { setCurrentProfile(null); setTempProfile({ name: '', allergies: '', emergencyContact: '', bloodType: '', age: '', sex: '', rut: '' }); console.warn("Perfil actual no encontrado."); } setLoading(false); }, (err) => { console.error("Error al cargar perfil:", err); setError("Error al cargar el perfil. Inténtalo de nuevo."); setLoading(false); }); return () => unsubscribe(); } }, [db, userId, currentProfileId, isAuthReady]); const handleUpdateProfile = async () => { if (!db || !userId || !currentProfileId || !currentProfile) return; setLoading(true); const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; const profileDocRef = doc(db, `artifacts/${appId}/users/${userId}/profiles`, currentProfileId); try { await updateDoc(profileDocRef, { name: tempProfile.name, allergies: tempProfile.allergies, emergencyContact: tempProfile.emergencyContact, bloodType: tempProfile.bloodType, age: tempProfile.age ? parseInt(tempProfile.age) : null, // Convertir a número sex: tempProfile.sex, rut: tempProfile.rut }); setEditMode(false); setModalContent({ title: "Perfil Actualizado", message: "Tu perfil ha sido guardado correctamente." }); setShowModal(true); } catch (e) { console.error("Error al actualizar perfil:", e); setModalContent({ title: "Error", message: "No se pudo actualizar el perfil. Inténtalo de nuevo." }); setShowModal(true); } finally { setLoading(false); } }; const handleAddFamilyProfile = async () => { if (!db || !userId) return; const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; const profilesColRef = collection(db, `artifacts/${appId}/users/${userId}/profiles`); setModalContent({ title: "Agregar Perfil Familiar", message: (
), showCancel: true, onClose: () => setShowModal(false), onConfirm: async () => { const form = document.getElementById('addFamilyForm'); const name = form.famName.value; const allergies = form.famAllergies.value; const emergencyContact = form.famEmergency.value; const bloodType = form.famBloodType.value; const age = form.famAge.value; const sex = form.famSex.value; const rut = form.famRut.value; if (!name) { setModalContent({ title: "Error", message: "El nombre del perfil es obligatorio." }); setShowModal(true); return; } try { const newProfileRef = await addDoc(profilesColRef, { name, allergies, emergencyContact, bloodType, age: age ? parseInt(age) : null, // Convertir a número sex, rut, isMain: false, createdAt: new Date().toISOString() }); setModalContent({ title: "Éxito", message: `Perfil de ${name} agregado correctamente.` }); setShowModal(true); } catch (e) { console.error("Error al agregar perfil familiar:", e); setModalContent({ title: "Error", message: "No se pudo agregar el perfil familiar." }); setShowModal(true); } } }); setShowModal(true); }; const handleDeleteProfile = (profileToDeleteId) => { if (profiles.length <= 1) { setModalContent({ title: "Error", message: "No puedes eliminar el único perfil. Debes tener al menos un perfil activo." }); setShowModal(true); return; } setModalContent({ title: "¿Eliminar Perfil?", message: "¿Estás seguro de que quieres eliminar este perfil? Esta acción es irreversible.", showCancel: true, onClose: () => setShowModal(false), onConfirm: async () => { if (!db || !userId) return; const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; const profileDocRef = doc(db, `artifacts/${appId}/users/${userId}/profiles`, profileToDeleteId); try { await deleteDoc(profileDocRef); // Si se elimina el perfil activo, cambia al primer perfil disponible if (currentProfileId === profileToDeleteId) { const remainingProfiles = profiles.filter(p => p.id !== profileToDeleteId); if (remainingProfiles.length > 0) { setCurrentProfileId(remainingProfiles[0].id); } else { // Esto no debería pasar si la validación de length <= 1 funciona console.warn("No quedan perfiles después de eliminar. Esto es un estado inesperado."); } } setModalContent({ title: "Perfil Eliminado", message: "El perfil ha sido eliminado correctamente." }); setShowModal(true); } catch (e) { console.error("Error al eliminar perfil:", e); setModalContent({ title: "Error", message: "No se pudo eliminar el perfil." }); setShowModal(true); } } }); setShowModal(true); }; return (

Perfil y Configuración

{loading ? (
Cargando perfil...
) : error ? (
{error}
) : currentProfile ? (

Mi Perfil Activo ({currentProfile.name})

{editMode ? (
setTempProfile({ ...tempProfile, name: e.target.value })} />
setTempProfile({ ...tempProfile, bloodType: e.target.value })} placeholder="Ej: A+" />
setTempProfile({ ...tempProfile, age: e.target.value })} placeholder="Ej: 30" />
setTempProfile({ ...tempProfile, rut: e.target.value })} placeholder="Ej: 12.345.678-9" />
setTempProfile({ ...tempProfile, allergies: e.target.value })} />
setTempProfile({ ...tempProfile, emergencyContact: e.target.value })} />
) : (

Nombre: {currentProfile.name}

Edad: {currentProfile.age || 'No especificado'}

Sexo: {currentProfile.sex || 'No especificado'}

Tipo de Sangre: {currentProfile.bloodType || 'No especificado'}

RUT: {currentProfile.rut || 'No especificado'}

Alergias: {currentProfile.allergies || 'Ninguna'}

Contacto de Emergencia: {currentProfile.emergencyContact || 'No especificado'}

ID de Usuario: {userId}

ID de Perfil Activo: {currentProfileId}

)}
) : (
No se encontró el perfil.
)}

Modo Familiar

Administra los medicamentos de otros miembros de la familia.

{profiles.length === 0 ? (
No hay perfiles familiares.
) : ( profiles.map((profile) => (
{profile.name} {currentProfileId === profile.id && ( Activo )}
{profile.isMain !== true && ( // No permitir eliminar el perfil principal )}
)) )}
{showModal && ( setShowModal(false)} onConfirm={modalContent.onConfirm} showCancel={modalContent.showCancel} /> )}
); } // Nueva Pantalla de Bienvenida (Splash Screen) function SplashScreen({ onNavigate }) { return (

Saludify

Tu salud, tu control.

); } // Componente principal de la aplicación function App() { const [currentPage, setCurrentPage] = useState('splash'); // Iniciar en la pantalla de bienvenida const { isAuthReady } = useAppContext(); const renderPage = () => { if (!isAuthReady) { return (
Cargando Saludify...
); } switch (currentPage) { case 'splash': return ; case 'home': return ; case 'add-medication': return ; case 'virtual-doctor': return ; case 'medication-assistant': return ; case 'sos-medication': return ; case 'emergency-mode': return ; case 'profile': return ; default: return ; } }; return (
{renderPage()} {currentPage !== 'splash' && currentPage !== 'emergency-mode' && ( )} {/* Botón flotante para Modo Emergencia */} {currentPage !== 'splash' && currentPage !== 'emergency-mode' && ( )}
); } export default function AppWrapper() { return ( ); }