mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-07 16:19:01 +00:00
fix(work-orders): split comp-doc dialog hook under max-lines gate
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
31dd9d5b72
commit
db2ca4d933
3 changed files with 135 additions and 59 deletions
|
|
@ -0,0 +1,58 @@
|
||||||
|
import { useEffect, useRef, type Dispatch, type SetStateAction } from "react";
|
||||||
|
import type { CompDocData, DocState } from "@/domain/work-orders/types/completion-doc";
|
||||||
|
import { docStateOf } from "@/domain/work-orders/utils/completion-doc-state";
|
||||||
|
|
||||||
|
type UseCompDocDialogSeedArgs = {
|
||||||
|
open: boolean;
|
||||||
|
infoId: string | number;
|
||||||
|
infoDocStatus?: string | null;
|
||||||
|
infoCompletedDate?: string | null;
|
||||||
|
completionDocStatus?: string | null;
|
||||||
|
data?: CompDocData;
|
||||||
|
setNotes: Dispatch<SetStateAction<string>>;
|
||||||
|
setDocState: Dispatch<SetStateAction<DocState>>;
|
||||||
|
setGeneratedAt: Dispatch<SetStateAction<string>>;
|
||||||
|
setEditDateCompleted: Dispatch<SetStateAction<string>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Prototype seeds once per open/WO session; detail refetches must not wipe edits. */
|
||||||
|
export function useCompDocDialogSeed({
|
||||||
|
open,
|
||||||
|
infoId,
|
||||||
|
infoDocStatus,
|
||||||
|
infoCompletedDate,
|
||||||
|
completionDocStatus,
|
||||||
|
data,
|
||||||
|
setNotes,
|
||||||
|
setDocState,
|
||||||
|
setGeneratedAt,
|
||||||
|
setEditDateCompleted,
|
||||||
|
}: UseCompDocDialogSeedArgs) {
|
||||||
|
const seedKeyRef = useRef<string | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!open) {
|
||||||
|
seedKeyRef.current = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const key = String(infoId);
|
||||||
|
if (seedKeyRef.current === key) return;
|
||||||
|
seedKeyRef.current = key;
|
||||||
|
setNotes(data?.notes ?? "");
|
||||||
|
setDocState(docStateOf(completionDocStatus || infoDocStatus));
|
||||||
|
setGeneratedAt(data?.generatedAt ?? "");
|
||||||
|
setEditDateCompleted(infoCompletedDate || "");
|
||||||
|
}, [
|
||||||
|
open,
|
||||||
|
infoId,
|
||||||
|
infoDocStatus,
|
||||||
|
infoCompletedDate,
|
||||||
|
completionDocStatus,
|
||||||
|
data?.notes,
|
||||||
|
data?.generatedAt,
|
||||||
|
setNotes,
|
||||||
|
setDocState,
|
||||||
|
setGeneratedAt,
|
||||||
|
setEditDateCompleted,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
import { useMemo, useRef, useState } from "react";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import { useLocationDetail } from "@/domain/locations/use-cases/use-location-detail";
|
import { useLocationDetail } from "@/domain/locations/use-cases/use-location-detail";
|
||||||
import type {
|
import type {
|
||||||
|
|
@ -11,8 +11,10 @@ import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-ta
|
||||||
import { useWorkOrderBoardDetail } from "@/domain/work-orders/use-cases/use-work-order-detail";
|
import { useWorkOrderBoardDetail } from "@/domain/work-orders/use-cases/use-work-order-detail";
|
||||||
import { useUploadCompletionDoc } from "@/domain/work-orders/use-cases/use-work-order-mutations";
|
import { useUploadCompletionDoc } from "@/domain/work-orders/use-cases/use-work-order-mutations";
|
||||||
import { resolveCompDocSite } from "@/domain/work-orders/utils/completion-doc-site";
|
import { resolveCompDocSite } from "@/domain/work-orders/utils/completion-doc-site";
|
||||||
import { DOC_STATE_CFG, docStateOf } from "@/domain/work-orders/utils/completion-doc-state";
|
import { DOC_STATE_CFG } from "@/domain/work-orders/utils/completion-doc-state";
|
||||||
import { isWorkOrderDocumentsReadOnly } from "@/domain/work-orders/utils/work-order-media-limits";
|
import { isWorkOrderDocumentsReadOnly } from "@/domain/work-orders/utils/work-order-media-limits";
|
||||||
|
import { useCompDocDialogSeed } from "./use-comp-doc-dialog-seed";
|
||||||
|
import { useCompDocNotRequiredActions } from "./use-comp-doc-not-required-actions";
|
||||||
import { useCompDocPdfActions } from "./use-comp-doc-pdf-actions";
|
import { useCompDocPdfActions } from "./use-comp-doc-pdf-actions";
|
||||||
import { useCompDocPersistFlow } from "./use-comp-doc-persist-flow";
|
import { useCompDocPersistFlow } from "./use-comp-doc-persist-flow";
|
||||||
|
|
||||||
|
|
@ -71,45 +73,31 @@ export function useCompDocDialog({
|
||||||
const signOffAttachment = completion?.signOffAttachment;
|
const signOffAttachment = completion?.signOffAttachment;
|
||||||
const rowVersion = info.rowVersion || row.rowVersion;
|
const rowVersion = info.rowVersion || row.rowVersion;
|
||||||
const isDocumentsReadOnly = isWorkOrderDocumentsReadOnly(info.status);
|
const isDocumentsReadOnly = isWorkOrderDocumentsReadOnly(info.status);
|
||||||
|
|
||||||
const site = useMemo(() => resolveCompDocSite(info, locationDetail), [info, locationDetail]);
|
const site = useMemo(() => resolveCompDocSite(info, locationDetail), [info, locationDetail]);
|
||||||
|
|
||||||
const [notes, setNotes] = useState("");
|
const [notes, setNotes] = useState("");
|
||||||
const [docState, setDocState] = useState<DocState>("draft");
|
const [docState, setDocState] = useState<DocState>("draft");
|
||||||
const [generatedAt, setGeneratedAt] = useState("");
|
const [generatedAt, setGeneratedAt] = useState("");
|
||||||
const [editDateCompleted, setEditDateCompleted] = useState("");
|
const [editDateCompleted, setEditDateCompleted] = useState("");
|
||||||
const seedKeyRef = useRef<string | null>(null);
|
|
||||||
|
|
||||||
// Prototype seeds once per open/WO session. Detail refetches must not wipe
|
useCompDocDialogSeed({
|
||||||
// in-progress PM comments or date edits (Bugbot: dialog effect clears edits).
|
|
||||||
useEffect(() => {
|
|
||||||
if (!open) {
|
|
||||||
seedKeyRef.current = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const key = String(info.id);
|
|
||||||
if (seedKeyRef.current === key) return;
|
|
||||||
seedKeyRef.current = key;
|
|
||||||
setNotes(data?.notes ?? "");
|
|
||||||
setDocState(docStateOf(completion?.docStatus || info.docStatus));
|
|
||||||
setGeneratedAt(data?.generatedAt ?? "");
|
|
||||||
setEditDateCompleted(info.completedDate || "");
|
|
||||||
}, [
|
|
||||||
open,
|
open,
|
||||||
info.id,
|
infoId: info.id,
|
||||||
info.docStatus,
|
infoDocStatus: info.docStatus,
|
||||||
info.completedDate,
|
infoCompletedDate: info.completedDate,
|
||||||
completion?.docStatus,
|
completionDocStatus: completion?.docStatus,
|
||||||
data?.notes,
|
data,
|
||||||
data?.generatedAt,
|
setNotes,
|
||||||
]);
|
setDocState,
|
||||||
|
setGeneratedAt,
|
||||||
|
setEditDateCompleted,
|
||||||
|
});
|
||||||
|
|
||||||
const amazonRep = info.pocName || "";
|
const amazonRep = info.pocName || "";
|
||||||
const seaRep = info.tech || "";
|
const seaRep = info.tech || "";
|
||||||
const cfg = DOC_STATE_CFG[docState];
|
const cfg = DOC_STATE_CFG[docState];
|
||||||
const isNotRequired = docState === "not-required";
|
const isNotRequired = docState === "not-required";
|
||||||
const isGenerated = docState === "generated" || Boolean(signOffAttachment);
|
const isGenerated = docState === "generated" || Boolean(signOffAttachment);
|
||||||
const isBusy = uploadCompletionMutation.isPending || isFinalizing;
|
|
||||||
|
|
||||||
const docFields: DocFields = {
|
const docFields: DocFields = {
|
||||||
street: site.street,
|
street: site.street,
|
||||||
|
|
@ -137,37 +125,13 @@ export function useCompDocDialog({
|
||||||
onDraftSaved: notifyDraftSaved,
|
onDraftSaved: notifyDraftSaved,
|
||||||
});
|
});
|
||||||
|
|
||||||
async function handleMarkNotRequired() {
|
const { handleMarkNotRequired, handleUndo } = useCompDocNotRequiredActions({
|
||||||
const previous = docState;
|
docState,
|
||||||
setDocState("not-required");
|
setDocState,
|
||||||
setIsFinalizing(true);
|
persist,
|
||||||
try {
|
refreshAuthoritativeState,
|
||||||
await persist({}, "NN");
|
setIsFinalizing,
|
||||||
} catch (error) {
|
});
|
||||||
setDocState(previous);
|
|
||||||
refreshAuthoritativeState();
|
|
||||||
toast.error(
|
|
||||||
error instanceof Error ? error.message : "Failed to mark document as not required",
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
setIsFinalizing(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleUndo() {
|
|
||||||
const previous = docState;
|
|
||||||
setDocState("draft");
|
|
||||||
setIsFinalizing(true);
|
|
||||||
try {
|
|
||||||
await persist({}, "No");
|
|
||||||
} catch (error) {
|
|
||||||
setDocState(previous);
|
|
||||||
refreshAuthoritativeState();
|
|
||||||
toast.error(error instanceof Error ? error.message : "Failed to undo not-required");
|
|
||||||
} finally {
|
|
||||||
setIsFinalizing(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const { handleDownloadPdf, handleUploadPdf } = useCompDocPdfActions({
|
const { handleDownloadPdf, handleUploadPdf } = useCompDocPdfActions({
|
||||||
info,
|
info,
|
||||||
|
|
@ -203,7 +167,7 @@ export function useCompDocDialog({
|
||||||
cfg,
|
cfg,
|
||||||
isNotRequired,
|
isNotRequired,
|
||||||
isGenerated,
|
isGenerated,
|
||||||
isUploading: isBusy,
|
isUploading: uploadCompletionMutation.isPending || isFinalizing,
|
||||||
pdfInputRef,
|
pdfInputRef,
|
||||||
handleMarkNotRequired,
|
handleMarkNotRequired,
|
||||||
handleUndo,
|
handleUndo,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
import type { CompDocSaveStatus, DocState } from "@/domain/work-orders/types/completion-doc";
|
||||||
|
|
||||||
|
type PersistFn = (data: Record<string, never>, status: CompDocSaveStatus) => void | Promise<void>;
|
||||||
|
|
||||||
|
type UseCompDocNotRequiredActionsArgs = {
|
||||||
|
docState: DocState;
|
||||||
|
setDocState: (state: DocState) => void;
|
||||||
|
persist: PersistFn;
|
||||||
|
refreshAuthoritativeState: () => void;
|
||||||
|
setIsFinalizing: (value: boolean) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useCompDocNotRequiredActions({
|
||||||
|
docState,
|
||||||
|
setDocState,
|
||||||
|
persist,
|
||||||
|
refreshAuthoritativeState,
|
||||||
|
setIsFinalizing,
|
||||||
|
}: UseCompDocNotRequiredActionsArgs) {
|
||||||
|
async function handleMarkNotRequired() {
|
||||||
|
const previous = docState;
|
||||||
|
setDocState("not-required");
|
||||||
|
setIsFinalizing(true);
|
||||||
|
try {
|
||||||
|
await persist({}, "NN");
|
||||||
|
} catch (error) {
|
||||||
|
setDocState(previous);
|
||||||
|
refreshAuthoritativeState();
|
||||||
|
toast.error(
|
||||||
|
error instanceof Error ? error.message : "Failed to mark document as not required",
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
setIsFinalizing(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleUndo() {
|
||||||
|
const previous = docState;
|
||||||
|
setDocState("draft");
|
||||||
|
setIsFinalizing(true);
|
||||||
|
try {
|
||||||
|
await persist({}, "No");
|
||||||
|
} catch (error) {
|
||||||
|
setDocState(previous);
|
||||||
|
refreshAuthoritativeState();
|
||||||
|
toast.error(error instanceof Error ? error.message : "Failed to undo not-required");
|
||||||
|
} finally {
|
||||||
|
setIsFinalizing(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { handleMarkNotRequired, handleUndo };
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue