fix people
This commit is contained in:
65
web/app.js
65
web/app.js
@@ -51,6 +51,19 @@ const esc = (value) =>
|
||||
"'": "'",
|
||||
})[char]);
|
||||
|
||||
// Normalized person key from the vision-extracted buyer name: lowercase,
|
||||
// punctuation stripped, name tokens sorted so "Zahoor Bilal" and
|
||||
// "Bilal Zahoor" compare equal.
|
||||
function personKey(group) {
|
||||
const name = group.docs.map((d) => d.prospective_buyer).find((v) =>
|
||||
typeof v === "string" && v.trim()
|
||||
);
|
||||
if (!name) return null;
|
||||
const tokens = name.toLocaleLowerCase().replace(/[^\p{L}\p{N}]+/gu, " ")
|
||||
.trim().split(/\s+/).filter(Boolean).sort();
|
||||
return tokens.length ? tokens.join(" ") : null;
|
||||
}
|
||||
|
||||
function buildGroups(docs) {
|
||||
const map = new Map();
|
||||
docs.forEach((doc, index) => {
|
||||
@@ -71,7 +84,33 @@ function buildGroups(docs) {
|
||||
].filter(Boolean).join(" ");
|
||||
map.set(key, group);
|
||||
});
|
||||
return [...map.values()].sort((a, b) => a.key.localeCompare(b.key));
|
||||
|
||||
// Second pass: merge filename-based groups that refer to the same person
|
||||
// according to the extracted prospective_buyer. This catches typos in the
|
||||
// scan filenames (e.g. "Zaboor, Bilal" vs "Zahoor, Bilal") which would
|
||||
// otherwise show the same buyer twice. Groups without a prospective_buyer
|
||||
// are never merged.
|
||||
const byPerson = new Map();
|
||||
const merged = [];
|
||||
for (const group of map.values()) {
|
||||
const pKey = personKey(group);
|
||||
const target = pKey ? byPerson.get(pKey) : undefined;
|
||||
if (target) {
|
||||
target.docs.push(...group.docs);
|
||||
target.text += " " + group.text;
|
||||
continue;
|
||||
}
|
||||
if (pKey) byPerson.set(pKey, group);
|
||||
merged.push(group);
|
||||
}
|
||||
for (const group of merged) {
|
||||
group.docs.sort((a, b) => a.file_name.localeCompare(b.file_name));
|
||||
const preferred = group.docs.find((d) =>
|
||||
typeof d.prospective_buyer === "string" && d.prospective_buyer.trim()
|
||||
);
|
||||
if (preferred) group.displayName = preferred.prospective_buyer;
|
||||
}
|
||||
return merged.sort((a, b) => a.key.localeCompare(b.key));
|
||||
}
|
||||
|
||||
function visibleGroups() {
|
||||
@@ -298,4 +337,26 @@ async function load() {
|
||||
}
|
||||
}
|
||||
|
||||
void load();
|
||||
void load();
|
||||
|
||||
// ---- Window size reporting ----
|
||||
// The backend's native size APIs are unreliable (see main.ts), so the
|
||||
// webview reports its own viewport size. The first report, sent shortly
|
||||
// after startup, calibrates the decoration offset on the backend; later
|
||||
// reports track user resizes.
|
||||
let metricsTimer = null;
|
||||
function reportWindowMetrics() {
|
||||
fetch("/api/window-metrics", {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
innerWidth: globalThis.innerWidth,
|
||||
innerHeight: globalThis.innerHeight,
|
||||
}),
|
||||
}).catch(() => {});
|
||||
}
|
||||
globalThis.addEventListener("resize", () => {
|
||||
clearTimeout(metricsTimer);
|
||||
metricsTimer = setTimeout(reportWindowMetrics, 250);
|
||||
});
|
||||
setTimeout(reportWindowMetrics, 800); // calibration report
|
||||
Reference in New Issue
Block a user