mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
feat: enhance ClearanceChargesSection with file viewing and downloading capabilities
This commit is contained in:
@@ -102,8 +102,9 @@ export function ClearanceChargesTab({
|
||||
onError,
|
||||
});
|
||||
const bill = useMutation({
|
||||
mutationFn: (p: BillInput & { chargeId: string }) =>
|
||||
bookingsService.billClearanceCharge(bookingId, p.chargeId, p),
|
||||
// Body must be exactly the DTO — the API rejects unknown keys like chargeId.
|
||||
mutationFn: ({ chargeId, ...payload }: BillInput & { chargeId: string }) =>
|
||||
bookingsService.billClearanceCharge(bookingId, chargeId, payload),
|
||||
onSuccess: (next) => {
|
||||
toast.success("Charge amount saved");
|
||||
refresh(next);
|
||||
@@ -120,8 +121,8 @@ export function ClearanceChargesTab({
|
||||
onError,
|
||||
});
|
||||
const createMisc = useMutation({
|
||||
mutationFn: (p: BillInput & { file: File }) =>
|
||||
bookingsService.createMiscellaneousCharge(bookingId, p.file, p),
|
||||
mutationFn: ({ file, ...payload }: BillInput & { file: File }) =>
|
||||
bookingsService.createMiscellaneousCharge(bookingId, file, payload),
|
||||
onSuccess: (next) => {
|
||||
toast.success("Miscellaneous charge created");
|
||||
// Remount the form so the next charge starts from an empty one.
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
import { useState } from "react";
|
||||
import { Alert, Box, Button, Group, Stack, Text, Textarea } from "@mantine/core";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { Check, CreditCard, Receipt, X } from "lucide-react";
|
||||
import { Check, CreditCard, Download, Eye, FileText, Receipt, X } from "lucide-react";
|
||||
import { Link } from "react-router-dom";
|
||||
import toast from "react-hot-toast";
|
||||
|
||||
import type { Freight } from "@edr/types";
|
||||
import { isViewable } from "@edr/ui-common";
|
||||
|
||||
import { useFileViewer } from "@/hooks/useFileViewer";
|
||||
import { useInvoicePayment } from "@/hooks/useInvoicePayment";
|
||||
import { bookingsService } from "@/services/bookings.service";
|
||||
import { downloadStoredFile, fetchViewableFile } from "@/services/files.service";
|
||||
import { formatAmount } from "../utils";
|
||||
|
||||
import { IconSquare } from "./Documents";
|
||||
import { PaymentMethodModal } from "./PaymentMethodModal";
|
||||
import { CardTitle, SectionCard } from "./layout";
|
||||
|
||||
@@ -50,6 +54,7 @@ export function ClearanceChargesSection({ bookingId }: { bookingId: string }) {
|
||||
const [note, setNote] = useState("");
|
||||
const [payCharge, setPayCharge] = useState<Freight.ClearanceCharge | null>(null);
|
||||
const pay = useInvoicePayment();
|
||||
const { view, viewer } = useFileViewer();
|
||||
|
||||
const onError = (e: unknown) =>
|
||||
toast.error(e instanceof Error ? e.message : "Could not update the charge");
|
||||
@@ -132,6 +137,38 @@ export function ClearanceChargesSection({ bookingId }: { bookingId: string }) {
|
||||
</Text>
|
||||
</Group>
|
||||
|
||||
{/* GL's supporting document (port bill, receipt…) — what the
|
||||
price is based on, so the customer can check before deciding. */}
|
||||
{c.file && (
|
||||
<Group
|
||||
justify="space-between"
|
||||
wrap="nowrap"
|
||||
mt="sm"
|
||||
style={{ border: "1px solid #EEF2F6", borderRadius: 10, padding: "8px 10px" }}
|
||||
>
|
||||
<Group gap={8} wrap="nowrap" style={{ minWidth: 0 }}>
|
||||
<FileText size={16} color="#2E5B96" />
|
||||
<Text fz="12.5px" c="#10202F" truncate>
|
||||
{c.file.name}
|
||||
</Text>
|
||||
</Group>
|
||||
<Group gap={6} wrap="nowrap">
|
||||
{isViewable({ name: c.file.name, url: "" }) && (
|
||||
<IconSquare
|
||||
icon={<Eye size={15} />}
|
||||
onClick={() =>
|
||||
void fetchViewableFile(c.file!.id, c.file!.name).then(view)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<IconSquare
|
||||
icon={<Download size={15} />}
|
||||
onClick={() => void downloadStoredFile(c.file!.id, c.file!.name)}
|
||||
/>
|
||||
</Group>
|
||||
</Group>
|
||||
)}
|
||||
|
||||
{c.status === "REJECTED" && c.customerNote && (
|
||||
<Alert color="red" variant="light" radius="md" p="xs" mt="sm">
|
||||
<Text fz="12.5px">
|
||||
@@ -246,6 +283,7 @@ export function ClearanceChargesSection({ bookingId }: { bookingId: string }) {
|
||||
otp={pay.otp}
|
||||
bill={pay.bill}
|
||||
/>
|
||||
{viewer}
|
||||
</SectionCard>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user