import * as React from 'react'; import { __ } from '@wordpress/i18n'; import type { CatalogApi } from './api'; type Place = { latitude: number; longitude: number; label: string; }; export function ClubLocationForm({ api }: { api: CatalogApi; }): React.ReactElement { const [address, setAddress] = React.useState(''), [resolvedAddress, setResolvedAddress] = React.useState(''); const [latitude, setLatitude] = React.useState(''), [longitude, setLongitude] = React.useState(''); const [places, setPlaces] = React.useState([]), [selected, setSelected] = React.useState(''); const [busy, setBusy] = React.useState(true), [error, setError] = React.useState(''), [notice, setNotice] = React.useState(''); React.useEffect(() => { let active = true; void api.location().then(location => { if (active) { setAddress(location.address ?? ''); setResolvedAddress(location.address ?? ''); setLatitude(String(location.latitude ?? '')); setLongitude(String(location.longitude ?? '')); } }) .catch(cause => { if (active) setError(cause instanceof Error ? cause.message : __('The request failed. Please try again.', 'abece-booking')); }) .finally(() => { if (active) setBusy(false); }); return () => { active = false; }; }, [api]); async function search(): Promise { setBusy(true); setError(''); setNotice(''); setPlaces([]); setSelected(''); try { const result = await api.searchLocation(address); setPlaces(result.results); if (!result.results.length) setNotice(__('No address found. Add the town and country, or enter coordinates manually.', 'abece-booking')); } catch (cause) { setError(cause instanceof Error ? cause.message : __('The request failed. Please try again.', 'abece-booking')); } finally { setBusy(false); } } function choose(place: Place): void { setLatitude(String(place.latitude)); setLongitude(String(place.longitude)); setResolvedAddress(address); setSelected(place.label); setPlaces([]); setNotice(__('Coordinates filled in. Check the location, then save.', 'abece-booking')); } function coordinate(value: string, limit: number): number | null { const text = value.trim(); if (!text) return null; const number = Number(text.replace(',', '.')); if (!/^[+-]?(?:\d+(?:[.,]\d*)?|[.,]\d+)$/.test(text) || !Number.isFinite(number) || Math.abs(number) > limit) throw new Error(__('Enter decimal coordinates within the stated ranges.', 'abece-booking')); return number; } async function save(event: React.FormEvent): Promise { event.preventDefault(); setBusy(true); setError(''); setNotice(''); try { await api.saveLocation({ address, latitude: coordinate(latitude, 90), longitude: coordinate(longitude, 180) }); setNotice(__('Changes saved.', 'abece-booking')); } catch (cause) { setError(cause instanceof Error ? cause.message : __('The request failed. Please try again.', 'abece-booking')); } finally { setBusy(false); } } const needsLookup = address.trim() !== '' && address !== resolvedAddress; return
{__('Club location', 'abece-booking')}

{__('Coordinates are used to calculate sunrise and sunset. Positive offsets mean later; negative offsets mean earlier.', 'abece-booking')}

{error &&

{error}

}{notice &&

{notice}

}
void save(event)}>
{ setAddress(event.target.value); setPlaces([]); setSelected(''); setNotice(''); }} aria-describedby="asb-location-search-help"/>

{__('Enter the venue street, town and country.', 'abece-booking')} {__('Only clicking Find location sends this address to OpenStreetMap/Nominatim. Enter public venue addresses only.', 'abece-booking')}

{places.length > 0 &&

{__('Choose the matching address', 'abece-booking')}

    {places.map((place, i) =>
  • )}
} {selected &&

{selected}

}

© OpenStreetMap contributors · {__('Address search service policy', 'abece-booking')}

{__('Enter coordinates manually', 'abece-booking')}

{__('Use decimal degrees, for example latitude 50.0755 and longitude 14.4378. A decimal comma is also accepted.', 'abece-booking')}

{ setLatitude(event.target.value); setResolvedAddress(address); }}/>−90 … 90
{ setLongitude(event.target.value); setResolvedAddress(address); }}/>−180 … 180
{needsLookup &&

{__('Choose an address search result or update the coordinates manually before saving.', 'abece-booking')}

}

; }