mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
121 lines
4.2 KiB
TypeScript
121 lines
4.2 KiB
TypeScript
import { Tabs } from "@mantine/core";
|
|
import { Banknote, DollarSign, Receipt } from "lucide-react";
|
|
import { useSearchParams } from "react-router-dom";
|
|
|
|
import { useAuth } from "@/auth/useAuth";
|
|
import { useManualPaymentSettingsQuery } from "@/hooks/useManualPaymentSettings";
|
|
import { PageContainer, PageHeader } from "@/components/page";
|
|
import { FREIGHT_PERMS, hasPermission } from "@/lib/permissions";
|
|
|
|
import InvoicesPanel from "./InvoicesPage";
|
|
import UsdPaymentsPanel from "./UsdPaymentsPage";
|
|
|
|
/**
|
|
* Invoices and USD Payments used to be separate routes/pages with
|
|
* near-identical chrome. They're merged here as URL-linkable tabs (`?tab=`)
|
|
* on one page — each tab keeps the permission it was individually gated on
|
|
* before, and just doesn't render if the user lacks it.
|
|
*
|
|
* The Payments tab was removed; its summary (total collected, ETB/USD) now
|
|
* lives as a card at the top of the Invoices tab instead. Manual payments are
|
|
* split into one tab per currency — ETB keeps the original `?tab=manual-payments`
|
|
* key so existing links and the old redirect still land somewhere valid.
|
|
*/
|
|
const TABS = [
|
|
{
|
|
key: "invoices",
|
|
label: "Invoices",
|
|
icon: Receipt,
|
|
permission: FREIGHT_PERMS.invoices.view,
|
|
subtitle:
|
|
"Every invoice issued across bookings, warehouse fees and clearance charges.",
|
|
Panel: InvoicesPanel,
|
|
},
|
|
{
|
|
key: "manual-payments",
|
|
label: "Manual Payments (ETB)",
|
|
icon: Banknote,
|
|
// Same gate as Invoices, not a dedicated key — mirrors the old route.
|
|
permission: FREIGHT_PERMS.invoices.view,
|
|
/** Hidden unless manual settlement is switched on for this currency. */
|
|
manualCurrency: "ETB",
|
|
subtitle:
|
|
"Import and export invoices in ETB that Finance settles by hand (bank transfer or counter). Upload the customer's slip and confirm the payment before the pay window closes.",
|
|
Panel: () => <UsdPaymentsPanel currency="ETB" />,
|
|
},
|
|
{
|
|
key: "manual-payments-usd",
|
|
label: "Manual Payments (USD)",
|
|
icon: DollarSign,
|
|
permission: FREIGHT_PERMS.invoices.view,
|
|
manualCurrency: "USD",
|
|
subtitle:
|
|
"Import and export invoices in USD that Finance settles by hand (bank transfer or counter). Upload the customer's slip and confirm the payment before the pay window closes.",
|
|
Panel: () => <UsdPaymentsPanel currency="USD" />,
|
|
},
|
|
] as const;
|
|
|
|
type TabKey = (typeof TABS)[number]["key"];
|
|
|
|
export default function FinanceHubPage() {
|
|
const { user } = useAuth();
|
|
const [searchParams, setSearchParams] = useSearchParams();
|
|
|
|
// A currency whose manual-payment channel is switched off has no tab at all
|
|
// — the list would be empty and every confirmation refused.
|
|
const { data: manualSettings } = useManualPaymentSettingsQuery();
|
|
const manualEnabled = (currency: "ETB" | "USD") =>
|
|
!manualSettings ||
|
|
(currency === "ETB" ? manualSettings.etbEnabled : manualSettings.usdEnabled);
|
|
|
|
const visibleTabs = TABS.filter(
|
|
(tab) =>
|
|
hasPermission(user, tab.permission) &&
|
|
(!("manualCurrency" in tab) || manualEnabled(tab.manualCurrency)),
|
|
);
|
|
const requested = searchParams.get("tab");
|
|
const active: TabKey =
|
|
visibleTabs.find((tab) => tab.key === requested)?.key ??
|
|
visibleTabs[0]?.key ??
|
|
"invoices";
|
|
const activeTab = visibleTabs.find((tab) => tab.key === active);
|
|
|
|
const handleChange = (value: string | null) => {
|
|
if (!value) return;
|
|
setSearchParams(
|
|
(prev) => {
|
|
const next = new URLSearchParams(prev);
|
|
next.set("tab", value);
|
|
return next;
|
|
},
|
|
{ replace: true },
|
|
);
|
|
};
|
|
|
|
return (
|
|
<PageContainer>
|
|
<PageHeader title={activeTab?.label ?? "Invoices"} subtitle={activeTab?.subtitle} />
|
|
|
|
<Tabs value={active} onChange={handleChange} keepMounted={false}>
|
|
<Tabs.List>
|
|
{visibleTabs.map((tab) => (
|
|
<Tabs.Tab
|
|
key={tab.key}
|
|
value={tab.key}
|
|
leftSection={<tab.icon size={16} />}
|
|
>
|
|
{tab.label}
|
|
</Tabs.Tab>
|
|
))}
|
|
</Tabs.List>
|
|
|
|
{visibleTabs.map((tab) => (
|
|
<Tabs.Panel key={tab.key} value={tab.key} pt="lg">
|
|
<tab.Panel />
|
|
</Tabs.Panel>
|
|
))}
|
|
</Tabs>
|
|
</PageContainer>
|
|
);
|
|
}
|