mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-07 02:22:06 +00:00
129 lines
4.3 KiB
TypeScript
129 lines
4.3 KiB
TypeScript
import { useCallback, useState } from "react";
|
|
import { useParams } from "react-router";
|
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
import { Text } from "@/components/ui/text";
|
|
import { DispatchDetailSections } from "@/app/v/[token]/dispatch/_components/dispatch-detail-sections";
|
|
import { DispatchSummaryCard } from "@/app/v/[token]/dispatch/_components/dispatch-summary-card";
|
|
import { RefuseDispatchDialog } from "@/app/v/[token]/dispatch/_components/refuse-dispatch-dialog";
|
|
import { useVendorPortal } from "@/app/v/_components/vendor-portal-context";
|
|
import { vendorPortalApi } from "@/domain/vendor-portal/api/vendor-portal-api";
|
|
import { isVendorPortalLockedStatus } from "@/domain/vendor-portal/lib/status-helpers";
|
|
import type { VendorPortalDispatchDetail } from "@/domain/vendor-portal/types/vendor-portal";
|
|
import { queryKeys } from "@/infra/query-key/query-key";
|
|
|
|
export default function VendorPortalDispatchPage() {
|
|
const { token } = useVendorPortal();
|
|
const { id = "" } = useParams();
|
|
const dispatchId = Number(id);
|
|
const queryClient = useQueryClient();
|
|
const [busy, setBusy] = useState(false);
|
|
const [actionError, setActionError] = useState("");
|
|
const [refuseOpen, setRefuseOpen] = useState(false);
|
|
|
|
const { data, isLoading, error, refetch } = useQuery({
|
|
queryKey: queryKeys.vendorPortal.dispatch(token, dispatchId),
|
|
queryFn: () => vendorPortalApi.getDispatch(token, dispatchId),
|
|
enabled: Boolean(token && dispatchId),
|
|
});
|
|
|
|
const refresh = useCallback(async () => {
|
|
await refetch();
|
|
await queryClient.invalidateQueries({ queryKey: queryKeys.vendorPortal.dispatches(token) });
|
|
}, [refetch, queryClient, token]);
|
|
|
|
const pollEvidenceDocument = useCallback(
|
|
(documentId: number) => vendorPortalApi.getDocumentStatus(token, dispatchId, documentId),
|
|
[token, dispatchId],
|
|
);
|
|
|
|
const runAction = async (action: () => Promise<void>, confirmMsg?: string) => {
|
|
if (confirmMsg && !window.confirm(confirmMsg)) return;
|
|
setActionError("");
|
|
setBusy(true);
|
|
try {
|
|
await action();
|
|
await refresh();
|
|
} catch {
|
|
setActionError("Unable to update this dispatch. Please try again.");
|
|
} finally {
|
|
setBusy(false);
|
|
}
|
|
};
|
|
|
|
const updateLocal = (
|
|
updater: (current: VendorPortalDispatchDetail) => VendorPortalDispatchDetail,
|
|
) => {
|
|
queryClient.setQueryData(
|
|
queryKeys.vendorPortal.dispatch(token, dispatchId),
|
|
(current: unknown) => {
|
|
if (!current) return current;
|
|
return updater(current as VendorPortalDispatchDetail);
|
|
},
|
|
);
|
|
};
|
|
|
|
const requestCancel = () => {
|
|
const reason = window.prompt("Reason for cancel request?");
|
|
if (reason == null) return;
|
|
void runAction(() => vendorPortalApi.requestCancel(token, dispatchId, reason));
|
|
};
|
|
|
|
if (isLoading && !data) {
|
|
return (
|
|
<Text variant="feedback" className="vp-card vp-muted">
|
|
Loading dispatch…
|
|
</Text>
|
|
);
|
|
}
|
|
|
|
if (error && !data) {
|
|
return <Text variant="error">Unable to load this dispatch. Please try again.</Text>;
|
|
}
|
|
|
|
if (!data) return null;
|
|
|
|
const locked = isVendorPortalLockedStatus(data.status);
|
|
|
|
return (
|
|
<>
|
|
<DispatchSummaryCard
|
|
token={token}
|
|
data={data}
|
|
locked={locked}
|
|
busy={busy}
|
|
onAccept={() => void runAction(() => vendorPortalApi.accept(token, dispatchId))}
|
|
onRefuse={() => setRefuseOpen(true)}
|
|
onStart={() =>
|
|
void runAction(() => vendorPortalApi.changeStatus(token, dispatchId, "In Progress"))
|
|
}
|
|
onComplete={() =>
|
|
void runAction(
|
|
() => vendorPortalApi.changeStatus(token, dispatchId, "Completed"),
|
|
"Mark this dispatch as completed?",
|
|
)
|
|
}
|
|
onRequestCancel={requestCancel}
|
|
/>
|
|
<Text variant="error" when={Boolean(actionError)}>
|
|
{actionError}
|
|
</Text>
|
|
|
|
<DispatchDetailSections
|
|
token={token}
|
|
dispatchId={dispatchId}
|
|
data={data}
|
|
locked={locked}
|
|
refresh={refresh}
|
|
pollEvidenceDocument={pollEvidenceDocument}
|
|
updateLocal={updateLocal}
|
|
/>
|
|
|
|
<RefuseDispatchDialog
|
|
open={refuseOpen}
|
|
dispatchId={dispatchId}
|
|
onClose={() => setRefuseOpen(false)}
|
|
onRefused={() => setActionError("")}
|
|
/>
|
|
</>
|
|
);
|
|
}
|