mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-06 17:02:05 +00:00
Keep Flag, comments, and extra docs writable after completion, and hide the completed status menu.
155 lines
5.2 KiB
TypeScript
155 lines
5.2 KiB
TypeScript
import { useParams } from "react-router";
|
|
import { useState } from "react";
|
|
import { Box } from "@mui/material";
|
|
import { QueryErrorPanel } from "@/components/ui/query-error-panel";
|
|
import { DetailPageSkeleton } from "./_components/loading/detail-page-skeleton";
|
|
import { DispatchCreateModal } from "./_components/dispatch-create-modal";
|
|
import { DispatchDetailModal } from "./_components/dispatch-detail-modal";
|
|
import { WorkOrderActivityPanel } from "./_components/view/work-order-activity-panel";
|
|
import { WorkOrderDispatchesAccordion } from "./_components/view/work-order-dispatches-accordion";
|
|
import { WorkOrderVendorEditorDialog } from "./_components/view/work-order-vendor-editor-dialog";
|
|
import { WorkOrderViewAccordions } from "./_components/view/work-order-view-accordions";
|
|
import { WorkOrderViewDetails } from "./_components/view/work-order-view-details";
|
|
import { WorkOrderViewHeader } from "./_components/view/work-order-view-header";
|
|
import { useWorkOrderViewPage } from "./_hooks/use-work-order-view-page";
|
|
import { WorkOrderCompleteDialog } from "./_components/list/work-order-complete-dialog";
|
|
import {
|
|
detailToClosabilityInput,
|
|
getClosabilityGaps,
|
|
isCompletionStatusLabel,
|
|
} from "@/domain/work-orders/utils/wo-closability";
|
|
import {
|
|
isWorkOrderCoreLocked,
|
|
isWorkOrderFullyLocked,
|
|
} from "@/domain/work-orders/utils/work-order-lock";
|
|
import type { WorkOrderStatus } from "@/domain/work-orders/types/work-order";
|
|
|
|
export default function WorkOrderViewPage() {
|
|
const { id } = useParams();
|
|
const workOrderId = id ?? "";
|
|
const view = useWorkOrderViewPage(workOrderId);
|
|
const [confirmComplete, setConfirmComplete] = useState(false);
|
|
|
|
if (view.isLoading && !view.wo) {
|
|
return <DetailPageSkeleton variant="view" />;
|
|
}
|
|
|
|
if (!view.wo) {
|
|
return (
|
|
<Box className="p-4">
|
|
<QueryErrorPanel
|
|
message={view.error instanceof Error ? view.error.message : "Work order not found."}
|
|
onRetry={() => void view.refetch()}
|
|
/>
|
|
</Box>
|
|
);
|
|
}
|
|
|
|
const wo = view.wo;
|
|
const isLocked = isWorkOrderCoreLocked(wo.status) || isWorkOrderFullyLocked(wo.status);
|
|
|
|
const handleStatusChange = (status: string) => {
|
|
if (isLocked) return;
|
|
const isCompletionStatus = isCompletionStatusLabel(status);
|
|
if (
|
|
isCompletionStatus &&
|
|
(!view.isClosabilityReady || getClosabilityGaps(detailToClosabilityInput(wo)).length > 0)
|
|
) {
|
|
return;
|
|
}
|
|
if (isCompletionStatus) {
|
|
setConfirmComplete(true);
|
|
return;
|
|
}
|
|
view.statusMutation.mutate(status as WorkOrderStatus);
|
|
};
|
|
|
|
return (
|
|
<Box className="flex flex-col gap-4 p-4">
|
|
<WorkOrderViewHeader
|
|
wo={wo}
|
|
workOrderId={workOrderId}
|
|
isClosabilityReady={view.isClosabilityReady}
|
|
statusAnchor={view.statusAnchor}
|
|
onStatusAnchorChange={view.setStatusAnchor}
|
|
onStatusChange={handleStatusChange}
|
|
onOpenDispatch={() => view.setDispatchOpen(true)}
|
|
readOnly={isLocked}
|
|
/>
|
|
|
|
<WorkOrderViewDetails
|
|
wo={view.wo}
|
|
users={view.users}
|
|
assignAnchor={view.assignAnchor}
|
|
onAssignAnchorChange={view.setAssignAnchor}
|
|
onAssign={(userId, userName) => {
|
|
if (isLocked) return;
|
|
view.assignmentMutation.mutate({ userId, userName });
|
|
}}
|
|
onUnassign={() => {
|
|
if (isLocked) return;
|
|
view.assignmentMutation.mutate({ userId: "", userName: "" });
|
|
}}
|
|
readOnly={isLocked}
|
|
/>
|
|
|
|
<WorkOrderViewAccordions wo={view.wo} />
|
|
|
|
<WorkOrderDispatchesAccordion
|
|
wo={view.wo}
|
|
vendorViewOnly={isLocked}
|
|
onOpenDispatchDetail={view.setDispatchDetailId}
|
|
onOpenVendorEditor={view.openVendorEditor}
|
|
/>
|
|
|
|
<WorkOrderActivityPanel
|
|
customerComments={view.customerComments}
|
|
internalComments={view.internalComments}
|
|
auditLog={view.auditLog}
|
|
mentionUsers={view.mentionUsers}
|
|
isSubmitting={view.commentMutation.isPending}
|
|
onSubmitComment={view.submitComment}
|
|
/>
|
|
|
|
{view.dispatchOpen && (
|
|
<DispatchCreateModal
|
|
workOrder={view.wo}
|
|
onClose={() => view.setDispatchOpen(false)}
|
|
onDispatched={() => void view.refetch()}
|
|
/>
|
|
)}
|
|
{view.dispatchDetailId != null && (
|
|
<DispatchDetailModal
|
|
dispatchId={view.dispatchDetailId}
|
|
workOrderId={workOrderId}
|
|
onClose={() => view.setDispatchDetailId(null)}
|
|
onUpdated={() => void view.refetch()}
|
|
/>
|
|
)}
|
|
|
|
<WorkOrderVendorEditorDialog
|
|
editor={view.vendorEditor}
|
|
loading={view.vendorEditorLoading}
|
|
error={view.vendorEditorError}
|
|
isSaving={view.vendorMutation.isPending}
|
|
viewOnly={isLocked}
|
|
onClose={() => {
|
|
if (!view.vendorMutation.isPending) view.setVendorEditor(null);
|
|
}}
|
|
onSave={view.saveVendorEditor}
|
|
onEditorChange={view.setVendorEditor}
|
|
/>
|
|
|
|
<WorkOrderCompleteDialog
|
|
open={confirmComplete}
|
|
isPending={view.statusMutation.isPending}
|
|
onDialogClose={() => setConfirmComplete(false)}
|
|
onKeepOpen={() => setConfirmComplete(false)}
|
|
onConfirm={() => {
|
|
view.statusMutation.mutate("Done");
|
|
setConfirmComplete(false);
|
|
}}
|
|
/>
|
|
</Box>
|
|
);
|
|
}
|