diff --git a/App.tsx b/App.tsx index 1346f70..ae93ec7 100644 --- a/App.tsx +++ b/App.tsx @@ -836,7 +836,16 @@ const App: React.FC = () => {
- +
}> diff --git a/components/Dashboard.tsx b/components/Dashboard.tsx index c32079d..0ce81d7 100644 --- a/components/Dashboard.tsx +++ b/components/Dashboard.tsx @@ -12,6 +12,10 @@ interface DashboardProps { contextData?: AggregatedData | null; adsData?: AdsRecord[]; rawData?: SalesRecord[]; + stockMap?: Map; + vendorStockMap?: Map; + buyBoxLostMap?: Map }>; + top50Mode?: 'eu' | 'uk'; } const COLORS = ['#6366f1', '#ec4899', '#10b981', '#f59e0b', '#8b5cf6', '#0ea5e9']; @@ -814,7 +818,13 @@ const Dashboard: React.FC = ({ data, contextData, adsData = [], {/* Top Movers Table - Full Width */} {rawData && rawData.length > 0 && (
- +
)}
diff --git a/components/TopMovers.tsx b/components/TopMovers.tsx index 8d5d852..7753487 100644 --- a/components/TopMovers.tsx +++ b/components/TopMovers.tsx @@ -2,15 +2,23 @@ import React, { useState, useMemo, useCallback } from 'react'; import * as XLSX from 'xlsx'; import { SalesRecord } from '../types'; import { DownloadIcon } from './Icons'; +import { StockBadge } from './StockBadge'; +import { VendorStockBadge } from './VendorStockBadge'; +import { BuyBoxWarningBadge } from './BuyBoxWarningBadge'; interface TopMoversProps { data: SalesRecord[]; + stockMap?: Map; + vendorStockMap?: Map; + buyBoxLostMap?: Map }>; + top50Mode?: 'eu' | 'uk'; } type Metric = 'sellOut' | 'units'; interface SkuAggr { sku: string; + asin: string; title: string; line: string; previousValue: number; @@ -27,7 +35,11 @@ const MoversTable: React.FC<{ previousYear: number; currentYear: number; type: 'growth' | 'decline'; -}> = ({ title, data, metric, previousYear, currentYear, type }) => { + stockMap?: Map; + vendorStockMap?: Map; + buyBoxLostMap?: Map }>; + top50Mode?: 'eu' | 'uk'; +}> = ({ title, data, metric, previousYear, currentYear, type, stockMap, vendorStockMap, buyBoxLostMap, top50Mode = 'eu' }) => { const formatValue = (val: number) => { if (metric === 'sellOut') return `€${val.toLocaleString('de-DE', { maximumFractionDigits: 0 })}`; @@ -84,6 +96,9 @@ const MoversTable: React.FC<{ Rank SKU Details Product Line + Stock + Vendor + Buy Box {previousYear} {currentYear} Diff @@ -113,6 +128,25 @@ const MoversTable: React.FC<{ + {/* Stock Badge */} + + + + + {/* Vendor Stock Badge */} + + + + + {/* Buy Box Warning Badge */} + + + + {formatValue(item.previousValue)} @@ -148,7 +182,7 @@ const MoversTable: React.FC<{ ); }; -const TopMovers: React.FC = ({ data }) => { +const TopMovers: React.FC = ({ data, stockMap, vendorStockMap, buyBoxLostMap, top50Mode = 'eu' }) => { const [metric, setMetric] = useState('sellOut'); const [viewMode, setViewMode] = useState<'growth' | 'decline'>('growth'); @@ -167,14 +201,14 @@ const TopMovers: React.FC = ({ data }) => { if (!currentYear || !previousYear) return { growers: [], decliners: [] }; // Map: SKU -> { currentVal, previousVal, metadata } - const map = new Map(); + const map = new Map(); data.forEach(row => { // Only care about the two comparison years if (row.year !== currentYear && row.year !== previousYear) return; if (!map.has(row.sku)) { - map.set(row.sku, { current: 0, previous: 0, title: row.title, line: row.line }); + map.set(row.sku, { current: 0, previous: 0, title: row.title, line: row.line, asin: row.asin }); } const entry = map.get(row.sku)!; @@ -204,6 +238,7 @@ const TopMovers: React.FC = ({ data }) => { list.push({ sku, + asin: val.asin, title: val.title, line: val.line, previousValue: val.previous, @@ -297,6 +332,10 @@ const TopMovers: React.FC = ({ data }) => { previousYear={previousYear} currentYear={currentYear} type={viewMode} + stockMap={stockMap} + vendorStockMap={vendorStockMap} + buyBoxLostMap={buyBoxLostMap} + top50Mode={top50Mode} />