Merge pull request #108 from Sea-Haven-Industries/feature/wo-board-completed-date-column

feat(work-orders): editable completed date board column (SH-216)
This commit is contained in:
Alexandre Brandizzi 2026-08-12 12:23:02 -03:00 • committed by GitHub
commit 011bf0ae8a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 54 additions and 4 deletions

View file

@ -16,6 +16,7 @@ export function toInlineDraftRow(draft: WorkOrderTableDraft) {
location: draft.location,
dispatcherId: draft.dispatcherId,
scheduledOn: draft.scheduledOn,
completedDate: "",
dueDate: draft.dueDate,
pm: draft.pm,
serviceNotes: draft.serviceNotes,

View file

@ -12,8 +12,9 @@ export const WO_TABLE_COLS = [
{ key: "appt", label: "APPT TIME", w: 128 },
{ key: "status", label: "STATUS", w: 148 },
{ key: "doc", label: "COMP DOC", w: 84 },
{ key: "completed", label: "COMPLETED DATE", w: 130 },
{ key: "actions", label: "", w: 100 },
] as const;
export const WO_TABLE_MIN_WIDTH = 1504;
export const WO_TABLE_MIN_WIDTH = 1634;
export const WO_TABLE_ROW_HEIGHT = 52;

View file

@ -33,6 +33,14 @@ type WoTableInlineRowCellsProps = {
onPatch: (patch: Partial<WorkOrderTableDraft>) => void;
};
function InlineMutedDashCell() {
return (
<td style={{ padding: "0 14px" }}>
<span style={{ fontSize: 11, color: "var(--color-text-muted)" }}>—</span>
</td>
);
}
export function WoTableInlineRowCells({
draft,
weekDefault,
@ -164,9 +172,8 @@ export function WoTableInlineRowCells({
/>
</td>
<td style={{ padding: "0 14px" }}>
<span style={{ fontSize: 11, color: "var(--color-text-muted)" }}>—</span>
</td>
<InlineMutedDashCell />
<InlineMutedDashCell />
</>
);
}

View file

@ -3,6 +3,7 @@ import type { VendorDropdownItem } from "@/domain/work-orders/types/work-order";
import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row";
import { ApptTimeCell } from "./cells/appt-time-cell";
import { CompDocCell } from "./cells/comp-doc-cell";
import { DateCell } from "./cells/date-cell";
import { PMTypeCell } from "./cells/pm-type-cell";
import { StatusCell } from "./cells/status-cell";
import { VendorCell } from "./cells/vendor-cell";
@ -102,6 +103,17 @@ export function WoTableRowServiceCells({
onOpenMedia={() => handlers.onOpenMedia(row)}
/>
</td>
<td
className="group/cell"
style={{ padding: "0 14px", ...mutationCellStyle }}
onClick={(e) => e.stopPropagation()}
>
<DateCell
value={row.completedDate}
q={search}
onSave={(date) => onPatchRow({ completedDate: date })}
/>
</td>
</>
);
}

View file

@ -147,6 +147,8 @@ export interface WorkOrderBoardRowApi {
flagColor?: string | null;
dueDate?: string | null;
scheduledDate?: string | null;
/** ISO date when work was completed; optional on list rows until BE confirms. */
completedDate?: string | null;
targetWeek?: string | null;
scheduleWeekOnly?: boolean | null;
dayGroup?: string | null;

View file

@ -18,6 +18,7 @@ export const SLIDE_OVER_EDIT_KEYS = [
"targetWeek",
"scheduleWeekOnly",
"dueDate",
"completedDate",
"apptTime",
"pm",
"serviceNotes",

View file

@ -0,0 +1,26 @@
import { describe, expect, it } from "vitest";
import { WO_TABLE_COLS } from "@/app/(protected)/workorders/_components/list/table/wo-table-cols";
import { expandScalarBoardOps } from "@/domain/work-orders/mappers/expand-scalar-board-ops";
import { mapWorkOrderTableRow } from "@/domain/work-orders/mappers/work-order-table-row-mapper";
describe("COMPLETED DATE board column wiring", () => {
it("includes COMPLETED DATE column after COMP DOC", () => {
const keys = WO_TABLE_COLS.map((col) => col.key);
expect(keys).toContain("completed");
expect(keys.indexOf("completed")).toBeGreaterThan(keys.indexOf("doc"));
});
it("expands completedDate patch to board field op", () => {
const ops = expandScalarBoardOps({ completedDate: "2026-07-30" });
expect(ops).toEqual([{ field: "completedDate", value: "2026-07-30" }]);
});
it("maps completedDate returned by a board GET row", () => {
const row = mapWorkOrderTableRow({
id: 42,
completedDate: "2026-07-30T00:00:00Z",
});
expect(row.completedDate).toBe("2026-07-30");
});
});