mirror of
https://github.com/christianvidalwolf-prog/CrazeAnalytix.git
synced 2026-08-03 12:45:23 +02:00
feat: add cumulative YoY sales chart to Dashboard
New line chart shows accumulated sell-out (€) or units month by month, comparing all available years on the same axis for like-for-like year-over-year tracking. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
b31911a9df
commit
9f9c0c2975
@@ -479,6 +479,22 @@ const Dashboard: React.FC<DashboardProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const [seasonalityMetric, setSeasonalityMetric] = useState<'sellOut' | 'units'>('sellOut');
|
const [seasonalityMetric, setSeasonalityMetric] = useState<'sellOut' | 'units'>('sellOut');
|
||||||
const [top10Metric, setTop10Metric] = useState<'sellOut' | 'units'>('sellOut');
|
const [top10Metric, setTop10Metric] = useState<'sellOut' | 'units'>('sellOut');
|
||||||
|
const [cumulativeMetric, setCumulativeMetric] = useState<'sellOut' | 'units'>('sellOut');
|
||||||
|
|
||||||
|
const cumulativeData = useMemo(() => {
|
||||||
|
const source = cumulativeMetric === 'sellOut' ? data.seasonality : data.seasonalityUnits;
|
||||||
|
const years = data.availableYears;
|
||||||
|
const running: Record<string, number> = {};
|
||||||
|
years.forEach(y => { running[y] = 0; });
|
||||||
|
return source.map(point => {
|
||||||
|
const result: Record<string, number | string> = { name: point.name };
|
||||||
|
years.forEach(y => {
|
||||||
|
running[y] = (running[y] || 0) + ((point[y] as number) || 0);
|
||||||
|
result[y] = running[y];
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}, [data.seasonality, data.seasonalityUnits, data.availableYears, cumulativeMetric]);
|
||||||
|
|
||||||
// Calculate Ads KPIs by Year
|
// Calculate Ads KPIs by Year
|
||||||
const adsKPIsByYear = useMemo(() => {
|
const adsKPIsByYear = useMemo(() => {
|
||||||
@@ -804,6 +820,54 @@ const Dashboard: React.FC<DashboardProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</ExpandableCard>
|
</ExpandableCard>
|
||||||
|
|
||||||
|
{/* Cumulative Sales Chart - YoY comparison month by month */}
|
||||||
|
<ExpandableCard title="Cumulative Sales YoY (Month by Month)" className="h-96">
|
||||||
|
<div className="flex flex-col h-full">
|
||||||
|
<div className="flex justify-end mb-2">
|
||||||
|
<div className="bg-slate-900 p-1 rounded-lg border border-slate-800 flex text-xs">
|
||||||
|
<button
|
||||||
|
onClick={(e) => { e.stopPropagation(); setCumulativeMetric('sellOut'); }}
|
||||||
|
className={`px-3 py-1 rounded-md transition-colors ${cumulativeMetric === 'sellOut' ? 'bg-indigo-600 text-white shadow-sm' : 'text-slate-400 hover:text-white'}`}
|
||||||
|
>
|
||||||
|
Sell Out (€)
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={(e) => { e.stopPropagation(); setCumulativeMetric('units'); }}
|
||||||
|
className={`px-3 py-1 rounded-md transition-colors ${cumulativeMetric === 'units' ? 'bg-indigo-600 text-white shadow-sm' : 'text-slate-400 hover:text-white'}`}
|
||||||
|
>
|
||||||
|
Units
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 min-h-0">
|
||||||
|
<ResponsiveContainer width="100%" height="100%">
|
||||||
|
<LineChart data={cumulativeData}>
|
||||||
|
<CartesianGrid strokeDasharray="3 3" stroke="#1e293b" />
|
||||||
|
<XAxis dataKey="name" stroke="#64748b" />
|
||||||
|
<YAxis
|
||||||
|
stroke="#64748b"
|
||||||
|
tickFormatter={(val) => cumulativeMetric === 'sellOut' ? `€${(val / 1000).toFixed(0)}k` : val.toLocaleString('de-DE')}
|
||||||
|
/>
|
||||||
|
<Tooltip content={(props: any) => <SeasonalityTooltip {...props} metric={cumulativeMetric} />} />
|
||||||
|
<Legend />
|
||||||
|
{data.availableYears.map((year, index) => (
|
||||||
|
<Line
|
||||||
|
key={year}
|
||||||
|
type="monotone"
|
||||||
|
dataKey={year}
|
||||||
|
name={year}
|
||||||
|
stroke={COLORS[index % COLORS.length]}
|
||||||
|
strokeWidth={3}
|
||||||
|
dot={{ r: 4, strokeWidth: 2 }}
|
||||||
|
activeDot={{ r: 6 }}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</LineChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ExpandableCard>
|
||||||
|
|
||||||
{/* Country Chart - Uses Specific Data 'data' usually, unless we want to broaden it. Kept specific for now. */}
|
{/* Country Chart - Uses Specific Data 'data' usually, unless we want to broaden it. Kept specific for now. */}
|
||||||
<ExpandableCard title="Revenue Distribution by Customer" className="h-80">
|
<ExpandableCard title="Revenue Distribution by Customer" className="h-80">
|
||||||
<ResponsiveContainer width="100%" height="100%">
|
<ResponsiveContainer width="100%" height="100%">
|
||||||
|
|||||||
Reference in New Issue
Block a user