diff --git a/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-detail.png b/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-detail.png
index 52d00495..ffa12f37 100644
Binary files a/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-detail.png and b/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-detail.png differ
diff --git a/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-error.png b/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-error.png
index f07dbc15..907f118a 100644
Binary files a/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-error.png and b/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-error.png differ
diff --git a/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-filters.png b/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-filters.png
index 7af374c4..97a77e79 100644
Binary files a/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-filters.png and b/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-filters.png differ
diff --git a/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-list.png b/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-list.png
index bf2ebed4..d2e41781 100644
Binary files a/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-list.png and b/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-list.png differ
diff --git a/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-new.png b/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-new.png
index 0c225e74..13e7ffe3 100644
Binary files a/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-new.png and b/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-new.png differ
diff --git a/src/app/(protected)/workorders/_components/list/table/wo-table-head.tsx b/src/app/(protected)/workorders/_components/list/table/wo-table-head.tsx
index c490f17e..14a446fd 100644
--- a/src/app/(protected)/workorders/_components/list/table/wo-table-head.tsx
+++ b/src/app/(protected)/workorders/_components/list/table/wo-table-head.tsx
@@ -1,4 +1,5 @@
import { WO_TABLE_COLS } from "./wo-table-cols";
+import { WoTableHeaderLabel } from "./wo-table-header-label";
export function WoTableHead() {
return (
@@ -25,7 +26,7 @@ export function WoTableHead() {
borderBottom: "1px solid var(--border)",
}}
>
- {col.label}
+
{Boolean(srLabel) && {srLabel}}
);
diff --git a/src/app/(protected)/workorders/_components/list/table/wo-table-header-label.tsx b/src/app/(protected)/workorders/_components/list/table/wo-table-header-label.tsx
new file mode 100644
index 00000000..1902b463
--- /dev/null
+++ b/src/app/(protected)/workorders/_components/list/table/wo-table-header-label.tsx
@@ -0,0 +1,39 @@
+import { Tooltip } from "@mui/material";
+import { CircleQuestionMark } from "lucide-react";
+
+import { getWoTableHeaderTooltip } from "@/domain/work-orders/constants/wo-table-header-tooltips";
+
+type WoTableHeaderLabelProps = {
+ colKey: string;
+ label: string;
+};
+
+export function WoTableHeaderLabel({ colKey, label }: WoTableHeaderLabelProps) {
+ const tooltip = getWoTableHeaderTooltip(colKey);
+
+ if (!tooltip) {
+ return <>{label}>;
+ }
+
+ return (
+
+ {label}
+
+
+
+
+ );
+}
diff --git a/src/domain/work-orders/constants/wo-table-header-tooltips.ts b/src/domain/work-orders/constants/wo-table-header-tooltips.ts
new file mode 100644
index 00000000..24ff23be
--- /dev/null
+++ b/src/domain/work-orders/constants/wo-table-header-tooltips.ts
@@ -0,0 +1,17 @@
+/**
+ * Help copy for date-column headers on the work orders board table.
+ * Keyed by the `WO_TABLE_COLS` column key; only columns with copy here show a
+ * header help icon. `appt` (Appt Time) is an intentional open point — do not
+ * add it without a business-rule decision.
+ */
+export const WO_TABLE_HEADER_TOOLTIPS = {
+ sched: "The date the work is planned to happen. Setting it moves the work order to Scheduled.",
+ due: "The deadline for the work — when it must be completed by.",
+ completed: "The date the vendor actually finished the work. Required to complete the work order.",
+} as const;
+
+export function getWoTableHeaderTooltip(colKey: string): string | undefined {
+ return colKey in WO_TABLE_HEADER_TOOLTIPS
+ ? WO_TABLE_HEADER_TOOLTIPS[colKey as keyof typeof WO_TABLE_HEADER_TOOLTIPS]
+ : undefined;
+}
diff --git a/src/test/app/(protected)/workorders/wo-table-head-date-tooltips.test.tsx b/src/test/app/(protected)/workorders/wo-table-head-date-tooltips.test.tsx
new file mode 100644
index 00000000..a25bd953
--- /dev/null
+++ b/src/test/app/(protected)/workorders/wo-table-head-date-tooltips.test.tsx
@@ -0,0 +1,71 @@
+import { screen, within } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { describe, expect, it } from "vitest";
+
+import { WoTableHead } from "@/app/(protected)/workorders/_components/list/table/wo-table-head";
+import { getWoTableHeaderTooltip } from "@/domain/work-orders/constants/wo-table-header-tooltips";
+import { renderWithProviders } from "@/test/test-utils";
+
+const CASES = [
+ {
+ columnName: "SCHEDULE ON",
+ tooltip:
+ "The date the work is planned to happen. Setting it moves the work order to Scheduled.",
+ },
+ {
+ columnName: "DUE DATE",
+ tooltip: "The deadline for the work — when it must be completed by.",
+ },
+ {
+ columnName: "COMPLETED DATE",
+ tooltip: "The date the vendor actually finished the work. Required to complete the work order.",
+ },
+];
+
+function renderHead() {
+ return renderWithProviders(
+
+
+
,
+ { withAuth: false },
+ );
+}
+
+describe("WoTableHead date column header tooltips (SH-195)", () => {
+ it.each(CASES)(
+ "shows the $columnName help icon and tooltip copy on hover",
+ async ({ columnName, tooltip }) => {
+ const user = userEvent.setup();
+ renderHead();
+
+ const header = screen.getByRole("columnheader", { name: new RegExp(`^${columnName}`) });
+ const icon = within(header).getByRole("button", { name: `${columnName} column help` });
+
+ await user.hover(icon);
+
+ const tip = await screen.findByText(tooltip);
+ expect(tip).toBeInTheDocument();
+ },
+ 15000,
+ );
+
+ it("moves focus to the help icon on tab and keeps it keyboard reachable", async () => {
+ const user = userEvent.setup();
+ renderHead();
+
+ const header = screen.getByRole("columnheader", { name: /^SCHEDULE ON/ });
+ const icon = within(header).getByRole("button", { name: "SCHEDULE ON column help" });
+
+ await user.tab();
+
+ expect(icon).toHaveFocus();
+ });
+
+ it("does not add a help icon to Appt Time (open point, not implemented)", () => {
+ renderHead();
+
+ const header = screen.getByRole("columnheader", { name: "APPT TIME" });
+ expect(within(header).queryByRole("img")).not.toBeInTheDocument();
+ expect(getWoTableHeaderTooltip("appt")).toBeUndefined();
+ });
+});