import React, { useMemo } from 'react'; import { Product } from './types'; import { calculateProductMetrics, formatCurrency, formatPercent } from './utils'; import { X } from 'lucide-react'; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Cell, ReferenceLine } from 'recharts'; interface WaterfallModalProps { product: Product | null; includeCOGS: boolean; onClose: () => void; } export const WaterfallModal: React.FC = ({ product, includeCOGS, onClose }) => { if (!product) return null; const data = useMemo(() => { const metrics = calculateProductMetrics(product, includeCOGS); let currentTotal = product.grossSales; const steps = [ { name: 'Gross Sales', value: product.grossSales, isTotal: true, color: '#6366f1' }, // Indigo { name: 'PPC', value: -product.ppcSpend, isTotal: false, color: '#ef4444' }, // Rose { name: 'Deals', value: -product.deals, isTotal: false, color: '#f97316' }, // Orange { name: 'Promos', value: -product.promos, isTotal: false, color: '#f59e0b' }, // Amber { name: 'Chargebacks', value: -product.chargebacks, isTotal: false, color: '#eab308' }, // Yellow ]; if (includeCOGS) { steps.push({ name: 'COGS', value: -product.cogs, isTotal: false, color: '#64748b' }); // Slate } steps.push({ name: 'Net Margin', value: metrics.netMargin, isTotal: true, color: metrics.netMargin >= 0 ? '#10b981' : '#ef4444' }); const chartData = steps.map(step => { if (step.isTotal) { return { name: step.name, start: 0, end: step.value, val: step.value, color: step.color, isTotal: true }; } else { const start = currentTotal; currentTotal += step.value; // value is negative return { name: step.name, start: currentTotal, // The bottom of the visible bar end: start, // The top of the visible bar val: step.value, color: step.color, isTotal: false }; } }); // Transform for stacked bar chart: [bottomTransparent, visibleBar] return chartData.map(d => ({ name: d.name, transparent: d.start, visible: Math.abs(d.end - d.start), val: d.val, color: d.color, isTotal: d.isTotal })); }, [product, includeCOGS]); const metrics = calculateProductMetrics(product, includeCOGS); return (

{product.name}

{product.sku} | {product.asin}

Gross Sales

{formatCurrency(product.grossSales)}

Net Margin

= 0 ? 'text-emerald-400' : 'text-rose-400'}`}>{formatCurrency(metrics.netMargin)}

Margin %

= 0.2 ? 'text-emerald-400' : metrics.marginPercent >= 0.1 ? 'text-amber-400' : 'text-rose-400'}`}> {formatPercent(metrics.marginPercent)}

ACOS

{formatPercent(metrics.acos)}

Profitability Analysis (Waterfall)

Breakdown of deductions from gross sales to net margin.

`$${val / 1000}k`} tick={{ fontSize: 12, fill: '#8B949E' }} axisLine={false} tickLine={false} /> { if (active && payload && payload.length) { const data = payload[0].payload; return (

{data.name}

{data.val > 0 && !data.isTotal ? '+' : ''}{formatCurrency(data.val)}

); } return null; }} /> {data.map((entry, index) => ( ))}
); };