Skip to content

Commit

Permalink
refactor: don't need to actually use the initialcenter, just watch fo…
Browse files Browse the repository at this point in the history
…rm context value
  • Loading branch information
clintonlunn committed Sep 20, 2024
1 parent 13be01f commit cd78534
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ export const AreaLatLngForm: React.FC<{ initLat: number, initLng: number, uuid:
<div className='w-full h-100vh'>
<div className='h-[90vh] lg:h-[50vh] w-full'>
<CoordinatePickerMap
initialCenter={[initLng, initLat]}
onCoordinateConfirmed={() => {
setPickerSelected(false)
}}
Expand Down
61 changes: 21 additions & 40 deletions src/components/maps/CoordinatePickerMap.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -10,72 +10,47 @@ 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<CoordinatePickerMapProps> = ({
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<string>('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<string>(MAP_STYLES.light.style)
const triggerButtonRef = useRef<HTMLButtonElement>(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 })
}, 100)

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])
}
Expand All @@ -101,6 +76,13 @@ export const CoordinatePickerMap: React.FC<CoordinatePickerMapProps> = ({
}
}

// 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'
Expand All @@ -111,8 +93,8 @@ export const CoordinatePickerMap: React.FC<CoordinatePickerMapProps> = ({
id='coordinate-picker-map'
onLoad={onLoad}
initialViewState={{
longitude: initialCoordinates.lng,
latitude: initialCoordinates.lat,
longitude: center?.lng ?? 0,
latitude: center?.lat ?? 0,
zoom: initialZoom
}}
onDragStart={() => {
Expand All @@ -132,13 +114,12 @@ export const CoordinatePickerMap: React.FC<CoordinatePickerMapProps> = ({
{showFullscreenControl && <FullscreenControl />}
<GeolocateControl position='top-left' onGeolocate={handleGeolocate} />
<NavigationControl showCompass={false} position='bottom-right' />
{(dynamicInitialCenter != null) && (
<Marker longitude={initialCoordinates.lng} latitude={initialCoordinates.lat} anchor='bottom'>
{center != null && (
<Marker longitude={center.lng} latitude={center.lat} anchor='bottom'>
<MapPin size={36} weight='fill' className='text-accent' />
</Marker>
)}
{/* Show crosshair marker if the selected coordinates are different from the initial center */}
{(newSelectedCoord.lng !== dynamicInitialCenter?.[0] && newSelectedCoord.lat !== dynamicInitialCenter?.[1]) && (
{isNewCoord() && (
<Marker
longitude={newSelectedCoord.lng}
latitude={newSelectedCoord.lat}
Expand Down

0 comments on commit cd78534

Please sign in to comment.