mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 15:18:11 +00:00
140 lines
4.2 KiB
TypeScript
140 lines
4.2 KiB
TypeScript
import { useState } from "react";
|
|
import { Download, Zap, FileText, Clock } from "lucide-react";
|
|
import { Stack, Text, Button } from "@mantine/core";
|
|
|
|
import { AllocateBookingWizard } from "@/components/trainScheduling/AllocateBookingWizard";
|
|
import type { BookingDetail } from "@/types/booking";
|
|
import { BookingActionsMenu } from "./BookingActionsMenu";
|
|
import { SectionCard } from "./detail/SectionCard";
|
|
import { toBookingListRow } from "@/features/bookings/mapBookingListRow";
|
|
import { canAllocateBooking } from "@/features/bookings/booking-actions.config";
|
|
import type { useBookingMutations } from "@/hooks/bookings/useBookings";
|
|
|
|
type Mutations = ReturnType<typeof useBookingMutations>;
|
|
|
|
interface BookingActionsToolbarProps {
|
|
booking: BookingDetail;
|
|
mutations: Mutations;
|
|
}
|
|
|
|
/** Detail-page actions: primary toolbar + downloads. */
|
|
export function BookingActionsToolbar({ booking, mutations }: BookingActionsToolbarProps) {
|
|
const row = toBookingListRow(booking);
|
|
const { status } = booking;
|
|
const [allocateOpen, setAllocateOpen] = useState(false);
|
|
|
|
const downloadBlob = async (fn: () => Promise<Blob>, filename: string) => {
|
|
const blob = await fn();
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement("a");
|
|
a.href = url;
|
|
a.download = filename;
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
};
|
|
|
|
if (status === "REJECTED" || status === "CANCELLED" || status === "COMPLETED") {
|
|
return null;
|
|
}
|
|
|
|
if (status === "CHANGES_REQUESTED") {
|
|
return (
|
|
<SectionCard icon={Zap} title="Awaiting customer">
|
|
<Stack gap="sm">
|
|
<Text size="sm" c="dimmed">
|
|
No staff actions until resubmit.
|
|
</Text>
|
|
{booking.latestChangeRequestNote && (
|
|
<Text
|
|
size="sm"
|
|
p="sm"
|
|
style={{
|
|
borderRadius: 8,
|
|
border: "1px solid var(--mantine-color-gray-2)",
|
|
background: "var(--mantine-color-gray-0)",
|
|
lineHeight: 1.5,
|
|
}}
|
|
>
|
|
{booking.latestChangeRequestNote}
|
|
</Text>
|
|
)}
|
|
</Stack>
|
|
</SectionCard>
|
|
);
|
|
}
|
|
|
|
if (["DRAFT", "PENDING_CONSOLIDATION", "CONSOLIDATED"].includes(status)) {
|
|
return (
|
|
<SectionCard icon={Zap} title="No staff actions">
|
|
<Text size="sm" c="dimmed">
|
|
Monitor until the customer or system advances status.
|
|
</Text>
|
|
</SectionCard>
|
|
);
|
|
}
|
|
|
|
if (
|
|
["FULLY_EXECUTED", "PNR_GENERATED", "PAYMENT_VERIFICATION_IN_PROGRESS"].includes(
|
|
status,
|
|
)
|
|
) {
|
|
return (
|
|
<Stack gap="lg">
|
|
<SectionCard icon={Clock} title="Awaiting customer payment">
|
|
<Stack gap="sm">
|
|
<Text size="sm" c="dimmed">
|
|
Payment is completed by the customer. The booking status updates
|
|
automatically once payment is confirmed, then moves to Operations.
|
|
</Text>
|
|
{status === "FULLY_EXECUTED" && (
|
|
<BookingActionsMenu row={row} variant="toolbar" />
|
|
)}
|
|
</Stack>
|
|
</SectionCard>
|
|
</Stack>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Stack gap="lg">
|
|
<SectionCard icon={Zap} title="Staff actions">
|
|
<Stack gap="sm">
|
|
<Text size="xs" c="dimmed">
|
|
Confirm each step before it is applied.
|
|
</Text>
|
|
<BookingActionsMenu
|
|
row={row}
|
|
variant="toolbar"
|
|
onAllocateBooking={() => setAllocateOpen(true)}
|
|
/>
|
|
</Stack>
|
|
</SectionCard>
|
|
|
|
{status === "CONTRACT_READY" && (
|
|
<SectionCard icon={FileText} title="Documents">
|
|
<Button
|
|
variant="default"
|
|
leftSection={<Download size={16} />}
|
|
onClick={() =>
|
|
downloadBlob(
|
|
() => mutations.downloadContract(),
|
|
`contract-${booking.reference}.txt`,
|
|
)
|
|
}
|
|
>
|
|
Download contract
|
|
</Button>
|
|
</SectionCard>
|
|
)}
|
|
|
|
{canAllocateBooking(booking) ? (
|
|
<AllocateBookingWizard
|
|
booking={booking}
|
|
opened={allocateOpen}
|
|
onClose={() => setAllocateOpen(false)}
|
|
/>
|
|
) : null}
|
|
</Stack>
|
|
);
|
|
}
|