shoc-frontend-new/src/domain/work-orders/utils/slide-over-draft.ts
Arthur Bassi 7a30335ab8 feat(work-orders): add per-WO Aveta indicators and advanced filter
Dispatchers can flag Aveta on Service and Notes and filter those rows
without a site-level attribute.
2026-08-24 15:16:51 -03:00

106 lines
3 KiB
TypeScript

import type { WorkOrderAdditionalContact } from "@/domain/work-orders/types/work-order-additional-contact";
import type {
WorkOrderTablePatch,
WorkOrderTableRow,
} from "@/domain/work-orders/types/work-order-table-row";
/**
* Fields compared for dirty state and included in Save patch.
* Only keys that map to board PATCH (or required companions like dispatcherName).
* Primary POC scalars and tech phone are not board-editable — exclude so Save cannot no-op.
* additionalContacts is board-editable (SH-218 PATCH field).
*/
export const SLIDE_OVER_EDIT_KEYS = [
"woNumber",
"site",
"type",
"dispatcherId",
"dispatcherName",
"scheduledOn",
"targetWeek",
"scheduleWeekOnly",
"dueDate",
"completedDate",
"apptTime",
"pm",
"serviceNotes",
"extraServices",
"avetaRequired",
"additionalContacts",
"vendorId",
// company/tech are display companions; board persists vendor via vendorId only
"status",
] as const satisfies ReadonlyArray<keyof WorkOrderTableRow>;
type EditKey = (typeof SLIDE_OVER_EDIT_KEYS)[number];
function sameExtraServices(a: string[] | undefined, b: string[] | undefined): boolean {
const left = a ?? [];
const right = b ?? [];
if (left.length !== right.length) return false;
return left.every((value, index) => value === right[index]);
}
function sameAdditionalContacts(
a: WorkOrderAdditionalContact[] | undefined,
b: WorkOrderAdditionalContact[] | undefined,
): boolean {
const left = a ?? [];
const right = b ?? [];
if (left.length !== right.length) return false;
return left.every((contact, index) => {
const other = right[index];
return (
contact.name === other.name &&
contact.phone === other.phone &&
(contact.notes ?? "") === (other.notes ?? "")
);
});
}
export function isSlideOverDraftDirty(
draft: WorkOrderTableRow,
baseline: WorkOrderTableRow,
): boolean {
for (const key of SLIDE_OVER_EDIT_KEYS) {
if (key === "extraServices") {
if (!sameExtraServices(draft.extraServices, baseline.extraServices)) return true;
continue;
}
if (key === "additionalContacts") {
if (!sameAdditionalContacts(draft.additionalContacts, baseline.additionalContacts)) {
return true;
}
continue;
}
if (draft[key] !== baseline[key]) return true;
}
return false;
}
export function buildSlideOverPatch(
draft: WorkOrderTableRow,
baseline: WorkOrderTableRow,
): WorkOrderTablePatch {
const patch: WorkOrderTablePatch = {};
for (const key of SLIDE_OVER_EDIT_KEYS) {
if (key === "extraServices") {
if (!sameExtraServices(draft.extraServices, baseline.extraServices)) {
patch.extraServices = draft.extraServices;
}
continue;
}
if (key === "additionalContacts") {
if (!sameAdditionalContacts(draft.additionalContacts, baseline.additionalContacts)) {
patch.additionalContacts = draft.additionalContacts;
}
continue;
}
if (draft[key] !== baseline[key]) {
(patch as Record<EditKey, WorkOrderTableRow[EditKey]>)[key] = draft[key];
}
}
return patch;
}