Files
trackgo-fe/packages/ui/src/components/map/route-map.tsx
T
shancheas 27dfc167d2 feat: implement location management with interactive maps
- Introduced a new `LocationMap` component for handling latitude and longitude inputs in forms and detail views.
- Updated form and detail components to utilize the `LocationMap`, enhancing user experience by allowing map-based location selection.
- Added internationalization support for map-related labels in English and Indonesian.
- Developed unit tests for the `LocationMap` to ensure functionality and reliability.

This commit enhances the application by providing a user-friendly interface for managing geographical locations, improving data accuracy and user interaction.
2026-08-26 07:56:04 +07:00

55 lines
1.9 KiB
TypeScript

import { useEffect } from 'react';
import { CircleMarker, MapContainer, Polyline, TileLayer, Tooltip, useMap } from 'react-leaflet';
import { Box, Text } from '@mantine/core';
import type { RouteGeometry } from './route-geometry';
import { toLeafletLatLngs } from './route-geometry';
import { OSM_ATTRIBUTION, OSM_TILE_URL } from './osm';
import 'leaflet/dist/leaflet.css';
function FitRouteBounds({ positions }: { positions: Array<[number, number]> }) {
const map = useMap();
useEffect(() => {
if (positions.length === 0) return;
if (positions.length === 1) {
map.setView(positions[0], 14);
return;
}
map.fitBounds(positions, { padding: [24, 24] });
}, [map, positions]);
return null;
}
export interface RouteMapProps {
geometry?: RouteGeometry | null;
height?: number;
}
export function RouteMap({ geometry, height = 280 }: RouteMapProps) {
const positions = toLeafletLatLngs(geometry);
if (positions.length === 0) {
return (
<Box h={height} bdrs="md" bd="1px solid var(--mantine-color-default-border)" p="md">
<Text size="sm" c="dimmed">
No route geometry
</Text>
</Box>
);
}
return (
<Box h={height} bdrs="md" style={{ overflow: 'hidden' }}>
<MapContainer center={positions[0]} zoom={12} style={{ height: '100%', width: '100%' }} scrollWheelZoom>
<TileLayer attribution={OSM_ATTRIBUTION} url={OSM_TILE_URL} />
<Polyline positions={positions} pathOptions={{ color: 'var(--mantine-color-blue-6)', weight: 4 }} />
{positions.map((position, index) => (
<CircleMarker key={`${position[0]}-${position[1]}-${index}`} center={position} radius={8} pathOptions={{ color: 'var(--mantine-color-blue-8)' }}>
<Tooltip permanent>{index + 1}</Tooltip>
</CircleMarker>
))}
<FitRouteBounds positions={positions} />
</MapContainer>
</Box>
);
}