import React, { useMemo, useState } from 'react'; import { ProductForecastData } from '../types'; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, LineChart, Line, Legend, ComposedChart, Area } from 'recharts'; interface ForecastViewProps { data: ProductForecastData[]; } const COLORS = ['#6366f1', '#ec4899', '#10b981', '#f59e0b', '#8b5cf6', '#0ea5e9']; const ForecastView: React.FC = ({ data }) => { const [searchTerm, setSearchTerm] = useState(''); // Global Aggregate Data const globalMonthlyData = useMemo(() => { const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; return months.map(m => { let forecast = 0; let actual = 0; data.forEach(p => { const monthPoint = p.monthlyData.find(md => md.month === m); if (monthPoint) { forecast += monthPoint.forecastUnits; actual += monthPoint.actualUnits; } }); return { name: m, Forecast: forecast, Actual: actual }; }); }, [data]); const globalSummary = useMemo(() => { let totalForecast = 0; let totalActual = 0; data.forEach(p => { totalForecast += p.annualForecast; p.monthlyData.forEach(md => { totalActual += md.actualUnits; }); }); const fulfillment = totalForecast > 0 ? (totalActual / totalForecast) * 100 : 0; return { totalForecast, totalActual, fulfillment }; }, [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]); const sortedProducts = useMemo(() => { return [...filteredProducts].sort((a, b) => b.annualForecast - a.annualForecast); }, [filteredProducts]); return (
{/* Summary Cards */}

Total Forecast 2026

{globalSummary.totalForecast.toLocaleString('de-DE')} Units

Total Actual Sales 2026

{globalSummary.totalActual.toLocaleString('de-DE')} Units

Global Fulfillment

= 100 ? 'text-emerald-400' : 'text-indigo-400'}`}> {globalSummary.fulfillment.toFixed(1)}%
{/* Fulfillment Progress Bar */}
{/* Main Trend Chart */}

Monthly Evolution: Forecast vs Actual

{/* Product Table */}

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" />
{sortedProducts.map((p) => { const actualTotal = p.monthlyData.reduce((acc, md) => acc + md.actualUnits, 0); const fulfillment = p.annualForecast > 0 ? (actualTotal / p.annualForecast) * 100 : 0; return ( ); })}
Product Info Annual Forecast Actual 2026 Fulfillment % Monthly Status (YTD)
{p.asin} {p.title}
{p.annualForecast.toLocaleString('de-DE')} {actualTotal.toLocaleString('de-DE')} = 50 ? 'bg-emerald-500/10 text-emerald-400' : fulfillment >= 20 ? 'bg-indigo-500/10 text-indigo-400' : 'bg-slate-800 text-slate-500'}`}> {fulfillment.toFixed(1)}%
{p.monthlyData.map((md, idx) => { const isMet = md.actualUnits >= md.forecastUnits && md.forecastUnits > 0; const height = md.forecastUnits > 0 ? (Math.min(1.5, md.actualUnits / md.forecastUnits) * 100) : 0; return (
0 ? 'bg-indigo-500' : 'bg-slate-800'}`} style={{ height: `${Math.max(10, height)}%` }} title={`${md.month}: ${md.actualUnits} / ${md.forecastUnits}`} >
); })}
); }; export default ForecastView;