From 798b3e4f6b85c00c9eff0ac4d81597fd7e524e53 Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Thu, 26 Mar 2026 22:57:07 +0200 Subject: [PATCH] feat(wds): replace 3-field form with UAT autocomplete search Same search pattern as parcel-sync module: type name or SIRUTA code, pick from dropdown, city is added instantly. Already-queued cities are filtered out from results. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/app/(modules)/wds/page.tsx | 148 +++++++++++++++++++++------------ 1 file changed, 97 insertions(+), 51 deletions(-) diff --git a/src/app/(modules)/wds/page.tsx b/src/app/(modules)/wds/page.tsx index 7fad55d..49fcf58 100644 --- a/src/app/(modules)/wds/page.tsx +++ b/src/app/(modules)/wds/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState, useEffect, useCallback } from "react"; +import { useState, useEffect, useCallback, useDeferredValue, useRef } from "react"; import { Loader2, RefreshCw, @@ -12,6 +12,7 @@ import { XCircle, Clock, MapPin, + Search, } from "lucide-react"; import { Button } from "@/shared/components/ui/button"; import { Input } from "@/shared/components/ui/input"; @@ -72,10 +73,13 @@ export default function WeekendDeepSyncPage() { const [loading, setLoading] = useState(true); const [actionLoading, setActionLoading] = useState(false); - // Add city form - const [newSiruta, setNewSiruta] = useState(""); - const [newName, setNewName] = useState(""); - const [newCounty, setNewCounty] = useState(""); + // UAT autocomplete for adding cities + type UatEntry = { siruta: string; name: string; county?: string }; + const [uatData, setUatData] = useState([]); + const [uatQuery, setUatQuery] = useState(""); + const [uatResults, setUatResults] = useState([]); + const [showUatResults, setShowUatResults] = useState(false); + const uatRef = useRef(null); const fetchState = useCallback(async () => { try { @@ -90,8 +94,46 @@ export default function WeekendDeepSyncPage() { useEffect(() => { void fetchState(); + // Load UAT list for autocomplete + fetch("/api/eterra/uats") + .then((r) => r.json()) + .then((data: { uats?: UatEntry[] }) => { + if (data.uats) setUatData(data.uats); + }) + .catch(() => { + fetch("/uat.json") + .then((r) => r.json()) + .then((fallback: UatEntry[]) => setUatData(fallback)) + .catch(() => {}); + }); }, [fetchState]); + // UAT autocomplete filter + const normalizeText = (text: string) => + text.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().trim(); + + const deferredUatQuery = useDeferredValue(uatQuery); + useEffect(() => { + const raw = deferredUatQuery.trim(); + if (raw.length < 2) { setUatResults([]); return; } + const isDigit = /^\d+$/.test(raw); + const query = normalizeText(raw); + const nameMatches: UatEntry[] = []; + const countyOnly: UatEntry[] = []; + for (const item of uatData) { + // Skip cities already in queue + if (state?.cities.some((c) => c.siruta === item.siruta)) continue; + if (isDigit) { + if (item.siruta.startsWith(raw)) nameMatches.push(item); + } else { + if (normalizeText(item.name).includes(query)) nameMatches.push(item); + else if (item.county && normalizeText(item.county).includes(query)) + countyOnly.push(item); + } + } + setUatResults([...nameMatches, ...countyOnly].slice(0, 10)); + }, [deferredUatQuery, uatData, state?.cities]); + const doAction = async (body: Record) => { setActionLoading(true); try { @@ -107,18 +149,17 @@ export default function WeekendDeepSyncPage() { setActionLoading(false); }; - const handleAdd = async () => { - if (!newSiruta.trim() || !newName.trim()) return; + const handleAddUat = async (uat: UatEntry) => { await doAction({ action: "add", - siruta: newSiruta.trim(), - name: newName.trim(), - county: newCounty.trim(), + siruta: uat.siruta, + name: uat.name, + county: uat.county ?? "", priority: 3, }); - setNewSiruta(""); - setNewName(""); - setNewCounty(""); + setUatQuery(""); + setUatResults([]); + setShowUatResults(false); }; if (loading) { @@ -353,53 +394,58 @@ export default function WeekendDeepSyncPage() { })} - {/* Add city form */} + {/* Add city — UAT autocomplete */}

Adauga oras in coada

-
-
- +
+
+ setNewSiruta(e.target.value)} - className="w-28 h-8 text-sm" + placeholder="Cauta UAT — scrie nume sau cod SIRUTA..." + value={uatQuery} + onChange={(e) => { + setUatQuery(e.target.value); + setShowUatResults(true); + }} + onFocus={() => setShowUatResults(true)} + onBlur={() => setTimeout(() => setShowUatResults(false), 150)} + className="pl-9 h-9" + autoComplete="off" />
-
- - setNewName(e.target.value)} - className="h-8 text-sm" - /> -
-
- - setNewCounty(e.target.value)} - className="w-32 h-8 text-sm" - /> -
- + {showUatResults && uatResults.length > 0 && ( +
+ {uatResults.map((item) => ( + + ))} +
+ )}