import { useCallback, useEffect, useRef, useState } from "react"; import type { EventGpsCoordinate } from "./event-location-coordinate"; export type EventLocationAddressResolver = (coordinate: EventGpsCoordinate, signal: AbortSignal) => Promise; export type EventLocationAddressLookup = { pending: boolean; error: string | null; changeLocation: (value: string) => void; retry: () => void; }; export function useEventLocationAddress({ active = true, coordinate, resolveAddress, onChange }: { active?: boolean; coordinate: EventGpsCoordinate | null; resolveAddress: EventLocationAddressResolver; onChange: (value: string) => void; }): EventLocationAddressLookup { const [pending, setPending] = useState(false); const [error, setError] = useState(null); const [retryGeneration, setRetryGeneration] = useState(0); const requestRef = useRef(null); const longitude = coordinate?.[0]; const latitude = coordinate?.[1]; useEffect(() => { setError(null); if (!active || longitude === undefined || latitude === undefined) { setPending(false); return; } const controller = new AbortController(); requestRef.current = controller; setPending(true); onChange(""); // Coalesce keyboard adjustments. GPS stays immediate while only the final // point is reverse-geocoded; a former point's address must never be reused. const timer = window.setTimeout(async () => { if (controller.signal.aborted) return; try { const address = await resolveAddress([longitude, latitude], controller.signal); if (!controller.signal.aborted) onChange(address); } catch (failure) { if (!controller.signal.aborted) { setError(failure instanceof Error ? failure.message : "地址查询失败,请重试或手动填写"); } } finally { if (!controller.signal.aborted) setPending(false); } }, 250); return () => { window.clearTimeout(timer); controller.abort(); if (requestRef.current === controller) requestRef.current = null; }; }, [active, longitude, latitude, resolveAddress, onChange, retryGeneration]); const changeLocation = useCallback((value: string) => { requestRef.current?.abort(); setPending(false); setError(null); onChange(value); }, [onChange]); return { pending, error, changeLocation, retry: () => setRetryGeneration((current) => current + 1) }; }