teqo-backup/src/components/campaign/shared/useNearestMunicipalitySlug.ts
Cursor Agent 7e6bc9d984
B125 — nearest município first in search suggest + wizard
- Restore B117 home search: scopeMunicipalities, merge prefix, session prompt
- Shared useNearestMunicipalitySlug (B14 key) for busca geral + wizard
- Wizard merge uses geoSlug only — no Perto de você / km copy on rows
- Impl plan: docs/plans/municipio-geo-topo-sugestoes-busca-impl.md

Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>
2026-08-02 18:21:52 +00:00

82 lines
2.2 KiB
TypeScript

'use client'
import { useEffect, useRef, useState } from 'react'
import {
loadMunicipalityGeometryModule,
loadMunicipalityZoneGeometryModule,
} from '@/lib/bahiaGeometries'
import { resolveNearbyMunicipality, type AccessibleMunicipality } from '@/lib/municipalityProximity'
import {
hasPromptedThisSession,
markPromptedThisSession,
readGeolocationPermissionState,
requestCurrentPosition,
} from '@/utilities/campaignGeolocation'
/**
* B125 — nearest in-scope município slug for suggest surfaces (home search + wizard).
* Prompts once per tab session (B14 key) on first enable when permission is not denied.
* Fail-soft: every other outcome returns `null` with no error UI.
*/
export const useNearestMunicipalitySlug = (
accessible: readonly AccessibleMunicipality[],
enabled: boolean,
): string | null => {
const [nearestSlug, setNearestSlug] = useState<string | null>(null)
const autoStartedRef = useRef(false)
useEffect(() => {
if (!enabled || autoStartedRef.current || accessible.length === 0) return
autoStartedRef.current = true
let cancelled = false
const resolveNearest = async () => {
const loaded = await Promise.all([
requestCurrentPosition(),
loadMunicipalityGeometryModule(),
]).catch(() => null)
if (cancelled || !loaded) return
const [result, geometry] = loaded
if (!result.ok) return
const zoneModule = await loadMunicipalityZoneGeometryModule().catch(() => null)
const resolution = resolveNearbyMunicipality({
point: result.fix,
geometry,
zoneGeometry: zoneModule ?? undefined,
accessible,
})
if (cancelled || resolution.kind !== 'inScope') return
setNearestSlug(resolution.municipality.slug)
}
const start = async () => {
const permission = await readGeolocationPermissionState()
if (permission === 'granted') {
void resolveNearest()
return
}
if (permission !== 'denied' && !hasPromptedThisSession()) {
markPromptedThisSession()
void resolveNearest()
}
}
void start()
return () => {
cancelled = true
}
}, [accessible, enabled])
return nearestSlug
}