'use client' import { useState, useEffect, useRef, type ReactNode } from 'react' type GeoData = Record> interface BarrioAutocompleteFieldProps { name: string label: ReactNode value: string required: boolean departamento?: string | null ciudad?: string | null onChange: (value: string) => void error?: string } export function BarrioAutocompleteField({ name, label, value, required, departamento, ciudad, onChange, error, }: BarrioAutocompleteFieldProps) { const [geoData, setGeoData] = useState(null) const [open, setOpen] = useState(false) const [activeIdx, setActiveIdx] = useState(-1) useEffect(() => { fetch('/data/geo_paraguay_full.json') .then((r) => r.json()) .then(setGeoData) .catch(() => {}) }, []) const barrios: string[] = (() => { if (!geoData) return [] if (departamento && ciudad) { return geoData[departamento]?.[ciudad] ?? [] } if (departamento) { return Object.values(geoData[departamento] ?? {}).flat() } return Object.values(geoData).flatMap((d) => Object.values(d).flat()) })() const query = value.trim().toLowerCase() const suggestions = query.length >= 2 ? barrios.filter((b) => b.toLowerCase().includes(query)).slice(0, 10) : [] function handleInput(v: string) { onChange(v) setOpen(true) setActiveIdx(-1) } function select(barrio: string) { onChange(barrio) setOpen(false) setActiveIdx(-1) } function handleKeyDown(e: React.KeyboardEvent) { if (!open || suggestions.length === 0) return if (e.key === 'ArrowDown') { e.preventDefault() setActiveIdx((i) => Math.min(i + 1, suggestions.length - 1)) } else if (e.key === 'ArrowUp') { e.preventDefault() setActiveIdx((i) => Math.max(i - 1, -1)) } else if (e.key === 'Enter' && activeIdx >= 0) { e.preventDefault() select(suggestions[activeIdx]) } else if (e.key === 'Escape') { setOpen(false) } } const listId = `${name}-suggestions` return (
0 ? listId : undefined} aria-activedescendant={activeIdx >= 0 ? `${name}-opt-${activeIdx}` : undefined} autoComplete="off" className="text-short-input" onChange={(e) => handleInput(e.target.value)} onKeyDown={handleKeyDown} onFocus={() => { if (suggestions.length > 0) setOpen(true) }} onBlur={() => setTimeout(() => setOpen(false), 150)} /> {open && suggestions.length > 0 && (
    {suggestions.map((barrio, i) => (
  • select(barrio)} > {barrio}
  • ))}
)}
{error && ( )}
) }