Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions app/components/Map.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { useAtomValue, useAtom } from 'jotai'
import 'maplibre-gl/dist/maplibre-gl.css'
import { Map as MapGL } from 'react-map-gl/maplibre'
import { enableEditingAtom, mapStyleAtom, viewStateAtom } from '~/lib/mapStore'
import DrawControl from './drawControl'
import { TerminalsLayer } from './TerminalsLayer'
import { Popup } from 'react-map-gl/maplibre'
import { drawnFeaturesAtom } from '~/lib/mapStore'
import { useState, useEffect } from 'react'
import { useClient } from 'urql'
import { createTerminal } from '~/lib/graphql/mutations'
import centroid from '@turf/centroid'

export function Map() {
const mapStyle = useAtomValue(mapStyleAtom)
const viewState = useAtomValue(viewStateAtom)
const enableEditing = useAtomValue(enableEditingAtom)
const [drawnFeatures] = useAtom(drawnFeaturesAtom)
const [, setDrawnFeatures] = useAtom(drawnFeaturesAtom)

const [terminalName, setTerminalName] = useState('')
const [isSubmitting, setIsSubmitting] = useState(false)
const client = useClient()

const center = drawnFeatures ? centroid(drawnFeatures[0]?.geometry) : null

const handleCreate = async () => {
if (!terminalName.trim() || !drawnFeatures?.[0] || isSubmitting) return

setIsSubmitting(true)
try {
const feature = drawnFeatures[0]
const centerPoint = centroid(feature.geometry)

await client.mutation(createTerminal, {
name: terminalName.trim(),
longitude: centerPoint.geometry.coordinates[0],
latitude: centerPoint.geometry.coordinates[1],
geometry: feature.geometry
}).toPromise()

// Clear the drawn features and form after successful creation
setDrawnFeatures(null)
setTerminalName('')
} catch (error) {
console.error('Failed to create terminal:', error)
} finally {
setIsSubmitting(false)
}
}

const handleCancel = () => {
setDrawnFeatures(null)
setTerminalName('')
}

// Reset form when drawn features change
useEffect(() => {
if (!drawnFeatures) {
setTerminalName('')
}
}, [drawnFeatures])

return (
<MapGL initialViewState={viewState} mapStyle={mapStyle}>
{enableEditing ? <DrawControl /> : null}
<TerminalsLayer />
{drawnFeatures && center ? (
<Popup
longitude={center.geometry.coordinates[0]!}
latitude={center.geometry.coordinates[1]!}
anchor='top'
closeOnClick={false}
closeButton={false}
>
<div className='p-3 min-w-[250px]'>
<label className='block text-sm font-medium mb-2'>Terminal Name</label>
<input
type='text'
value={terminalName}
onChange={(e) => setTerminalName(e.target.value)}
placeholder='Enter terminal name'
className='w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent mb-3'
disabled={isSubmitting}
autoFocus
onKeyDown={(e) => {
if (e.key === 'Enter' && terminalName.trim()) {
handleCreate()
} else if (e.key === 'Escape') {
handleCancel()
}
}}
/>
<div className='flex gap-2'>
<button
type='button'
className='btn btn-primary flex-1'
onClick={handleCreate}
disabled={!terminalName.trim() || isSubmitting}
>
{isSubmitting ? 'Creating...' : 'Create'}
</button>
<button
type='button'
className='btn flex-1'
onClick={handleCancel}
disabled={isSubmitting}
>
Cancel
</button>
</div>
</div>
</Popup>
) : null}
</MapGL>
)
}