From 99e4b2c34bf19e065a85d3f55e9a864a6ebd1faf Mon Sep 17 00:00:00 2001 From: Christian Vidal Wolf Date: Mon, 27 Apr 2026 11:33:04 +0200 Subject: [PATCH] Fix: restore Top50 ranking badges (white/gradient) next to inventory badges across all views --- App.tsx | 4 ++++ components/Dashboard.tsx | 17 ++++++++++++++++- components/DataGrid.tsx | 13 +++++++++++++ components/TopMovers.tsx | 32 ++++++++++++++++++++++++++++++-- components/VendorDataView.tsx | 18 +++++++++++++++++- components/WeeklyRow.tsx | 12 ++++++++++++ components/mkt/MasterTable.tsx | 18 +++++++++++++++++- components/mkt/MktDataView.tsx | 5 ++++- 8 files changed, 113 insertions(+), 6 deletions(-) diff --git a/App.tsx b/App.tsx index fe4c843..0b5db49 100644 --- a/App.tsx +++ b/App.tsx @@ -860,6 +860,8 @@ const App: React.FC = () => { buyBoxLostMap={buyBoxLostMap} top50Mode={top50Mode} rawData={ytdFilteredData} + velocityMap={velocityMap} + top50Ranking={top50Ranking2025} /> @@ -957,6 +959,7 @@ const App: React.FC = () => { vendorStockMap={vendorStockMap} top50Mode={filters.customer.includes('Amazon UK') ? 'uk' : 'eu'} velocityMap={velocityMap} + top50Ranking={top50Ranking2025} /> @@ -980,6 +983,7 @@ const App: React.FC = () => { top50Mode={filters.customer.includes('Amazon UK') ? 'uk' : 'eu'} velocityMap={velocityMap} buyBoxLostMap={buyBoxLostMap} + top50Ranking={top50Ranking2025} /> diff --git a/components/Dashboard.tsx b/components/Dashboard.tsx index d47feb4..1160732 100644 --- a/components/Dashboard.tsx +++ b/components/Dashboard.tsx @@ -16,6 +16,8 @@ interface DashboardProps { vendorStockMap?: Map; buyBoxLostMap?: Map }>; top50Mode?: 'eu' | 'uk'; + top50Ranking?: { eu: Map; uk: Map }; + velocityMap?: Map; } const COLORS = ['#6366f1', '#ec4899', '#10b981', '#f59e0b', '#8b5cf6', '#0ea5e9']; @@ -463,7 +465,18 @@ const GrowthTable: React.FC<{ ); } -const Dashboard: React.FC = ({ data, contextData, adsData = [], rawData = [], stockMap, vendorStockMap, buyBoxLostMap, top50Mode }) => { +const Dashboard: React.FC = ({ + data, + contextData, + adsData = [], + rawData = [], + stockMap, + vendorStockMap, + buyBoxLostMap, + top50Mode = 'eu', + top50Ranking, + velocityMap +}) => { const [seasonalityMetric, setSeasonalityMetric] = useState<'sellOut' | 'units'>('sellOut'); const [top10Metric, setTop10Metric] = useState<'sellOut' | 'units'>('sellOut'); @@ -824,6 +837,8 @@ const Dashboard: React.FC = ({ data, contextData, adsData = [], vendorStockMap={vendorStockMap} buyBoxLostMap={buyBoxLostMap} top50Mode={top50Mode} + velocityMap={velocityMap} + top50Ranking={top50Ranking} /> )} diff --git a/components/DataGrid.tsx b/components/DataGrid.tsx index ecf75ed..684505d 100644 --- a/components/DataGrid.tsx +++ b/components/DataGrid.tsx @@ -1387,6 +1387,19 @@ const DataGrid: React.FC = ({ data, filters, hasCustomerFilter, a {stockMap && ( )} + {(() => { + const asin = (row.asin || '').trim().toUpperCase(); + if (asin && top50Ranking) { + if (top50Mode === 'eu') { + const rank = top50Ranking.eu.get(asin); + if (rank) return ; + } else { + const rank = top50Ranking.uk.get(asin); + if (rank) return ; + } + } + return null; + })()} diff --git a/components/TopMovers.tsx b/components/TopMovers.tsx index 4071921..c468060 100644 --- a/components/TopMovers.tsx +++ b/components/TopMovers.tsx @@ -4,6 +4,7 @@ import { SalesRecord } from '../types'; import { DownloadIcon } from './Icons'; import { StockBadge } from './StockBadge'; import { VendorStockBadge } from './VendorStockBadge'; +import { Top50Badge } from './Top50Badge'; import { BuyBoxWarningBadge } from './BuyBoxWarningBadge'; interface TopMoversProps { @@ -12,6 +13,8 @@ interface TopMoversProps { vendorStockMap?: Map; buyBoxLostMap?: Map }>; top50Mode?: 'eu' | 'uk'; + velocityMap?: Map; + top50Ranking?: { eu: Map; uk: Map }; } type Metric = 'sellOut' | 'units'; @@ -39,7 +42,9 @@ const MoversTable: React.FC<{ vendorStockMap?: Map; buyBoxLostMap?: Map }>; top50Mode?: 'eu' | 'uk'; -}> = ({ title, data, metric, previousYear, currentYear, type, stockMap, vendorStockMap, buyBoxLostMap, top50Mode = 'eu' }) => { + velocityMap?: Map; + top50Ranking?: { eu: Map; uk: Map }; +}> = ({ title, data, metric, previousYear, currentYear, type, stockMap, vendorStockMap, buyBoxLostMap, top50Mode = 'eu', velocityMap, top50Ranking }) => { const formatValue = (val: number) => { if (metric === 'sellOut') return `€${val.toLocaleString('de-DE', { maximumFractionDigits: 0 })}`; @@ -131,6 +136,19 @@ const MoversTable: React.FC<{ {/* Stock Badge */} + {(() => { + const asin = item.asin.trim().toUpperCase(); + if (asin && top50Ranking) { + if (top50Mode === 'eu') { + const rank = top50Ranking.eu.get(asin); + if (rank) return ; + } else { + const rank = top50Ranking.uk.get(asin); + if (rank) return ; + } + } + return null; + })()} {/* Vendor Stock Badge */} @@ -182,7 +200,15 @@ const MoversTable: React.FC<{ ); }; -const TopMovers: React.FC = ({ data, stockMap, vendorStockMap, buyBoxLostMap, top50Mode = 'eu' }) => { +const TopMovers: React.FC = ({ + data, + stockMap, + vendorStockMap, + buyBoxLostMap, + top50Mode = 'eu', + velocityMap, + top50Ranking +}) => { const [metric, setMetric] = useState('sellOut'); const [viewMode, setViewMode] = useState<'growth' | 'decline'>('growth'); @@ -336,6 +362,8 @@ const TopMovers: React.FC = ({ data, stockMap, vendorStockMap, b vendorStockMap={vendorStockMap} buyBoxLostMap={buyBoxLostMap} top50Mode={top50Mode} + velocityMap={velocityMap} + top50Ranking={top50Ranking} /> diff --git a/components/VendorDataView.tsx b/components/VendorDataView.tsx index 3cb20e2..c35bfb3 100644 --- a/components/VendorDataView.tsx +++ b/components/VendorDataView.tsx @@ -4,6 +4,7 @@ import { BSRRecord, CombinedKPIs } from '../types'; import { BuyBoxWarningBadge } from './BuyBoxWarningBadge'; import { StockBadge } from './StockBadge'; import { VendorStockBadge } from './VendorStockBadge'; +import { Top50Badge } from './Top50Badge'; import { BSRUnitsCorrelationChart } from './BSRUnitsCorrelationChart'; interface VendorDataViewProps { @@ -15,6 +16,7 @@ interface VendorDataViewProps { vendorStockMap?: Map; top50Mode?: 'eu' | 'uk'; velocityMap?: Map; + top50Ranking?: { eu: Map; uk: Map }; } interface ChartPoint { @@ -320,7 +322,8 @@ const VendorDataView: React.FC = ({ stockMap, vendorStockMap, top50Mode = 'eu', - velocityMap + velocityMap, + top50Ranking }) => { const activeMarkets = useMemo(() => { const m = new Set(bsrData.map(r => r.market)); @@ -481,6 +484,19 @@ const VendorDataView: React.FC = ({ {stockMap && ( )} + {(() => { + const asin = productInfo.asin.trim().toUpperCase(); + if (asin && top50Ranking) { + if (top50Mode === 'eu') { + const rank = top50Ranking.eu.get(asin); + if (rank) return ; + } else { + const rank = top50Ranking.uk.get(asin); + if (rank) return ; + } + } + return null; + })()} = React.memo(({ {stockMap && ( )} + {(() => { + if (asin && top50Ranking) { + if (top50Mode === 'eu') { + const rank = top50Ranking.eu.get(asin); + if (rank) return ; + } else { + const rank = top50Ranking.uk.get(asin); + if (rank) return ; + } + } + return null; + })()} {experimentMap && ( ; buyBoxLostMap?: Map }>; + top50Ranking?: { eu: Map; uk: Map }; } type SortKey = 'name' | 'grossSales' | 'ppcSpend' | 'deals' | 'promos' | 'chargebacks' | 'netMargin' | 'marginPercent'; @@ -28,7 +30,8 @@ export const MasterTable: React.FC = ({ vendorStockMap, top50Mode = 'eu', velocityMap, - buyBoxLostMap + buyBoxLostMap, + top50Ranking }) => { const [sortKey, setSortKey] = useState('marginPercent'); const [sortOrder, setSortOrder] = useState('asc'); @@ -196,6 +199,19 @@ export const MasterTable: React.FC = ({ {stockMap && ( )} + {(() => { + const asin = product.asin.trim().toUpperCase(); + if (asin && top50Ranking) { + if (top50Mode === 'eu') { + const rank = top50Ranking.eu.get(asin); + if (rank) return ; + } else { + const rank = top50Ranking.uk.get(asin); + if (rank) return ; + } + } + return null; + })()} ; buyBoxLostMap?: Map }>; + top50Ranking?: { eu: Map; uk: Map }; } export default function MktDataView({ @@ -104,7 +105,8 @@ export default function MktDataView({ vendorStockMap, top50Mode = 'eu', velocityMap, - buyBoxLostMap + buyBoxLostMap, + top50Ranking }: MktDataViewProps) { const [includeCOGS, setIncludeCOGS] = useState(true); const [selectedProduct, setSelectedProduct] = useState(null); @@ -332,6 +334,7 @@ export default function MktDataView({ top50Mode={top50Mode} velocityMap={velocityMap} buyBoxLostMap={buyBoxLostMap} + top50Ranking={top50Ranking} />