mirror of
https://github.com/christianvidalwolf-prog/CrazeAnalytix.git
synced 2026-08-03 13:15:24 +02:00
feat: add units/revenue toggle to Weekly Sales and improve traffic data parsing
This commit is contained in:
+109
-28
@@ -153,7 +153,8 @@ const WeeklyRow: React.FC<{
|
||||
vendorStockMap?: Map<string, { eu: number; uk: number }>;
|
||||
velocityMap?: Map<string, number>;
|
||||
buyBoxLostMap?: Map<string, { countries: string[]; reasons: Record<string, string> }>;
|
||||
}> = React.memo(({ row, weeks, onDrillDown, stockMap, top50Ranking, top50Mode, sortConfig, renderGrowth, customerFilters, vendorStockMap, velocityMap, buyBoxLostMap }) => {
|
||||
primaryMetric: 'units' | 'revenue';
|
||||
}> = React.memo(({ row, weeks, onDrillDown, stockMap, top50Ranking, top50Mode, sortConfig, renderGrowth, customerFilters, vendorStockMap, velocityMap, buyBoxLostMap, primaryMetric }) => {
|
||||
const ranks: { rank: number; label: string; theme: 'amber' | 'blue' | 'indigo' }[] = [];
|
||||
const asin = row.asin.trim().toUpperCase();
|
||||
|
||||
@@ -222,8 +223,8 @@ const WeeklyRow: React.FC<{
|
||||
|
||||
return (
|
||||
<td key={week} className={`p-3 py-2 text-center border-r border-white/5 align-middle ${sortConfig?.key === week ? 'bg-white/[0.01]' : ''}`}>
|
||||
<div className="flex flex-col items-center justify-center gap-0.5">
|
||||
{/* Units with tooltip */}
|
||||
{/* Primary Metric based on toggle */}
|
||||
{primaryMetric === 'units' ? (
|
||||
<MetricDetailTooltip
|
||||
currentValue={val}
|
||||
previousValue={prevVal}
|
||||
@@ -241,10 +242,31 @@ const WeeklyRow: React.FC<{
|
||||
{val > 0 && renderGrowth(val, prevVal)}
|
||||
</div>
|
||||
</MetricDetailTooltip>
|
||||
) : (
|
||||
<MetricDetailTooltip
|
||||
currentValue={spend}
|
||||
previousValue={prevSpend}
|
||||
yoyValue={yoySpend}
|
||||
currentWeekLabel={`Week ${weekNum} (${year})`}
|
||||
previousWeekLabel={`Week ${prevWeekNum} (${year})`}
|
||||
yoyWeekLabel={`Week ${weekNum} (${parseInt(year) - 1})`}
|
||||
metricName="Revenue"
|
||||
metricColor="text-white"
|
||||
formatValue={(v) => `€${v.toLocaleString('de-DE', { minimumFractionDigits: 0, maximumFractionDigits: 0 })}`}
|
||||
>
|
||||
<div className="flex items-center gap-1">
|
||||
<span className={`text-sm font-bold ${spend > 0 ? (sortConfig?.key === week && sortConfig.metric === 'spend' ? 'text-amber-400' : 'text-white') : 'text-slate-700'}`}>
|
||||
{spend > 0 ? `€${spend.toLocaleString('de-DE', { minimumFractionDigits: 0, maximumFractionDigits: 0 })}` : '-'}
|
||||
</span>
|
||||
{spend > 0 && renderGrowth(spend, prevSpend)}
|
||||
</div>
|
||||
</MetricDetailTooltip>
|
||||
)}
|
||||
|
||||
<div className="flex flex-col items-center">
|
||||
{/* Spend with tooltip */}
|
||||
{spend > 0 && (
|
||||
<div className="flex flex-col items-center">
|
||||
{/* Secondary Metric (the one not selected) */}
|
||||
{primaryMetric === 'units' ? (
|
||||
spend > 0 && (
|
||||
<MetricDetailTooltip
|
||||
currentValue={spend}
|
||||
previousValue={prevSpend}
|
||||
@@ -263,29 +285,49 @@ const WeeklyRow: React.FC<{
|
||||
{renderGrowth(spend, prevSpend)}
|
||||
</div>
|
||||
</MetricDetailTooltip>
|
||||
)}
|
||||
|
||||
{/* GV with tooltip */}
|
||||
{gv > 0 && (
|
||||
)
|
||||
) : (
|
||||
val > 0 && (
|
||||
<MetricDetailTooltip
|
||||
currentValue={gv}
|
||||
previousValue={prevGv}
|
||||
yoyValue={yoyGv}
|
||||
currentValue={val}
|
||||
previousValue={prevVal}
|
||||
yoyValue={yoyUnits}
|
||||
currentWeekLabel={`Week ${weekNum} (${year})`}
|
||||
previousWeekLabel={`Week ${prevWeekNum} (${year})`}
|
||||
yoyWeekLabel={`Week ${weekNum} (${parseInt(year) - 1})`}
|
||||
metricName="GV (Glance View)"
|
||||
metricColor="text-teal-400"
|
||||
metricName="Units"
|
||||
metricColor="text-indigo-400"
|
||||
>
|
||||
<div className="flex items-center gap-1">
|
||||
<span className={`text-[9px] font-black tracking-tighter ${sortConfig?.key === week && sortConfig.metric === 'gv' ? 'text-teal-300' : 'text-teal-500/70'}`}>
|
||||
GV: {gv.toLocaleString('de-DE')}
|
||||
<span className={`text-[11px] font-medium ${sortConfig?.key === week && sortConfig.metric === 'units' ? 'text-amber-300' : 'text-indigo-400/80'}`}>
|
||||
{val.toLocaleString('de-DE')} Units
|
||||
</span>
|
||||
{renderGrowth(gv, prevGv)}
|
||||
{renderGrowth(val, prevVal)}
|
||||
</div>
|
||||
</MetricDetailTooltip>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
|
||||
{/* GV with tooltip - Always small/bottom */}
|
||||
{gv > 0 && (
|
||||
<MetricDetailTooltip
|
||||
currentValue={gv}
|
||||
previousValue={prevGv}
|
||||
yoyValue={yoyGv}
|
||||
currentWeekLabel={`Week ${weekNum} (${year})`}
|
||||
previousWeekLabel={`Week ${prevWeekNum} (${year})`}
|
||||
yoyWeekLabel={`Week ${weekNum} (${parseInt(year) - 1})`}
|
||||
metricName="GV (Glance View)"
|
||||
metricColor="text-teal-400"
|
||||
>
|
||||
<div className="flex items-center gap-1">
|
||||
<span className={`text-[9px] font-black tracking-tighter ${sortConfig?.key === week && sortConfig.metric === 'gv' ? 'text-teal-300' : 'text-teal-500/70'}`}>
|
||||
GV: {gv.toLocaleString('de-DE')}
|
||||
</span>
|
||||
{renderGrowth(gv, prevGv)}
|
||||
</div>
|
||||
</MetricDetailTooltip>
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
);
|
||||
@@ -324,6 +366,7 @@ const WeeklyGrid: React.FC<WeeklyGridProps & { top50Mode: 'eu' | 'uk' }> = ({
|
||||
const [growthThreshold, setGrowthThreshold] = useState(10);
|
||||
const [showOnlyTop50, setShowOnlyTop50] = useState(false);
|
||||
const [displayCount, setDisplayCount] = useState(50);
|
||||
const [primaryMetric, setPrimaryMetric] = useState<'units' | 'revenue'>('units');
|
||||
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// State for Column Filters (SKU, ASIN, Title, Line)
|
||||
@@ -700,6 +743,28 @@ const WeeklyGrid: React.FC<WeeklyGridProps & { top50Mode: 'eu' | 'uk' }> = ({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Metric Toggle */}
|
||||
<div className="flex bg-slate-950/50 p-1 rounded-xl border border-white/10 shadow-sm ml-auto lg:ml-0">
|
||||
<button
|
||||
onClick={() => setPrimaryMetric('units')}
|
||||
className={`px-3 py-1.5 rounded-lg text-xs font-bold transition-all ${primaryMetric === 'units'
|
||||
? 'bg-indigo-600 text-white shadow-lg shadow-indigo-500/20'
|
||||
: 'text-slate-400 hover:text-white'
|
||||
}`}
|
||||
>
|
||||
Units
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setPrimaryMetric('revenue')}
|
||||
className={`px-3 py-1.5 rounded-lg text-xs font-bold transition-all ${primaryMetric === 'revenue'
|
||||
? 'bg-indigo-600 text-white shadow-lg shadow-indigo-500/20'
|
||||
: 'text-slate-400 hover:text-white'
|
||||
}`}
|
||||
>
|
||||
Revenue (€)
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Export Button */}
|
||||
<button
|
||||
onClick={handleExportExcel}
|
||||
@@ -909,14 +974,29 @@ const WeeklyGrid: React.FC<WeeklyGridProps & { top50Mode: 'eu' | 'uk' }> = ({
|
||||
{weeks.map((week, idx) => (
|
||||
<th key={week} className="p-3 text-sm font-black text-white text-center border-r border-white/10">
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="flex items-center gap-1">
|
||||
<span>{weekTotals[week]?.units.toLocaleString('de-DE') || 0}</span>
|
||||
{renderGrowth(weekTotals[week]?.units || 0, weekTotals[weeks[idx + 1]]?.units || 0)}
|
||||
</div>
|
||||
<div className="flex items-center justify-center gap-1 text-[10px] text-indigo-400 font-bold">
|
||||
<span>€{(weekTotals[week]?.spend || 0).toLocaleString('de-DE', { minimumFractionDigits: 0, maximumFractionDigits: 0 })}</span>
|
||||
{renderGrowth(weekTotals[week]?.spend || 0, weekTotals[weeks[idx + 1]]?.spend || 0)}
|
||||
</div>
|
||||
{primaryMetric === 'units' ? (
|
||||
<>
|
||||
<div className="flex items-center gap-1">
|
||||
<span>{weekTotals[week]?.units.toLocaleString('de-DE') || 0}</span>
|
||||
{renderGrowth(weekTotals[week]?.units || 0, weekTotals[weeks[idx + 1]]?.units || 0)}
|
||||
</div>
|
||||
<div className="flex items-center justify-center gap-1 text-[10px] text-indigo-400 font-bold">
|
||||
<span>€{(weekTotals[week]?.spend || 0).toLocaleString('de-DE', { minimumFractionDigits: 0, maximumFractionDigits: 0 })}</span>
|
||||
{renderGrowth(weekTotals[week]?.spend || 0, weekTotals[weeks[idx + 1]]?.spend || 0)}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex items-center gap-1">
|
||||
<span>€{(weekTotals[week]?.spend || 0).toLocaleString('de-DE', { minimumFractionDigits: 0, maximumFractionDigits: 0 })}</span>
|
||||
{renderGrowth(weekTotals[week]?.spend || 0, weekTotals[weeks[idx + 1]]?.spend || 0)}
|
||||
</div>
|
||||
<div className="flex items-center justify-center gap-1 text-[10px] text-indigo-400 font-bold">
|
||||
<span>{(weekTotals[week]?.units || 0).toLocaleString('de-DE')} Units</span>
|
||||
{renderGrowth(weekTotals[week]?.units || 0, weekTotals[weeks[idx + 1]]?.units || 0)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<div className="flex items-center justify-center gap-1 text-[9px] text-teal-400 font-black tracking-tight mt-0.5">
|
||||
<span>GV: {(weekTotals[week]?.gv || 0).toLocaleString('de-DE')}</span>
|
||||
{renderGrowth(weekTotals[week]?.gv || 0, weekTotals[weeks[idx + 1]]?.gv || 0)}
|
||||
@@ -947,6 +1027,7 @@ const WeeklyGrid: React.FC<WeeklyGridProps & { top50Mode: 'eu' | 'uk' }> = ({
|
||||
customerFilters={customerFilters}
|
||||
velocityMap={velocityMap}
|
||||
buyBoxLostMap={buyBoxLostMap}
|
||||
primaryMetric={primaryMetric}
|
||||
/>
|
||||
))}
|
||||
{displayCount < sortedRows.length && (
|
||||
|
||||
Reference in New Issue
Block a user