Files
edr-platform/apps/edr-freight-web/backoffice/src/components/overview/tabs/OverviewBillingTabPanel.tsx

138 lines
4.3 KiB
TypeScript

import { Banknote, CreditCard, Wallet } from "lucide-react";
import {
Bar,
BarChart,
CartesianGrid,
Cell,
Legend,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from "recharts";
import { Grid, Paper, Stack, Text } from "@mantine/core";
import type { IOverviewBillingTab } from "@/types/overview";
import { OverviewDonutChart } from "../OverviewDonutChart";
import { OverviewKpiStrip } from "../OverviewKpiStrip";
import { OverviewPaymentChart } from "../OverviewPaymentChart";
import { overviewChartColors } from "../overview.styles";
function formatCurrency(amount: number, currency: "ETB" | "USD") {
return new Intl.NumberFormat("en-US", {
style: "currency",
currency,
maximumFractionDigits: 0,
}).format(amount);
}
const METHOD_LABELS: Record<string, string> = {
telebirr: "Telebirr",
"cbe-birr": "CBE Birr",
ebirr: "eBirr",
};
interface OverviewBillingTabPanelProps {
data: IOverviewBillingTab;
}
export function OverviewBillingTabPanel({ data }: OverviewBillingTabPanelProps) {
const methodChartData = data.paymentsByMethod.map((item) => ({
name: METHOD_LABELS[item.method] ?? item.method,
count: item.count,
}));
return (
<Stack gap="lg">
<OverviewKpiStrip
items={[
{
label: "Revenue MTD (ETB)",
value: formatCurrency(data.kpis.revenueMtdEtb, "ETB"),
icon: Banknote,
accent: "emerald",
},
{
label: "Revenue MTD (USD)",
value: formatCurrency(data.kpis.revenueMtdUsd, "USD"),
icon: Wallet,
},
{
label: "Pending payments",
value: data.kpis.pendingPayments,
icon: CreditCard,
accent: "amber",
},
{
label: "Successful MTD",
value: data.kpis.successfulPaymentsMtd,
icon: Banknote,
},
]}
/>
<Grid gap="md">
<Grid.Col span={{ base: 12, lg: 8 }}>
<OverviewPaymentChart data={data.paymentTrend} />
</Grid.Col>
<Grid.Col span={{ base: 12, lg: 4 }}>
<OverviewDonutChart
title="Revenue by currency (MTD)"
data={data.revenueByCurrency.map((item) => ({
name: item.currency,
value: item.amount,
}))}
emptyMessage="No revenue this month"
/>
</Grid.Col>
</Grid>
<Grid gap="md">
<Grid.Col span={{ base: 12, md: 6 }}>
<OverviewDonutChart
title="Payments by status"
data={data.paymentsByStatus.map((item) => ({
name: item.status.replace(/-/g, " "),
value: item.count,
}))}
/>
</Grid.Col>
<Grid.Col span={{ base: 12, md: 6 }}>
<Paper p="lg" radius="lg" withBorder h="100%" style={{ minHeight: 300 }}>
<Stack gap="md">
<Text fw={600}>Payments by method</Text>
{methodChartData.length === 0 ? (
<Text size="sm" c="dimmed" ta="center" py="xl">
No payment methods recorded
</Text>
) : (
<ResponsiveContainer width="100%" height={260}>
<BarChart data={methodChartData} margin={{ top: 8, right: 8, left: 0, bottom: 0 }}>
<CartesianGrid strokeDasharray="3 3" stroke="#e5e7eb" />
<XAxis dataKey="name" tick={{ fontSize: 11 }} stroke="#94a3b8" />
<YAxis allowDecimals={false} tick={{ fontSize: 12 }} stroke="#94a3b8" />
<Tooltip />
<Legend />
<Bar dataKey="count" name="Transactions" radius={[6, 6, 0, 0]}>
{methodChartData.map((entry, index) => (
<Cell
key={entry.name}
fill={
overviewChartColors.pipeline[
index % overviewChartColors.pipeline.length
]
}
/>
))}
</Bar>
</BarChart>
</ResponsiveContainer>
)}
</Stack>
</Paper>
</Grid.Col>
</Grid>
</Stack>
);
}