import {
ActionIcon,
Box,
Button,
Card,
Center,
Container,
Group,
Loader,
SimpleGrid,
Stack,
Tabs,
Text,
} from "@mantine/core";
import {
ArrowLeft,
ArrowRight,
Banknote,
Download,
FileText,
IdCard,
LayoutGrid,
Package,
} from "lucide-react";
import { useMutation, useQuery } from "@tanstack/react-query";
import { useMemo } from "react";
import { useNavigate, useParams } from "react-router-dom";
import {
BookingStatusBadge,
CompanyStatusBadge,
CompanyTypeBadge,
PaymentStatusBadge,
ProfileApprovalActions,
ProfileChips,
ProfileStatusBadge,
ProfileTypeBadge,
TableCard,
formatBytes,
formatDate,
formatMoney,
humanize,
} from "@/components/customers";
import { KpiStrip, PageContainer, PageHeader } from "@/components/page";
import { api } from "@/services/api";
import type {
CompanyProfile,
CustomerBooking,
CustomerDocument,
CustomerPayment,
} from "@/types/customer";
import { DataTable, type ColumnDef } from "@edr/ui-common";
function InfoField({ label, value }: { label: string; value?: string | null }) {
return (
{label}
{value && value.trim() ? value : "—"}
);
}
function tableStatus(query: { isLoading: boolean; isError: boolean }) {
return query.isLoading ? "loading" : query.isError ? "error" : "success";
}
export default function CustomerDetailPage() {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const { data: company, isLoading } = useQuery(
api.customers.getById.queryOptions({
input: { id: id ?? "" },
enabled: Boolean(id),
}),
);
const approveMutation = useMutation(
api.customers.setCompanyStatus.mutationOptions(),
);
const bookingsQuery = useQuery(
api.customers.bookings.queryOptions({
input: { id: id ?? "" },
enabled: Boolean(id),
}),
);
const documentsQuery = useQuery(
api.customers.documents.queryOptions({
input: { id: id ?? "" },
enabled: Boolean(id),
}),
);
const paymentsQuery = useQuery(
api.customers.payments.queryOptions({
input: { id: id ?? "" },
enabled: Boolean(id),
}),
);
const bookings = bookingsQuery.data ?? [];
const documents = documentsQuery.data ?? [];
const payments = paymentsQuery.data ?? [];
const totalPaid = useMemo(
() =>
payments
.filter((p) => p.status === "success")
.reduce((sum, p) => sum + p.amount, 0),
[payments],
);
const paidCurrency = payments[0]?.currency ?? "ETB";
const profileColumns: ColumnDef[] = useMemo(
() => [
{
id: "type",
header: "Role",
cell: ({ row }) => ,
},
{
id: "reference",
header: "Reference",
cell: ({ row }) => (
{row.original.reference}
),
},
{
id: "businessLicense",
header: "Business license",
cell: ({ row }) => (
{row.original.businessLicense || "—"}
),
},
{
id: "status",
header: "Status",
cell: ({ row }) => ,
},
{
id: "createdAt",
header: "Registered",
cell: ({ row }) => (
{formatDate(row.original.createdAt)}
),
},
{
id: "actions",
header: "",
meta: { headerClassName: "text-right", cellClassName: "text-right" },
cell: ({ row }) => (
),
},
],
[],
);
const bookingColumns: ColumnDef[] = useMemo(
() => [
{
id: "reference",
header: "Booking",
cell: ({ row }) => (
{row.original.reference}
),
},
{
id: "route",
header: "Route",
cell: ({ row }) => {
const b = row.original;
return (
{b.originLabel}
{b.destinationLabel}
);
},
},
{
id: "type",
header: "Type",
cell: ({ row }) => (
{humanize(row.original.tradeDirection)} ·{" "}
{humanize(row.original.freightType)}
),
},
{
id: "status",
header: "Status",
cell: ({ row }) => ,
},
{
id: "amount",
header: "Amount",
meta: { headerClassName: "text-right", cellClassName: "text-right" },
cell: ({ row }) => (
{formatMoney(row.original.totalAmount, row.original.currency)}
),
},
{
id: "createdAt",
header: "Created",
meta: { headerClassName: "text-right", cellClassName: "text-right" },
cell: ({ row }) => (
{formatDate(row.original.createdAt)}
),
},
],
[],
);
const documentColumns: ColumnDef[] = useMemo(
() => [
{
id: "name",
header: "Document",
cell: ({ row }) => (
{row.original.name}
),
},
{
id: "code",
header: "Type",
cell: ({ row }) => (
{humanize(row.original.code)}
),
},
{
id: "size",
header: "Size",
cell: ({ row }) => (
{formatBytes(row.original.size)}
),
},
{
id: "uploadedAt",
header: "Uploaded",
cell: ({ row }) => (
{formatDate(row.original.uploadedAt)}
),
},
{
id: "actions",
header: "",
meta: { headerClassName: "text-right", cellClassName: "text-right" },
cell: ({ row }) => (
),
},
],
[],
);
const paymentColumns: ColumnDef[] = useMemo(
() => [
{
id: "reference",
header: "Payment",
cell: ({ row }) => (
{row.original.reference}
),
},
{
id: "booking",
header: "Booking",
cell: ({ row }) => (
{row.original.bookingReference}
),
},
{
id: "method",
header: "Method",
cell: ({ row }) => (
{humanize(row.original.method)}
),
},
{
id: "status",
header: "Status",
cell: ({ row }) => ,
},
{
id: "paidAt",
header: "Paid",
cell: ({ row }) => (
{formatDate(row.original.paidAt)}
),
},
{
id: "amount",
header: "Amount",
meta: { headerClassName: "text-right", cellClassName: "text-right" },
cell: ({ row }) => (
{formatMoney(row.original.amount, row.original.currency)}
),
},
],
[],
);
if (isLoading) {
return (
);
}
if (!company) {
return (
Customer not found
}
onClick={() => navigate("/dashboard/customers")}
>
Back to customers
);
}
return (
{company.status === "pending" && (
)}
}
/>
}>
Overview
}>
Bookings
}>
Documents
}>
Payments
{/* OVERVIEW */}
p.status === "pending",
).length,
icon: IdCard,
color: "yellow",
},
{
label: "Bookings",
value: bookings.length,
icon: Package,
color: "blue",
},
{
label: "Total paid",
value: formatMoney(totalPaid, paidCurrency),
icon: Banknote,
color: "edr-green",
},
]}
/>
Company information
Role profiles
{/* BOOKINGS */}
void bookingsQuery.refetch(),
}
: undefined
}
/>
{/* DOCUMENTS */}
void documentsQuery.refetch(),
}
: undefined
}
/>
{/* PAYMENTS */}
void paymentsQuery.refetch(),
}
: undefined
}
/>
);
}