From acf3faec368fed6149046009ad070806f733774f Mon Sep 17 00:00:00 2001 From: Christian Vidal Wolf Date: Wed, 17 Jun 2026 16:25:41 +0200 Subject: [PATCH] feat: add vendor stock badges to Sell-in vs Budget first column Shows aggregated EU and UK vendor stock per SKU (sum across all ASINs) in the first column, matching the style used in other dashboard tabs. Co-Authored-By: Claude Sonnet 4.6 --- App.tsx | 2 +- components/ForecastView.tsx | 49 +++++++++++++++++++++++++++++++++---- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/App.tsx b/App.tsx index 1186cf9..d60007f 100644 --- a/App.tsx +++ b/App.tsx @@ -898,7 +898,7 @@ const App: React.FC = () => { }>
- +
diff --git a/components/ForecastView.tsx b/components/ForecastView.tsx index 6d9650c..2fb85e4 100644 --- a/components/ForecastView.tsx +++ b/components/ForecastView.tsx @@ -2,6 +2,7 @@ import React, { useState, useMemo, useCallback, useRef } from 'react'; import * as XLSX from 'xlsx'; import { ExcelFilter } from './ExcelFilter'; import { ColumnFilterCondition } from '../types'; +import { AmazonSmileIcon } from './Icons'; const MONTHS = ['January','February','March','April','May','June','July','August','September','October','November','December']; const MONTHS_SHORT = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; @@ -33,6 +34,8 @@ interface ComparisonRow { budgetDiscrepancy: boolean; pctPeriod: number; pctAnnual: number; + vendorStockEU: number; + vendorStockUK: number; } function parseSellIn(buffer: ArrayBuffer): Map { @@ -132,8 +135,34 @@ const ComparisonTableRow: React.FC<{ row: ComparisonRow }> = React.memo(({ row } const barWidth = Math.min(100, row.pctPeriod); return ( - - {row.sku} + +
+ {row.sku} + {(row.vendorStockEU > 0 || row.vendorStockUK > 0) && ( +
+ {row.vendorStockEU > 0 && ( +
+ + EU + {row.vendorStockEU.toLocaleString('de-DE')} +
+ )} + {row.vendorStockUK > 0 && ( +
+ + UK + {row.vendorStockUK.toLocaleString('de-DE')} +
+ )} +
+ )} +
@@ -188,9 +217,10 @@ const ComparisonTableRow: React.FC<{ row: ComparisonRow }> = React.memo(({ row } interface ForecastViewProps { asinMetadata?: Map; + vendorStockMap?: Map; } -const ForecastView: React.FC = ({ asinMetadata }) => { +const ForecastView: React.FC = ({ asinMetadata, vendorStockMap }) => { const [sellInData, setSellInData] = useState | null>(null); const [budgetData, setBudgetData] = useState | null>(null); const [sellInFileName, setSellInFileName] = useState(''); @@ -258,10 +288,17 @@ const ForecastView: React.FC = ({ asinMetadata }) => { const pctPeriod = periodForecast > 0 ? (actualUnits / periodForecast) * 100 : 0; const pctAnnual = budgetYearTotal > 0 ? (actualUnits / budgetYearTotal) * 100 : 0; const meta = skuMetadata.get(budgetRow.sku); + const asins = meta?.asins ?? []; + const vendorStockEU = asins.reduce((sum, asin) => { + return sum + (vendorStockMap?.get(asin.trim().toUpperCase())?.eu ?? 0); + }, 0); + const vendorStockUK = asins.reduce((sum, asin) => { + return sum + (vendorStockMap?.get(asin.trim().toUpperCase())?.uk ?? 0); + }, 0); rows.push({ sku: budgetRow.sku, description: budgetRow.description, - asins: meta?.asins ?? [], + asins, title: meta?.title ?? '', actualUnits, periodForecast, @@ -269,10 +306,12 @@ const ForecastView: React.FC = ({ asinMetadata }) => { budgetDiscrepancy, pctPeriod, pctAnnual, + vendorStockEU, + vendorStockUK, }); }); return rows; - }, [budgetData, sellInData, cutoffMonth, skuMetadata]); + }, [budgetData, sellInData, cutoffMonth, skuMetadata, vendorStockMap]); const passesTextFilter = useCallback((value: string, filter?: ColumnFilterCondition): boolean => { if (!filter) return true;