Files
points-of-interest/client/src/hooks/useUserLocation.ts
T
2025-10-10 14:55:36 +02:00

89 lines
2.3 KiB
TypeScript

import { useCallback, useEffect, useRef, useState } from 'react'
import type { Point } from '@/types/api'
function geolocationErrorMessage(error: GeolocationPositionError): string {
switch (error.code) {
case error.PERMISSION_DENIED:
return 'location.error.permissionDenied'
case error.POSITION_UNAVAILABLE:
return 'location.error.unavailable'
case error.TIMEOUT:
return 'location.error.timeout'
default:
return 'location.error.generic'
}
}
export function useUserLocation() {
const [location, setLocation] = useState<Point | null>(null)
const [error, setError] = useState<string | null>(null)
const [isRequesting, setIsRequesting] = useState<boolean>(false)
const watchIdRef = useRef<number | null>(null)
const clearWatch = useCallback(() => {
if (typeof navigator === 'undefined' || !navigator.geolocation) {
return
}
if (watchIdRef.current !== null) {
navigator.geolocation.clearWatch(watchIdRef.current)
watchIdRef.current = null
}
}, [])
const start = useCallback(() => {
if (typeof navigator === 'undefined' || !navigator.geolocation) {
setError('location.error.unsupported')
setIsRequesting(false)
return
}
clearWatch()
setIsRequesting(true)
setError(null)
navigator.geolocation.getCurrentPosition(
(position) => {
setLocation({ lat: position.coords.latitude, lng: position.coords.longitude })
setIsRequesting(false)
setError(null)
},
(geoError) => {
setError(geolocationErrorMessage(geoError))
setIsRequesting(false)
},
{ enableHighAccuracy: true, timeout: 10000 },
)
const watchId = navigator.geolocation.watchPosition(
(position) => {
setLocation({ lat: position.coords.latitude, lng: position.coords.longitude })
setError(null)
setIsRequesting(false)
},
(geoError) => {
setError(geolocationErrorMessage(geoError))
setIsRequesting(false)
},
{ enableHighAccuracy: true, maximumAge: 15000, timeout: 10000 },
)
watchIdRef.current = watchId
}, [clearWatch])
useEffect(() => {
start()
return () => {
clearWatch()
}
}, [clearWatch, start])
return {
location,
error,
isRequesting,
refresh: start,
}
}