fix(ancpi): UAT debounce + list tooltips + expired download + ePay retry
1. UAT search: 150ms debounce prevents slow re-renders on keystroke 2. Lista mea tooltips: "Scoate Extrase CF" shows exact credit cost, status badges show expiry dates and clear instructions 3. Expired extracts: both Descarcă (old version) + Actualizează shown 4. ePay auto-connect: retry 2x with 3s delay, check session before connect, re-attempt on disconnect detection Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -621,27 +621,30 @@ export function ParcelSyncModule() {
|
||||
setUatResults([]);
|
||||
return;
|
||||
}
|
||||
const isDigit = /^\d+$/.test(raw);
|
||||
const query = normalizeText(raw);
|
||||
// Filter and sort: UAT name matches first, then county-only matches
|
||||
const nameMatches: typeof uatData = [];
|
||||
const countyOnlyMatches: typeof uatData = [];
|
||||
const timer = setTimeout(() => {
|
||||
const isDigit = /^\d+$/.test(raw);
|
||||
const query = normalizeText(raw);
|
||||
// Filter and sort: UAT name matches first, then county-only matches
|
||||
const nameMatches: typeof uatData = [];
|
||||
const countyOnlyMatches: typeof uatData = [];
|
||||
|
||||
for (const item of uatData) {
|
||||
if (isDigit) {
|
||||
if (item.siruta.startsWith(raw)) nameMatches.push(item);
|
||||
} else {
|
||||
const nameMatch = normalizeText(item.name).includes(query);
|
||||
const countyMatch =
|
||||
item.county && normalizeText(item.county).includes(query);
|
||||
if (nameMatch) nameMatches.push(item);
|
||||
else if (countyMatch) countyOnlyMatches.push(item);
|
||||
for (const item of uatData) {
|
||||
if (isDigit) {
|
||||
if (item.siruta.startsWith(raw)) nameMatches.push(item);
|
||||
} else {
|
||||
const nameMatch = normalizeText(item.name).includes(query);
|
||||
const countyMatch =
|
||||
item.county && normalizeText(item.county).includes(query);
|
||||
if (nameMatch) nameMatches.push(item);
|
||||
else if (countyMatch) countyOnlyMatches.push(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// UAT name matches first (priority), then county-only matches
|
||||
const results = [...nameMatches, ...countyOnlyMatches].slice(0, 12);
|
||||
setUatResults(results);
|
||||
// UAT name matches first (priority), then county-only matches
|
||||
const results = [...nameMatches, ...countyOnlyMatches].slice(0, 12);
|
||||
setUatResults(results);
|
||||
}, 150);
|
||||
return () => clearTimeout(timer);
|
||||
}, [uatQuery, uatData]);
|
||||
|
||||
/* ════════════════════════════════════════════════════════════ */
|
||||
@@ -2925,37 +2928,65 @@ export function ParcelSyncModule() {
|
||||
CSV din lista
|
||||
</Button>
|
||||
{/* Download all valid CF extracts as ZIP */}
|
||||
{searchList.some((p) => cfStatusMap[p.nrCad] === "valid") && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="border-emerald-200 text-emerald-700 dark:border-emerald-800 dark:text-emerald-400"
|
||||
disabled={listCfDownloading}
|
||||
onClick={() => void handleListCfDownloadZip()}
|
||||
>
|
||||
{listCfDownloading ? (
|
||||
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin" />
|
||||
) : (
|
||||
<Archive className="mr-1 h-3.5 w-3.5" />
|
||||
)}
|
||||
Descarca Extrase CF
|
||||
</Button>
|
||||
)}
|
||||
{searchList.some((p) => cfStatusMap[p.nrCad] === "valid") && (() => {
|
||||
const validCount = searchList.filter((p) => cfStatusMap[p.nrCad] === "valid").length;
|
||||
return (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="border-emerald-200 text-emerald-700 dark:border-emerald-800 dark:text-emerald-400"
|
||||
disabled={listCfDownloading}
|
||||
onClick={() => void handleListCfDownloadZip()}
|
||||
>
|
||||
{listCfDownloading ? (
|
||||
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin" />
|
||||
) : (
|
||||
<Archive className="mr-1 h-3.5 w-3.5" />
|
||||
)}
|
||||
Descarca Extrase CF
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{`Descarca ZIP cu ${validCount} extrase valide din lista`}</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
);
|
||||
})()}
|
||||
{/* Order CF extracts for list */}
|
||||
{epayStatus.connected && (
|
||||
<Button
|
||||
size="sm"
|
||||
disabled={listCfOrdering}
|
||||
onClick={() => void handleListCfOrder()}
|
||||
>
|
||||
{listCfOrdering ? (
|
||||
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin" />
|
||||
) : (
|
||||
<FileText className="mr-1 h-3.5 w-3.5" />
|
||||
)}
|
||||
Scoate Extrase CF
|
||||
</Button>
|
||||
)}
|
||||
{epayStatus.connected && (() => {
|
||||
const newCount = searchList.filter((p) => {
|
||||
const s = cfStatusMap[p.nrCad];
|
||||
return s !== "valid" && s !== "expired" && s !== "processing";
|
||||
}).length;
|
||||
const updateCount = searchList.filter((p) => cfStatusMap[p.nrCad] === "expired").length;
|
||||
const totalCredits = newCount + updateCount;
|
||||
const validCount = searchList.filter((p) => cfStatusMap[p.nrCad] === "valid").length;
|
||||
return (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
size="sm"
|
||||
disabled={listCfOrdering}
|
||||
onClick={() => void handleListCfOrder()}
|
||||
>
|
||||
{listCfOrdering ? (
|
||||
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin" />
|
||||
) : (
|
||||
<FileText className="mr-1 h-3.5 w-3.5" />
|
||||
)}
|
||||
Scoate Extrase CF
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{`Comanda ${newCount} extrase noi + ${updateCount} actualizari = ${totalCredits} credite. ${validCount} existente valide raman.`}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
);
|
||||
})()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2999,6 +3030,7 @@ export function ParcelSyncModule() {
|
||||
<tbody>
|
||||
{searchList.map((p, idx) => {
|
||||
const cfStatus = cfStatusMap[p.nrCad];
|
||||
const cfExpiry = cfExpiryDates[p.nrCad];
|
||||
return (
|
||||
<tr
|
||||
key={`list-${p.nrCad}-${p.immovablePk}`}
|
||||
@@ -3022,23 +3054,38 @@ export function ParcelSyncModule() {
|
||||
{p.proprietari || "\u2014"}
|
||||
</td>
|
||||
<td className="px-3 py-2 text-center">
|
||||
{cfStatus === "valid" ? (
|
||||
<span className="inline-flex items-center rounded-full border px-2 py-0.5 text-[10px] font-medium bg-emerald-100 text-emerald-700 border-emerald-200 dark:bg-emerald-950/40 dark:text-emerald-400 dark:border-emerald-800">
|
||||
Valid
|
||||
</span>
|
||||
) : cfStatus === "expired" ? (
|
||||
<span className="inline-flex items-center rounded-full border px-2 py-0.5 text-[10px] font-medium bg-orange-100 text-orange-700 border-orange-200 dark:bg-orange-950/40 dark:text-orange-400 dark:border-orange-800">
|
||||
Expirat
|
||||
</span>
|
||||
) : cfStatus === "processing" ? (
|
||||
<span className="inline-flex items-center rounded-full border px-2 py-0.5 text-[10px] font-medium bg-yellow-100 text-yellow-700 border-yellow-200 dark:bg-yellow-950/40 dark:text-yellow-400 dark:border-yellow-800 animate-pulse">
|
||||
Procesare
|
||||
</span>
|
||||
) : (
|
||||
<span className="inline-flex items-center rounded-full border px-2 py-0.5 text-[10px] font-medium bg-muted text-muted-foreground border-muted-foreground/20">
|
||||
Lipsa
|
||||
</span>
|
||||
)}
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
{cfStatus === "valid" ? (
|
||||
<span className="inline-flex items-center rounded-full border px-2 py-0.5 text-[10px] font-medium bg-emerald-100 text-emerald-700 border-emerald-200 dark:bg-emerald-950/40 dark:text-emerald-400 dark:border-emerald-800 cursor-default">
|
||||
Valid
|
||||
</span>
|
||||
) : cfStatus === "expired" ? (
|
||||
<span className="inline-flex items-center rounded-full border px-2 py-0.5 text-[10px] font-medium bg-orange-100 text-orange-700 border-orange-200 dark:bg-orange-950/40 dark:text-orange-400 dark:border-orange-800 cursor-default">
|
||||
Expirat
|
||||
</span>
|
||||
) : cfStatus === "processing" ? (
|
||||
<span className="inline-flex items-center rounded-full border px-2 py-0.5 text-[10px] font-medium bg-yellow-100 text-yellow-700 border-yellow-200 dark:bg-yellow-950/40 dark:text-yellow-400 dark:border-yellow-800 animate-pulse cursor-default">
|
||||
Procesare
|
||||
</span>
|
||||
) : (
|
||||
<span className="inline-flex items-center rounded-full border px-2 py-0.5 text-[10px] font-medium bg-muted text-muted-foreground border-muted-foreground/20 cursor-default">
|
||||
Lipsa
|
||||
</span>
|
||||
)}
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{cfStatus === "valid"
|
||||
? (cfExpiry ? `Extras CF valid pana la ${formatShortDate(cfExpiry)}` : "Extras CF valid")
|
||||
: cfStatus === "expired"
|
||||
? (cfExpiry ? `Extras CF expirat pe ${formatShortDate(cfExpiry)}. Va fi actualizat automat la 'Scoate Extrase CF'.` : "Extras CF expirat. Va fi actualizat automat la 'Scoate Extrase CF'.")
|
||||
: cfStatus === "processing"
|
||||
? "Comanda in curs de procesare"
|
||||
: "Nu exista extras CF. Apasa 'Scoate Extrase CF' pentru a comanda."}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</td>
|
||||
<td className="px-3 py-2">
|
||||
<Button
|
||||
|
||||
Reference in New Issue
Block a user