diff --git a/frontend/App.js b/frontend/App.js index 8e16150..8c80dbf 100644 --- a/frontend/App.js +++ b/frontend/App.js @@ -2,6 +2,8 @@ import { StatusBar } from 'expo-status-bar'; import { StyleSheet, Text, View, TextInput, TouchableOpacity, ActivityIndicator, ScrollView, Alert, RefreshControl } from 'react-native'; import { useState, useEffect, useCallback } from 'react'; import AsyncStorage from '@react-native-async-storage/async-storage'; +import * as Notifications from 'expo-notifications'; +import * as Device from 'expo-device'; const API_URL = 'http://10.137.112.65:8000'; @@ -9,6 +11,13 @@ const COLONIAS = [ 'Zona Centro', 'Las Arboledas', 'Trojes', 'San Juanico', 'Los Olivos', 'Rancho Seco', 'Las Insurgentes' ]; +Notifications.setNotificationHandler({ + handleNotification: async () => ({ + shouldShowAlert: true, + shouldPlaySound: true, + shouldSetBadge: false, + }), +}); export default function App() { const [screen, setScreen] = useState('splash'); @@ -27,7 +36,10 @@ export default function App() { const [direccion, setDireccion] = useState(''); const [codigoPostal, setCodigoPostal] = useState(''); - useEffect(() => { cargarSesion(); }, []); +useEffect(() => { + cargarSesion(); + registrarNotificaciones(); +}, []); useEffect(() => { if (screen === 'eta' && domicilioActivo && token) { @@ -167,9 +179,29 @@ export default function App() { headers: { 'Authorization': `Bearer ${t || token}` } }); const data = await res.json(); - if (data.mensaje) setEta(data); + if (data.mensaje) { + if (data.evento === 'TRUCK_PROXIMITY' && eta?.evento !== 'TRUCK_PROXIMITY') { + enviarNotificacionLocal( + '🚨 ¡Camión cercano!', + `El camión está a menos de 15 minutos de ${data.colonia}. Saca tus bolsas a la acera.` + ); + } + if (data.evento === 'ROUTE_START' && eta?.evento !== 'ROUTE_START') { + enviarNotificacionLocal( + '🟢 Ruta iniciada', + `El camión de ${data.colonia} ha salido. Prepara tus residuos.` + ); + } + if (data.evento === 'ROUTE_COMPLETED' && eta?.evento !== 'ROUTE_COMPLETED') { + enviarNotificacionLocal( + '✅ Servicio finalizado', + `El camión de ${data.colonia} ha concluido su jornada.` + ); + } + setEta(data); + } } catch { if (!silencioso) Alert.alert('Error', 'No se pudo obtener el ETA'); } - if (!silencioso) setLoading(false); + setLoading(false); }; const onRefresh = useCallback(async () => { @@ -178,10 +210,23 @@ export default function App() { setRefreshing(false); }, [domicilioActivo, token]); + const registrarNotificaciones = async () => { + if (!Device.isDevice) return; + const { status } = await Notifications.requestPermissionsAsync(); + if (status !== 'granted') return; + }; + + const enviarNotificacionLocal = async (titulo, cuerpo) => { + await Notifications.scheduleNotificationAsync({ + content: { title: titulo, body: cuerpo, sound: true }, + trigger: null, + }); + }; + const seleccionarDomicilio = async (dom) => { setDomicilioActivo(dom); await AsyncStorage.setItem('domicilioId', String(dom.id)); - consultarETA(dom.id, token); + consultarETA(dom.id, token, true); }; if (screen === 'splash') return ( @@ -302,7 +347,8 @@ export default function App() { {domicilios.length > 1 && ( + style={{ width: '100%', marginBottom: 12 }} + contentContainerStyle={{ alignItems: 'center', paddingVertical: 4 }}> {domicilios.map(d => (