mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
- Remove nested git repository from bugulma/frontend/.git - Add all frontend files to main repository tracking - Convert from separate frontend/backend repos to unified monorepo - Preserve all frontend code and development history as tracked files - Eliminate nested repository complexity for simpler development workflow This creates a proper monorepo structure with frontend and backend coexisting in the same repository for easier development and deployment.
114 lines
3.7 KiB
TypeScript
114 lines
3.7 KiB
TypeScript
import L, { LatLngTuple } from 'leaflet';
|
|
import 'leaflet/dist/leaflet.css';
|
|
import { useEffect, useRef } from 'react';
|
|
import { MapContainer, Marker, TileLayer, useMap } from 'react-leaflet';
|
|
|
|
// Fix for default marker icon issue in Leaflet with webpack/vite
|
|
delete (L.Icon.Default.prototype as unknown as { _getIconUrl?: unknown })._getIconUrl;
|
|
L.Icon.Default.mergeOptions({
|
|
iconRetinaUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon-2x.png',
|
|
iconUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon.png',
|
|
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-shadow.png',
|
|
});
|
|
|
|
interface MapPickerProps {
|
|
value?: { lat: number; lng: number };
|
|
onChange?: (value: { lat: number; lng: number }) => void;
|
|
location?: { lat: number; lng: number };
|
|
onLocationChange?: (value: { lat: number; lng: number }) => void;
|
|
}
|
|
|
|
/**
|
|
* Component to sync map center with value prop and zoom in when location changes
|
|
*/
|
|
const MapCenterSync = ({ value }: { value: { lat: number; lng: number } }) => {
|
|
const map = useMap();
|
|
const lastValueRef = useRef<{ lat: number; lng: number } | null>(null);
|
|
|
|
useEffect(() => {
|
|
// Check if this is a new location (not just initial render)
|
|
const isNewLocation =
|
|
!lastValueRef.current ||
|
|
Math.abs(lastValueRef.current.lat - value.lat) > 0.0001 ||
|
|
Math.abs(lastValueRef.current.lng - value.lng) > 0.0001;
|
|
|
|
if (isNewLocation) {
|
|
// Zoom in to a closer level when a place is selected
|
|
const targetZoom = 16; // Closer zoom level for selected location
|
|
map.setView([value.lat, value.lng], targetZoom, { animate: true });
|
|
lastValueRef.current = { lat: value.lat, lng: value.lng };
|
|
}
|
|
}, [map, value.lat, value.lng]);
|
|
|
|
return null;
|
|
};
|
|
|
|
const MapPicker = ({ value, onChange, location, onLocationChange }: MapPickerProps) => {
|
|
// Support both prop naming conventions for backward compatibility
|
|
const actualValue = value || location || { lat: 54.5384152, lng: 52.7955953 };
|
|
const actualOnChange = onChange || onLocationChange || (() => {});
|
|
const position: LatLngTuple = [actualValue.lat, actualValue.lng];
|
|
|
|
return (
|
|
<div className="h-64 w-full rounded-lg border overflow-hidden relative">
|
|
<MapContainer
|
|
center={position}
|
|
zoom={13}
|
|
scrollWheelZoom={true}
|
|
attributionControl={false}
|
|
className="rounded-lg h-full w-full"
|
|
>
|
|
<MapCenterSync value={actualValue} />
|
|
|
|
{/* Optional: Add a tile layer for reference (can be removed if you want blank map) */}
|
|
<TileLayer
|
|
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
|
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
|
opacity={0.3}
|
|
/>
|
|
|
|
<Marker
|
|
position={position}
|
|
draggable={true}
|
|
eventHandlers={{
|
|
dragend: (e) => {
|
|
const marker = e.target;
|
|
const newPosition = marker.getLatLng();
|
|
actualOnChange({ lat: newPosition.lat, lng: newPosition.lng });
|
|
},
|
|
}}
|
|
/>
|
|
|
|
{/* Click handler for map */}
|
|
<MapClickHandler onChange={actualOnChange} />
|
|
</MapContainer>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Component to handle map clicks
|
|
*/
|
|
const MapClickHandler = ({
|
|
onChange,
|
|
}: {
|
|
onChange: (value: { lat: number; lng: number }) => void;
|
|
}) => {
|
|
const map = useMap();
|
|
|
|
useEffect(() => {
|
|
const handleClick = (e: L.LeafletMouseEvent) => {
|
|
onChange({ lat: e.latlng.lat, lng: e.latlng.lng });
|
|
};
|
|
|
|
map.on('click', handleClick);
|
|
return () => {
|
|
map.off('click', handleClick);
|
|
};
|
|
}, [map, onChange]);
|
|
|
|
return null;
|
|
};
|
|
|
|
export default MapPicker;
|