mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 23:28:11 +00:00
- Create migration for booking_requests table with necessary fields and indexes. - Implement BookingRequestRepository for database operations related to booking requests. - Develop BookingRequestService to handle business logic for submitting, accepting, rejecting, and canceling booking requests. - Create DTOs for creating booking requests and reviewing them. - Define BookingRequest entity to map to the booking_requests table. - Add UI components for managing shipment requests, including detail and list pages. - Implement OperationDatePicker component for selecting available shipment days.
110 lines
3.7 KiB
TypeScript
110 lines
3.7 KiB
TypeScript
import { Banknote, Receipt } from "lucide-react";
|
|
import { Divider, Group, Paper, Stack, Text } from "@mantine/core";
|
|
|
|
import type { BookingDetail } from "@/types/booking";
|
|
|
|
import { SectionCard } from "./detail/SectionCard";
|
|
import { detailStyles } from "./detail/booking-detail.styles";
|
|
|
|
export function BookingPricingSummary({ booking }: { booking: BookingDetail }) {
|
|
const computed = Number(booking.totalAmount);
|
|
// The booking price is computed from the contract and is NOT staff-editable.
|
|
// A historical `adjustedTotalAmount` (from before adjustments were removed)
|
|
// is still shown read-only so old records render correctly.
|
|
const isAdjusted =
|
|
booking.adjustedTotalAmount !== null &&
|
|
booking.adjustedTotalAmount !== undefined;
|
|
const effective = isAdjusted ? Number(booking.adjustedTotalAmount) : computed;
|
|
|
|
const lineItems = booking.pricingBreakdown?.lineItems ?? [];
|
|
|
|
const fmt = (n: number) =>
|
|
`${booking.paymentCurrency} ${n.toLocaleString(undefined, { minimumFractionDigits: 2 })}`;
|
|
|
|
return (
|
|
<SectionCard icon={Banknote} title="Pricing & payment">
|
|
<Stack gap="md">
|
|
<Paper radius="md" withBorder p="md" style={detailStyles.highlightCard}>
|
|
<Text size="xs" c="dimmed" fw={500} tt="uppercase" lts="0.04em">
|
|
{isAdjusted ? "Adjusted total" : "Total amount"}
|
|
</Text>
|
|
<Text
|
|
size="xl"
|
|
fw={700}
|
|
c="edr-green.9"
|
|
mt={4}
|
|
style={{ fontVariantNumeric: "tabular-nums", letterSpacing: "-0.5px" }}
|
|
>
|
|
{fmt(effective)}
|
|
</Text>
|
|
{isAdjusted && (
|
|
<Text size="xs" c="dimmed" mt={2}>
|
|
Computed: {fmt(computed)}
|
|
{booking.adjustmentReason ? ` · ${booking.adjustmentReason}` : ""}
|
|
</Text>
|
|
)}
|
|
</Paper>
|
|
|
|
<Row label="Payment status" value={booking.paymentStatus} />
|
|
{booking.pnrCode && <Row label="PNR code" value={booking.pnrCode} mono />}
|
|
|
|
{lineItems.length > 0 && (
|
|
<>
|
|
<Divider color="var(--mantine-color-gray-2)" />
|
|
<Group gap={6}>
|
|
<Receipt size={13} color="var(--mantine-color-gray-5)" />
|
|
<Text size="xs" c="dimmed" fw={500} tt="uppercase" lts="0.04em">
|
|
Price breakdown
|
|
</Text>
|
|
</Group>
|
|
<Stack gap="xs">
|
|
{lineItems.map((li, i) => (
|
|
<Group
|
|
key={`${li.code}-${i}`}
|
|
justify="space-between"
|
|
px="sm"
|
|
py={6}
|
|
style={{
|
|
borderRadius: 8,
|
|
border: "1px solid var(--mantine-color-gray-2)",
|
|
background: "var(--mantine-color-gray-0)",
|
|
}}
|
|
>
|
|
<Text size="sm" c="dimmed">
|
|
{li.description}
|
|
</Text>
|
|
<Text size="sm" fw={600} style={{ fontVariantNumeric: "tabular-nums" }}>
|
|
{Number(li.amount).toLocaleString()} {li.currency}
|
|
</Text>
|
|
</Group>
|
|
))}
|
|
</Stack>
|
|
</>
|
|
)}
|
|
</Stack>
|
|
</SectionCard>
|
|
);
|
|
}
|
|
|
|
function Row({ label, value, mono }: { label: string; value: string; mono?: boolean }) {
|
|
return (
|
|
<Group
|
|
justify="space-between"
|
|
px="sm"
|
|
py="xs"
|
|
style={{
|
|
borderRadius: 8,
|
|
border: "1px solid var(--mantine-color-gray-2)",
|
|
background: "var(--mantine-color-gray-0)",
|
|
}}
|
|
>
|
|
<Text size="sm" c="dimmed">
|
|
{label}
|
|
</Text>
|
|
<Text size="sm" fw={600} ff={mono ? "monospace" : undefined}>
|
|
{value}
|
|
</Text>
|
|
</Group>
|
|
);
|
|
}
|