e.stopPropagation(),
+ },
+ }}
+ >
+ {Boolean(allowWeekMode) && (
+
+ {(["week", "date"] as const).map((m) => {
+ const activeMode = cellMode === m;
+ return (
+
+ );
+ })}
+
+ )}
+
+ {allowWeekMode && cellMode === "week" ? (
+ {
+ onChange("");
+ onChangeWeek?.(mon);
+ close();
+ }}
+ />
+ ) : (
+ {
+ onChange(iso);
+ close();
+ }}
+ />
+ )}
+
+ >
+ );
+}
diff --git a/src/app/(protected)/workorders/_components/wizard/wizard-footer.tsx b/src/app/(protected)/workorders/_components/wizard/wizard-footer.tsx
new file mode 100644
index 00000000..4240f19a
--- /dev/null
+++ b/src/app/(protected)/workorders/_components/wizard/wizard-footer.tsx
@@ -0,0 +1,110 @@
+import { Check, ChevronLeft, ChevronRight, Lightbulb } from "lucide-react";
+import { Button } from "@/components/ui/button";
+import {
+ WIZARD_STEPS,
+ canContinueWizardStep1,
+ canCreateWorkOrderFromWizard,
+ isWizardStepValid,
+ type WorkOrderWizardDraft,
+} from "@/domain/work-orders/types/work-order-wizard";
+
+type WizardFooterProps = {
+ step: number;
+ draft: WorkOrderWizardDraft;
+ onCancel: () => void;
+ onBack: () => void;
+ onContinue: () => void;
+ onCreate: () => void;
+ isCreating: boolean;
+};
+
+export function WizardFooter({
+ step,
+ draft,
+ onCancel,
+ onBack,
+ onContinue,
+ onCreate,
+ isCreating,
+}: WizardFooterProps) {
+ const stepValid = isWizardStepValid(step, draft);
+ const canCreate = canCreateWorkOrderFromWizard(draft);
+ const canContinue1 = canContinueWizardStep1(draft);
+
+ return (
+
+ {step === 1 ? (
+
+ ) : (
+
}
+ sx={{ fontSize: 13, borderColor: "var(--color-border)", minHeight: 36 }}
+ >
+ Back
+
+ )}
+
+
+ {step === 1 && !canContinue1 && (
+
+ Pick a type to continue
+
+ )}
+
+
+ {step < WIZARD_STEPS.length ? (
+
}
+ sx={{
+ background: "var(--color-primary)",
+ color: "#fff",
+ height: 36,
+ fontSize: 13,
+ fontWeight: 500,
+ ...(!stepValid ? { opacity: 0.5, pointerEvents: "none" } : {}),
+ }}
+ >
+ Continue
+
+ ) : (
+
: undefined}
+ sx={{
+ background: "var(--color-primary)",
+ color: "#fff",
+ height: 36,
+ fontSize: 13,
+ fontWeight: 500,
+ ...(!canCreate ? { opacity: 0.5, pointerEvents: "none" } : {}),
+ }}
+ >
+ Create work order
+
+ )}
+
+ );
+}
diff --git a/src/app/(protected)/workorders/_components/wizard/wizard-sidebar.tsx b/src/app/(protected)/workorders/_components/wizard/wizard-sidebar.tsx
new file mode 100644
index 00000000..62a13a75
--- /dev/null
+++ b/src/app/(protected)/workorders/_components/wizard/wizard-sidebar.tsx
@@ -0,0 +1,225 @@
+import { ClipboardList } from "lucide-react";
+import {
+ WIZARD_STATUS_DOTS,
+ WIZARD_STEPS,
+ type WizardWOStatus,
+ type WorkOrderWizardDraft,
+} from "@/domain/work-orders/types/work-order-wizard";
+import {
+ fmtDate,
+ fmtWeekRange,
+ formatApptRange,
+} from "@/domain/work-orders/utils/wizard-date-utils";
+import {
+ ColorDot,
+ StepCircle,
+} from "@/app/(protected)/workorders/_components/wizard/wizard-labels";
+
+type WizardSidebarProps = {
+ step: number;
+ draft: WorkOrderWizardDraft;
+};
+
+export function WizardSidebar({ step, draft }: WizardSidebarProps) {
+ return (
+
+
+ This work order
+
+ {summary.map(([label, val], i) => (
+
+
+ {label}
+
+ {label === "Status" ? (
+
+
+
+ {statusLabel}
+
+
+ ) : (
+
+ {val}
+
+ )}
+
+ ))}
+
+ );
+}
diff --git a/src/app/(protected)/workorders/_components/wizard/wizard-step-location-service.tsx b/src/app/(protected)/workorders/_components/wizard/wizard-step-location-service.tsx
new file mode 100644
index 00000000..28a19d9b
--- /dev/null
+++ b/src/app/(protected)/workorders/_components/wizard/wizard-step-location-service.tsx
@@ -0,0 +1,180 @@
+import { ExternalLink, Info, Mail, MapPin, Phone } from "lucide-react";
+import { Text } from "@/components/ui/text";
+import type { LocationOption } from "@/domain/work-orders/types/work-order";
+import type { Location } from "@/domain/locations/types/location";
+import type { WorkOrderWizardDraft } from "@/domain/work-orders/types/work-order-wizard";
+import { WizardFieldSelect } from "@/app/(protected)/workorders/_components/wizard/wizard-field-select";
+import {
+ DLG_INPUT_CLS,
+ DLG_INPUT_STYLE,
+} from "@/app/(protected)/workorders/_components/wizard/wizard-input-styles";
+import {
+ Detail,
+ WizLabel,
+ WizSubLabel,
+} from "@/app/(protected)/workorders/_components/wizard/wizard-labels";
+
+type ServiceOption = { id: string | number; value: string };
+
+type WizardStepLocationServiceProps = {
+ draft: WorkOrderWizardDraft;
+ locations: LocationOption[];
+ locationDetail: Location | undefined;
+ services: ServiceOption[];
+ onUpdate: