UNPKG

bananas-commerce-admin

Version:

What's this, an admin for apes?

120 lines 5.86 kB
import React, { useCallback, useEffect, useMemo, useState } from "react"; import { Stack } from "@mui/material"; import { styled, useTheme } from "@mui/material/styles"; import { ChartContainer, ChartsLegend } from "@mui/x-charts"; import { useDrawingArea } from "@mui/x-charts/hooks"; import { PieChart } from "@mui/x-charts/PieChart"; import WidgetCard from "../../../components/WidgetCard"; import { useI18n } from "../../../contexts/I18nContext"; import { getHumanReadablePaymentMethod, } from "../utils/getHumanReadablePaymentMethod"; /** * Calculate the percentage of a payment method. */ function calculatePercentage(count, total) { return Math.round((count / total) * 100); } const StyledTitle = styled("text")(({ theme }) => ({ fill: theme.palette.text.primary, textAnchor: "middle", dominantBaseline: "central", fontWeight: 700, fontSize: theme.typography.h4.fontSize, })); const StyledSubtitle = styled("text")(({ theme }) => ({ fill: theme.palette.text.secondary, textAnchor: "middle", dominantBaseline: "central", fontSize: theme.typography.htmlFontSize, })); function PieCenterLabel({ title, subtitle }) { const { width, height, left, top } = useDrawingArea(); return (React.createElement(React.Fragment, null, React.createElement(StyledTitle, { x: left + width / 2, y: top - 10 + height / 2 }, title), React.createElement(StyledSubtitle, { x: left + width / 2, y: top + 25 + height / 2 }, subtitle))); } const PaymentMethodWidget = ({ data, sx }) => { const { t } = useI18n(); const theme = useTheme(); const total = useMemo(() => data.reduce((acc, curr) => acc + curr.count, 0), [data]); const dataSeries = useMemo(() => { // Accumulate counts per payment method name using a Map for efficient lookups const paymentMethodMap = data.reduce((map, item) => { const { name, color } = getHumanReadablePaymentMethod(item.method, { disambiguateCards: false, theme, }); if (map.has(name)) { const existingItem = map.get(name); existingItem.count += item.count; existingItem.value += item.count; } else { map.set(name, { ...item, color, name, value: item.count, label: name }); } return map; }, new Map()); // Convert Map values to an array and sort by count in descending order const sortedItems = Array.from(paymentMethodMap.values()).sort((a, b) => b.count - a.count); // Take the top 5 items and accumulate the rest into an 'Other' category const topItems = sortedItems.slice(0, 5); const otherItems = sortedItems.slice(5); if (otherItems.length > 0) { const otherTotals = otherItems.reduce((totals, item) => { totals.count += item.count; totals.value += item.value; return totals; }, { count: 0, value: 0 }); topItems.push({ method: "other", name: "Other", count: otherTotals.count, value: otherTotals.value, color: theme.palette.grey[300], label: "Other", }); } // Map the items to include percentage labels return topItems.map((item) => { const percentage = calculatePercentage(item.count, total); return { ...item, label: `${item.name} ${percentage}%` }; }); }, [data, total, theme]); const [highlighted, setHighlighted] = useState(dataSeries?.[0]); // Update highlight when data changes. useEffect(() => { setHighlighted(dataSeries?.[0]); }, [data, total, highlighted]); const handleHighlightChange = useCallback((highlight) => { if (typeof highlight?.dataIndex === "number") { setHighlighted(dataSeries[highlight.dataIndex]); } else { setHighlighted(dataSeries?.[0]); } }, [data, total, highlighted]); const highlightedPercentage = useMemo(() => { if (highlighted == null) return null; const percentage = calculatePercentage(highlighted.count, total); if (Number.isNaN(percentage) || !Number.isFinite(percentage)) return null; return percentage; }, [data, total, highlighted]); return (React.createElement(WidgetCard, { gridColumn: { md: "span 6", sm: "span 1" }, gridRow: "span 2", sx: sx, title: t("Payment Methods") }, React.createElement(Stack, { alignItems: "center", direction: { xs: "column", sm: "row" }, justifyContent: "center" }, React.createElement(PieChart, { height: 275, margin: { top: 0, right: 0, bottom: 0, left: 0 }, series: [ { data: dataSeries, innerRadius: 75, highlightScope: { fade: "global", highlight: "item" }, }, ], slotProps: { legend: { hidden: true, }, }, sx: { py: { xs: 1, sm: 3 } }, width: 275, onHighlightChange: handleHighlightChange }, highlighted != null && (React.createElement(PieCenterLabel, { subtitle: highlighted.name, title: `${highlightedPercentage}%` }))), React.createElement(ChartContainer, { dataset: dataSeries, height: 8 + dataSeries.length * 32, margin: { top: 0, right: 0, bottom: 0, left: 0 }, series: dataSeries.map(({ label, color }) => ({ type: "bar", label, color })), width: 200 }, React.createElement(ChartsLegend, { direction: "column", position: { vertical: "middle", horizontal: "left" } }))))); }; export default PaymentMethodWidget; //# sourceMappingURL=PaymentMethodWidget.js.map