refactor(parcel-sync): global UAT bar, connection pill, reorder tabs
- UAT autocomplete always visible above tabs (all tabs share it) - Connection status pill in top-right: breathing green dot when connected, dropdown with credentials form / disconnect button - Tab order: Cautare Parcele (1st) -> Catalog Layere -> Export (last) - Renamed 'Butonul Magic' to just 'Magic' - Removed connection/UAT cards from inside Export tab
This commit is contained in:
@@ -35,8 +35,7 @@ const validate = (body: ExportBundleRequest) => {
|
||||
return { username, password, siruta, jobId, mode };
|
||||
};
|
||||
|
||||
const sleep = (ms: number) =>
|
||||
new Promise((resolve) => setTimeout(resolve, ms));
|
||||
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
const scheduleClear = (jobId?: string) => {
|
||||
if (!jobId) return;
|
||||
@@ -112,11 +111,7 @@ export async function POST(req: Request) {
|
||||
pushProgress();
|
||||
};
|
||||
|
||||
const setPhaseState = (
|
||||
next: string,
|
||||
weight: number,
|
||||
nextTotal?: number,
|
||||
) => {
|
||||
const setPhaseState = (next: string, weight: number, nextTotal?: number) => {
|
||||
phase = next;
|
||||
currentWeight = weight;
|
||||
phaseTotal = nextTotal;
|
||||
@@ -145,7 +140,7 @@ export async function POST(req: Request) {
|
||||
updateOverall(0);
|
||||
};
|
||||
|
||||
const withHeartbeat = async <T,>(task: () => Promise<T>) => {
|
||||
const withHeartbeat = async <T>(task: () => Promise<T>) => {
|
||||
let tick = 0.1;
|
||||
updatePhaseProgress(tick, 1);
|
||||
const interval = setInterval(() => {
|
||||
@@ -284,7 +279,7 @@ export async function POST(req: Request) {
|
||||
|
||||
let lastRequest = 0;
|
||||
const minInterval = 250;
|
||||
const throttled = async <T,>(fn: () => Promise<T>) => {
|
||||
const throttled = async <T>(fn: () => Promise<T>) => {
|
||||
let attempt = 0;
|
||||
while (true) {
|
||||
const now = Date.now();
|
||||
@@ -330,7 +325,11 @@ export async function POST(req: Request) {
|
||||
|
||||
const normalizeIntravilan = (values: string[]) => {
|
||||
const normalized = values
|
||||
.map((v) => String(v ?? "").trim().toLowerCase())
|
||||
.map((v) =>
|
||||
String(v ?? "")
|
||||
.trim()
|
||||
.toLowerCase(),
|
||||
)
|
||||
.filter(Boolean);
|
||||
const unique = new Set(normalized);
|
||||
if (!unique.size) return "-";
|
||||
@@ -359,8 +358,7 @@ export async function POST(req: Request) {
|
||||
const address = item?.immovableAddresses?.[0]?.address ?? null;
|
||||
if (!address) return "-";
|
||||
const parts: string[] = [];
|
||||
if (address.addressDescription)
|
||||
parts.push(address.addressDescription);
|
||||
if (address.addressDescription) parts.push(address.addressDescription);
|
||||
if (address.street) parts.push(`Str. ${address.street}`);
|
||||
if (address.buildingNo) parts.push(`Nr. ${address.buildingNo}`);
|
||||
if (address.locality?.name) parts.push(address.locality.name);
|
||||
@@ -368,18 +366,12 @@ export async function POST(req: Request) {
|
||||
};
|
||||
|
||||
/* Building cross-ref map */
|
||||
const buildingMap = new Map<
|
||||
string,
|
||||
{ has: boolean; legal: boolean }
|
||||
>();
|
||||
const buildingMap = new Map<string, { has: boolean; legal: boolean }>();
|
||||
for (const feature of cladiriFeatures) {
|
||||
const attrs = feature.attributes ?? {};
|
||||
const immovableId =
|
||||
attrs.IMMOVABLE_ID ?? attrs.IMOVABLE_ID ?? null;
|
||||
const immovableId = attrs.IMMOVABLE_ID ?? attrs.IMOVABLE_ID ?? null;
|
||||
const workspaceId = attrs.WORKSPACE_ID ?? null;
|
||||
const baseRef = baseCadRef(
|
||||
attrs.NATIONAL_CADASTRAL_REFERENCE ?? "",
|
||||
);
|
||||
const baseRef = baseCadRef(attrs.NATIONAL_CADASTRAL_REFERENCE ?? "");
|
||||
const isLegal =
|
||||
Number(attrs.IS_LEGAL ?? 0) === 1 ||
|
||||
String(attrs.IS_LEGAL ?? "").toLowerCase() === "true";
|
||||
@@ -408,8 +400,7 @@ export async function POST(req: Request) {
|
||||
|
||||
const addOwner = (landbook: string, name: string) => {
|
||||
if (!landbook || !name) return;
|
||||
const existing =
|
||||
ownersByLandbook.get(landbook) ?? new Set<string>();
|
||||
const existing = ownersByLandbook.get(landbook) ?? new Set<string>();
|
||||
existing.add(name);
|
||||
ownersByLandbook.set(landbook, existing);
|
||||
};
|
||||
@@ -444,9 +435,7 @@ export async function POST(req: Request) {
|
||||
(listResponse?.content ?? []).forEach((item: any) => {
|
||||
const idKey = normalizeId(item?.immovablePk);
|
||||
if (idKey) immovableListById.set(idKey, item);
|
||||
const cadKey = normalizeCadRef(
|
||||
item?.identifierDetails ?? "",
|
||||
);
|
||||
const cadKey = normalizeCadRef(item?.identifierDetails ?? "");
|
||||
if (cadKey) immovableListByCad.set(cadKey, item);
|
||||
});
|
||||
listPage += 1;
|
||||
@@ -499,10 +488,7 @@ export async function POST(req: Request) {
|
||||
];
|
||||
csvRows.push(headers.join(","));
|
||||
|
||||
const detailsByObjectId = new Map<
|
||||
string,
|
||||
Record<string, unknown>
|
||||
>();
|
||||
const detailsByObjectId = new Map<string, Record<string, unknown>>();
|
||||
|
||||
for (let index = 0; index < terenuriFeatures.length; index += 1) {
|
||||
const feature = terenuriFeatures[index]!;
|
||||
@@ -533,15 +519,11 @@ export async function POST(req: Request) {
|
||||
);
|
||||
immAppsCache.set(appKey, apps);
|
||||
}
|
||||
const chosen = pickApplication(
|
||||
apps,
|
||||
Number(applicationId ?? 0),
|
||||
);
|
||||
const chosen = pickApplication(apps, Number(applicationId ?? 0));
|
||||
const appId =
|
||||
chosen?.applicationId ??
|
||||
(applicationId ? Number(applicationId) : null);
|
||||
solicitant =
|
||||
chosen?.solicitant ?? chosen?.deponent ?? solicitant;
|
||||
solicitant = chosen?.solicitant ?? chosen?.deponent ?? solicitant;
|
||||
|
||||
if (appId) {
|
||||
const folKey = `${workspaceId}:${immovableId}:${appId}`;
|
||||
@@ -563,8 +545,7 @@ export async function POST(req: Request) {
|
||||
}
|
||||
}
|
||||
|
||||
const cadRefRaw = (attrs.NATIONAL_CADASTRAL_REFERENCE ??
|
||||
"") as string;
|
||||
const cadRefRaw = (attrs.NATIONAL_CADASTRAL_REFERENCE ?? "") as string;
|
||||
const cadRef = normalizeCadRef(cadRefRaw);
|
||||
const immKey = normalizeId(immovableId);
|
||||
const listItem =
|
||||
@@ -573,51 +554,37 @@ export async function POST(req: Request) {
|
||||
const docKey = listItem?.immovablePk
|
||||
? normalizeId(listItem.immovablePk)
|
||||
: "";
|
||||
const docItem = docKey
|
||||
? docByImmovable.get(docKey)
|
||||
: undefined;
|
||||
const docItem = docKey ? docByImmovable.get(docKey) : undefined;
|
||||
const landbookIE = docItem?.landbookIE ?? "";
|
||||
const owners =
|
||||
landbookIE && ownersByLandbook.get(String(landbookIE))
|
||||
? Array.from(
|
||||
ownersByLandbook.get(String(landbookIE)) ?? [],
|
||||
)
|
||||
? Array.from(ownersByLandbook.get(String(landbookIE)) ?? [])
|
||||
: [];
|
||||
const ownersByCad =
|
||||
cadRefRaw && ownersByLandbook.get(String(cadRefRaw))
|
||||
? Array.from(
|
||||
ownersByLandbook.get(String(cadRefRaw)) ?? [],
|
||||
)
|
||||
? Array.from(ownersByLandbook.get(String(cadRefRaw)) ?? [])
|
||||
: [];
|
||||
proprietari =
|
||||
Array.from(new Set([...owners, ...ownersByCad])).join(
|
||||
"; ",
|
||||
) || proprietari;
|
||||
Array.from(new Set([...owners, ...ownersByCad])).join("; ") ||
|
||||
proprietari;
|
||||
|
||||
nrCF =
|
||||
docItem?.landbookIE ||
|
||||
listItem?.paperLbNo ||
|
||||
listItem?.paperCadNo ||
|
||||
nrCF;
|
||||
const nrCFVechiRaw =
|
||||
listItem?.paperLbNo || listItem?.paperCadNo || "";
|
||||
const nrCFVechiRaw = listItem?.paperLbNo || listItem?.paperCadNo || "";
|
||||
nrCFVechi =
|
||||
docItem?.landbookIE && nrCFVechiRaw !== nrCF
|
||||
? nrCFVechiRaw
|
||||
: nrCFVechi;
|
||||
nrTopo =
|
||||
listItem?.topNo ||
|
||||
docItem?.topNo ||
|
||||
listItem?.paperCadNo ||
|
||||
nrTopo;
|
||||
addressText = listItem
|
||||
? formatAddress(listItem)
|
||||
: addressText;
|
||||
listItem?.topNo || docItem?.topNo || listItem?.paperCadNo || nrTopo;
|
||||
addressText = listItem ? formatAddress(listItem) : addressText;
|
||||
|
||||
const parcelRef = baseCadRef(cadRefRaw);
|
||||
const wKey = makeWorkspaceKey(workspaceId, immovableId);
|
||||
const build =
|
||||
(immKey ? buildingMap.get(immKey) : undefined) ??
|
||||
const build = (immKey ? buildingMap.get(immKey) : undefined) ??
|
||||
(wKey ? buildingMap.get(wKey) : undefined) ??
|
||||
(parcelRef ? buildingMap.get(parcelRef) : undefined) ?? {
|
||||
has: false,
|
||||
@@ -637,10 +604,8 @@ export async function POST(req: Request) {
|
||||
NR_TOPO: nrTopo,
|
||||
ADRESA: addressText,
|
||||
PROPRIETARI: proprietari,
|
||||
SUPRAFATA_2D:
|
||||
areaValue !== null ? Number(areaValue.toFixed(2)) : "",
|
||||
SUPRAFATA_R:
|
||||
areaValue !== null ? Math.round(areaValue) : "",
|
||||
SUPRAFATA_2D: areaValue !== null ? Number(areaValue.toFixed(2)) : "",
|
||||
SUPRAFATA_R: areaValue !== null ? Math.round(areaValue) : "",
|
||||
SOLICITANT: solicitant,
|
||||
INTRAVILAN: intravilan,
|
||||
CATEGORIE_FOLOSINTA: categorie,
|
||||
@@ -671,8 +636,7 @@ export async function POST(req: Request) {
|
||||
];
|
||||
csvRows.push(row.join(","));
|
||||
|
||||
if (index % 10 === 0)
|
||||
updatePhaseProgress(index + 1, terenuriCount);
|
||||
if (index % 10 === 0) updatePhaseProgress(index + 1, terenuriCount);
|
||||
}
|
||||
|
||||
updatePhaseProgress(terenuriFeatures.length, terenuriCount);
|
||||
@@ -737,9 +701,7 @@ export async function POST(req: Request) {
|
||||
]),
|
||||
);
|
||||
const magicFeatures = terenuriGeo.features.map((feature) => {
|
||||
const objectId = String(
|
||||
feature.properties?.OBJECTID ?? "",
|
||||
);
|
||||
const objectId = String(feature.properties?.OBJECTID ?? "");
|
||||
const extra = detailsByObjectId.get(objectId) ?? {};
|
||||
return {
|
||||
...feature,
|
||||
@@ -870,9 +832,7 @@ export async function POST(req: Request) {
|
||||
scheduleClear(jobId);
|
||||
const lower = errMessage.toLowerCase();
|
||||
const statusCode =
|
||||
lower.includes("login failed") || lower.includes("session")
|
||||
? 401
|
||||
: 400;
|
||||
lower.includes("login failed") || lower.includes("session") ? 401 : 400;
|
||||
return new Response(JSON.stringify({ error: errMessage }), {
|
||||
status: statusCode,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
|
||||
@@ -75,11 +75,7 @@ export async function POST(req: Request) {
|
||||
pushProgress();
|
||||
};
|
||||
|
||||
const setPhaseState = (
|
||||
next: string,
|
||||
weight: number,
|
||||
nextTotal?: number,
|
||||
) => {
|
||||
const setPhaseState = (next: string, weight: number, nextTotal?: number) => {
|
||||
phase = next;
|
||||
currentWeight = weight;
|
||||
phaseTotal = nextTotal;
|
||||
@@ -108,7 +104,7 @@ export async function POST(req: Request) {
|
||||
updateOverall(0);
|
||||
};
|
||||
|
||||
const withHeartbeat = async <T,>(task: () => Promise<T>) => {
|
||||
const withHeartbeat = async <T>(task: () => Promise<T>) => {
|
||||
let tick = 0.1;
|
||||
updatePhaseProgress(tick, 1);
|
||||
const interval = setInterval(() => {
|
||||
@@ -161,8 +157,7 @@ export async function POST(req: Request) {
|
||||
count = await client.countLayer(layer, validated.siruta);
|
||||
}
|
||||
} catch (error) {
|
||||
const msg =
|
||||
error instanceof Error ? error.message : "Count error";
|
||||
const msg = error instanceof Error ? error.message : "Count error";
|
||||
if (!msg.toLowerCase().includes("count unavailable")) throw error;
|
||||
}
|
||||
updatePhaseProgress(2, 2);
|
||||
@@ -187,9 +182,7 @@ export async function POST(req: Request) {
|
||||
onProgress: (value, totalCount) => {
|
||||
updatePhaseProgress(
|
||||
value,
|
||||
typeof totalCount === "number"
|
||||
? totalCount
|
||||
: value + pageSize,
|
||||
typeof totalCount === "number" ? totalCount : value + pageSize,
|
||||
);
|
||||
},
|
||||
})
|
||||
@@ -200,16 +193,11 @@ export async function POST(req: Request) {
|
||||
onProgress: (value, totalCount) => {
|
||||
updatePhaseProgress(
|
||||
value,
|
||||
typeof totalCount === "number"
|
||||
? totalCount
|
||||
: value + pageSize,
|
||||
typeof totalCount === "number" ? totalCount : value + pageSize,
|
||||
);
|
||||
},
|
||||
});
|
||||
updatePhaseProgress(
|
||||
features.length,
|
||||
count ?? features.length,
|
||||
);
|
||||
updatePhaseProgress(features.length, count ?? features.length);
|
||||
finishPhase();
|
||||
|
||||
/* Fields */
|
||||
@@ -274,9 +262,7 @@ export async function POST(req: Request) {
|
||||
scheduleClear(jobId);
|
||||
const lower = errMessage.toLowerCase();
|
||||
const statusCode =
|
||||
lower.includes("login failed") || lower.includes("session")
|
||||
? 401
|
||||
: 400;
|
||||
lower.includes("login failed") || lower.includes("session") ? 401 : 400;
|
||||
return new Response(JSON.stringify({ error: errMessage }), {
|
||||
status: statusCode,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
|
||||
Reference in New Issue
Block a user