WFDASHDRIVER-APP/components/LocationTracker.tsx

102 lines
3.5 KiB
TypeScript
Raw Normal View History

'use client';
import { useEffect, useRef } from 'react';
import { useAuth } from '@/components/AuthProvider';
import { getSettings, saveDriverLocation, isAuthenticated } from '@/lib/pocketbase';
export default function LocationTracker() {
const { isLoggedIn } = useAuth();
const watchRef = useRef<number | null>(null);
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
const wakeLockRef = useRef<WakeLockSentinel | null>(null);
useEffect(() => {
// Skip entirely when not signed in — previously the watcher
// was set up regardless of auth, which meant we requested a
// GPS lock on the login screen (and ate battery doing nothing).
if (!isLoggedIn) return;
if (!('geolocation' in navigator)) return;
const settings = getSettings();
const intervalMs = Math.max(30000, settings.locationInterval * 1000);
const sendLocation = (position: GeolocationPosition) => {
if (!isAuthenticated()) return;
if (position.coords.accuracy > settings.minimumAccuracy) return;
const auth = JSON.parse(localStorage.getItem('pocketbase_auth') || '{}');
const user = auth?.model;
if (!user) return;
saveDriverLocation({
// PB schema note: driver_locations stores the user relation under
// `relation`, not `driver`. Using the wrong key here silently
// 400'd inside a try/catch — see lib/types.ts DriverLocation.
relation: user.id,
latitude: position.coords.latitude,
longitude: position.coords.longitude,
accuracy: position.coords.accuracy || undefined,
altitude: position.coords.altitude || undefined,
speed: position.coords.speed || undefined,
heading: position.coords.heading || undefined,
timestamp: new Date().toISOString(),
});
};
// 1. watchPosition keeps GPS active (helps Android stay alive longer)
watchRef.current = navigator.geolocation.watchPosition(
sendLocation,
() => {},
{
enableHighAccuracy: settings.enableHighAccuracy,
maximumAge: 5000, // fresh GPS every 5s
timeout: 30000,
}
);
// 2. Interval fallback (for when watchPosition is throttled)
intervalRef.current = setInterval(() => {
navigator.geolocation.getCurrentPosition(
sendLocation,
() => {},
{ enableHighAccuracy: settings.enableHighAccuracy, maximumAge: intervalMs, timeout: 30000 }
);
}, intervalMs);
// 3. Screen Wake Lock — keeps phone awake while app is open
if ('wakeLock' in navigator) {
navigator.wakeLock.request('screen')
.then((lock) => { wakeLockRef.current = lock; })
.catch(() => {});
// Re-acquire if page regains focus
const onFocus = () => {
if (!wakeLockRef.current) {
navigator.wakeLock.request('screen')
.then((lock) => { wakeLockRef.current = lock; })
.catch(() => {});
}
};
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') onFocus();
});
}
return () => {
if (watchRef.current !== null) {
navigator.geolocation.clearWatch(watchRef.current);
watchRef.current = null;
}
if (intervalRef.current !== null) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
if (wakeLockRef.current) {
wakeLockRef.current.release();
wakeLockRef.current = null;
}
};
}, [isLoggedIn]);
return null;
}