diff --git a/src/app/(default)/editArea/[slug]/general/components/AreaLatLngForm.tsx b/src/app/(default)/editArea/[slug]/general/components/AreaLatLngForm.tsx index b0f9e0436..40a638e28 100644 --- a/src/app/(default)/editArea/[slug]/general/components/AreaLatLngForm.tsx +++ b/src/app/(default)/editArea/[slug]/general/components/AreaLatLngForm.tsx @@ -56,7 +56,6 @@ export const AreaLatLngForm: React.FC<{ initLat: number, initLng: number, uuid:
{ setPickerSelected(false) }} diff --git a/src/components/maps/CoordinatePickerMap.tsx b/src/components/maps/CoordinatePickerMap.tsx index 844d5b17b..ca93c6cfc 100644 --- a/src/components/maps/CoordinatePickerMap.tsx +++ b/src/components/maps/CoordinatePickerMap.tsx @@ -1,6 +1,6 @@ import React, { useCallback, useState, useRef, useEffect } from 'react' import { Map, FullscreenControl, ScaleControl, NavigationControl, Marker, GeolocateControl, GeolocateResultEvent } from 'react-map-gl/maplibre' -import maplibregl, { MapLibreEvent } from 'maplibre-gl' +import { MapLibreEvent } from 'maplibre-gl' import dynamic from 'next/dynamic' import { useDebouncedCallback } from 'use-debounce' import { MAP_STYLES, type MapStyles } from './MapSelector' @@ -10,64 +10,40 @@ import AlertDialog from '../ui/micro/AlertDialogue' import useResponsive from '@/js/hooks/useResponsive' import { MapPin, Crosshair } from '@phosphor-icons/react' -export interface CameraInfo { - center: { - lng: number - lat: number - } - zoom: number -} - interface CoordinatePickerMapProps { showFullscreenControl?: boolean - initialCenter?: [number, number] - initialViewState?: { - bounds: maplibregl.LngLatBoundsLike - fitBoundsOptions: maplibregl.FitBoundsOptions - } onCoordinateConfirmed?: (coordinates: [number, number] | null) => void name?: string } export const CoordinatePickerMap: React.FC = ({ - showFullscreenControl = true, initialCenter, onCoordinateConfirmed + showFullscreenControl = true, onCoordinateConfirmed }) => { const initialZoom = 14 const defaultCoords = { lng: 0, lat: 0 } const [newSelectedCoord, setNewSelectedCoord] = useState<{ lng: number, lat: number }>(defaultCoords) const [cursor, setCursor] = useState('default') - const [dynamicInitialCenter, setDynamicInitialCenter] = useState<[number, number] | null>(initialCenter ?? null) + const [center, setCenter] = useState<{ lat: number, lng: number } | null>(null) const { isMobile } = useResponsive() const [mapStyle, setMapStyle] = useState(MAP_STYLES.light.style) const triggerButtonRef = useRef(null) const { watch, setValue } = useFormContext() - // Use latlngStr from form context as it may differ from initialCenter if updated without page reload + // Watch the 'latlngStr' value from form context const watchedCoords = watch('latlngStr') as string - const initialCoordinates = dynamicInitialCenter != null - ? { lng: dynamicInitialCenter[0], lat: dynamicInitialCenter[1] } - : { lng: 0, lat: 0 } - useEffect(() => { if (watchedCoords != null) { const [lat, lng] = watchedCoords.split(',').map(Number) - - // Update dynamicInitialCenter if it's different from watchedCoords - if (dynamicInitialCenter == null || lat !== dynamicInitialCenter[1] || lng !== dynamicInitialCenter[0]) { - setDynamicInitialCenter([lng, lat]) - } - + setCenter({ lat, lng }) setNewSelectedCoord({ lat, lng }) } - }, [watchedCoords, dynamicInitialCenter]) + }, [watchedCoords]) const onLoad = useCallback((e: MapLibreEvent) => { - if (e.target == null) return - if (dynamicInitialCenter != null) { - e.target.jumpTo({ center: { lng: dynamicInitialCenter?.[0] ?? 0, lat: dynamicInitialCenter?.[1] ?? 0 }, zoom: initialZoom }) - } - }, [dynamicInitialCenter]) + if (e.target == null || center == null) return + e.target.jumpTo({ center: { lat: center.lat, lng: center.lng }, zoom: initialZoom }) + }, [center]) const updateCoordinates = useDebouncedCallback((lng, lat) => { setNewSelectedCoord({ lng, lat }) @@ -75,7 +51,6 @@ export const CoordinatePickerMap: React.FC = ({ const confirmSelection = (): void => { setValue('latlngStr', `${newSelectedCoord.lat?.toFixed(5) ?? 0},${newSelectedCoord.lng?.toFixed(5) ?? 0}`, { shouldDirty: true, shouldValidate: true }) - setDynamicInitialCenter([newSelectedCoord.lng, newSelectedCoord.lat]) if (onCoordinateConfirmed != null) { onCoordinateConfirmed([newSelectedCoord.lng ?? 0, newSelectedCoord.lat ?? 0]) } @@ -101,6 +76,13 @@ export const CoordinatePickerMap: React.FC = ({ } } + // Compare newSelectedCoord with watchedCoords to decide whether to show the crosshair + const isNewCoord = (): boolean => { + if (watchedCoords === null) return false + const [lat, lng] = watchedCoords.split(',').map(Number) + return !(newSelectedCoord.lat === lat && newSelectedCoord.lng === lng) + } + const anchorClass = isMobile ? 'fixed bottom-1/4 left-1/2 transform -translate-x-1/2' : 'fixed bottom-1/4 left-1/2 transform -translate-x-1/2' @@ -111,8 +93,8 @@ export const CoordinatePickerMap: React.FC = ({ id='coordinate-picker-map' onLoad={onLoad} initialViewState={{ - longitude: initialCoordinates.lng, - latitude: initialCoordinates.lat, + longitude: center?.lng ?? 0, + latitude: center?.lat ?? 0, zoom: initialZoom }} onDragStart={() => { @@ -132,13 +114,12 @@ export const CoordinatePickerMap: React.FC = ({ {showFullscreenControl && } - {(dynamicInitialCenter != null) && ( - + {center != null && ( + )} - {/* Show crosshair marker if the selected coordinates are different from the initial center */} - {(newSelectedCoord.lng !== dynamicInitialCenter?.[0] && newSelectedCoord.lat !== dynamicInitialCenter?.[1]) && ( + {isNewCoord() && (