import { StatusBar } from 'expo-status-bar'; import { StyleSheet, Text, View, TextInput, TouchableOpacity, ActivityIndicator, ScrollView, Alert } from 'react-native'; import { useState, useEffect } from 'react'; import AsyncStorage from '@react-native-async-storage/async-storage'; const API_URL = 'http://10.137.112.65:8000'; export default function App() { const [screen, setScreen] = useState('splash'); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [token, setToken] = useState(null); const [domicilioId, setDomicilioId] = useState(null); const [eta, setEta] = useState(null); const [loading, setLoading] = useState(false); const [colonia, setColonia] = useState(''); const [direccion, setDireccion] = useState(''); useEffect(() => { cargarSesion(); }, []); const cargarSesion = async () => { try { const t = await AsyncStorage.getItem('token'); const d = await AsyncStorage.getItem('domicilioId'); if (t && d) { setToken(t); setDomicilioId(parseInt(d)); setScreen('eta'); consultarETA(parseInt(d), t); } else if (t) { setToken(t); setScreen('domicilio'); } else { setScreen('login'); } } catch { setScreen('login'); } }; const guardarSesion = async (t, dId) => { await AsyncStorage.setItem('token', t); if (dId) await AsyncStorage.setItem('domicilioId', String(dId)); }; const cerrarSesion = async () => { await AsyncStorage.clear(); setToken(null); setDomicilioId(null); setEta(null); setEmail(''); setPassword(''); setDireccion(''); setColonia(''); setScreen('login'); }; const register = async () => { if (!email.trim() || !password.trim()) { Alert.alert('Campos requeridos', 'Por favor ingresa tu email y contraseña'); return; } if (password.length < 4) { Alert.alert('Contraseña débil', 'La contraseña debe tener al menos 4 caracteres'); return; } setLoading(true); try { const res = await fetch(`${API_URL}/auth/register`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }), }); const data = await res.json(); if (data.access_token) { setToken(data.access_token); await guardarSesion(data.access_token, null); setScreen('domicilio'); } else { Alert.alert('Error', data.detail || 'Error al registrar'); } } catch { Alert.alert('Error', 'No se pudo conectar al servidor'); } setLoading(false); }; const login = async () => { if (!email.trim() || !password.trim()) { Alert.alert('Campos requeridos', 'Por favor ingresa tu email y contraseña'); return; } setLoading(true); try { const res = await fetch(`${API_URL}/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }), }); const data = await res.json(); if (data.access_token) { setToken(data.access_token); await guardarSesion(data.access_token, null); const domGuardado = await AsyncStorage.getItem('domicilioId'); if (domGuardado) { setDomicilioId(parseInt(domGuardado)); setScreen('eta'); consultarETA(parseInt(domGuardado), data.access_token); } else { setScreen('domicilio'); } } else { Alert.alert('Error', 'Credenciales incorrectas'); } } catch { Alert.alert('Error', 'No se pudo conectar al servidor'); } setLoading(false); }; const guardarDomicilio = async () => { setLoading(true); try { const res = await fetch(`${API_URL}/domicilios`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, }, body: JSON.stringify({ direccion, colonia, lat: 20.5185, lng: -100.8450 }), }); const data = await res.json(); if (data.id) { setDomicilioId(data.id); await guardarSesion(token, data.id); setScreen('eta'); consultarETA(data.id, token); } else { Alert.alert('Error', data.detail || 'Colonia no encontrada'); } } catch { Alert.alert('Error', 'No se pudo guardar el domicilio'); } setLoading(false); }; const consultarETA = async (id, t) => { setLoading(true); try { const res = await fetch(`${API_URL}/eta/${id || domicilioId}`, { headers: { 'Authorization': `Bearer ${t || token}` }, }); const data = await res.json(); if (data.mensaje) setEta(data); else { await cerrarSesion(); } } catch { Alert.alert('Error', 'No se pudo obtener el ETA'); } setLoading(false); }; if (screen === 'splash') return ( 🚛 BasuraApp ); if (screen === 'login') return ( 🚛 BasuraApp Ingresa a tu cuenta {loading ? : <> Iniciar sesión Crear cuenta nueva } ); if (screen === 'domicilio') return ( 📍 Mi domicilio ¿En qué colonia vives? Colonias: Zona Centro, Las Arboledas, Trojes, San Juanico, Los Olivos, Rancho Seco, Las Insurgentes {loading ? : Guardar y ver horario } Cerrar sesión ); if (screen === 'eta') return ( 🕐 Horario de recolección {loading ? : eta ? <> {eta.evento === 'TRUCK_PROXIMITY' ? '🚨 ¡Camión cercano!' : eta.evento === 'ROUTE_START' ? '🟢 Ruta iniciada' : eta.evento === 'ROUTE_COMPLETED' ? '✅ Servicio finalizado' : '🚛 En camino'} {eta.mensaje} Ventana de llegada {eta.ventana_inicio} – {eta.ventana_fin} 📍 {eta.colonia} · {eta.route_id} 🔒 Solo ves la información de tu zona. No se muestra la ruta completa del camión. consultarETA(domicilioId, token)}> Actualizar setScreen('separacion')}> 📚 Guía de separación setScreen('reporte')}> 📋 Reportar incidencia Cerrar sesión : Sin datos} ); if (screen === 'separacion') return ( ♻️ Guía de separación {[ { emoji: '🟢', tipo: 'Orgánicos', ejemplos: 'Cáscaras, restos de comida, café, frutas' }, { emoji: '🔵', tipo: 'Reciclables', ejemplos: 'Papel, cartón, plástico, vidrio, metal' }, { emoji: '🔴', tipo: 'Sanitarios', ejemplos: 'Pañales, papel higiénico, gasas, algodón' }, { emoji: '⚠️', tipo: 'Especiales', ejemplos: 'Pilas, medicamentos, electrónicos, pinturas' }, ].map(item => ( {item.emoji} {item.tipo} {item.ejemplos} ))} setScreen('eta')}> ← Volver al horario ); if (screen === 'reporte') return ( 📋 Reportar incidencia ¿Qué problema tuviste? {['El camión no pasó', 'Pasó fuera de horario', 'No recogió mis residuos', 'Otro'].map(tipo => ( { await fetch(`${API_URL}/reportes?domicilio_id=${domicilioId}&tipo=${tipo}&descripcion=${tipo}`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}` } }); Alert.alert('¡Gracias!', 'Tu reporte fue enviado correctamente.'); setScreen('eta'); }}> {tipo} ))} setScreen('eta')}> ← Cancelar ); } const styles = StyleSheet.create({ splashContainer: { flex: 1, backgroundColor: '#1a7a4a', alignItems: 'center', justifyContent: 'center' }, splashEmoji: { fontSize: 72 }, splashTitle: { fontSize: 36, fontWeight: 'bold', color: '#fff', marginTop: 16 }, container: { flexGrow: 1, backgroundColor: '#f0f4f8', alignItems: 'center', justifyContent: 'center', padding: 24 }, bigEmoji: { fontSize: 64, marginBottom: 8 }, title: { fontSize: 28, fontWeight: 'bold', color: '#1a7a4a', marginBottom: 6, textAlign: 'center' }, subtitle: { fontSize: 15, color: '#555', marginBottom: 24, textAlign: 'center' }, input: { width: '100%', backgroundColor: '#fff', borderRadius: 10, padding: 14, fontSize: 15, marginBottom: 12, borderWidth: 1, borderColor: '#ddd' }, btn: { width: '100%', backgroundColor: '#1a7a4a', borderRadius: 10, padding: 16, alignItems: 'center', marginTop: 8 }, btnText: { color: '#fff', fontWeight: 'bold', fontSize: 16 }, btnSecondary: { width: '100%', borderRadius: 10, padding: 16, alignItems: 'center', marginTop: 8, borderWidth: 1, borderColor: '#1a7a4a' }, btnSecondaryText: { color: '#1a7a4a', fontWeight: 'bold', fontSize: 15 }, hint: { fontSize: 11, color: '#888', marginBottom: 16, textAlign: 'center' }, logoutText: { color: '#e53935', fontSize: 14, textAlign: 'center' }, etaCard: { width: '100%', backgroundColor: '#fff', borderRadius: 16, padding: 20, marginBottom: 16, borderWidth: 1, borderColor: '#d0e8d8' }, etaEvento: { fontSize: 18, fontWeight: 'bold', color: '#1a7a4a', marginBottom: 8 }, etaMensaje: { fontSize: 15, color: '#333', marginBottom: 16, lineHeight: 22 }, ventanaBox: { backgroundColor: '#e8f5ee', borderRadius: 10, padding: 14, marginBottom: 12 }, ventanaLabel: { fontSize: 12, color: '#555', marginBottom: 4 }, ventanaHora: { fontSize: 24, fontWeight: 'bold', color: '#1a7a4a' }, coloniaText: { fontSize: 12, color: '#888' }, privacyBox: { width: '100%', backgroundColor: '#fff8e1', borderRadius: 10, padding: 14, marginBottom: 16, borderWidth: 1, borderColor: '#ffe082' }, privacyText: { fontSize: 12, color: '#795548', textAlign: 'center' }, separacionCard: { width: '100%', backgroundColor: '#fff', borderRadius: 12, padding: 16, marginBottom: 12, flexDirection: 'row', alignItems: 'center', gap: 14, borderWidth: 1, borderColor: '#ddd' }, separacionEmoji: { fontSize: 32 }, separacionTipo: { fontSize: 16, fontWeight: 'bold', color: '#333' }, separacionEjemplos: { fontSize: 12, color: '#666', marginTop: 2 }, });