fix(SH-357): disable Incomplete without a schedule date

This commit is contained in:
Alexandre Brandizzi 2026-10-01 16:10:46 -03:00
parent 88307764c5
commit cbb2edf2a6
13 changed files with 27 additions and 24 deletions

View file

@ -19,7 +19,7 @@ function resolveInlineDraftSchedule(draft: WorkOrderTableDraft) {
return { return {
scheduleWeekOnly, scheduleWeekOnly,
status: resolveCreationStatus({ status: resolveCreationStatus({
status: draft.status || "Incomplete", status: draft.status || "Pending",
scheduledOn: draft.scheduledOn, scheduledOn: draft.scheduledOn,
scheduleWeekOnly, scheduleWeekOnly,
}), }),

View file

@ -230,7 +230,7 @@ export function WoTableInlineRowCells({
dispatcherId={draft.dispatcherId} dispatcherId={draft.dispatcherId}
users={users} users={users}
onSave={(id) => { onSave={(id) => {
onPatch({ dispatcherId: id, status: draft.status || "Incomplete" }); onPatch({ dispatcherId: id, status: draft.status || "Pending" });
}} }}
/> />
</InlineFieldCell> </InlineFieldCell>

View file

@ -9,7 +9,6 @@ export function useNewWoWizardDraft(open: boolean) {
const [step, setStep] = useState(1); const [step, setStep] = useState(1);
const [draft, setDraft] = useState<WorkOrderWizardDraft>({ const [draft, setDraft] = useState<WorkOrderWizardDraft>({
...EMPTY_WIZARD_DRAFT, ...EMPTY_WIZARD_DRAFT,
status: "Incomplete",
}); });
const [svcOpen, setSvcOpen] = useState(false); const [svcOpen, setSvcOpen] = useState(false);
const [svcSearch, setSvcSearch] = useState(""); const [svcSearch, setSvcSearch] = useState("");
@ -18,7 +17,7 @@ export function useNewWoWizardDraft(open: boolean) {
useEffect(() => { useEffect(() => {
if (open) { if (open) {
setStep(1); setStep(1);
setDraft({ ...EMPTY_WIZARD_DRAFT, status: "Incomplete" }); setDraft({ ...EMPTY_WIZARD_DRAFT });
setSvcOpen(false); setSvcOpen(false);
setSvcSearch(""); setSvcSearch("");
setShowErrors(false); setShowErrors(false);

View file

@ -40,7 +40,6 @@ export function useNewWoWizardState({
const [showErrors, setShowErrors] = useState(false); const [showErrors, setShowErrors] = useState(false);
const [draft, setDraft] = useState<WorkOrderWizardDraft>({ const [draft, setDraft] = useState<WorkOrderWizardDraft>({
...EMPTY_WIZARD_DRAFT, ...EMPTY_WIZARD_DRAFT,
status: "Incomplete",
}); });
const [pocAutoFilledFor, setPocAutoFilledFor] = useState(""); const [pocAutoFilledFor, setPocAutoFilledFor] = useState("");
@ -83,7 +82,7 @@ export function useNewWoWizardState({
if (open) { if (open) {
setStep(1); setStep(1);
setShowErrors(false); setShowErrors(false);
setDraft({ ...EMPTY_WIZARD_DRAFT, status: "Incomplete" }); setDraft({ ...EMPTY_WIZARD_DRAFT });
setPocAutoFilledFor(""); setPocAutoFilledFor("");
setDuplicateRow(null); setDuplicateRow(null);
} }

View file

@ -53,6 +53,6 @@ export function buildWizardSidebarSummaryRows(draft: WorkOrderWizardDraft): [str
["Technician", draft.vendorName || "—"], ["Technician", draft.vendorName || "—"],
["Company", draft.vendorName || "—"], ["Company", draft.vendorName || "—"],
["Appt time", draft.apptStart ? formatApptRange(draft.apptStart, draft.apptEnd) : "—"], ["Appt time", draft.apptStart ? formatApptRange(draft.apptStart, draft.apptEnd) : "—"],
["Status", draft.status || "Incomplete"], ["Status", draft.status || "Pending"],
]; ];
} }

View file

@ -8,9 +8,9 @@ import { ColorDot } from "@/app/(protected)/workorders/_components/wizard/wizard
export function WizardSidebarSummary({ draft }: { draft: WorkOrderWizardDraft }) { export function WizardSidebarSummary({ draft }: { draft: WorkOrderWizardDraft }) {
const summary = buildWizardSidebarSummaryRows(draft); const summary = buildWizardSidebarSummaryRows(draft);
const statusLabel = draft.status || "Incomplete"; const statusLabel = draft.status || "Pending";
const statusValue = statusLabel as WizardWOStatus; const statusValue = statusLabel as WizardWOStatus;
const statusDotColor = WIZARD_STATUS_DOTS[statusValue] ?? WIZARD_STATUS_DOTS.Incomplete; const statusDotColor = WIZARD_STATUS_DOTS[statusValue] ?? WIZARD_STATUS_DOTS.Pending;
return ( return (
<div style={{ marginTop: "auto", paddingTop: 44 }}> <div style={{ marginTop: "auto", paddingTop: 44 }}>

View file

@ -194,8 +194,8 @@ export function WizardStepVendorTime({
draft.technicianAssigned === false draft.technicianAssigned === false
? undefined ? undefined
: vendors.find((v) => String(v.id) === draft.vendorId); : vendors.find((v) => String(v.id) === draft.vendorId);
const statusValue = (draft.status || "Incomplete") as WizardWOStatus; const statusValue = (draft.status || "Pending") as WizardWOStatus;
const statusDotColor = WIZARD_STATUS_DOTS[statusValue] ?? WIZARD_STATUS_DOTS.Incomplete; const statusDotColor = WIZARD_STATUS_DOTS[statusValue] ?? WIZARD_STATUS_DOTS.Pending;
const selectedDistance = formatVendorDistance(selectedVendor?.distanceMiles); const selectedDistance = formatVendorDistance(selectedVendor?.distanceMiles);
const closabilityGaps = getClosabilityGaps(wizardDraftToClosabilityInput(draft)); const closabilityGaps = getClosabilityGaps(wizardDraftToClosabilityInput(draft));

View file

@ -60,7 +60,7 @@ export function useWorkOrdersTableUiState(weekMonday: string) {
setDraft({ setDraft({
...EMPTY_TABLE_DRAFT, ...EMPTY_TABLE_DRAFT,
scheduledOn, scheduledOn,
status: scheduledOn ? "Scheduled" : "Incomplete", status: scheduledOn ? "Scheduled" : "Pending",
}); });
}, },
[weekMonday], [weekMonday],

View file

@ -8,11 +8,7 @@ import {
WORK_ORDER_TYPE_API, WORK_ORDER_TYPE_API,
} from "@/domain/work-orders/types/work-order-board"; } from "@/domain/work-orders/types/work-order-board";
import type { import type { WOType, WorkOrderWizardDraft } from "@/domain/work-orders/types/work-order-wizard";
WizardWOStatus,
WOType,
WorkOrderWizardDraft,
} from "@/domain/work-orders/types/work-order-wizard";
import { fmtDateRange } from "@/domain/work-orders/utils/wizard-date-utils"; import { fmtDateRange } from "@/domain/work-orders/utils/wizard-date-utils";
@ -20,6 +16,7 @@ import { assignWizardScheduleFields } from "@/domain/work-orders/mappers/assign-
import { assignWizardVendorApptFields } from "@/domain/work-orders/mappers/assign-wizard-vendor-appt-fields"; import { assignWizardVendorApptFields } from "@/domain/work-orders/mappers/assign-wizard-vendor-appt-fields";
import { assignWizardServicePocFields } from "@/domain/work-orders/mappers/assign-wizard-service-poc-fields"; import { assignWizardServicePocFields } from "@/domain/work-orders/mappers/assign-wizard-service-poc-fields";
import { resolveIsAddOnForCreate } from "@/domain/work-orders/utils/wo-addon-cutoff"; import { resolveIsAddOnForCreate } from "@/domain/work-orders/utils/wo-addon-cutoff";
import { resolveCreationStatus } from "@/domain/work-orders/utils/wo-lifecycle-transitions";
const WO_TYPE_TO_API: Record<WOType, WorkOrderTypeApi> = { const WO_TYPE_TO_API: Record<WOType, WorkOrderTypeApi> = {
PM: WORK_ORDER_TYPE_API.PM, PM: WORK_ORDER_TYPE_API.PM,
@ -114,7 +111,7 @@ export function mapWizardDraftToBoardCreatePayload(
}; };
if (draft.status) { if (draft.status) {
payload.lifecycleStatus = LIFECYCLE_STATUS_API[draft.status as WizardWOStatus]; payload.lifecycleStatus = LIFECYCLE_STATUS_API[resolveCreationStatus(draft)];
} }
if (draft.woNumber.trim()) { if (draft.woNumber.trim()) {

View file

@ -175,7 +175,7 @@ export const EMPTY_TABLE_DRAFT: WorkOrderTableDraft = {
techPhone: "", techPhone: "",
apptStart: "", apptStart: "",
apptEnd: "", apptEnd: "",
status: "Incomplete", status: "Pending",
pocName: "", pocName: "",
pocPhone: "", pocPhone: "",
pocNotes: "", pocNotes: "",

View file

@ -109,7 +109,7 @@ export const EMPTY_WIZARD_DRAFT: WorkOrderWizardDraft = {
vendorNotes: "", vendorNotes: "",
apptStart: "", apptStart: "",
apptEnd: "", apptEnd: "",
status: "Incomplete", status: "Pending",
pocName: "", pocName: "",
pocPhone: "", pocPhone: "",
pocNotes: "", pocNotes: "",

View file

@ -38,6 +38,8 @@ export const CREATION_INLINE_STATUSES: readonly WizardWOStatus[] = [
export const SCHEDULED_NEEDS_DATE_MSG = export const SCHEDULED_NEEDS_DATE_MSG =
"Set a Schedule On date before marking this work order as Scheduled."; "Set a Schedule On date before marking this work order as Scheduled.";
export const INCOMPLETE_NEEDS_DATE_MSG =
"Set a Schedule On date before marking this work order as Incomplete.";
export const PENDING_NEEDS_NO_DATE_MSG = export const PENDING_NEEDS_NO_DATE_MSG =
"Clear the Schedule On date before marking this work order as Pending."; "Clear the Schedule On date before marking this work order as Pending.";
@ -134,6 +136,9 @@ export function getStatusOptionState(
status: WizardWOStatus, status: WizardWOStatus,
closabilityGaps: string[], closabilityGaps: string[],
): StatusOptionState { ): StatusOptionState {
if (status === "Incomplete" && !hasConcreteScheduleDate(row)) {
return { disabled: true, title: INCOMPLETE_NEEDS_DATE_MSG };
}
if (status === "Pending" && hasConcreteScheduleDate(row)) { if (status === "Pending" && hasConcreteScheduleDate(row)) {
return { disabled: true, title: PENDING_NEEDS_NO_DATE_MSG }; return { disabled: true, title: PENDING_NEEDS_NO_DATE_MSG };
} }
@ -211,5 +216,8 @@ export function resolveCreationStatus(row: ScheduleDateInput & { status: string
if (autoStatus === "Scheduled" || autoStatus === "Pending") { if (autoStatus === "Scheduled" || autoStatus === "Pending") {
return autoStatus; return autoStatus;
} }
return (row.status || "Incomplete") as WizardWOStatus; if (!row.status || (row.status === "Incomplete" && !hasConcreteScheduleDate(row))) {
return "Pending";
}
return row.status as WizardWOStatus;
} }

View file

@ -61,7 +61,7 @@ describe("mapWizardDraftToBoardCreatePayload", () => {
isAddOn: false, isAddOn: false,
lifecycleStatus: 1, lifecycleStatus: 2,
}); });
}); });
@ -283,7 +283,7 @@ describe("mapWizardDraftToBoardCreatePayload", () => {
expect(payload.scheduledDate).toBeUndefined(); expect(payload.scheduledDate).toBeUndefined();
}); });
it("keeps Incomplete on week-only create and omits scheduledDate", () => { it("normalizes Incomplete to Pending on week-only create and omits scheduledDate", () => {
const payload = mapWizardDraftToBoardCreatePayload({ const payload = mapWizardDraftToBoardCreatePayload({
...EMPTY_WIZARD_DRAFT, ...EMPTY_WIZARD_DRAFT,
type: "PM", type: "PM",
@ -293,7 +293,7 @@ describe("mapWizardDraftToBoardCreatePayload", () => {
targetWeek: "2026-06-22", targetWeek: "2026-06-22",
}); });
expect(payload.lifecycleStatus).toBe(LIFECYCLE_STATUS_API.Incomplete); expect(payload.lifecycleStatus).toBe(LIFECYCLE_STATUS_API.Pending);
expect(payload.scheduleWeekOnly).toBe(true); expect(payload.scheduleWeekOnly).toBe(true);
expect(payload.targetWeek).toBe("2026-06-22"); expect(payload.targetWeek).toBe("2026-06-22");
expect(payload.scheduledDate).toBeUndefined(); expect(payload.scheduledDate).toBeUndefined();