mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 00:52:50 +00:00
feat: enhance ClearanceChargesSection with file viewing and downloading capabilities
This commit is contained in:
@@ -102,8 +102,9 @@ export function ClearanceChargesTab({
|
|||||||
onError,
|
onError,
|
||||||
});
|
});
|
||||||
const bill = useMutation({
|
const bill = useMutation({
|
||||||
mutationFn: (p: BillInput & { chargeId: string }) =>
|
// Body must be exactly the DTO — the API rejects unknown keys like chargeId.
|
||||||
bookingsService.billClearanceCharge(bookingId, p.chargeId, p),
|
mutationFn: ({ chargeId, ...payload }: BillInput & { chargeId: string }) =>
|
||||||
|
bookingsService.billClearanceCharge(bookingId, chargeId, payload),
|
||||||
onSuccess: (next) => {
|
onSuccess: (next) => {
|
||||||
toast.success("Charge amount saved");
|
toast.success("Charge amount saved");
|
||||||
refresh(next);
|
refresh(next);
|
||||||
@@ -120,8 +121,8 @@ export function ClearanceChargesTab({
|
|||||||
onError,
|
onError,
|
||||||
});
|
});
|
||||||
const createMisc = useMutation({
|
const createMisc = useMutation({
|
||||||
mutationFn: (p: BillInput & { file: File }) =>
|
mutationFn: ({ file, ...payload }: BillInput & { file: File }) =>
|
||||||
bookingsService.createMiscellaneousCharge(bookingId, p.file, p),
|
bookingsService.createMiscellaneousCharge(bookingId, file, payload),
|
||||||
onSuccess: (next) => {
|
onSuccess: (next) => {
|
||||||
toast.success("Miscellaneous charge created");
|
toast.success("Miscellaneous charge created");
|
||||||
// Remount the form so the next charge starts from an empty one.
|
// Remount the form so the next charge starts from an empty one.
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Alert, Box, Button, Group, Stack, Text, Textarea } from "@mantine/core";
|
import { Alert, Box, Button, Group, Stack, Text, Textarea } from "@mantine/core";
|
||||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
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 { Link } from "react-router-dom";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
|
|
||||||
import type { Freight } from "@edr/types";
|
import type { Freight } from "@edr/types";
|
||||||
|
import { isViewable } from "@edr/ui-common";
|
||||||
|
|
||||||
|
import { useFileViewer } from "@/hooks/useFileViewer";
|
||||||
import { useInvoicePayment } from "@/hooks/useInvoicePayment";
|
import { useInvoicePayment } from "@/hooks/useInvoicePayment";
|
||||||
import { bookingsService } from "@/services/bookings.service";
|
import { bookingsService } from "@/services/bookings.service";
|
||||||
|
import { downloadStoredFile, fetchViewableFile } from "@/services/files.service";
|
||||||
import { formatAmount } from "../utils";
|
import { formatAmount } from "../utils";
|
||||||
|
|
||||||
|
import { IconSquare } from "./Documents";
|
||||||
import { PaymentMethodModal } from "./PaymentMethodModal";
|
import { PaymentMethodModal } from "./PaymentMethodModal";
|
||||||
import { CardTitle, SectionCard } from "./layout";
|
import { CardTitle, SectionCard } from "./layout";
|
||||||
|
|
||||||
@@ -50,6 +54,7 @@ export function ClearanceChargesSection({ bookingId }: { bookingId: string }) {
|
|||||||
const [note, setNote] = useState("");
|
const [note, setNote] = useState("");
|
||||||
const [payCharge, setPayCharge] = useState<Freight.ClearanceCharge | null>(null);
|
const [payCharge, setPayCharge] = useState<Freight.ClearanceCharge | null>(null);
|
||||||
const pay = useInvoicePayment();
|
const pay = useInvoicePayment();
|
||||||
|
const { view, viewer } = useFileViewer();
|
||||||
|
|
||||||
const onError = (e: unknown) =>
|
const onError = (e: unknown) =>
|
||||||
toast.error(e instanceof Error ? e.message : "Could not update the charge");
|
toast.error(e instanceof Error ? e.message : "Could not update the charge");
|
||||||
@@ -132,6 +137,38 @@ export function ClearanceChargesSection({ bookingId }: { bookingId: string }) {
|
|||||||
</Text>
|
</Text>
|
||||||
</Group>
|
</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 && (
|
{c.status === "REJECTED" && c.customerNote && (
|
||||||
<Alert color="red" variant="light" radius="md" p="xs" mt="sm">
|
<Alert color="red" variant="light" radius="md" p="xs" mt="sm">
|
||||||
<Text fz="12.5px">
|
<Text fz="12.5px">
|
||||||
@@ -246,6 +283,7 @@ export function ClearanceChargesSection({ bookingId }: { bookingId: string }) {
|
|||||||
otp={pay.otp}
|
otp={pay.otp}
|
||||||
bill={pay.bill}
|
bill={pay.bill}
|
||||||
/>
|
/>
|
||||||
|
{viewer}
|
||||||
</SectionCard>
|
</SectionCard>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user