const AreaSearch = ({ value, district, province, postal, onChange }) => { const initLabel = [district, value, province].filter(Boolean).join(", "); const [step, setStep] = React.useState("province"); const [selProv, setSelProv] = React.useState(null); const [selCity, setSelCity] = React.useState(null); const [cities, setCities] = React.useState([]); const [districts, setDistricts] = React.useState([]); const [open, setOpen] = React.useState(false); const [loading, setLoading] = React.useState(false); const [filter, setFilter] = React.useState(""); const [picked, setPicked] = React.useState(!!value); const [label, setLabel] = React.useState(initLabel); const wrap = React.useRef(null); const [dropPos, setDropPos] = React.useState({ top:0, left:0, width:300 }); const calcPos = () => { if (!wrap.current) return; const rect = wrap.current.getBoundingClientRect(); setDropPos({ top: rect.bottom + 4, left: rect.left, width: rect.width }); }; const PROVINCES = [ {id:"11",name:"Aceh"},{id:"12",name:"Sumatera Utara"},{id:"13",name:"Sumatera Barat"}, {id:"14",name:"Riau"},{id:"15",name:"Jambi"},{id:"16",name:"Sumatera Selatan"}, {id:"17",name:"Bengkulu"},{id:"18",name:"Lampung"},{id:"19",name:"Kep. Bangka Belitung"}, {id:"21",name:"Kepulauan Riau"},{id:"31",name:"DKI Jakarta"},{id:"32",name:"Jawa Barat"}, {id:"33",name:"Jawa Tengah"},{id:"34",name:"DI Yogyakarta"},{id:"35",name:"Jawa Timur"}, {id:"36",name:"Banten"},{id:"51",name:"Bali"},{id:"52",name:"Nusa Tenggara Barat"}, {id:"53",name:"Nusa Tenggara Timur"},{id:"61",name:"Kalimantan Barat"},{id:"62",name:"Kalimantan Tengah"}, {id:"63",name:"Kalimantan Selatan"},{id:"64",name:"Kalimantan Timur"},{id:"65",name:"Kalimantan Utara"}, {id:"71",name:"Sulawesi Utara"},{id:"72",name:"Sulawesi Tengah"},{id:"73",name:"Sulawesi Selatan"}, {id:"74",name:"Sulawesi Tenggara"},{id:"75",name:"Gorontalo"},{id:"76",name:"Sulawesi Barat"}, {id:"81",name:"Maluku"},{id:"82",name:"Maluku Utara"},{id:"91",name:"Papua Barat"},{id:"94",name:"Papua"} ]; React.useEffect(() => { const h = (e) => { if (wrap.current && !wrap.current.contains(e.target)) setOpen(false); }; document.addEventListener("mousedown", h); return () => document.removeEventListener("mousedown", h); }, []); const go = async (url) => { const r = await fetch(url); return r.json(); }; const openDrop = () => { if (picked) return; calcPos(); setStep("province"); setFilter(""); setOpen(true); }; const pickProv = async (p) => { setSelProv(p); setStep("city"); setFilter(""); setLoading(true); try { setCities(await go(`api/wilayah.php?type=regencies&id=${p.id}`)); } catch { setCities([]); } setLoading(false); }; const pickCity = async (c) => { setSelCity(c); setStep("district"); setFilter(""); setLoading(true); try { setDistricts(await go(`api/wilayah.php?type=districts&id=${c.id}`)); } catch { setDistricts([]); } setLoading(false); }; const pickDist = async (d) => { // Langsung tutup dropdown & set picked dulu const lbl = `${d.name}, ${selCity.name}, ${selProv.name}`; setLabel(lbl); setPicked(true); setOpen(false); onChange(selCity.name, d.name, selProv.name, "", d.id); // Fetch kodepos di background try { const v = await Promise.race([ go(`api/wilayah.php?type=villages&id=${d.id}`), new Promise((_,rej) => setTimeout(() => rej("timeout"), 5000)) ]); if (Array.isArray(v) && v.length && v[0].postal_code) { onChange(selCity.name, d.name, selProv.name, String(v[0].postal_code), d.id); } } catch {} }; const clear = () => { setLabel(""); setPicked(false); setSelProv(null); setSelCity(null); setStep("province"); setFilter(""); onChange("","","","",""); }; const filtered = (list) => !filter ? list : list.filter(i => i.name.toLowerCase().includes(filter.toLowerCase())); const curList = step==="province" ? PROVINCES : step==="city" ? cities : districts; const titles = { province:"Pilih Provinsi", city:"Pilih Kota / Kabupaten", district:"Pilih Kecamatan" }; const holders = { province:"Cari provinsi...", city:"Cari kota/kabupaten...", district:"Cari kecamatan..." }; const inp = { width:"100%", padding:"11px 14px", border:picked?"1px solid #86efac":"1px solid #e0deda", background:picked?"#f0fdf4":"#fafaf8", fontFamily:"'DM Sans',sans-serif", fontSize:13, color:"#111", outline:"none", borderRadius:2, cursor:picked?"default":"pointer", boxSizing:"border-box" }; return (
{picked ? : }
{open && (
{selProv && {setStep("province");setFilter("");}} style={{ cursor:"pointer",color:"#888",textDecoration:"underline" }}>{selProv.name}} {selProv && } {selCity && {setStep("city");setFilter("");}} style={{ cursor:"pointer",color:"#888",textDecoration:"underline" }}>{selCity.name}} {selCity && } {titles[step]}
setFilter(e.target.value)} placeholder={holders[step]} style={{ width:"100%",padding:"8px 12px",border:"1px solid #e8e6e2",borderRadius:2,fontFamily:"'DM Sans',sans-serif",fontSize:12,color:"#111",outline:"none",boxSizing:"border-box" }} />
{loading &&

Memuat...

} {!loading && filtered(curList).length===0 &&

Tidak ditemukan

} {!loading && filtered(curList).map((item) => (
e.currentTarget.style.background="#f9f8f6"} onMouseLeave={e=>e.currentTarget.style.background="#fff"} onClick={()=>step==="province"?pickProv(item):step==="city"?pickCity(item):pickDist(item)}> {item.name}
))}
)}
); }; Object.assign(window, { AreaSearch });