From 0fc6f2324dc76fea7d05c648c6fb826712b1adc5 Mon Sep 17 00:00:00 2001 From: Christian Vidal Wolf Date: Fri, 23 Jan 2026 10:07:37 +0100 Subject: [PATCH] feat: separate Pan-EU and UK Top 50 results in Weekly Sales - App.tsx: Always calculate both EU and UK Top 50 maps. - WeeklyGrid.tsx: Added top50Mode state and EU/UK toggle. - WeeklyGrid.tsx: Updated filtering and sorting to respect the selected Top 50 mode. - WeeklyGrid.tsx: Enhanced product badges to show selected group rank. --- App.tsx | 25 +++------ components/WeeklyGrid.tsx | 111 +++++++++++++++++++++++--------------- 2 files changed, 74 insertions(+), 62 deletions(-) diff --git a/App.tsx b/App.tsx index adc3623..88056bc 100644 --- a/App.tsx +++ b/App.tsx @@ -340,25 +340,14 @@ const App: React.FC = () => { return rankMap; }; - if (filters.customer.length > 0) { - // Filtered mode: Rank products based on currently selected countries - const filtered2025 = data2025.filter(r => filters.customer.includes(r.customer)); - return { - type: 'filtered' as const, - overall: calculateTop50(filtered2025) - }; - } else { - // Dual mode: Separate Pan-EU and UK rankings when no countries are selected - const euData = data2025.filter(r => !r.customer.toLowerCase().includes('uk')); - const ukData = data2025.filter(r => r.customer.toLowerCase().includes('uk')); + const euData = data2025.filter(r => !r.customer.toLowerCase().includes('uk')); + const ukData = data2025.filter(r => r.customer.toLowerCase().includes('uk')); - return { - type: 'dual' as const, - eu: calculateTop50(euData), - uk: calculateTop50(ukData) - }; - } - }, [rawData, filters.customer]); + return { + eu: calculateTop50(euData), + uk: calculateTop50(ukData) + }; + }, [rawData]); // Combine Sales & Ads Data dynamically based on current filters const combinedAdsData = useMemo(() => { diff --git a/components/WeeklyGrid.tsx b/components/WeeklyGrid.tsx index 7d1a611..95a3f88 100644 --- a/components/WeeklyGrid.tsx +++ b/components/WeeklyGrid.tsx @@ -6,10 +6,8 @@ import { pivotWeeklySalesData, WeeklyPivotRow } from '../services/dataProcessor' interface WeeklyGridProps { data: CombinedKPIs[]; top50Ranking?: { - type: 'filtered' | 'dual'; - overall?: Map; - eu?: Map; - uk?: Map; + eu: Map; + uk: Map; }; onDrillDown?: (sku: string) => void; } @@ -66,6 +64,7 @@ const WeeklyGrid: React.FC = ({ data, top50Ranking, onDrillDown const [growthFilterMode, setGrowthFilterMode] = useState<'all' | 'up' | 'down' | 'stable'>('all'); const [growthThreshold, setGrowthThreshold] = useState(10); const [showOnlyTop50, setShowOnlyTop50] = useState(false); + const [top50Mode, setTop50Mode] = useState<'eu' | 'uk'>('eu'); // Default sort: most recent week, descending, units const [sortConfig, setSortConfig] = useState(() => { @@ -78,7 +77,19 @@ const WeeklyGrid: React.FC = ({ data, top50Ranking, onDrillDown // Reset pagination when search changes useEffect(() => { setCurrentPage(1); - }, [debouncedSearch, showOnlyTop50]); + }, [debouncedSearch, showOnlyTop50, top50Mode]); + + // Auto-detect best Top 50 mode based on currently selected data + useEffect(() => { + const hasUK = rows.some(r => r.customer.toLowerCase().includes('uk')); + const hasEU = rows.some(r => !r.customer.toLowerCase().includes('uk')); + + if (hasUK && !hasEU) { + setTop50Mode('uk'); + } else if (hasEU && !hasUK) { + setTop50Mode('eu'); + } + }, [rows]); const handleSort = useCallback((weekKey: string, metric: 'units' | 'spend' | 'rank' | 'gv') => { setSortConfig(prev => { @@ -115,10 +126,12 @@ const WeeklyGrid: React.FC = ({ data, top50Ranking, onDrillDown if (showOnlyTop50 && top50Ranking) { result = result.filter(r => { const asin = r.asin.trim().toUpperCase(); - if (top50Ranking.type === 'filtered') { - return top50Ranking.overall?.has(asin); + const isUK = r.customer.toLowerCase().includes('uk'); + + if (top50Mode === 'eu') { + return !isUK && top50Ranking.eu.has(asin); } else { - return top50Ranking.eu?.has(asin) || top50Ranking.uk?.has(asin); + return isUK && top50Ranking.uk.has(asin); } }); } @@ -181,13 +194,14 @@ const WeeklyGrid: React.FC = ({ data, top50Ranking, onDrillDown let rankA = 999; let rankB = 999; - if (top50Ranking?.type === 'filtered') { - rankA = top50Ranking.overall?.get(asinA) || 999; - rankB = top50Ranking.overall?.get(asinB) || 999; - } else if (top50Ranking?.type === 'dual') { - // In dual mode, prioritize EU rank, then UK rank - rankA = top50Ranking.eu?.get(asinA) || top50Ranking.uk?.get(asinA) || 999; - rankB = top50Ranking.eu?.get(asinB) || top50Ranking.uk?.get(asinB) || 999; + if (top50Ranking) { + if (top50Mode === 'eu') { + rankA = top50Ranking.eu.get(asinA) || 999; + rankB = top50Ranking.eu.get(asinB) || 999; + } else { + rankA = top50Ranking.uk.get(asinA) || 999; + rankB = top50Ranking.uk.get(asinB) || 999; + } } return direction === 'asc' ? rankA - rankB : rankB - rankA; @@ -290,31 +304,42 @@ const WeeklyGrid: React.FC = ({ data, top50Ranking, onDrillDown {/* Top 50 Filter Toggle */} {top50Ranking && ( - (top50Ranking.overall?.size || 0) > 0 || - (top50Ranking.eu?.size || 0) > 0 || - (top50Ranking.uk?.size || 0) > 0 + (top50Ranking.eu.size || 0) > 0 || + (top50Ranking.uk.size || 0) > 0 ) && ( - + {showOnlyTop50 && ( - - - +
+ + +
)} - + )} {/* Export Button */} @@ -447,14 +472,12 @@ const WeeklyGrid: React.FC = ({ data, top50Ranking, onDrillDown const ranks = []; if (top50Ranking) { - if (top50Ranking.type === 'filtered') { - const rank = top50Ranking.overall?.get(asin); - if (rank) ranks.push({ rank, label: '', theme: 'amber' as const }); + if (top50Mode === 'eu') { + const rank = top50Ranking.eu.get(asin); + if (rank) ranks.push({ rank, label: 'EU', theme: 'indigo' as const }); } else { - const euRank = top50Ranking.eu?.get(asin); - const ukRank = top50Ranking.uk?.get(asin); - if (euRank) ranks.push({ rank: euRank, label: 'EU', theme: 'indigo' as const }); - if (ukRank) ranks.push({ rank: ukRank, label: 'UK', theme: 'blue' as const }); + const rank = top50Ranking.uk.get(asin); + if (rank) ranks.push({ rank, label: 'UK', theme: 'blue' as const }); } }