- Added package.json with dependencies for Next.js, React, and Tailwind CSS. - Created postcss.config.js for Tailwind CSS and autoprefixer integration. - Added SVG icon for the application in public/icons/icon.svg. - Created manifest.json for PWA support with app details and icon. - Configured Tailwind CSS in tailwind.config.js with custom colors and animations. - Set up TypeScript configuration in tsconfig.json for strict type checking and module resolution.
111 lines
3.1 KiB
TypeScript
111 lines
3.1 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useRef, useCallback } from 'react';
|
|
import { getSettings, saveDriverLocation, addToQueue, isAuthenticated } from '@/lib/pocketbase';
|
|
|
|
export default function LocationTracker() {
|
|
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
|
const watchRef = useRef<number | null>(null);
|
|
|
|
const sendLocation = useCallback(async (position: GeolocationPosition) => {
|
|
if (!isAuthenticated()) return;
|
|
|
|
const user = JSON.parse(localStorage.getItem('pocketbase_auth') || '{}')?.model;
|
|
if (!user) return;
|
|
|
|
const locationData = {
|
|
driver: user.id,
|
|
latitude: position.coords.latitude,
|
|
longitude: position.coords.longitude,
|
|
accuracy: position.coords.accuracy,
|
|
altitude: position.coords.altitude || undefined,
|
|
speed: position.coords.speed || undefined,
|
|
heading: position.coords.heading || undefined,
|
|
timestamp: new Date().toISOString(),
|
|
};
|
|
|
|
try {
|
|
await saveDriverLocation(locationData);
|
|
} catch (error) {
|
|
console.error('Failed to save location:', error);
|
|
// Queue for sync when back online
|
|
addToQueue({
|
|
type: 'status_update',
|
|
data: locationData,
|
|
});
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (!('geolocation' in navigator)) {
|
|
console.warn('Geolocation not supported');
|
|
return;
|
|
}
|
|
|
|
const settings = getSettings();
|
|
const intervalMs = Math.max(10000, settings.locationInterval * 1000);
|
|
|
|
const startTracking = () => {
|
|
// Use watchPosition for more frequent updates
|
|
watchRef.current = navigator.geolocation.watchPosition(
|
|
sendLocation,
|
|
(error) => {
|
|
console.error('Geolocation error:', error);
|
|
},
|
|
{
|
|
enableHighAccuracy: settings.enableHighAccuracy,
|
|
maximumAge: intervalMs,
|
|
timeout: 10000,
|
|
}
|
|
);
|
|
|
|
// Also send on interval as backup
|
|
intervalRef.current = setInterval(() => {
|
|
navigator.geolocation.getCurrentPosition(
|
|
sendLocation,
|
|
(error) => console.error('Interval geolocation error:', error),
|
|
{
|
|
enableHighAccuracy: settings.enableHighAccuracy,
|
|
timeout: 10000,
|
|
}
|
|
);
|
|
}, intervalMs);
|
|
};
|
|
|
|
// Start tracking if authenticated
|
|
if (isAuthenticated()) {
|
|
startTracking();
|
|
}
|
|
|
|
// Listen for auth changes
|
|
const handleAuthChange = () => {
|
|
if (isAuthenticated()) {
|
|
startTracking();
|
|
} else {
|
|
stopTracking();
|
|
}
|
|
};
|
|
|
|
// Check periodically for auth state
|
|
const authCheckInterval = setInterval(handleAuthChange, 5000);
|
|
|
|
const stopTracking = () => {
|
|
if (watchRef.current !== null) {
|
|
navigator.geolocation.clearWatch(watchRef.current);
|
|
watchRef.current = null;
|
|
}
|
|
if (intervalRef.current !== null) {
|
|
clearInterval(intervalRef.current);
|
|
intervalRef.current = null;
|
|
}
|
|
};
|
|
|
|
return () => {
|
|
stopTracking();
|
|
clearInterval(authCheckInterval);
|
|
};
|
|
}, [sendLocation]);
|
|
|
|
// This component doesn't render anything
|
|
return null;
|
|
}
|