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;