feat: Add YTD (Year-To-Date) cumulative lines to chart

- Calculate accumulated Sell Out and Units per week for each year
- Add toggle button to show/hide YTD lines (cyan color)
- YTD lines use thicker stroke with lower opacity for distinction
This commit is contained in:
Christian Vidal Wolf
2026-02-02 11:38:26 +01:00
parent dfe9a88ceb
commit ceb389cfb0
+60
View File
@@ -249,6 +249,7 @@ const DataGrid: React.FC<DataGridProps> = ({ data, hasCustomerFilter, adsData, s
const [visibleMetrics, setVisibleMetrics] = useState<('sellOut' | 'units')[]>(['sellOut', 'units']);
const [showAdsMetrics, setShowAdsMetrics] = useState(true);
const [showAttributedSales, setShowAttributedSales] = useState(false);
const [showYTD, setShowYTD] = useState(false);
const [showOnlyTop50, setShowOnlyTop50] = useState(false);
const [showDimensionMenu, setShowDimensionMenu] = useState(false);
const dimensionRef = useRef<HTMLDivElement>(null);
@@ -350,6 +351,27 @@ const DataGrid: React.FC<DataGridProps> = ({ data, hasCustomerFilter, adsData, s
});
}
// Calculate YTD (Year-To-Date) cumulative values for each year
const ytdAccumulators: { [year: string]: { sellOut: number; units: number } } = {};
yearsInView.forEach((year: string) => {
ytdAccumulators[year] = { sellOut: 0, units: 0 };
});
salesChartData.forEach((point: any) => {
yearsInView.forEach((year: string) => {
const sellOutKey = isMultiYear ? `${year}_sellOut` : 'sellOut';
const unitsKey = isMultiYear ? `${year}_units` : 'units';
// Accumulate values
ytdAccumulators[year].sellOut += (point[sellOutKey] as number) || 0;
ytdAccumulators[year].units += (point[unitsKey] as number) || 0;
// Add YTD values directly to point
point[`${year}_ytdSellOut`] = ytdAccumulators[year].sellOut;
point[`${year}_ytdUnits`] = ytdAccumulators[year].units;
});
});
return {
chartData: salesChartData,
uniqueYears: yearsInView,
@@ -700,6 +722,33 @@ const DataGrid: React.FC<DataGridProps> = ({ data, hasCustomerFilter, adsData, s
strokeWidth={2}
dot={false}
/>
),
// YTD Sell Out line (cumulative)
showYTD && visibleMetrics.includes('sellOut') && (
<Line
key={`${year}_ytdSellOut`}
type="monotone"
dataKey={`${year}_ytdSellOut`}
name={`YTD Sell Out ${year}`}
stroke={CHART_COLORS[idx % CHART_COLORS.length]}
strokeWidth={3}
strokeOpacity={0.6}
dot={false}
/>
),
// YTD Units line (cumulative)
showYTD && visibleMetrics.includes('units') && (
<Line
key={`${year}_ytdUnits`}
type="monotone"
dataKey={`${year}_ytdUnits`}
name={`YTD Units ${year}`}
stroke={CHART_COLORS[idx % CHART_COLORS.length]}
strokeWidth={3}
strokeDasharray="10 5"
strokeOpacity={0.6}
dot={false}
/>
)
])
) : (
@@ -856,6 +905,17 @@ const DataGrid: React.FC<DataGridProps> = ({ data, hasCustomerFilter, adsData, s
<span className="hidden sm:inline">{showAttributedSales ? 'Hide Attr. Sales' : 'Show Attr. Sales'}</span>
</button>
)}
{/* YTD (Year-To-Date) Toggle */}
<button
onClick={() => setShowYTD(!showYTD)}
className={`flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium border transition-colors ${showYTD ? 'bg-cyan-600/20 text-cyan-400 border-cyan-500/50' : 'bg-slate-800 text-slate-300 border-slate-700 hover:bg-slate-700'}`}
>
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" strokeWidth={2} stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" d="M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 0 1 3 19.875v-6.75ZM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V8.625ZM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V4.125Z" />
</svg>
<span className="hidden sm:inline">{showYTD ? 'Hide YTD' : 'Show YTD'}</span>
</button>
</div>
<div className="flex items-center gap-3 w-full lg:w-auto justify-between lg:justify-end">