feat: geolocalización GPS con Haversine para detectar zona automáticamente
This commit is contained in:
@@ -2,6 +2,7 @@ import { StatusBar } from 'expo-status-bar';
|
|||||||
import { StyleSheet, Text, View, TextInput, TouchableOpacity, ActivityIndicator, ScrollView, Alert, RefreshControl } from 'react-native';
|
import { StyleSheet, Text, View, TextInput, TouchableOpacity, ActivityIndicator, ScrollView, Alert, RefreshControl } from 'react-native';
|
||||||
import { useState, useEffect, useCallback } from 'react';
|
import { useState, useEffect, useCallback } from 'react';
|
||||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||||
|
import * as Location from 'expo-location';
|
||||||
|
|
||||||
const API_URL = 'http://10.137.112.65:8000';
|
const API_URL = 'http://10.137.112.65:8000';
|
||||||
|
|
||||||
@@ -32,6 +33,7 @@ export default function App() {
|
|||||||
completed: true,
|
completed: true,
|
||||||
});
|
});
|
||||||
const [alertaOperativa, setAlertaOperativa] = useState(null);
|
const [alertaOperativa, setAlertaOperativa] = useState(null);
|
||||||
|
const [localizando, setLocalizando] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
cargarSesion();
|
cargarSesion();
|
||||||
@@ -260,6 +262,38 @@ export default function App() {
|
|||||||
} catch {}
|
} catch {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const usarUbicacion = async () => {
|
||||||
|
setLocalizando(true);
|
||||||
|
try {
|
||||||
|
const { status } = await Location.requestForegroundPermissionsAsync();
|
||||||
|
if (status !== 'granted') {
|
||||||
|
Alert.alert('Permiso denegado', 'Necesitamos acceso a tu ubicación para encontrar tu zona de recolección');
|
||||||
|
setLocalizando(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const location = await Location.getCurrentPositionAsync({ accuracy: Location.Accuracy.High });
|
||||||
|
const { latitude, longitude } = location.coords;
|
||||||
|
|
||||||
|
const res = await fetch(
|
||||||
|
`${API_URL}/domicilios/ruta-por-coordenadas?lat=${latitude}&lng=${longitude}`,
|
||||||
|
{ headers: { 'Authorization': `Bearer ${token}` } }
|
||||||
|
);
|
||||||
|
const data = await res.json();
|
||||||
|
if (data.cobertura) {
|
||||||
|
setColoniaSeleccionada(data.colonia_sugerida);
|
||||||
|
Alert.alert(
|
||||||
|
'📍 Ubicación detectada',
|
||||||
|
`Se detectó tu zona: ${data.colonia_sugerida}\nRuta: ${data.nombre_ruta}\nDistancia: ${data.distancia_metros}m`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Alert.alert('Sin cobertura', 'Tu ubicación no está dentro de las zonas de servicio de Celaya');
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Alert.alert('Error', 'No se pudo obtener tu ubicación');
|
||||||
|
}
|
||||||
|
setLocalizando(false);
|
||||||
|
};
|
||||||
|
|
||||||
if (screen === 'splash') return (
|
if (screen === 'splash') return (
|
||||||
<View style={styles.splashContainer}>
|
<View style={styles.splashContainer}>
|
||||||
<Text style={styles.splashEmoji}>🚛</Text>
|
<Text style={styles.splashEmoji}>🚛</Text>
|
||||||
@@ -319,6 +353,15 @@ export default function App() {
|
|||||||
value={direccion} onChangeText={setDireccion} />
|
value={direccion} onChangeText={setDireccion} />
|
||||||
<TextInput style={styles.input} placeholder="Código postal (ej: 38000)"
|
<TextInput style={styles.input} placeholder="Código postal (ej: 38000)"
|
||||||
value={codigoPostal} onChangeText={setCodigoPostal} keyboardType="numeric" />
|
value={codigoPostal} onChangeText={setCodigoPostal} keyboardType="numeric" />
|
||||||
|
<TouchableOpacity
|
||||||
|
style={[styles.btnUbicacion, localizando && { opacity: 0.6 }]}
|
||||||
|
onPress={usarUbicacion}
|
||||||
|
disabled={localizando}>
|
||||||
|
{localizando
|
||||||
|
? <ActivityIndicator color="#1a7a4a" size="small" />
|
||||||
|
: <Text style={styles.btnUbicacionText}>📡 Usar mi ubicación actual</Text>
|
||||||
|
}
|
||||||
|
</TouchableOpacity>
|
||||||
<TouchableOpacity style={[styles.input, styles.combobox]}
|
<TouchableOpacity style={[styles.input, styles.combobox]}
|
||||||
onPress={() => setMostrarColonias(!mostrarColonias)}>
|
onPress={() => setMostrarColonias(!mostrarColonias)}>
|
||||||
<Text style={{ color: coloniaSeleccionada ? '#1a1a1a' : '#999', fontSize: 15 }}>
|
<Text style={{ color: coloniaSeleccionada ? '#1a1a1a' : '#999', fontSize: 15 }}>
|
||||||
@@ -553,4 +596,6 @@ const styles = StyleSheet.create({
|
|||||||
alertaBox: { width: '100%', backgroundColor: '#fff3e0', borderRadius: 10, padding: 14, marginBottom: 16, borderWidth: 1, borderColor: '#ff9800' },
|
alertaBox: { width: '100%', backgroundColor: '#fff3e0', borderRadius: 10, padding: 14, marginBottom: 16, borderWidth: 1, borderColor: '#ff9800' },
|
||||||
alertaTitulo: { fontSize: 14, fontWeight: 'bold', color: '#e65100', marginBottom: 4 },
|
alertaTitulo: { fontSize: 14, fontWeight: 'bold', color: '#e65100', marginBottom: 4 },
|
||||||
alertaMensaje: { fontSize: 13, color: '#bf360c' },
|
alertaMensaje: { fontSize: 13, color: '#bf360c' },
|
||||||
|
btnUbicacion: { width: '100%', borderRadius: 10, padding: 14, alignItems: 'center', marginBottom: 12, borderWidth: 1.5, borderColor: '#1a7a4a', borderStyle: 'dashed', backgroundColor: '#e8f5ee' },
|
||||||
|
btnUbicacionText: { color: '#1a7a4a', fontWeight: '500', fontSize: 14 },
|
||||||
});
|
});
|
||||||
Reference in New Issue
Block a user