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, location: draft.location,
dispatcherId: draft.dispatcherId, dispatcherId: draft.dispatcherId,
scheduledOn: draft.scheduledOn, scheduledOn: draft.scheduledOn,
completedDate: "",
dueDate: draft.dueDate, dueDate: draft.dueDate,
pm: draft.pm, pm: draft.pm,
serviceNotes: draft.serviceNotes, serviceNotes: draft.serviceNotes,

View file

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

View file

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

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 type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row";
import { ApptTimeCell } from "./cells/appt-time-cell"; import { ApptTimeCell } from "./cells/appt-time-cell";
import { CompDocCell } from "./cells/comp-doc-cell"; import { CompDocCell } from "./cells/comp-doc-cell";
import { DateCell } from "./cells/date-cell";
import { PMTypeCell } from "./cells/pm-type-cell"; import { PMTypeCell } from "./cells/pm-type-cell";
import { StatusCell } from "./cells/status-cell"; import { StatusCell } from "./cells/status-cell";
import { VendorCell } from "./cells/vendor-cell"; import { VendorCell } from "./cells/vendor-cell";
@ -102,6 +103,17 @@ export function WoTableRowServiceCells({
onOpenMedia={() => handlers.onOpenMedia(row)} onOpenMedia={() => handlers.onOpenMedia(row)}
/> />
</td> </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; flagColor?: string | null;
dueDate?: string | null; dueDate?: string | null;
scheduledDate?: string | null; scheduledDate?: string | null;
/** ISO date when work was completed; optional on list rows until BE confirms. */
completedDate?: string | null;
targetWeek?: string | null; targetWeek?: string | null;
scheduleWeekOnly?: boolean | null; scheduleWeekOnly?: boolean | null;
dayGroup?: string | null; dayGroup?: string | null;

View file

@ -18,6 +18,7 @@ export const SLIDE_OVER_EDIT_KEYS = [
"targetWeek", "targetWeek",
"scheduleWeekOnly", "scheduleWeekOnly",
"dueDate", "dueDate",
"completedDate",
"apptTime", "apptTime",
"pm", "pm",
"serviceNotes", "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");
});
});