161 lines
4.3 KiB
TypeScript
161 lines
4.3 KiB
TypeScript
import React, { useState, useEffect, useRef } from 'react';
|
|
import { View, Text } from 'react-native';
|
|
import MapView, { Marker, Polyline, PROVIDER_DEFAULT } from 'react-native-maps';
|
|
import { useAppTheme } from '@theme';
|
|
import { Coordinates } from '@app-types/index';
|
|
import { getStyles } from './mapView.styles';
|
|
import {
|
|
getRouteDirections,
|
|
getHaversineDistance,
|
|
} from '@services/locationService';
|
|
|
|
interface MapViewComponentProps {
|
|
origin?: Coordinates;
|
|
destination?: Coordinates;
|
|
currentLocation?: Coordinates;
|
|
showRoute?: boolean;
|
|
style?: any;
|
|
}
|
|
|
|
export const MapViewComponent: React.FC<MapViewComponentProps> = ({
|
|
origin,
|
|
destination,
|
|
currentLocation,
|
|
showRoute = false,
|
|
style,
|
|
}) => {
|
|
const { colors } = useAppTheme();
|
|
const styles = getStyles(colors);
|
|
const mapRef = useRef<MapView>(null);
|
|
const [routeCoords, setRouteCoords] = useState<Coordinates[]>([]);
|
|
const lastFetchedOrigin = useRef<Coordinates | null>(null);
|
|
|
|
const defaultRegion = {
|
|
latitude: currentLocation?.latitude || origin?.latitude || 12.9716,
|
|
longitude: currentLocation?.longitude || origin?.longitude || 77.5946,
|
|
latitudeDelta: 0.05,
|
|
longitudeDelta: 0.05,
|
|
};
|
|
|
|
// Fetch routing coordinates
|
|
useEffect(() => {
|
|
let active = true;
|
|
if (showRoute && origin && destination) {
|
|
// Calculate distance from last fetched origin
|
|
if (lastFetchedOrigin.current) {
|
|
const dist = getHaversineDistance(origin, lastFetchedOrigin.current);
|
|
// If driver moved less than 50 meters (0.05 km), skip re-fetching to prevent spamming
|
|
if (dist < 0.05 && routeCoords.length > 0) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
getRouteDirections(origin, destination)
|
|
.then(points => {
|
|
if (active) {
|
|
setRouteCoords(points);
|
|
lastFetchedOrigin.current = origin;
|
|
}
|
|
})
|
|
.catch(err => {
|
|
console.error('Error in MapViewComponent getRouteDirections:', err);
|
|
if (active) {
|
|
setRouteCoords([origin, destination]);
|
|
}
|
|
});
|
|
} else {
|
|
setRouteCoords([]);
|
|
lastFetchedOrigin.current = null;
|
|
}
|
|
return () => {
|
|
active = false;
|
|
};
|
|
}, [
|
|
showRoute,
|
|
origin?.latitude,
|
|
origin?.longitude,
|
|
destination?.latitude,
|
|
destination?.longitude,
|
|
routeCoords.length,
|
|
]);
|
|
|
|
// Adjust camera to fit all coordinates
|
|
useEffect(() => {
|
|
const coordsToFit: Coordinates[] = [];
|
|
if (currentLocation) {
|
|
coordsToFit.push(currentLocation);
|
|
}
|
|
if (origin) {
|
|
coordsToFit.push(origin);
|
|
}
|
|
if (destination) {
|
|
coordsToFit.push(destination);
|
|
}
|
|
|
|
if (coordsToFit.length > 0 && mapRef.current) {
|
|
const timer = setTimeout(() => {
|
|
mapRef.current?.fitToCoordinates(coordsToFit, {
|
|
edgePadding: { top: 60, right: 60, bottom: 60, left: 60 },
|
|
animated: true,
|
|
});
|
|
}, 500);
|
|
return () => clearTimeout(timer);
|
|
}
|
|
}, [
|
|
currentLocation?.latitude,
|
|
currentLocation?.longitude,
|
|
origin?.latitude,
|
|
origin?.longitude,
|
|
destination?.latitude,
|
|
destination?.longitude,
|
|
]);
|
|
|
|
return (
|
|
<View style={[styles.container, style]}>
|
|
<MapView
|
|
ref={mapRef}
|
|
provider={PROVIDER_DEFAULT}
|
|
style={styles.map}
|
|
initialRegion={defaultRegion}
|
|
showsUserLocation={true}
|
|
loadingEnabled={true}
|
|
>
|
|
{currentLocation && (
|
|
<Marker
|
|
coordinate={currentLocation}
|
|
title="Your Location"
|
|
pinColor={colors.primary}
|
|
/>
|
|
)}
|
|
{origin && (
|
|
<Marker
|
|
coordinate={origin}
|
|
title="Pickup Location"
|
|
pinColor={colors.statusOffline}
|
|
/>
|
|
)}
|
|
{destination && (
|
|
<Marker
|
|
coordinate={destination}
|
|
title="Drop Location"
|
|
pinColor={colors.statusOnline}
|
|
/>
|
|
)}
|
|
{showRoute && routeCoords.length > 0 && (
|
|
<Polyline
|
|
coordinates={routeCoords}
|
|
strokeColor={colors.primary}
|
|
strokeWidth={4}
|
|
/>
|
|
)}
|
|
</MapView>
|
|
<View style={styles.mockOverlay}>
|
|
<Text style={styles.mockText}>📍 Live Navigation Map Active</Text>
|
|
</View>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
export default MapViewComponent;
|
|
|