Add value distribution to order range dialog

This commit is contained in:
2024-12-23 23:21:54 -05:00
parent 154e96e520
commit 90a003fccd
2 changed files with 138 additions and 41 deletions

View File

@@ -113,7 +113,7 @@ const TimeSeriesChart = ({
return (
<div className="h-[400px] w-full">
<ResponsiveContainer width="100%" height={height}>
<ChartComponent data={data} margin={{ top: 10, right: 30, left: 20, bottom: 5 }}>
<ChartComponent data={data} margin={{ top: 10, right: 20, left: -20, bottom: 5 }}>
<CartesianGrid strokeDasharray="3 3" className="stroke-muted" />
<XAxis
dataKey="timestamp"
@@ -740,6 +740,31 @@ const RefundDetails = ({ data }) => {
const OrderRangeDetails = ({ data }) => {
if (!data?.length) return <div className="text-muted-foreground">No data available for the selected time range.</div>;
// Get the data from the entire period
const allData = data.reduce((acc, day) => {
// Initialize distribution data structure if not exists
if (!acc.orderValueDistribution) {
acc.orderValueDistribution = day.orderValueDistribution?.map(range => ({
...range,
count: 0,
total: 0
})) || [];
}
// Aggregate distribution data
day.orderValueDistribution?.forEach((range, index) => {
if (acc.orderValueDistribution[index]) {
acc.orderValueDistribution[index].count += range.count;
acc.orderValueDistribution[index].total += range.total;
}
});
// Track total orders for percentage calculation
acc.totalOrders = (acc.totalOrders || 0) + (day.orders || 0);
return acc;
}, {});
const timeSeriesData = data.map(day => ({
timestamp: day.timestamp,
largest: day.orderValueRange?.largest || 0,
@@ -747,6 +772,17 @@ const OrderRangeDetails = ({ data }) => {
average: day.averageOrderValue || 0
}));
// Transform distribution data using aggregated values
const formattedDistributionData = allData.orderValueDistribution?.map(range => {
const totalRevenue = allData.orderValueDistribution.reduce((sum, r) => sum + (r.total || 0), 0);
return {
range: range.max === 'Infinity' ? `$${range.min}+` : `$${range.min}-${range.max}`,
count: range.count,
total: range.total,
percentage: ((range.count / (allData.totalOrders || 1)) * 100).toFixed(1),
revenuePercentage: ((range.total / (totalRevenue || 1)) * 100).toFixed(1)
};
}) || [];
return (
<div className="space-y-8">
@@ -772,6 +808,73 @@ const OrderRangeDetails = ({ data }) => {
/>
</div>
{formattedDistributionData.length > 0 && (
<div>
<h3 className="text-lg font-medium mb-4">Order Value Distribution</h3>
<div className="rounded-lg border bg-card">
<Table>
<TableHeader>
<TableRow>
<TableHead className="">Range</TableHead>
<TableHead className="text-right">Orders</TableHead>
<TableHead className="text-right">Total Revenue</TableHead>
<TableHead className="text-right">% of Orders</TableHead>
<TableHead className="text-right">% of Revenue</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{formattedDistributionData.map((range, index) => (
<TableRow key={index}>
<TableCell className="font-medium whitespace-nowrap">{range.range}</TableCell>
<TableCell className="text-right whitespace-nowrap">{range.count.toLocaleString()}</TableCell>
<TableCell className="text-right whitespace-nowrap">{formatCurrency(range.total)}</TableCell>
<TableCell className="text-right whitespace-nowrap">{range.percentage}%</TableCell>
<TableCell className="text-right whitespace-nowrap">{range.revenuePercentage}%</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
<div className="mt-4 h-[300px]">
<ResponsiveContainer width="100%" height="100%">
<BarChart data={formattedDistributionData} margin={{ top: 10, right: 20, left: -20, bottom: 40 }}>
<CartesianGrid strokeDasharray="3 3" className="stroke-muted" />
<XAxis
dataKey="range"
angle={-45}
textAnchor="end"
height={80}
className="text-xs"
/>
<YAxis
className="text-xs"
tickFormatter={(value) => `${value}%`}
/>
<Tooltip
content={({ active, payload }) => {
if (!active || !payload?.length) return null;
const data = payload[0].payload;
return (
<div className="bg-background border rounded-lg shadow-lg p-3">
<p className="font-medium">{data.range}</p>
<p className="text-sm">Orders: {data.count.toLocaleString()}</p>
<p className="text-sm">Revenue: {formatCurrency(data.total)}</p>
<p className="text-sm">% of Orders: {data.percentage}%</p>
<p className="text-sm">% of Revenue: {data.revenuePercentage}%</p>
</div>
);
}}
/>
<Bar
dataKey="percentage"
name="Percentage of Orders"
fill="hsl(262.1 83.3% 57.8%)"
/>
</BarChart>
</ResponsiveContainer>
</div>
</div>
)}
</div>
);
};