/** * useLocation Hook * React hook for GPS location tracking */ import { useState, useEffect, useCallback, useRef } from 'react'; import Geolocation from '@react-native-community/geolocation'; export function useLocation(options = {}) { const [location, setLocation] = useState(null); const [hasPermission, setHasPermission] = useState(false); const [isTracking, setIsTracking] = useState(false); const [error, setError] = useState(null); const watchIdRef = useRef(null); const defaultOptions = { enableHighAccuracy: true, timeout: 15000, maximumAge: 10000, distanceFilter: 10, // meters ...options, }; /** * Request location permission */ const requestPermission = useCallback(async () => { try { const result = await Geolocation.requestAuthorization(); setHasPermission(result === 'granted'); return result === 'granted'; } catch (err) { setError(err.message); return false; } }, []); /** * Get current location (one-time) */ const getCurrentLocation = useCallback(() => { return new Promise((resolve, reject) => { Geolocation.getCurrentPosition( (position) => { const loc = { latitude: position.coords.latitude, longitude: position.coords.longitude, altitude: position.coords.altitude, accuracy: position.coords.accuracy, heading: position.coords.heading, speed: position.coords.speed, timestamp: new Date(position.timestamp).toISOString(), }; setLocation(loc); setError(null); resolve(loc); }, (err) => { setError(err.message); reject(err); }, defaultOptions ); }); }, [defaultOptions]); /** * Start continuous location tracking */ const startTracking = useCallback(() => { if (watchIdRef.current) { return; // Already tracking } setIsTracking(true); watchIdRef.current = Geolocation.watchPosition( (position) => { const loc = { latitude: position.coords.latitude, longitude: position.coords.longitude, altitude: position.coords.altitude, accuracy: position.coords.accuracy, heading: position.coords.heading, speed: position.coords.speed, timestamp: new Date(position.timestamp).toISOString(), }; setLocation(loc); setError(null); }, (err) => { setError(err.message); }, { ...defaultOptions, distanceFilter: defaultOptions.distanceFilter, } ); }, [defaultOptions]); /** * Stop location tracking */ const stopTracking = useCallback(() => { if (watchIdRef.current) { Geolocation.clearWatch(watchIdRef.current); watchIdRef.current = null; } setIsTracking(false); }, []); /** * Toggle tracking */ const toggleTracking = useCallback(() => { if (isTracking) { stopTracking(); } else { startTracking(); } }, [isTracking, startTracking, stopTracking]); // Cleanup on unmount useEffect(() => { return () => { if (watchIdRef.current) { Geolocation.clearWatch(watchIdRef.current); } }; }, []); return { // State location, hasPermission, isTracking, error, // Actions requestPermission, getCurrentLocation, startTracking, stopTracking, toggleTracking, }; }