diff --git a/frontend/App.js b/frontend/App.js
index 1a653cf..6f16309 100644
--- a/frontend/App.js
+++ b/frontend/App.js
@@ -1,29 +1,249 @@
-"use strict";
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-Object.defineProperty(exports, "AppFragmentNode", {
- enumerable: true,
- get: function() {
- return AppFragmentNode;
- }
-});
-function _core() {
- const data = require("@urql/core");
- _core = function() {
- return data;
- };
- return data;
-}
-const AppFragmentNode = (0, _core().gql)`
- fragment AppFragment on App {
- id
- scopeKey
- ownerAccount {
- id
- name
- }
- }
-`;
+import { StatusBar } from 'expo-status-bar';
+import { StyleSheet, Text, View, TextInput, TouchableOpacity, ActivityIndicator, ScrollView, Alert } from 'react-native';
+import { useState } from 'react';
-//# sourceMappingURL=App.js.map
\ No newline at end of file
+const API_URL = 'http://10.137.112.65:8000';
+
+export default function App() {
+ const [screen, setScreen] = useState('login');
+ 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('');
+
+ const register = async () => {
+ 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);
+ setScreen('domicilio');
+ } else {
+ Alert.alert('Error', data.detail || 'Error al registrar');
+ }
+ } catch (e) {
+ Alert.alert('Error', 'No se pudo conectar al servidor');
+ }
+ setLoading(false);
+ };
+
+ const login = async () => {
+ 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);
+ setScreen('domicilio');
+ } else {
+ Alert.alert('Error', 'Credenciales incorrectas');
+ }
+ } catch (e) {
+ 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);
+ setScreen('eta');
+ consultarETA(data.id);
+ } else {
+ Alert.alert('Error', data.detail || 'Colonia no encontrada');
+ }
+ } catch (e) {
+ Alert.alert('Error', 'No se pudo guardar el domicilio');
+ }
+ setLoading(false);
+ };
+
+ const consultarETA = async (id) => {
+ setLoading(true);
+ try {
+ const res = await fetch(`${API_URL}/eta/${id}`, {
+ headers: { 'Authorization': `Bearer ${token}` },
+ });
+ const data = await res.json();
+ setEta(data);
+ } catch (e) {
+ Alert.alert('Error', 'No se pudo obtener el ETA');
+ }
+ setLoading(false);
+ };
+
+ if (screen === 'login') return (
+
+
+ 🚛 BasuraApp
+ Ingresa a tu cuenta
+
+
+ {loading ? : <>
+
+ Iniciar sesión
+
+
+ Registrarme
+
+ >}
+
+ );
+
+ if (screen === 'domicilio') return (
+
+ 📍 Mi domicilio
+ ¿En qué colonia vives?
+
+
+ Colonias disponibles: Zona Centro, Las Arboledas, Trojes, San Juanico, Los Olivos, Rancho Seco, Las Insurgentes
+ {loading ? :
+
+ Guardar y ver horario
+ }
+
+ );
+
+ 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)}>
+ Actualizar
+
+ setScreen('separacion')}>
+ 📚 Guía de separación
+
+ setScreen('reporte')}>
+ 📋 Reportar incidencia
+
+ > : 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({
+ container: { flexGrow: 1, backgroundColor: '#f0f4f8', alignItems: 'center',
+ justifyContent: 'center', padding: 24 },
+ 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' },
+ 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 },
+});
\ No newline at end of file