mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
fix: ui
This commit is contained in:
@@ -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={{
|
||||
|
||||
@@ -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 />}>
|
||||
|
||||
Reference in New Issue
Block a user