diff --git a/scripts/governance-baseline.json b/scripts/governance-baseline.json index d82858fd..93a682d9 100644 --- a/scripts/governance-baseline.json +++ b/scripts/governance-baseline.json @@ -8,11 +8,6 @@ "maxLines": 797, "reason": "Work-order detail route page; legacy godfile targeted for decomposition into focused state components." }, - { - "path": "src/app/(protected)/workorders/_components/dispatch-detail-modal.tsx", - "maxLines": 782, - "reason": "Dispatch detail modal; oversized legacy component pending extraction of sections/fields." - }, { "path": "src/app/(protected)/vendors/index.tsx", "maxLines": 612, diff --git a/src/app/(protected)/workorders/_components/dispatch/dispatch-detail/dispatch-checklist-section.tsx b/src/app/(protected)/workorders/_components/dispatch/dispatch-detail/dispatch-checklist-section.tsx index 1eb41674..03ff527a 100644 --- a/src/app/(protected)/workorders/_components/dispatch/dispatch-detail/dispatch-checklist-section.tsx +++ b/src/app/(protected)/workorders/_components/dispatch/dispatch-detail/dispatch-checklist-section.tsx @@ -42,7 +42,7 @@ export function DispatchChecklistSection({ /> {item.itemText} - {item.isCompleted && (item.completedBy || item.completedAt) && ( + {item.isCompleted && Boolean(item.completedBy || item.completedAt) && ( {item.completedBy?.trim() || "Unknown"} {item.completedAt ? ` · ${formatDateTime(item.completedAt)}` : ""} diff --git a/src/app/(protected)/workorders/_components/dispatch/dispatch-detail/dispatch-edit-form.tsx b/src/app/(protected)/workorders/_components/dispatch/dispatch-detail/dispatch-edit-form.tsx index a34baa47..1a0a27f2 100644 --- a/src/app/(protected)/workorders/_components/dispatch/dispatch-detail/dispatch-edit-form.tsx +++ b/src/app/(protected)/workorders/_components/dispatch/dispatch-detail/dispatch-edit-form.tsx @@ -133,7 +133,7 @@ export function DispatchDetailsView({ highlight={dispatch.status === "Sent" && !dispatch.acknowledgedAt ? waitColor : undefined} /> - {dispatch.description && ( + {Boolean(dispatch.description) && ( )} {!isLocked && ( diff --git a/src/app/(protected)/workorders/_components/dispatch/dispatch-detail/dispatch-signoffs-section.tsx b/src/app/(protected)/workorders/_components/dispatch/dispatch-detail/dispatch-signoffs-section.tsx index 57288b9b..00c5e177 100644 --- a/src/app/(protected)/workorders/_components/dispatch/dispatch-detail/dispatch-signoffs-section.tsx +++ b/src/app/(protected)/workorders/_components/dispatch/dispatch-detail/dispatch-signoffs-section.tsx @@ -26,7 +26,7 @@ export function DispatchSignoffsSection({ {type} {signoff ? ( - {signoff.signatureMethod === "drawn" && signoff.signature && ( + {signoff.signatureMethod === "drawn" && Boolean(signoff.signature) && ( Signature void; }; +type UpliftCardProps = Omit & { + uplift: UpliftRequest; +}; + +function UpliftCard({ uplift, isLocked, onApprove, onDeny }: UpliftCardProps) { + const canDecide = uplift.canDecide && uplift.status === "Pending" && !isLocked; + + return ( + + + + {uplift.requiredTier === 2 && ( + Tier 2 · Manager approval + )} + + ${Number(uplift.currentNTE ?? 0).toFixed(2)} → ${Number(uplift.requestedNTE).toFixed(2)}{" "} + (+${Number(uplift.delta).toFixed(2)}) + + + {Boolean(uplift.vendorReason) && ( + + Reason: {uplift.vendorReason} + + )} + {Boolean(uplift.requestedByVendorName || uplift.requestedAt) && ( + + Requested by {uplift.requestedByVendorName || "vendor"} + {uplift.requestedAt ? ` · ${formatDateTime(uplift.requestedAt)}` : ""} + + )} + {uplift.status !== "Pending" && + Boolean(uplift.decidedByName || uplift.decidedAt || uplift.decisionNote) && ( + + {Boolean(uplift.decidedByName || uplift.decidedAt) && ( + + {uplift.status} by {uplift.decidedByName || "—"} + {uplift.decidedAt ? ` · ${formatDateTime(uplift.decidedAt)}` : ""} + + )} + {Boolean(uplift.decisionNote) && ( + + Note: {uplift.decisionNote} + + )} + + )} + {uplift.status === "Pending" && ( + + {(["approve", "deny"] as const).map((action) => ( + + + + + + ))} + + )} + + ); +} + export function DispatchUpliftsSection({ uplifts, isLocked, @@ -24,82 +96,15 @@ export function DispatchUpliftsSection({ No uplift requests. ) : ( - {uplifts.map((uplift) => { - const canDecide = uplift.canDecide && uplift.status === "Pending" && !isLocked; - - return ( - - - - {uplift.requiredTier === 2 && ( - Tier 2 · Manager approval - )} - - ${Number(uplift.currentNTE ?? 0).toFixed(2)} → $ - {Number(uplift.requestedNTE).toFixed(2)} (+$ - {Number(uplift.delta).toFixed(2)}) - - - {uplift.vendorReason && ( - - Reason: {uplift.vendorReason} - - )} - {(uplift.requestedByVendorName || uplift.requestedAt) && ( - - Requested by {uplift.requestedByVendorName || "vendor"} - {uplift.requestedAt ? ` · ${formatDateTime(uplift.requestedAt)}` : ""} - - )} - {uplift.status !== "Pending" && - (uplift.decidedByName || uplift.decidedAt || uplift.decisionNote) && ( - - {(uplift.decidedByName || uplift.decidedAt) && ( - - {uplift.status} by {uplift.decidedByName || "—"} - {uplift.decidedAt ? ` · ${formatDateTime(uplift.decidedAt)}` : ""} - - )} - {uplift.decisionNote && ( - - Note: {uplift.decisionNote} - - )} - - )} - {uplift.status === "Pending" && ( - - - - - - - - - - - - - )} - - ); - })} + {uplifts.map((uplift) => ( + + ))} )} diff --git a/src/app/(protected)/workorders/_components/dispatch/dispatch-detail/index.tsx b/src/app/(protected)/workorders/_components/dispatch/dispatch-detail/index.tsx index 487cfcd5..7189fe1e 100644 --- a/src/app/(protected)/workorders/_components/dispatch/dispatch-detail/index.tsx +++ b/src/app/(protected)/workorders/_components/dispatch/dispatch-detail/index.tsx @@ -124,7 +124,7 @@ export function DispatchDetailModal({ - {controller.sigCaptureType && ( + {controller.sigCaptureType != null && ( controller.setSigCaptureType(null)} @@ -142,7 +142,7 @@ export function DispatchDetailModal({ /> )} - {controller.upliftAction && ( + {controller.upliftAction != null && ( item.isCompleted).length; + const signoffTypes = new Set(dispatch.signoffs.map((signoff) => signoff.signoffType)); + const missing: string[] = []; + + if (checklistDone < checklistTotal) { + missing.push(`${checklistTotal - checklistDone} checklist item(s)`); + } + if (!signoffTypes.has("Customer")) { + missing.push("Customer sign-off"); + } + if (!signoffTypes.has("Vendor")) { + missing.push("Vendor sign-off"); + } + + return { + missing, + canVerify: missing.length === 0 && (checklistTotal > 0 || dispatch.signoffs.length >= 2), + }; +} + export function useDispatchDetailController( dispatchId: string | number, workOrderId: string | number, @@ -62,35 +88,7 @@ export function useDispatchDetailController( const isLocked = dispatch ? isDispatchLocked(dispatch) : false; - const verifyState = useMemo(() => { - if (!dispatch) { - return { canVerify: false, missing: [] as string[] }; - } - - const checklistTotal = dispatch.checklistItems.length; - const checklistDone = dispatch.checklistItems.filter((item) => item.isCompleted).length; - const signoffCount = dispatch.signoffs.length; - const missing: string[] = []; - - if (checklistTotal > 0 && checklistDone < checklistTotal) { - missing.push(`${checklistTotal - checklistDone} checklist item(s)`); - } - - if (signoffCount < 2) { - const types = dispatch.signoffs.map((signoff) => signoff.signoffType); - if (!types.includes("Customer")) { - missing.push("Customer sign-off"); - } - if (!types.includes("Vendor")) { - missing.push("Vendor sign-off"); - } - } - - return { - missing, - canVerify: missing.length === 0 && (checklistTotal > 0 || signoffCount >= 2), - }; - }, [dispatch]); + const verifyState = useMemo(() => buildVerifyState(dispatch), [dispatch]); const beginEditing = () => { if (dispatch) {