import React, { useMemo, useState } from 'react'; import { CombinedKPIs } from '../types'; import { pivotWeeklySalesData, WeeklyPivotRow } from '../services/dataProcessor'; interface WeeklyGridProps { data: CombinedKPIs[]; } type SortConfig = { key: string; // weekKey direction: 'asc' | 'desc'; } | null; const WeeklyGrid: React.FC = ({ data }) => { const { rows, weeks } = useMemo(() => pivotWeeklySalesData(data), [data]); // Default sort: most recent week, descending const [sortConfig, setSortConfig] = useState(() => { if (weeks.length > 0) { return { key: weeks[0], direction: 'desc' }; } return null; }); const handleSort = (weekKey: string) => { setSortConfig(prev => { if (prev?.key === weekKey) { return { key: weekKey, direction: prev.direction === 'asc' ? 'desc' : 'asc' }; } return { key: weekKey, direction: 'desc' }; }); }; // Sort rows globally (Ungrouped) const sortedRows = useMemo(() => { const result = [...rows]; if (sortConfig) { result.sort((a, b) => { const valA = a.unitsByWeek[sortConfig.key] || 0; const valB = b.unitsByWeek[sortConfig.key] || 0; if (sortConfig.direction === 'asc') { return valA - valB; } return valB - valA; }); } return result; }, [rows, sortConfig]); // Calculate totals per week const weekTotals = useMemo(() => { const totals: { [weekKey: string]: { units: number, spend: number } } = {}; weeks.forEach(week => { totals[week] = rows.reduce((acc, row) => { acc.units += (row.unitsByWeek[week] || 0); acc.spend += (row.spendByWeek[week] || 0); return acc; }, { units: 0, spend: 0 }); }); return totals; }, [rows, weeks]); const renderGrowth = (current: number, previous: number) => { if (!previous || previous === 0) return null; const pct = ((current - previous) / previous) * 100; const isPositive = pct >= 0; return ( {isPositive ? '▲' : '▼'}{Math.abs(pct).toFixed(0)}% ); }; return (
{weeks.map(week => ( ))} {weeks.map((week, idx) => ( ))} {sortedRows.map((row) => ( {weeks.map((week, idx) => { const val = row.unitsByWeek[week] || 0; const prevVal = row.unitsByWeek[weeks[idx + 1]] || 0; const spend = row.spendByWeek[week] || 0; return ( ); })} ))}
Product Details handleSort(week)} >
{week.split('-')[1]}/{week.split('-')[0].slice(-2)} {sortConfig?.key === week && ( {sortConfig.direction === 'asc' ? '↑' : '↓'} )}
Units / Spend
TOTALS
{weekTotals[week].units.toLocaleString('de-DE')} {renderGrowth(weekTotals[week].units, weekTotals[weeks[idx + 1]]?.units)}
€{weekTotals[week].spend.toLocaleString('de-DE', { minimumFractionDigits: 0, maximumFractionDigits: 0 })}
{row.sku} {row.title} {row.line}
0 ? (sortConfig?.key === week ? 'text-indigo-400' : 'text-white') : 'text-slate-700'}`}> {val > 0 ? val.toLocaleString('de-DE') : '-'} {val > 0 && renderGrowth(val, prevVal)}
{spend > 0 && ( €{spend.toLocaleString('de-DE', { minimumFractionDigits: 0, maximumFractionDigits: 0 })} )}
); }; export default WeeklyGrid;