This commit is contained in:
Nathnael
2026-08-14 07:04:57 +00:00
parent a33494a3ae
commit ab5a4117df
2 changed files with 111 additions and 109 deletions

View File

@@ -173,7 +173,10 @@ export default function CustomerDetailPage() {
enabled: Boolean(id),
}),
);
const contractsQuery = useContractList({ companyId: id, pageSize: 100 }, Boolean(id));
const contractsQuery = useContractList(
{ companyId: id, pageSize: 100 },
Boolean(id),
);
const { pagination: invoicePagination, setPagination: setInvoicePagination } =
usePagination({
@@ -462,42 +465,31 @@ export default function CustomerDetailPage() {
const documentColumns: ColumnDef<CustomerDocument>[] = useMemo(
() => [
{
id: "name",
header: "Document",
cell: ({ row }) => {
const doc = row.original;
return (
<Stack gap={2}>
<Group gap="sm" wrap="nowrap">
<FileText size={16} className="shrink-0 text-edr-muted" />
<Text size="sm" c="edr-text" truncate>
{doc.name}
</Text>
{doc.reviewStatus === "change_requested" && (
<Badge size="xs" color="orange" variant="light">
Change requested
</Badge>
)}
</Group>
{/* The note is the whole point of the request — show it inline so a
second reviewer sees what was already asked for. */}
{doc.reviewStatus === "change_requested" && doc.reviewNote && (
<Text size="xs" c="dimmed" pl={24}>
{doc.reviewNote}
</Text>
)}
</Stack>
);
},
},
{
id: "code",
header: "Type",
cell: ({ row }) => (
<Text size="sm" c="dimmed">
{humanize(row.original.code)}
</Text>
<Stack gap={2}>
<Group gap="sm" wrap="nowrap">
<FileText size={16} className="shrink-0 text-edr-muted" />
<Text size="sm" c="edr-text" truncate>
{humanize(row.original.code)}
</Text>
{row.original.reviewStatus === "change_requested" && (
<Badge size="xs" color="orange" variant="light">
Change requested
</Badge>
)}
</Group>
{/* The note is the whole point of the request — show it inline so a
second reviewer sees what was already asked for. */}
{row.original.reviewStatus === "change_requested" &&
row.original.reviewNote && (
<Text size="xs" c="dimmed" pl={24}>
{row.original.reviewNote}
</Text>
)}
</Stack>
),
},
{
@@ -751,9 +743,8 @@ export default function CustomerDetailPage() {
]}
backTo="/dashboard/customers"
title={company.name}
subtitle={`TIN ${company.tin}${
company.country ? ` · ${company.country}` : ""
}`}
subtitle={`TIN ${company.tin}${company.country ? ` · ${company.country}` : ""
}`}
meta={
<Group gap="xs" wrap="nowrap">
<CompanyTypeBadge type={company.type} />
@@ -1247,13 +1238,15 @@ export default function CustomerDetailPage() {
status={tableStatus(bookingsQuery)}
emptyMessage="No bookings for this customer."
containerClassName="border-0 shadow-none bg-transparent"
onRowClick={(row) => navigate(`/dashboard/booking-requests/${row.id}`)}
onRowClick={(row) =>
navigate(`/dashboard/booking-requests/${row.id}`)
}
error={
bookingsQuery.isError
? {
message: "Failed to load bookings.",
onRetry: () => void bookingsQuery.refetch(),
}
message: "Failed to load bookings.",
onRetry: () => void bookingsQuery.refetch(),
}
: undefined
}
/>
@@ -1269,13 +1262,15 @@ export default function CustomerDetailPage() {
status={tableStatus(contractsQuery)}
emptyMessage="No contracts for this customer."
containerClassName="border-0 shadow-none bg-transparent"
onRowClick={(row) => navigate(`/dashboard/contract-requests/${row.id}`)}
onRowClick={(row) =>
navigate(`/dashboard/contract-requests/${row.id}`)
}
error={
contractsQuery.isError
? {
message: "Failed to load contracts.",
onRetry: () => void contractsQuery.refetch(),
}
message: "Failed to load contracts.",
onRetry: () => void contractsQuery.refetch(),
}
: undefined
}
/>
@@ -1295,9 +1290,9 @@ export default function CustomerDetailPage() {
error={
documentsQuery.isError
? {
message: "Failed to load documents.",
onRetry: () => void documentsQuery.refetch(),
}
message: "Failed to load documents.",
onRetry: () => void documentsQuery.refetch(),
}
: undefined
}
/>
@@ -1372,9 +1367,9 @@ export default function CustomerDetailPage() {
error={
paymentsQuery.isError
? {
message: "Failed to load payments.",
onRetry: () => void paymentsQuery.refetch(),
}
message: "Failed to load payments.",
onRetry: () => void paymentsQuery.refetch(),
}
: undefined
}
/>
@@ -1395,9 +1390,9 @@ export default function CustomerDetailPage() {
error={
invoicesQuery.isError
? {
message: "Failed to load invoices.",
onRetry: () => void invoicesQuery.refetch(),
}
message: "Failed to load invoices.",
onRetry: () => void invoicesQuery.refetch(),
}
: undefined
}
pagination={{

View File

@@ -336,6 +336,7 @@ const App = () => {
createProfile,
reapplyProfile,
isAuthenticated,
isShippingLine,
} = useAuth();
// Attribute replays and exceptions to the signed-in user (id/org only).
@@ -410,66 +411,72 @@ const App = () => {
at their own routes — nothing here is shared with the customer
branch below beyond the shell component itself. Contracts are
absent by design: shipping lines request bookings directly. */}
<Route element={<RequireShippingLine />}>
<Route
element={
<AppLayout
title="EDR Freight"
sidebarItems={shippingLineSidebarItems}
activeHref={location.pathname}
onNavigate={navigate}
userName={displayName}
userEmail={userEmail}
// Support chat is company-scoped; a shipping line has no
// company, so every poll would 403.
showSupportWidget={false}
>
<Outlet />
</AppLayout>
}
>
{isShippingLine && (
<Route element={<RequireShippingLine />}>
<Route
path="/shipping-line"
element={<ShippingLineHomePage />}
/>
<Route
path="/shipping-line/bookings"
element={<ShippingLineBookingsPage />}
/>
<Route
path="/shipping-line/bookings/:id"
element={<ShippingLineBookingDetailPage />}
/>
<Route
path="/shipping-line/bookings/:id/complete"
element={<ShippingLineCompletePage />}
/>
<Route
path="/shipping-line/invoices"
element={<ShippingLineInvoicesPage />}
/>
{/* Same detail component as the customer's /billing/:id — the
element={
<AppLayout
title="EDR Freight"
sidebarItems={shippingLineSidebarItems}
activeHref={location.pathname}
onNavigate={navigate}
userName={displayName}
userEmail={userEmail}
// Support chat is company-scoped; a shipping line has no
// company, so every poll would 403.
showSupportWidget={false}
>
<Outlet />
</AppLayout>
}
>
<Route
path="/shipping-line"
element={<ShippingLineHomePage />}
/>
<Route
path="/shipping-line/bookings"
element={<ShippingLineBookingsPage />}
/>
<Route
path="/shipping-line/bookings/:id"
element={<ShippingLineBookingDetailPage />}
/>
<Route
path="/shipping-line/bookings/:id/complete"
element={<ShippingLineCompletePage />}
/>
<Route
path="/shipping-line/invoices"
element={<ShippingLineInvoicesPage />}
/>
{/* Same detail component as the customer's /billing/:id — the
API scopes my-invoices to the signed-in payer either way,
and the page derives its back target from the URL. */}
<Route
path="/shipping-line/invoices/:id"
element={<InvoiceDetailPage />}
/>
<Route
path="/shipping-line/settings"
element={<ShippingLineSettingsPage />}
/>
<Route
path="/shipping-line/help"
element={<ShippingLineHelpPage />}
/>
{/* Old shared links land on the shipping-line equivalents. */}
<Route
path="/settings"
element={<Navigate to="/shipping-line/settings" replace />}
/>
<Route
path="/shipping-line/invoices/:id"
element={<InvoiceDetailPage />}
/>
<Route
path="/shipping-line/settings"
element={<ShippingLineSettingsPage />}
/>
<Route
path="/shipping-line/settings"
element={<ShippingLineSettingsPage />}
/>
<Route
path="/shipping-line/help"
element={<ShippingLineHelpPage />}
/>
{/* Old shared links land on the shipping-line equivalents. */}
<Route
path="/settings"
element={<Navigate to="/shipping-line/settings" replace />}
/>
</Route>
</Route>
</Route>
)}
{/* Customer app — unchanged. */}
<Route element={<RequireCustomer />}>