Files
edr-platform/apps/edr-freight-web/backoffice/src/components/contracts/BookingChangesRequestedAlert.tsx

149 lines
4.7 KiB
TypeScript

import { Alert, Button, Group, Paper, Stack, Text } from "@mantine/core";
import { DateInput } from "@mantine/dates";
import { AlertTriangle, Pencil, Send } from "lucide-react";
import { useState } from "react";
import { Link } from "react-router-dom";
import toast from "react-hot-toast";
import { bookingsService } from "@/services/bookings.service";
export interface BookingChangesRequestedAlertProps {
bookingId: string;
reference?: string | null;
/** Operations' note — what has to change before this can go back to them. */
note?: string | null;
/** Shipment day the booking currently holds; the resubmit default. */
scheduledDate?: string | null;
/** GL Ethiopia owns customs bookings, so only they get the resubmit control. */
canResubmit: boolean;
/** Completion-form route for editing the cargo before resubmitting —
* rendered only for resubmit-capable users when provided. */
editHref?: string;
onResubmitted?: () => void;
}
/**
* Operations sent a GL-created booking back for changes.
*
* The customer cannot act on this — GL created the booking on their behalf — so
* the note and the way out both live here, on the page GL works from. Resubmit
* re-requests operation on the chosen shipment day; the server re-checks the day
* has a departure that can carry the cargo and refuses with the reason if not.
*/
export function BookingChangesRequestedAlert({
bookingId,
reference,
note,
scheduledDate,
canResubmit,
editHref,
onResubmitted,
}: BookingChangesRequestedAlertProps) {
const [day, setDay] = useState<Date | null>(
scheduledDate ? new Date(scheduledDate) : null,
);
const [sending, setSending] = useState(false);
const resubmit = async () => {
if (!day) return;
setSending(true);
try {
await bookingsService.proceedToOperation(bookingId, day.toISOString());
toast.success("Sent back to Operations for review");
onResubmitted?.();
} catch {
// The http interceptor already toasts the server's own reason (no
// departure that day, no wagon that can carry the cargo, export train
// full…) — a second toast here would just duplicate it.
} finally {
setSending(false);
}
};
return (
<Alert
color="red"
radius="md"
icon={<AlertTriangle size={16} />}
title={`Operations returned booking ${reference ?? ""} for changes`.trim()}
>
<Stack gap="sm" align="flex-start">
{note ? (
<Paper
withBorder
radius="md"
p="sm"
bg="red.0"
style={{ borderColor: "var(--mantine-color-red-3)", width: "100%" }}
>
<Text size="xs" fw={700} c="red.9" tt="uppercase" mb={4}>
What Operations asked for
</Text>
<Text size="sm" style={{ whiteSpace: "pre-wrap" }}>
{note}
</Text>
</Paper>
) : (
<Text size="sm">
Operations returned this booking without a note contact them for
the detail before resubmitting.
</Text>
)}
<Text size="sm">
This booking was created by GL Ethiopia, so the customer cannot fix it.
Make the correction Operations asked for, then send it back for review.{" "}
<Text
component={Link}
to={`/dashboard/bookings/${bookingId}/clearance`}
inherit
fw={600}
c="red.8"
>
Open the booking
</Text>
</Text>
{canResubmit ? (
<Group gap="sm" align="flex-end" wrap="wrap">
<DateInput
label="Shipment day"
description="Keep the day or pick another with an open departure"
value={day}
onChange={(v) => setDay(v ? new Date(v) : null)}
minDate={new Date()}
size="sm"
w={230}
/>
<Button
color="red"
radius="md"
size="sm"
loading={sending}
disabled={!day}
leftSection={<Send size={15} />}
onClick={() => void resubmit()}
>
Resubmit to Operations
</Button>
{editHref ? (
<Button
component={Link}
to={editHref}
variant="default"
radius="md"
size="sm"
leftSection={<Pencil size={15} />}
>
Edit cargo & resubmit
</Button>
) : null}
</Group>
) : null}
</Stack>
</Alert>
);
}
export default BookingChangesRequestedAlert;