import React, { useEffect } from 'react';
import { MapContainer, TileLayer, Marker, Popup, useMapEvents, useMap, Polyline } from 'react-leaflet';
import 'leaflet/dist/leaflet.css';
import L from 'leaflet';
import icon from 'leaflet/dist/images/marker-icon.png';
import iconShadow from 'leaflet/dist/images/marker-shadow.png';
let DefaultIcon = L.icon({
iconUrl: icon,
shadowUrl: iconShadow,
iconSize: [25, 41],
iconAnchor: [12, 41],
});
L.Marker.prototype.options.icon = DefaultIcon;
const createCustomIcon = (color) => {
return new L.DivIcon({
className: 'custom-div-icon',
html: `
`,
iconSize: [22, 22],
iconAnchor: [11, 11]
});
};
const pickupIcon = createCustomIcon('#029676'); // Reliance Teal
const dropoffIcon = createCustomIcon('#FF4A4A'); // Danger Red
const carIcon = new L.DivIcon({
className: 'custom-car-icon',
html: `🚗
`,
iconSize: [32, 32],
iconAnchor: [16, 16]
});
const LocationSelector = ({ onLocationSelect }) => {
useMapEvents({
click(e) {
if (onLocationSelect) {
onLocationSelect(e.latlng.lat, e.latlng.lng);
}
},
});
return null;
};
export const MapBoundsUpdater = ({ pickup, dropoff }) => {
const map = useMap();
useEffect(() => {
if (pickup && dropoff) {
const bounds = L.latLngBounds(
[pickup.lat, pickup.lng],
[dropoff.lat, dropoff.lng]
);
map.fitBounds(bounds, { padding: [50, 50] });
} else if (pickup) {
map.flyTo([pickup.lat, pickup.lng], 13);
} else if (dropoff) {
map.flyTo([dropoff.lat, dropoff.lng], 13);
}
}, [pickup, dropoff, map]);
return null;
};
// ... keep AutocompleteInput as it was ...
let RCP_LOCATIONS = [
{ name: 'RCP Twin Towers', lat: 19.1171, lng: 73.0106 },
{ name: 'RCP LDC', lat: 19.1175, lng: 73.0110 },
{ name: 'RCP Main Gate', lat: 19.1160, lng: 73.0090 },
];
for (let i = 1; i <= 30; i++) {
RCP_LOCATIONS.push({ name: `RCP TC ${i}`, lat: 19.1172 + (i * 0.0001), lng: 73.0107 });
}
['A', 'B', 'C', 'D', 'E', 'F', 'G'].forEach((gate, idx) => {
RCP_LOCATIONS.push({ name: `RCP Gate ${gate}`, lat: 19.1165 + (idx * 0.0002), lng: 73.0095 });
});
import { useState } from 'react';
export const AutocompleteInput = ({ label, placeholder, value, onChange, onSelect, color }) => {
const [suggestions, setSuggestions] = useState([]);
const [showDropdown, setShowDropdown] = useState(false);
const [focusedIndex, setFocusedIndex] = useState(-1);
useEffect(() => {
setFocusedIndex(-1);
const delayDebounceFn = setTimeout(async () => {
if (value && showDropdown) {
let results = [];
if (value.toLowerCase().includes('rcp') || value.toLowerCase().includes('gate') || value.toLowerCase().includes('tc')) {
const rcpMatches = RCP_LOCATIONS.filter(loc => loc.name.toLowerCase().includes(value.toLowerCase())).map(loc => ({
properties: { name: loc.name, city: 'Ghansoli', state: 'Navi Mumbai', isCustom: true },
geometry: { coordinates: [loc.lng, loc.lat] }
}));
results = [...rcpMatches];
}
try {
const res = await fetch(`https://photon.komoot.io/api/?q=${encodeURIComponent(value)}&limit=5&lat=19.0760&lon=72.8777`);
const data = await res.json();
results = [...results, ...(data.features || [])];
// Sort results alphabetically by name
results.sort((a, b) => {
const nameA = a.properties.name || '';
const nameB = b.properties.name || '';
return nameA.localeCompare(nameB);
});
setSuggestions(results.slice(0, 8));
} catch (error) {
console.error(error);
}
} else {
setSuggestions([]);
}
}, 500);
return () => clearTimeout(delayDebounceFn);
}, [value, showDropdown]);
const handleSelect = (suggestion) => {
setShowDropdown(false);
const props = suggestion.properties;
const shortName = props.name || props.city || props.state || 'Selected Location';
onChange(shortName);
onSelect({
lat: suggestion.geometry.coordinates[1],
lng: suggestion.geometry.coordinates[0],
name: shortName
});
};
return (
{label}
{showDropdown && suggestions.length > 0 && (
{suggestions.map((s, idx) => (
{
e.preventDefault();
handleSelect(s);
}}
className={`px-4 py-3 border-white/5 cursor-pointer text-xs text-on-surface hover:bg-white/5 transition-colors flex items-center gap-2 ${idx < suggestions.length - 1 ? 'border-b' : ''} ${idx === focusedIndex ? 'bg-white/5' : ''}`}
onMouseEnter={() => setFocusedIndex(idx)}
onMouseLeave={() => setFocusedIndex(-1)}
>
{s.properties.isCustom ? (
[Internal] {s.properties.name}, {s.properties.city}
) : (
{s.properties.name ? s.properties.name + ', ' : ''}{s.properties.city ? s.properties.city + ', ' : ''}{s.properties.state || s.properties.country}
)}
))}
)}
);
};
const MapComponent = ({ pickupCoords, dropoffCoords, mapMode, setMapMode, onLocationSelect, routePolyline, liveDriverLocation }) => {
const defaultPosition = [19.0760, 72.8777];
let polylinePositions = [];
if (routePolyline) {
try {
const coords = JSON.parse(routePolyline);
// OSRM returns [lng, lat], Leaflet needs [lat, lng]
polylinePositions = coords.map(c => [c[1], c[0]]);
} catch (e) {
console.error("Failed to parse polyline", e);
}
}
return (
{setMapMode ? 'Live Route Planner' : 'Trip Map'}
{setMapMode && (
setMapMode('pickup')}
>
📍 Pick-up Pin
setMapMode('dropoff')}
>
📍 Drop-off Pin
)}
{setMapMode && (
Click anywhere on the map to pinpoint your exact {mapMode === 'pickup' ? 'Pick-up' : 'Drop-off'} location. It will automatically update the form above.
)}
{onLocationSelect && }
{pickupCoords && (
Pick-up: {pickupCoords.name || 'Custom'}
)}
{dropoffCoords && (
Drop-off: {dropoffCoords.name || 'Custom'}
)}
{polylinePositions.length > 0 && (
)}
{liveDriverLocation && (
Host's Live Location
)}
{(pickupCoords || dropoffCoords) && (
Route Selection:
Pick-up: {pickupCoords ? pickupCoords.name : 'Not set'}
Drop-off: {dropoffCoords ? dropoffCoords.name : 'Not set'}
)}
);
};
export default MapComponent;