mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-07 16:19:01 +00:00
fix(work-orders): exhaust fuzzy pages for exact WO number lookup
Prevent accepting duplicates that fall outside the first fuzzy search page.
This commit is contained in:
parent
6ac1b5cd42
commit
0153187a0b
3 changed files with 97 additions and 43 deletions
|
|
@ -2,7 +2,9 @@ import { useEffect, useState } from "react";
|
|||
|
||||
import { toast } from "react-toastify";
|
||||
|
||||
import { workOrdersApi } from "@/domain/work-orders/api/work-orders-api";
|
||||
import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row";
|
||||
import { findDuplicateWoNumberRow } from "@/domain/work-orders/utils/find-duplicate-wo-number-row";
|
||||
|
||||
import { HighlightText } from "./highlight-text";
|
||||
|
||||
|
|
@ -67,17 +69,16 @@ export function EditableWONumberCell({
|
|||
|
||||
const [draft, setDraft] = useState(value);
|
||||
|
||||
const [isChecking, setIsChecking] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!editing) {
|
||||
setDraft(value);
|
||||
}
|
||||
}, [value, editing]);
|
||||
|
||||
const findDuplicate = (d: string) =>
|
||||
allOrders.find((o) => o.woNumber === d && String(o.id) !== String(currentId));
|
||||
|
||||
const commit = () => {
|
||||
if (draft === value) {
|
||||
if (draft === value || isChecking) {
|
||||
setEditing(false);
|
||||
|
||||
return;
|
||||
|
|
@ -89,21 +90,26 @@ export function EditableWONumberCell({
|
|||
return;
|
||||
}
|
||||
|
||||
const duplicate = findDuplicate(draft);
|
||||
|
||||
if (duplicate) {
|
||||
onDuplicateFound?.(duplicate);
|
||||
|
||||
setDraft(value);
|
||||
|
||||
setEditing(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
onSave(draft);
|
||||
|
||||
setEditing(false);
|
||||
setIsChecking(true);
|
||||
void (async () => {
|
||||
try {
|
||||
const local = findDuplicateWoNumberRow(draft, allOrders, currentId);
|
||||
const remote = local ?? (await workOrdersApi.findByWoNumber(draft));
|
||||
const duplicate =
|
||||
remote && String(remote.id) !== String(currentId) ? remote : undefined;
|
||||
if (duplicate) {
|
||||
onDuplicateFound?.(duplicate);
|
||||
setDraft(value);
|
||||
return;
|
||||
}
|
||||
onSave(draft);
|
||||
} catch {
|
||||
toast.error("Unable to verify the work order number. Please try again.");
|
||||
} finally {
|
||||
setIsChecking(false);
|
||||
setEditing(false);
|
||||
}
|
||||
})();
|
||||
};
|
||||
|
||||
const cancel = () => {
|
||||
|
|
@ -113,20 +119,12 @@ export function EditableWONumberCell({
|
|||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
if (isChecking) {
|
||||
return;
|
||||
}
|
||||
if (draft !== value && draft.length === 11) {
|
||||
const duplicate = findDuplicate(draft);
|
||||
|
||||
if (duplicate) {
|
||||
onDuplicateFound?.(duplicate);
|
||||
|
||||
setDraft(value);
|
||||
|
||||
setEditing(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
onSave(draft);
|
||||
commit();
|
||||
return;
|
||||
}
|
||||
|
||||
setEditing(false);
|
||||
|
|
@ -139,6 +137,7 @@ export function EditableWONumberCell({
|
|||
{editing ? (
|
||||
<input
|
||||
autoFocus
|
||||
disabled={isChecking}
|
||||
inputMode="numeric"
|
||||
value={draft}
|
||||
onChange={(e) => setDraft(e.target.value.replace(/\D/g, "").slice(0, 11))}
|
||||
|
|
|
|||
|
|
@ -197,14 +197,31 @@ export const workOrdersApi = {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
// `board/search` without date or board filters searches the entire work-order collection.
|
||||
const result = await workOrdersApi.searchBoard({
|
||||
search: normalized,
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
});
|
||||
// `board/search` is fuzzy and paginated; exhaust pages until an exact WO# match appears.
|
||||
const pageSize = 100;
|
||||
let page = 1;
|
||||
let scanned = 0;
|
||||
let totalCount = Number.POSITIVE_INFINITY;
|
||||
|
||||
return result.items.find((row) => row.woNumber === normalized);
|
||||
while (scanned < totalCount) {
|
||||
const result = await workOrdersApi.searchBoard({
|
||||
search: normalized,
|
||||
page,
|
||||
pageSize,
|
||||
});
|
||||
const exact = result.items.find((row) => row.woNumber === normalized);
|
||||
if (exact) {
|
||||
return exact;
|
||||
}
|
||||
scanned += result.items.length;
|
||||
totalCount = result.totalCount;
|
||||
if (result.items.length === 0) {
|
||||
break;
|
||||
}
|
||||
page += 1;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getListByLocation: async (
|
||||
|
|
|
|||
|
|
@ -294,6 +294,9 @@ describe("workOrdersApi.searchBoard", () => {
|
|||
describe("workOrdersApi.findByWoNumber", () => {
|
||||
beforeEach(() => {
|
||||
apiGet.mockReset();
|
||||
});
|
||||
|
||||
it("searches globally without the active board filters", async () => {
|
||||
apiGet.mockResolvedValue({
|
||||
items: [
|
||||
{
|
||||
|
|
@ -304,11 +307,9 @@ describe("workOrdersApi.findByWoNumber", () => {
|
|||
],
|
||||
totalCount: 1,
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
pageSize: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it("searches globally without the active board filters", async () => {
|
||||
const result = await workOrdersApi.findByWoNumber("10000001235");
|
||||
|
||||
expect(apiGet).toHaveBeenCalledWith(
|
||||
|
|
@ -321,10 +322,47 @@ describe("workOrdersApi.findByWoNumber", () => {
|
|||
expect(Object.fromEntries(searchParams)).toEqual({
|
||||
search: "10000001235",
|
||||
page: "1",
|
||||
pageSize: "20",
|
||||
pageSize: "100",
|
||||
});
|
||||
expect(result).toMatchObject({ id: 505, woNumber: "10000001235" });
|
||||
});
|
||||
|
||||
it("pages through fuzzy search until the exact WO number is found", async () => {
|
||||
apiGet
|
||||
.mockResolvedValueOnce({
|
||||
items: Array.from({ length: 100 }, (_, index) => ({
|
||||
id: index + 1,
|
||||
woNumber: `fuzzy-match-${index}`,
|
||||
lifecycleStatusLabel: "Incomplete",
|
||||
})),
|
||||
totalCount: 101,
|
||||
page: 1,
|
||||
pageSize: 100,
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
items: [
|
||||
{
|
||||
id: 999,
|
||||
woNumber: "10000009999",
|
||||
lifecycleStatusLabel: "Incomplete",
|
||||
},
|
||||
],
|
||||
totalCount: 101,
|
||||
page: 2,
|
||||
pageSize: 100,
|
||||
});
|
||||
|
||||
const result = await workOrdersApi.findByWoNumber("10000009999");
|
||||
|
||||
expect(apiGet).toHaveBeenCalledTimes(2);
|
||||
const secondParams = apiGet.mock.calls[1]?.[1]?.searchParams as URLSearchParams;
|
||||
expect(Object.fromEntries(secondParams)).toMatchObject({
|
||||
search: "10000009999",
|
||||
page: "2",
|
||||
pageSize: "100",
|
||||
});
|
||||
expect(result).toMatchObject({ id: 999, woNumber: "10000009999" });
|
||||
});
|
||||
});
|
||||
|
||||
describe("workOrdersApi.patchBoardField", () => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue