lgtm 2
Some checks failed
Build and publish Docker image / build-and-push (push) Failing after 2m43s
CI / Check (push) Failing after 3m7s

This commit is contained in:
Andras Schmelczer 2026-05-14 22:39:41 +01:00
parent a8de0a614d
commit 3fa95819e3
30 changed files with 907 additions and 205 deletions

View file

@ -22,6 +22,13 @@ export interface SearchedLocation {
focusAddress?: string;
}
interface PostcodeLookupResponse {
postcode: string;
latitude: number;
longitude: number;
geometry: PostcodeGeometry;
}
const ZOOM_FOR_TYPE: Record<string, number> = {
city: 10,
borough: 12,
@ -48,11 +55,15 @@ export default function LocationSearch({
onLocationSearched,
onCurrentLocationFound,
onMouseEnter,
className = '',
inputClassName,
}: {
onFlyTo: (lat: number, lng: number, zoom: number, options?: MapFlyToOptions) => void;
onLocationSearched?: (postcode: SearchedLocation | null) => void;
onCurrentLocationFound?: (lat: number, lng: number) => void;
onMouseEnter?: () => void;
className?: string;
inputClassName?: string;
}) {
const { t } = useTranslation();
const search = useLocationSearch();
@ -86,10 +97,37 @@ export default function LocationSearch({
async (result: SearchResult) => {
if (result.type === 'place') {
const zoom = ZOOM_FOR_TYPE[result.place_type] ?? 14;
setError(null);
setLoading(true);
search.close();
onFlyTo(result.lat, result.lon, zoom);
onLocationSearched?.(null);
search.clear();
if (isMobile) setExpanded(false);
try {
const params = new URLSearchParams({
lat: String(result.lat),
lng: String(result.lon),
log: 'false',
});
const res = await fetch(`/api/nearest-postcode?${params}`, authHeaders());
if (!res.ok) {
setError(t('locationSearch.lookupFailed'));
return;
}
const json: PostcodeLookupResponse = await res.json();
onLocationSearched?.({
postcode: json.postcode,
geometry: json.geometry,
latitude: json.latitude,
longitude: json.longitude,
markerLatitude: result.lat,
markerLongitude: result.lon,
});
search.clear();
if (isMobile) setExpanded(false);
} catch {
setError(t('locationSearch.lookupFailed'));
} finally {
setLoading(false);
}
return;
}
@ -106,12 +144,7 @@ export default function LocationSearch({
setError(t('locationSearch.postcodeNotFound'));
return;
}
const json: {
postcode: string;
latitude: number;
longitude: number;
geometry: PostcodeGeometry;
} = await res.json();
const json: PostcodeLookupResponse = await res.json();
onFlyTo(result.lat, result.lon, 17);
onLocationSearched?.({
postcode: json.postcode,
@ -143,12 +176,7 @@ export default function LocationSearch({
setError(t('locationSearch.postcodeNotFound'));
return;
}
const json: {
postcode: string;
latitude: number;
longitude: number;
geometry: PostcodeGeometry;
} = await res.json();
const json: PostcodeLookupResponse = await res.json();
onFlyTo(json.latitude, json.longitude, POSTCODE_SEARCH_ZOOM);
onLocationSearched?.({
postcode: json.postcode,
@ -237,7 +265,7 @@ export default function LocationSearch({
<div
ref={containerRef}
data-tutorial="search"
className="flex flex-col pointer-events-auto"
className={`flex flex-col pointer-events-auto ${className}`}
onMouseEnter={onMouseEnter}
>
<div className="flex items-center shadow-lg rounded bg-white dark:bg-warm-800">
@ -248,7 +276,10 @@ export default function LocationSearch({
loading={loading}
placeholder={t('locationSearch.placeholder')}
size="sm"
inputClassName="px-2 py-2 text-sm w-56 border-none outline-none bg-transparent text-warm-700 dark:text-warm-200 placeholder-warm-400 dark:placeholder-warm-500"
inputClassName={
inputClassName ??
'px-2 py-2 text-sm w-56 border-none outline-none bg-transparent text-warm-700 dark:text-warm-200 placeholder-warm-400 dark:placeholder-warm-500'
}
inputRef={inputRef}
onInputChange={() => setError(null)}
/>