import { useEffect, useMemo, useState } from "react"; import { useQueryClient } from "@tanstack/react-query"; import { toast } from "react-toastify"; import { showCompDocDraftSavedToast } from "@/app/(protected)/workorders/_components/comp-doc/comp-doc-draft-toast"; import { locationsApi } from "@/domain/locations/api/locations-api"; import type { Location } from "@/domain/locations/types/location"; import { useLocationDetail } from "@/domain/locations/use-cases/use-location-detail"; import type { CompDocData, CompDocSaveStatus, DocFields, DocState, } from "@/domain/work-orders/types/completion-doc"; import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row"; import { getMockWoWizardLocationDetail } from "@/domain/work-orders/mocks/wo-wizard-mock-data"; import { buildDocHtml, printDoc } from "@/domain/work-orders/utils/completion-doc-html"; import { resolveCompDocSite } from "@/domain/work-orders/utils/completion-doc-site"; import { DOC_STATE_CFG, docStateOf, fmtDocNow, } from "@/domain/work-orders/utils/completion-doc-state"; import { queryKeys } from "@/infra/query-key/query-key"; type UseCompDocDialogParams = { row: WorkOrderTableRow; open: boolean; data?: CompDocData; onSave: (data: CompDocData, status: CompDocSaveStatus) => void | Promise; onDateCompletedChange?: (date: string) => void | Promise; }; function buildAddressLine(site: { street: string; fullAddress: string }): string { if (site.street.trim()) return site.street.trim(); return site.fullAddress !== "—" ? site.fullAddress : ""; } function locationUpdatePayload(location: Location, address: string): Location { return { ...location, address, }; } export function useCompDocDialog({ row, open, data, onSave, onDateCompletedChange, }: UseCompDocDialogParams) { const queryClient = useQueryClient(); const locId = String(row.locationId || ""); const isMockLocation = locId.startsWith("mock-"); const { data: apiLocationDetail } = useLocationDetail( isMockLocation || !locId ? undefined : locId, ); const locationDetail = isMockLocation ? getMockWoWizardLocationDetail(locId) : apiLocationDetail; const site = useMemo(() => resolveCompDocSite(row, locationDetail), [row, locationDetail]); const [notes, setNotes] = useState(""); const [docState, setDocState] = useState("draft"); const [generatedAt, setGeneratedAt] = useState(""); const [editDateCompleted, setEditDateCompleted] = useState(""); const [editAddress, setEditAddress] = useState(""); useEffect(() => { if (!open) return; setNotes(data?.notes ?? ""); setDocState(docStateOf(row.docStatus)); setGeneratedAt(data?.generatedAt ?? ""); setEditDateCompleted(row.completedDate || ""); setEditAddress(buildAddressLine(resolveCompDocSite(row, locationDetail))); }, [open, row, data?.notes, data?.generatedAt, locationDetail]); const amazonRep = row.pocName || ""; const seaRep = row.tech || ""; const cfg = DOC_STATE_CFG[docState]; const isNotRequired = docState === "not-required"; const isGenerated = docState === "generated"; const effectiveStreet = editAddress.trim() || site.street; const docFields: DocFields = { street: effectiveStreet, city: site.city, state: site.state, zip: site.zip, dateCompleted: editDateCompleted, amazonRep, seaRep, }; const previewSite = useMemo( () => ({ ...site, street: effectiveStreet, fullAddress: [effectiveStreet, site.label, site.zip].filter(Boolean).join(", ") || effectiveStreet || "—", }), [site, effectiveStreet], ); async function persist(extra: Partial, status: CompDocSaveStatus): Promise { await onSave({ notes, generatedAt, ...extra }, status); } async function syncCompletedDateIfChanged(): Promise { if (editDateCompleted !== (row.completedDate || "")) { await onDateCompletedChange?.(editDateCompleted); } } async function syncAddressIfChanged(): Promise { const next = editAddress.trim(); const current = buildAddressLine(site); if (next === current) return; if (isMockLocation || !locId) return; if (!locationDetail) { throw new Error("Location details are still loading. Try saving again."); } await locationsApi.update(locId, locationUpdatePayload(locationDetail, next)); void queryClient.invalidateQueries({ queryKey: queryKeys.locations.detail(locId) }); void queryClient.invalidateQueries({ queryKey: queryKeys.locations.all }); void queryClient.invalidateQueries({ queryKey: queryKeys.workOrders.all }); } function handleMarkNotRequired() { setDocState("not-required"); void persist({}, "NN"); } function handleUndo() { setDocState("draft"); void persist({}, "No"); } async function handleSaveDraft() { try { await persist({}, "No"); await syncCompletedDateIfChanged(); await syncAddressIfChanged(); showCompDocDraftSavedToast(); } catch (error) { toast.error(error instanceof Error ? error.message : "Failed to save draft"); } } async function handleGenerate() { const ts = fmtDocNow(); try { await persist({ generatedAt: ts }, "Yes"); await syncCompletedDateIfChanged(); await syncAddressIfChanged(); setGeneratedAt(ts); setDocState("generated"); } catch (error) { toast.error(error instanceof Error ? error.message : "Failed to generate document"); } } function handleDownloadPdf() { printDoc(buildDocHtml(row, { notes, generatedAt }, docFields)); } return { site: previewSite, notes, setNotes, docState, generatedAt, editAddress, setEditAddress, editDateCompleted, setEditDateCompleted, amazonRep, seaRep, cfg, isNotRequired, isGenerated, handleMarkNotRequired, handleUndo, handleSaveDraft, handleGenerate, handleDownloadPdf, }; }