From 475862003c94e68e15b8bfb469540b8171916033 Mon Sep 17 00:00:00 2001 From: Arthur Bassi Date: Wed, 22 Jul 2026 11:37:16 -0300 Subject: [PATCH] fix(work-orders): preserve slide-over draft and gate media close --- .../_components/comp-doc/comp-doc-co-line.tsx | 19 ++ .../comp-doc/comp-doc-detail-row.tsx | 39 +++ .../_components/comp-doc/comp-doc-preview.tsx | 292 ++++++++++++++++++ .../comp-doc/comp-doc-procedure-list.tsx | 32 ++ .../_components/comp-doc/comp-doc-sidebar.tsx | 207 +++++++++++++ .../_components/detail/audit-timeline.tsx | 7 +- .../detail/tabs/slide-over-completion-tab.tsx | 2 +- .../detail/work-order-detail-sections.tsx | 12 +- .../detail/work-order-slide-over.tsx | 44 ++- src/app/(protected)/workorders/index.tsx | 130 +++++++- .../use-work-order-table-mutations.ts | 17 +- .../utils/run-sequential-uploads.ts | 24 ++ .../utils/run-sequential-uploads.test.ts | 65 ++++ .../utils/slide-over-save-contract.test.ts | 76 +++++ 14 files changed, 929 insertions(+), 37 deletions(-) create mode 100644 src/app/(protected)/workorders/_components/comp-doc/comp-doc-co-line.tsx create mode 100644 src/app/(protected)/workorders/_components/comp-doc/comp-doc-detail-row.tsx create mode 100644 src/app/(protected)/workorders/_components/comp-doc/comp-doc-preview.tsx create mode 100644 src/app/(protected)/workorders/_components/comp-doc/comp-doc-procedure-list.tsx create mode 100644 src/app/(protected)/workorders/_components/comp-doc/comp-doc-sidebar.tsx create mode 100644 src/domain/work-orders/utils/run-sequential-uploads.ts create mode 100644 src/test/domain/work-orders/utils/run-sequential-uploads.test.ts create mode 100644 src/test/domain/work-orders/utils/slide-over-save-contract.test.ts diff --git a/src/app/(protected)/workorders/_components/comp-doc/comp-doc-co-line.tsx b/src/app/(protected)/workorders/_components/comp-doc/comp-doc-co-line.tsx new file mode 100644 index 00000000..5d3804bb --- /dev/null +++ b/src/app/(protected)/workorders/_components/comp-doc/comp-doc-co-line.tsx @@ -0,0 +1,19 @@ +import type { ElementType } from "react"; + +type CompDocCoLineProps = { + icon: ElementType; + text: string; + bold?: boolean; +}; + +export function CompDocCoLine({ icon: Icon, text, bold }: CompDocCoLineProps) { + return ( +
+ {text} + +
+ ); +} diff --git a/src/app/(protected)/workorders/_components/comp-doc/comp-doc-detail-row.tsx b/src/app/(protected)/workorders/_components/comp-doc/comp-doc-detail-row.tsx new file mode 100644 index 00000000..c5f08558 --- /dev/null +++ b/src/app/(protected)/workorders/_components/comp-doc/comp-doc-detail-row.tsx @@ -0,0 +1,39 @@ +import type { ElementType } from "react"; + +type CompDocDetailRowProps = { + icon: ElementType; + label: string; + value: string; + last?: boolean; +}; + +export function CompDocDetailRow({ icon: Icon, label, value, last }: CompDocDetailRowProps) { + return ( +
+ +
+
{label}
+
+ {value} +
+
+
+ ); +} diff --git a/src/app/(protected)/workorders/_components/comp-doc/comp-doc-preview.tsx b/src/app/(protected)/workorders/_components/comp-doc/comp-doc-preview.tsx new file mode 100644 index 00000000..318c7f63 --- /dev/null +++ b/src/app/(protected)/workorders/_components/comp-doc/comp-doc-preview.tsx @@ -0,0 +1,292 @@ +import { Ban, Building2, CheckCircle2, FileText, Mail, MapPin, Phone, Printer } from "lucide-react"; +import { Text } from "@/components/ui/text"; +import type { CompDocSiteInfo } from "@/domain/work-orders/types/completion-doc"; +import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row"; +import { SEAHAVEN_HEADER } from "@/domain/work-orders/utils/completion-doc-html"; +import { procedureFor, SAFETY_BULLETS } from "@/domain/work-orders/utils/completion-doc-procedures"; +import { serviceTitle } from "@/domain/work-orders/utils/completion-doc-service-title"; +import { CompDocCoLine } from "./comp-doc-co-line"; +import { CompDocProcedureList } from "./comp-doc-procedure-list"; + +type CompDocPreviewProps = { + row: WorkOrderTableRow; + site: CompDocSiteInfo; + notes: string; + generatedAt: string; + isGenerated: boolean; + isNotRequired: boolean; +}; + +export function CompDocPreview({ + row, + site, + notes, + generatedAt, + isGenerated, + isNotRequired, +}: CompDocPreviewProps) { + const proc = procedureFor(row.pm); + + return ( +
+
+ + {isGenerated ? ( + + ) : ( + + )} + {isGenerated ? "Generated document" : "Preview — not yet generated"} + +
+ +
+
+
+
+
+
+
+ Seahaven Industries +
+
+ + + + + +
+
+
+ + {isGenerated && ( +
+ Generated · {generatedAt} · v1 +
+ )} + + + {serviceTitle(row).toUpperCase()} + + + WO# {row.woNumber} + + +
+ + Site ID — {row.site} + + + Amazon.com Services LLC {row.site} + + + {site.street}, + + + {site.label} + +
+ + + Vendor / Technician:  + {row.tech || "—"} + {row.company ? ` · ${row.company}` : ""} + + +
    + {SAFETY_BULLETS.map((b, i) => ( +
  • + {b} +
  • + ))} +
+ + + {proc.heading} + + + {proc.intro} + + + + {Boolean(notes) && ( + <> + + PM Comments + + + {notes} + + + )} +
+
+
+ + {isNotRequired && ( +
+
+ NOT REQUIRED +
+
+ )} +
+
+
+ ); +} diff --git a/src/app/(protected)/workorders/_components/comp-doc/comp-doc-procedure-list.tsx b/src/app/(protected)/workorders/_components/comp-doc/comp-doc-procedure-list.tsx new file mode 100644 index 00000000..5d9de8b9 --- /dev/null +++ b/src/app/(protected)/workorders/_components/comp-doc/comp-doc-procedure-list.tsx @@ -0,0 +1,32 @@ +import type { Procedure } from "@/domain/work-orders/utils/completion-doc-procedures"; + +type CompDocProcedureListProps = { + proc: Procedure; +}; + +export function CompDocProcedureList({ proc }: CompDocProcedureListProps) { + return ( +
    + {proc.steps.map((st, i) => ( +
  1. + {st.text} + {st.sub != null && ( +
      + {st.sub.map((x, j) => ( +
    1. + {x} +
    2. + ))} +
    + )} +
  2. + ))} +
+ ); +} diff --git a/src/app/(protected)/workorders/_components/comp-doc/comp-doc-sidebar.tsx b/src/app/(protected)/workorders/_components/comp-doc/comp-doc-sidebar.tsx new file mode 100644 index 00000000..8e3b2c47 --- /dev/null +++ b/src/app/(protected)/workorders/_components/comp-doc/comp-doc-sidebar.tsx @@ -0,0 +1,207 @@ +import type { CSSProperties } from "react"; +import { Building2, MapPin, Users, Wrench } from "lucide-react"; +import type { CompDocSiteInfo, DocState } from "@/domain/work-orders/types/completion-doc"; +import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row"; +import { + DOC_STATE_CFG, + docStatusCardDescription, +} from "@/domain/work-orders/utils/completion-doc-state"; +import { CompDocDetailRow } from "./comp-doc-detail-row"; + +const COMP_DOC_INPUT_CLS = "w-full rounded-md px-2.5 py-1.5 focus:outline-none focus:ring-1"; + +const COMP_DOC_INPUT_STYLE: CSSProperties = { + fontSize: 13, + border: "1px solid var(--color-border)", + color: "var(--color-text-primary)", + background: "var(--color-bg-surface)", +}; + +type CompDocSidebarProps = { + row: WorkOrderTableRow; + site: CompDocSiteInfo; + docState: DocState; + generatedAt: string; + notes: string; + editDateCompleted: string; + amazonRep: string; + seaRep: string; + isGenerated: boolean; + onNotesChange: (value: string) => void; + onDateCompletedChange: (value: string) => void; +}; + +export function CompDocSidebar({ + row, + site, + docState, + generatedAt, + notes, + editDateCompleted, + amazonRep, + seaRep, + isGenerated, + onNotesChange, + onDateCompletedChange, +}: CompDocSidebarProps) { + const cfg = DOC_STATE_CFG[docState]; + const StateIcon = cfg.icon; + + const editRow = ( + label: string, + value: string, + onChange: (v: string) => void, + type = "text", + placeholder = "", + ) => ( +
+
+ {label} +
+ onChange(e.target.value)} + readOnly={isGenerated} + placeholder={placeholder} + className={COMP_DOC_INPUT_CLS} + style={{ + ...COMP_DOC_INPUT_STYLE, + ...(isGenerated + ? { + opacity: 0.6, + cursor: "default", + pointerEvents: "none" as const, + } + : {}), + }} + /> +
+ ); + + return ( +
+
+
+
+ +
+
+
+ {cfg.cardTitle} +
+
+ {docStatusCardDescription(docState, generatedAt)} +
+
+
+ +
+
+ Work Order Details +
+
+ + + + {editRow("Date Work Completed", editDateCompleted, onDateCompletedChange, "date")} + + +
+
+ +
+ +