Implement Weeks of Coverage indicator for Vendor Stock

This commit is contained in:
Christian Vidal Wolf
2026-01-28 10:34:46 +01:00
parent 5915bb4c0e
commit 22f4a639c0
6 changed files with 112 additions and 44 deletions
+1 -1
View File
@@ -74,7 +74,7 @@ const AdsRow: React.FC<{
{stockMap && (
<StockBadge stock={stockMap.get(item.sku?.replace(/(DE|EN)$/i, ''))} />
)}
<VendorStockBadge asin={item.asin} vendorStockMap={vendorStockMap} mode={top50Mode} />
<VendorStockBadge asin={item.asin} vendorStockMap={vendorStockMap} mode={top50Mode} avgWeeklySales={item.avgWeeklySales} />
</div>
</div>
</td>
+1 -1
View File
@@ -66,7 +66,7 @@ const ForecastRow: React.FC<{
{stockMap && (
<StockBadge stock={stockMap.get(item.sku?.replace(/(DE|EN)$/i, ''))} />
)}
<VendorStockBadge asin={item.asin} vendorStockMap={vendorStockMap} mode={top50Mode} />
<VendorStockBadge asin={item.asin} vendorStockMap={vendorStockMap} mode={top50Mode} avgWeeklySales={item.avgWeeklySales} />
</div>
</div>
</td>
+48 -38
View File
@@ -5,9 +5,10 @@ interface VendorStockBadgeProps {
asin: string;
vendorStockMap?: Map<string, { eu: number; uk: number }>;
mode: 'eu' | 'uk';
avgWeeklySales?: number;
}
export const VendorStockBadge: React.FC<VendorStockBadgeProps> = ({ asin, vendorStockMap, mode }) => {
export const VendorStockBadge: React.FC<VendorStockBadgeProps> = ({ asin, vendorStockMap, mode, avgWeeklySales }) => {
if (!vendorStockMap || !asin) return null;
const stockData = vendorStockMap.get(asin.toUpperCase());
@@ -15,48 +16,57 @@ export const VendorStockBadge: React.FC<VendorStockBadgeProps> = ({ asin, vendor
const stock = mode === 'uk' ? stockData.uk : stockData.eu;
// As per user request: "etiqueta será de color gris claro"
// Using a light gray/slate theme that fits the dashboard's premium look
// Calculate Weeks of Coverage (WOC)
const woc = (avgWeeklySales && avgWeeklySales > 0) ? stock / avgWeeklySales : null;
const wocColor = woc !== null ? (woc < 4 ? 'text-rose-500' : 'text-emerald-500') : 'text-slate-400';
const themeClasses = "bg-slate-200 text-slate-800 border-slate-300 shadow-sm";
return (
<div
className={`inline-flex items-center gap-1 px-2 py-0.5 rounded border text-[10px] font-bold transition-all hover:scale-105 active:scale-95 cursor-default ${themeClasses}`}
title={`Stock en Amazon Warehouse (${mode.toUpperCase()}): ${stock}`}
>
<svg
className="w-3.5 h-3.5"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
<div className="flex flex-col items-center gap-0.5">
<div
className={`inline-flex items-center gap-1 px-2 py-0.5 rounded border text-[10px] font-bold transition-all hover:scale-105 active:scale-95 cursor-default ${themeClasses}`}
title={`Stock en Amazon Warehouse (${mode.toUpperCase()}): ${stock}`}
>
<path
d="M17.5 14c.5 0 1 .5 1 1s-.5 1-1 1-1-.5-1-1 .5-1 1-1zm-11 0c.5 0 1 .5 1 1s-.5 1-1 1-1-.5-1-1 .5-1 1-1z"
fill="currentColor"
/>
<path
d="M3 13.5c0 4.7 3.8 8.5 8.5 8.5s8.5-3.8 8.5-8.5"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
/>
<path
d="M17 18.5c-1.5 1.5-3.5 2.5-5.5 2.5s-4-1-5.5-2.5"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
/>
<path
d="M19 18.5l1.5 1.5M5 18.5L3.5 20"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
/>
</svg>
<div className="flex flex-col leading-[0.8]">
<span className="text-[7px] font-black uppercase opacity-60">Vendor</span>
<span>{stock.toLocaleString('de-DE')}</span>
<svg
className="w-3.5 h-3.5"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M17.5 14c.5 0 1 .5 1 1s-.5 1-1 1-1-.5-1-1 .5-1 1-1zm-11 0c.5 0 1 .5 1 1s-.5 1-1 1-1-.5-1-1 .5-1 1-1z"
fill="currentColor"
/>
<path
d="M3 13.5c0 4.7 3.8 8.5 8.5 8.5s8.5-3.8 8.5-8.5"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
/>
<path
d="M17 18.5c-1.5 1.5-3.5 2.5-5.5 2.5s-4-1-5.5-2.5"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
/>
<path
d="M19 18.5l1.5 1.5M5 18.5L3.5 20"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
/>
</svg>
<div className="flex flex-col leading-[0.8]">
<span className="text-[7px] font-black uppercase opacity-60">Vendor</span>
<span>{stock.toLocaleString('de-DE')}</span>
</div>
</div>
{woc !== null && (
<div className={`text-[9px] font-black uppercase tracking-tighter ${wocColor}`}>
{woc.toFixed(1)} Weeks Cover
</div>
)}
</div>
);
};
+1 -1
View File
@@ -90,7 +90,7 @@ const WeeklyRow: React.FC<{
{stockMap && (
<StockBadge stock={stockMap.get(row.sku?.replace(/(DE|EN)$/i, ''))} />
)}
<VendorStockBadge asin={row.asin} vendorStockMap={vendorStockMap} mode={top50Mode} />
<VendorStockBadge asin={row.asin} vendorStockMap={vendorStockMap} mode={top50Mode} avgWeeklySales={row.avgWeeklySales} />
</div>
<span className="text-[9px] text-fuchsia-400/80 font-bold uppercase tracking-widest">{row.line}</span>
</div>