utopia-ui/lib/src/Components/Map/hooks/useReverseGeocode.ts

110 lines
2.8 KiB
TypeScript

/* eslint-disable @typescript-eslint/restrict-template-expressions */
import { useState, useEffect } from 'react'
interface GeocodeResult {
street?: string
housenumber?: string
postcode?: string
city?: string
town?: string
village?: string
district?: string
suburb?: string
neighbourhood?: string
state?: string
country?: string
}
interface GeocodeFeature {
properties: GeocodeResult
}
interface GeocodeResponse {
features?: GeocodeFeature[]
}
export function useReverseGeocode(
coordinates?: [number, number] | null,
enabled = true,
accuracy: 'municipality' | 'street' | 'house_number' = 'municipality',
) {
const [address, setAddress] = useState('')
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
if (!enabled || !coordinates) {
setAddress('')
return
}
const [longitude, latitude] = coordinates
if (!Number.isFinite(latitude) || !Number.isFinite(longitude)) {
return
}
const reverseGeocode = async () => {
setLoading(true)
setError(null)
try {
const response = await fetch(
`https://photon.komoot.io/reverse?lat=${latitude}&lon=${longitude}&lang=de&limit=1`,
)
if (!response.ok) {
throw new Error('Geocoding request failed')
}
const data = (await response.json()) as GeocodeResponse
if (data.features && data.features.length > 0) {
const props = data.features[0].properties
const municipality = props.city ?? props.town ?? props.village
let addressString = ''
switch (accuracy) {
case 'municipality':
addressString = municipality ?? ''
break
case 'street':
if (props.street && municipality) {
addressString = `${props.street}, ${municipality}`
} else {
addressString = municipality ?? ''
}
break
case 'house_number':
if (props.street && props.housenumber && municipality) {
addressString = `${props.street} ${props.housenumber}, ${municipality}`
} else if (props.street && municipality) {
addressString = `${props.street}, ${municipality}`
} else {
addressString = municipality ?? ''
}
break
}
setAddress(addressString)
} else {
setAddress('')
}
} catch (err) {
if (err instanceof Error) {
setError(err.message)
setAddress('')
} else {
throw err
}
} finally {
setLoading(false)
}
}
void reverseGeocode()
}, [coordinates, enabled, accuracy])
return { address, loading, error }
}