mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 09:58:12 +00:00
general contrat
This commit is contained in:
@@ -1,10 +1,14 @@
|
||||
import { Button, Group, type ButtonProps } from "@mantine/core";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { LucideIcon } from "lucide-react";
|
||||
import type { ReactNode } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
import type { Freight } from "@edr/types";
|
||||
|
||||
import { PayNowButton } from "@/pages/bookings/payments/PayNowButton";
|
||||
import { api } from "@/services/api";
|
||||
import { ContractClearanceAction } from "./ContractClearanceAction";
|
||||
import { deriveContractCustomerAction } from "./deriveContractCustomerAction";
|
||||
|
||||
@@ -56,6 +60,18 @@ export function ContractCustomerAction({
|
||||
return <PayNowButton booking={action.booking} label={action.label} size={size} />;
|
||||
}
|
||||
|
||||
if (action.type === "initiate") {
|
||||
return (
|
||||
<InitiateBookingButton
|
||||
contract={action.contract}
|
||||
label={action.label}
|
||||
icon={action.icon}
|
||||
size={size}
|
||||
listStyle={listStyle}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const Icon = action.icon;
|
||||
const variant = action.primary ? "filled" : "light";
|
||||
|
||||
@@ -80,6 +96,88 @@ export function ContractCustomerAction({
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* One-click bare booking instance under a GENERAL non-customs contract. No
|
||||
* form, no date, no window gate — the new instance lands in per-booking
|
||||
* clearance (AWAITING_DOCUMENTS) and the customer is taken straight to it.
|
||||
*/
|
||||
export function InitiateBookingButton({
|
||||
contract,
|
||||
label = "Initiate booking",
|
||||
icon: Icon,
|
||||
size = "xs",
|
||||
listStyle = false,
|
||||
fullWidth = false,
|
||||
}: {
|
||||
contract: Freight.IContract;
|
||||
label?: string;
|
||||
icon: LucideIcon;
|
||||
size?: ButtonProps["size"];
|
||||
listStyle?: boolean;
|
||||
fullWidth?: boolean;
|
||||
}) {
|
||||
const navigate = useNavigate();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const mutation = useMutation({
|
||||
mutationFn: () =>
|
||||
api.contracts.initiateBookingUnderContract.call({
|
||||
id: contract.id,
|
||||
// Multi-route contracts must name a route; single-route auto-selects.
|
||||
contractRouteId:
|
||||
(contract.routes?.length ?? 0) > 1
|
||||
? contract.routes![0].id
|
||||
: undefined,
|
||||
}),
|
||||
onSuccess: (booking) => {
|
||||
queryClient.invalidateQueries({ queryKey: api.bookings.list.queryKey() });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: api.contracts.get.queryKey({ id: contract.id }),
|
||||
});
|
||||
toast.success(
|
||||
"Booking initiated — upload your clearance documents to start the review.",
|
||||
);
|
||||
navigate(`/bookings/${booking.id}`);
|
||||
},
|
||||
onError: (e: Error) =>
|
||||
toast.error(e.message || "Could not initiate the booking"),
|
||||
});
|
||||
|
||||
return (
|
||||
<Button
|
||||
size={size}
|
||||
radius="md"
|
||||
h={listStyle ? 34 : undefined}
|
||||
variant="filled"
|
||||
color="edr-green"
|
||||
fullWidth={fullWidth}
|
||||
leftSection={<Icon size={15} />}
|
||||
loading={mutation.isPending}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
mutation.mutate();
|
||||
}}
|
||||
styles={
|
||||
listStyle
|
||||
? {
|
||||
root: {
|
||||
fontWeight: 600,
|
||||
fontSize: 13,
|
||||
paddingInline: 14,
|
||||
whiteSpace: "nowrap" as const,
|
||||
boxShadow: "0 1px 2px rgba(14,163,113,0.25)",
|
||||
},
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
fw={listStyle ? undefined : 700}
|
||||
fz={listStyle ? undefined : 13}
|
||||
>
|
||||
{label}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
/** Action column cell: doc button + primary customer action. */
|
||||
export function ContractCustomerActionCell({
|
||||
contract,
|
||||
|
||||
@@ -72,6 +72,14 @@ export type ContractCustomerAction =
|
||||
label: string;
|
||||
primary: boolean;
|
||||
icon: LucideIcon;
|
||||
}
|
||||
| {
|
||||
/** One-click bare booking instance (GENERAL non-customs) — mutation, not navigation. */
|
||||
type: "initiate";
|
||||
contract: Freight.IContract;
|
||||
label: string;
|
||||
primary: boolean;
|
||||
icon: LucideIcon;
|
||||
};
|
||||
|
||||
function findPayableBookingForContract(
|
||||
@@ -210,6 +218,15 @@ export function deriveContractCustomerAction(
|
||||
}
|
||||
|
||||
const bookingAction = getContractBookingAction(contract, bookings);
|
||||
if (bookingAction.kind === "initiate") {
|
||||
return {
|
||||
type: "initiate",
|
||||
contract,
|
||||
label: "Initiate booking",
|
||||
primary: true,
|
||||
icon: PackagePlus,
|
||||
};
|
||||
}
|
||||
if (bookingAction.kind === "book") {
|
||||
return {
|
||||
type: "navigate",
|
||||
|
||||
Reference in New Issue
Block a user