"use client"; import { useState } from "react"; import { useWatch, type UseFormReturn } from "react-hook-form"; import { MapPin } from "lucide-react"; import { parseCoordinatePair } from "@/lib/validations/coordinates"; import type { ContactInput } from "@/lib/validations/contact"; import { MapField } from "@/components/map/map-field"; import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; const COORDINATE_HINT = "Paste a “27.8506, 34.3136” pair into either field to fill both, or place the contact on the map."; const COORDINATES = [ { name: "latitude", label: "Latitude", placeholder: "e.g. 27.8506" }, { name: "longitude", label: "Longitude", placeholder: "e.g. 34.3136" }, ] as const; interface ContactPositionFieldProps { form: UseFormReturn; } /** * Where a contact is: the latitude and longitude inputs, and the map the dive * site form shows, drawn only once the diver asks for it. * * Not on open, because a map on screen has the browser fetch tiles from the * basemap host, and this dialog opens from the dive, course, certification, * service-record and trip forms as well - a diver adding a dive center from a * dive would contact that host without having asked for a map. `/privacy` §4.4 * says the same. The state needs no reset: the dialog's content unmounts when * it closes, so every opening starts with the map closed. * * No geocoding: the address is not looked up into a pin, nor a pin into an * address, so this field reaches no host until the map is drawn. */ export function ContactPositionField({ form }: ContactPositionFieldProps) { const [mapOpen, setMapOpen] = useState(false); const [latitude, longitude] = useWatch({ control: form.control, name: ["latitude", "longitude"], }); // The map and the paste write into the two inputs rather than holding a // position of their own. `shouldValidate` because a whole pair clears the // both-or-neither message. const setPosition = (position: { latitude: string; longitude: string }) => { const options = { shouldValidate: true, shouldDirty: true }; form.setValue("latitude", position.latitude, options); form.setValue("longitude", position.longitude, options); }; const handleCoordinatePaste = ( event: React.ClipboardEvent, ) => { const pair = parseCoordinatePair(event.clipboardData.getData("text")); if (!pair) return; event.preventDefault(); setPosition(pair); }; return (
{/* No `inputMode="decimal"`, for the dive site form's reason: iOS's keypad for it has no minus key. */}
{COORDINATES.map((coordinate) => ( ( {coordinate.label} } /> {/* Announced with each input and shown once below the pair - the dive site form's arrangement, for its reason. */} {COORDINATE_HINT} )} /> ))}

{COORDINATE_HINT}

{mapOpen ? ( ) : ( )}
); }