This commit is contained in:
natib21
2026-07-03 20:59:21 +00:00
parent 90ab1bd042
commit 7155ec7e01
3 changed files with 10 additions and 100 deletions

View File

@@ -57,10 +57,10 @@ export class LastMileService {
'last_mile',
records.map((r) => r.id),
);
const byId = new Map<string, { number: string; status: string }>();
const byId = new Map<string, { id: string; number: string; status: string }>();
for (const inv of invoices) {
if (!byId.has(inv.sourceId)) {
byId.set(inv.sourceId, { number: inv.invoiceNumber, status: String(inv.status) });
byId.set(inv.sourceId, { id: inv.id, number: inv.invoiceNumber, status: String(inv.status) });
}
}
for (const r of records) {

View File

@@ -14,6 +14,7 @@ import {
X,
} from "lucide-react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useNavigate } from "react-router-dom";
import type { ColumnDef } from "@edr/ui-common";
import { DataTable, DataTableFooter, usePagination } from "@edr/ui-common";
import {
@@ -467,6 +468,7 @@ const buildTripSlipHtml = (record: LastMileRecord) => {
const LastMilePage = () => {
const { toast } = useToast();
const qc = useQueryClient();
const navigate = useNavigate();
const { pagination, setPagination } = usePagination({ pageSize: 10 });
const [search, setSearch] = useState("");
@@ -495,8 +497,6 @@ const LastMilePage = () => {
const [distanceOpen, setDistanceOpen] = useState(false);
// Per-vehicle actual distance, keyed by vehicleId.
const [distanceRows, setDistanceRows] = useState<Record<string, string>>({});
const [invoiceOpen, setInvoiceOpen] = useState(false);
const [invoiceRecord, setInvoiceRecord] = useState<LastMileRecord | null>(null);
// Record pending invoice-generation confirmation (shows a summary first).
const [invoiceConfirm, setInvoiceConfirm] = useState<LastMileRecord | null>(null);
@@ -743,15 +743,6 @@ const LastMilePage = () => {
setDistanceRows({});
};
const openInvoice = (record: LastMileRecord) => {
setInvoiceRecord(record);
setInvoiceOpen(true);
};
const closeInvoice = () => {
setInvoiceOpen(false);
setInvoiceRecord(null);
};
const openAllocation = (id: string, containers?: LastMileContainerRow[]) => {
setActiveId(id);
@@ -1098,7 +1089,7 @@ const LastMilePage = () => {
return (
<Group gap="xs" wrap="nowrap">
<UnstyledButton
onClick={() => openInvoice(row.original)}
onClick={() => navigate(`/dashboard/invoices/${invoice.id}`)}
c="blue"
fw={500}
style={{ textDecoration: "underline", cursor: "pointer" }}
@@ -1775,87 +1766,6 @@ const LastMilePage = () => {
</Stack>
</Modal>
{/* Invoice modal */}
<Modal
opened={invoiceOpen}
onClose={closeInvoice}
title={<Text fw={600}>Invoice #345</Text>}
size="lg"
radius="lg"
centered
>
<Stack gap="md">
{invoiceRecord && (
<>
<Card withBorder padding="md" radius="md" bg="var(--mantine-color-gray-0)">
<Stack gap="sm">
<Group justify="space-between">
<Text fw={700}>EDR Freight</Text>
<Text fw={600} size="sm">Invoice #345</Text>
</Group>
<Divider />
<SimpleGrid cols={2} spacing="sm">
<InfoRow label="Booking" value={bookingRef(invoiceRecord)} />
<InfoRow label="Customer" value={customerName(invoiceRecord)} />
<InfoRow label="Pickup" value={originYardName(invoiceRecord)} />
<InfoRow label="Destination" value={deliveryLocation(invoiceRecord)} />
<InfoRow label="Est. Distance" value={invoiceRecord.estimatedKm ? `${invoiceRecord.estimatedKm} km` : "—"} />
<InfoRow label="Actual Distance" value={invoiceRecord.exactKm ? `${invoiceRecord.exactKm} km` : "—"} />
<InfoRow label="Advanced Payment" value={formatPrice(invoiceRecord.advancedPayment)} />
<InfoRow label="Post Payment" value={formatPrice(invoiceRecord.remainingPayment)} />
</SimpleGrid>
<Divider />
<Group justify="flex-end">
<Stack gap={0} align="flex-end" style={{ minWidth: 200 }}>
<Group justify="space-between" w="100%">
<Text size="sm" c="dimmed">Post Payment</Text>
<Text size="sm">{formatPrice(invoiceRecord.remainingPayment)}</Text>
</Group>
<Group justify="space-between" w="100%">
<Text size="sm" c="dimmed">Advanced Payment</Text>
<Text size="sm">{formatPrice(invoiceRecord.advancedPayment)}</Text>
</Group>
<Divider my="xs" />
{(() => {
const postPayment = parseFloat(String(invoiceRecord.remainingPayment));
const advancedPayment = parseFloat(String(invoiceRecord.advancedPayment));
const difference = postPayment - advancedPayment;
if (difference > 0) {
return (
<Group justify="space-between" w="100%">
<Text size="sm" fw={600}>Remaining to Pay</Text>
<Text fw={700} c="orange">{formatPrice(difference)}</Text>
</Group>
);
} else if (difference < 0) {
return (
<Group justify="space-between" w="100%">
<Text size="sm" fw={600}>Refund</Text>
<Text fw={700} c="green">{formatPrice(Math.abs(difference))}</Text>
</Group>
);
} else {
return (
<Group justify="space-between" w="100%">
<Text size="sm" fw={600}>Status</Text>
<Text fw={700} c="blue">Settled</Text>
</Group>
);
}
})()}
</Stack>
</Group>
</Stack>
</Card>
</>
)}
<Group justify="flex-end" gap="sm">
<Button variant="default" onClick={closeInvoice}>Close</Button>
</Group>
</Stack>
</Modal>
{/* Generate Invoice — confirmation summary */}
<Modal
opened={Boolean(invoiceConfirm)}
@@ -1904,10 +1814,10 @@ const LastMilePage = () => {
loading={generateInvoiceMutation.isPending}
onClick={() =>
generateInvoiceMutation.mutate(invoiceConfirm.id, {
onSuccess: () => {
const rec = invoiceConfirm;
onSuccess: (res) => {
setInvoiceConfirm(null);
openInvoice(rec);
const invoiceId = res?.data?.id;
if (invoiceId) navigate(`/dashboard/invoices/${invoiceId}`);
},
})
}

View File

@@ -65,7 +65,7 @@ export interface LastMileRecord {
vehicle?: LastMileVehicle | null;
}>;
/** Present only when an invoice has actually been generated (not on distance). */
invoice?: { number: string; status: string } | null;
invoice?: { id: string; number: string; status: string } | null;
createdAt: string;
updatedAt: string;
}
@@ -97,5 +97,5 @@ export const lastMileService = {
remainingPayment?: number,
) => api.post<LastMileRecord>(`${LM.BASE}/${id}/distances`, { distances, remainingPayment }),
generateInvoice: (id: string) =>
api.post<unknown>(`${LM.BASE}/${id}/invoice`),
api.post<{ id: string; invoiceNumber?: string } | null>(`${LM.BASE}/${id}/invoice`),
};