import { ResponsiveBar } from "@nivo/bar"; import { format, startOfMonth, subMonths } from "date-fns"; import { Receipt } from "lucide-react"; import { useGetList, useLocaleState, useTranslate } from "ra-core"; import { memo, useMemo } from "react"; import { getDateFnsLocale } from "@/i18n/date-fns"; import { Skeleton } from "@/components/ds/ui/skeleton"; import type { Invoice } from "../types"; const DEFAULT_LOCALE = "en-US"; const CURRENCY = "USD"; export const InvoicesChart = memo(() => { const translate = useTranslate(); const [locale] = useLocaleState(); const dateFnsLocale = getDateFnsLocale(locale); const acceptedLanguages = navigator ? navigator.languages || [navigator.language] : [DEFAULT_LOCALE]; const sixMonthsAgo = useMemo( () => subMonths(new Date(), 6).toISOString(), [], ); const { data, isPending } = useGetList("invoices", { pagination: { perPage: 100, page: 1 }, sort: { field: "issue_date", order: "ASC", }, filter: { "issue_date@gte": sixMonthsAgo, }, }); const months = useMemo(() => { if (!data) return []; // Group invoices by month const invoicesByMonth = data.reduce( (acc, invoice) => { const month = startOfMonth(new Date(invoice.issue_date)).toISOString(); if (!acc[month]) { acc[month] = []; } acc[month].push(invoice); return acc; }, {} as Record, ); // Calculate totals for each month const result = Object.keys(invoicesByMonth).map((month) => { const invoices = invoicesByMonth[month]; return { date: format(new Date(month), "MMM", { locale: dateFnsLocale }), paid: invoices .filter((inv: Invoice) => inv.status === "paid") .reduce((sum: number, inv: Invoice) => sum + (inv.total || 0), 0), pending: invoices .filter((inv: Invoice) => ["draft", "sent", "overdue"].includes(inv.status), ) .reduce((sum: number, inv: Invoice) => sum + (inv.total || 0), 0), }; }); return result; }, [data, dateFnsLocale]); if (isPending) { return (
); } if (months.length === 0) return null; return (

{translate("resources.invoices.name", { smart_count: 2 })}{" "} {translate("crm.dashboard.revenue")}

`${v / 1000}k`, }} tooltip={({ value, id, indexValue }) => (
{indexValue} ({id}):{" "} {value.toLocaleString( locale ?? acceptedLanguages.at(0) ?? DEFAULT_LOCALE, { style: "currency", currency: CURRENCY, }, )}
)} />
); });