diff --git a/src/app/(protected)/workorders/_components/list/table/cells/appt-time-cell.tsx b/src/app/(protected)/workorders/_components/list/table/cells/appt-time-cell.tsx index ff7fda7f..e43832d2 100644 --- a/src/app/(protected)/workorders/_components/list/table/cells/appt-time-cell.tsx +++ b/src/app/(protected)/workorders/_components/list/table/cells/appt-time-cell.tsx @@ -35,6 +35,20 @@ function slotStyle(active: boolean): React.CSSProperties { }; } +function nextStartSelection( + currentStart: string, + currentEnd: string, + slot: string, +): { start: string; end: string } { + if (slot === currentStart) { + return { start: "", end: "" }; + } + return { + start: slot, + end: currentEnd && currentEnd <= slot ? "" : currentEnd, + }; +} + function ApptTimeSlotList({ slots, active, @@ -120,10 +134,9 @@ export function ApptTimeCell({ apptTime, onSave }: ApptTimeCellProps) { slots={TIME_SLOTS} active={start} onPick={(t) => { - setStart(t); - if (end && end <= t) { - setEnd(""); - } + const next = nextStartSelection(start, end, t); + setStart(next.start); + setEnd(next.end); }} /> @@ -131,7 +144,13 @@ export function ApptTimeCell({ apptTime, onSave }: ApptTimeCellProps) { End (optional) - + { + setEnd(t === end ? "" : t); + }} + />
diff --git a/src/test/app/(protected)/workorders/appt-time-cell.test.tsx b/src/test/app/(protected)/workorders/appt-time-cell.test.tsx index 15aea687..07012d32 100644 --- a/src/test/app/(protected)/workorders/appt-time-cell.test.tsx +++ b/src/test/app/(protected)/workorders/appt-time-cell.test.tsx @@ -6,7 +6,7 @@ import { apptTimePopoverHint, commitApptTimeSelection, } from "@/domain/work-orders/utils/appt-time-selection"; -import { fmt12 } from "@/domain/work-orders/utils/wizard-date-utils"; +import { fmt12, formatApptRange } from "@/domain/work-orders/utils/wizard-date-utils"; describe("apptTimePopoverHint", () => { it("asks for start when empty", () => { @@ -100,6 +100,32 @@ describe("ApptTimeCell", () => { expect(onSave).not.toHaveBeenCalled(); }); + it("clears optional end when the selected end slot is toggled off", async () => { + const user = userEvent.setup(); + const onSave = vi.fn(); + render(); + + await user.click(screen.getByRole("button", { name: formatApptRange("09:00", "11:00") })); + const endSlots = await screen.findAllByRole("button", { name: fmt12("11:00") }); + await user.click(endSlots[endSlots.length - 1]!); + await user.click(screen.getByRole("button", { name: /^done$/i })); + + expect(onSave).toHaveBeenCalledWith("09:00"); + }); + + it("clears start and end when the selected start slot is toggled off", async () => { + const user = userEvent.setup(); + const onSave = vi.fn(); + render(); + + await user.click(screen.getByRole("button", { name: formatApptRange("09:00", "11:00") })); + const startSlots = await screen.findAllByRole("button", { name: fmt12("09:00") }); + await user.click(startSlots[0]!); + await user.click(screen.getByRole("button", { name: /^done$/i })); + + expect(onSave).toHaveBeenCalledWith(""); + }); + it("hydrates start-only stored times so Done can clear them", async () => { const user = userEvent.setup(); const onSave = vi.fn();