diff --git a/components/ForecastView.tsx b/components/ForecastView.tsx index b2eefab..250e375 100644 --- a/components/ForecastView.tsx +++ b/components/ForecastView.tsx @@ -1,5 +1,5 @@ -import React, { useMemo, useState } from 'react'; +import React, { useMemo, useState, useEffect } from 'react'; import { ProductForecastData, FilterState } from '../types'; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, @@ -30,6 +30,17 @@ const Top50Badge: React.FC<{ rank: number; label: string; theme?: 'amber' | 'ind const ForecastView: React.FC = ({ data, filters, top50Ranking }) => { const [searchTerm, setSearchTerm] = useState(''); + const [showOnlyTop50, setShowOnlyTop50] = useState(false); + const [top50Mode, setTop50Mode] = useState<'eu' | 'uk'>('eu'); + + // Auto-detect best Top 50 mode based on data + useEffect(() => { + const hasUK = data.some(p => p.line.toLowerCase().includes('uk') || (p.monthlyData && p.actualUnits > 0 && filters.customer.some(c => c.toLowerCase().includes('uk')))); + const hasEU = data.some(p => !p.line.toLowerCase().includes('uk')); + + // Simplified detection: if we have a lot of EU products, default EU, otherwise check UK + if (hasUK && !hasEU) setTop50Mode('uk'); + }, [data, filters.customer]); // Determine the "Current Month" based on available 2026 data const lastDataMonthIdx = useMemo(() => { @@ -84,18 +95,41 @@ const ForecastView: React.FC = ({ data, filters, top50Ranking }, [data]); const filteredProducts = useMemo(() => { - if (!searchTerm) return data; - const s = searchTerm.toLowerCase(); - return data.filter(p => - p.asin.toLowerCase().includes(s) || - p.sku.toLowerCase().includes(s) || - p.title.toLowerCase().includes(s) - ); - }, [data, searchTerm]); + let result = data; + + if (searchTerm) { + const s = searchTerm.toLowerCase(); + result = result.filter(p => + p.asin.toLowerCase().includes(s) || + p.sku.toLowerCase().includes(s) || + p.title.toLowerCase().includes(s) + ); + } + + if (showOnlyTop50 && top50Ranking) { + const currentRankMap = top50Mode === 'eu' ? top50Ranking.eu : top50Ranking.uk; + result = result.filter(p => currentRankMap.has(p.asin.toUpperCase())); + } + + return result; + }, [data, searchTerm, showOnlyTop50, top50Mode, top50Ranking]); const sortedProducts = useMemo(() => { - return [...filteredProducts].sort((a, b) => b.annualForecast - a.annualForecast); - }, [filteredProducts]); + const result = [...filteredProducts]; + + if (showOnlyTop50 && top50Ranking) { + const currentRankMap = top50Mode === 'eu' ? top50Ranking.eu : top50Ranking.uk; + result.sort((a, b) => { + const rankA = currentRankMap.get(a.asin.toUpperCase()) || 999; + const rankB = currentRankMap.get(b.asin.toUpperCase()) || 999; + return rankA - rankB; + }); + } else { + result.sort((a, b) => b.annualForecast - a.annualForecast); + } + + return result; + }, [filteredProducts, showOnlyTop50, top50Mode, top50Ranking]); return (
@@ -167,15 +201,43 @@ const ForecastView: React.FC = ({ data, filters, top50Ranking

Product Performance Comparison

-
- setSearchTerm(e.target.value)} - className="bg-slate-950 border border-slate-700 rounded-lg px-10 py-2 text-sm text-slate-200 focus:outline-none focus:border-indigo-500 w-full md:w-80" - /> - +
+ {/* Top 50 Toggle */} +
+ + {showOnlyTop50 && ( +
+ + +
+ )} +
+
+ setSearchTerm(e.target.value)} + className="bg-slate-950 border border-slate-700 rounded-lg px-10 py-2 text-sm text-slate-200 focus:outline-none focus:border-indigo-500 w-full md:w-80" + /> + +