import React, { useState, useMemo, useCallback } from 'react'; import * as XLSX from 'xlsx'; import { SalesRecord } from '../types'; import { DownloadIcon } from './Icons'; interface MarketGapReportProps { data: SalesRecord[]; } interface GapProduct { rank: number; asin: string; title: string; sku: string; line: string; deSellOut: number; deUnits: number; } const FlagDE = () => ( 🇩🇪 DE ); const MarketGapReport: React.FC = ({ data }) => { const availableYears = useMemo(() => { const years = Array.from(new Set(data.map(r => r.year))).sort((a, b) => b - a); return years; }, [data]); const [selectedYear, setSelectedYear] = useState(null); const effectiveYear = selectedYear ?? availableYears[0] ?? new Date().getFullYear(); const top5 = useMemo((): GapProduct[] => { if (data.length === 0) return []; // 1. Build set of ASINs ever sold in Amazon ES (all years) const esAsins = new Set(); data.forEach(r => { if (r.customer?.toLowerCase().includes('amazon es')) { esAsins.add(r.asin.trim().toUpperCase()); } }); // 2. Build metadata map (title, sku, line) from all years — prefer longest title const metaMap = new Map(); data.forEach(r => { const asin = r.asin.trim().toUpperCase(); const existing = metaMap.get(asin); if (!existing || (r.title && r.title.length > (existing.title?.length || 0))) { metaMap.set(asin, { title: r.title || r.articleName || asin, sku: r.sku || '', line: r.line || 'Unassigned' }); } }); // 3. Aggregate DE sales for the selected year const deMap = new Map(); data.forEach(r => { if (r.year !== effectiveYear) return; if (!r.customer?.toLowerCase().includes('amazon de')) return; const asin = r.asin.trim().toUpperCase(); const entry = deMap.get(asin) || { sellOut: 0, units: 0 }; entry.sellOut += r.sellOut || 0; entry.units += r.units || 0; deMap.set(asin, entry); }); // 4. Filter out ASINs sold in ES, sort desc by sellOut, top 5 const results: GapProduct[] = []; deMap.forEach((val, asin) => { if (esAsins.has(asin)) return; if (val.sellOut <= 0) return; const meta = metaMap.get(asin) || { title: asin, sku: '', line: 'Unassigned' }; results.push({ rank: 0, asin, title: meta.title, sku: meta.sku, line: meta.line, deSellOut: val.sellOut, deUnits: val.units, }); }); results.sort((a, b) => b.deSellOut - a.deSellOut); return results.slice(0, 5).map((r, i) => ({ ...r, rank: i + 1 })); }, [data, effectiveYear]); const handleExport = useCallback(() => { if (top5.length === 0) return; const exportData = top5.map(p => ({ Rank: p.rank, ASIN: p.asin, Title: p.title, SKU: p.sku, 'Product Line': p.line, [`DE Sell Out ${effectiveYear} (€)`]: Number(p.deSellOut.toFixed(2)), [`DE Units ${effectiveYear}`]: p.deUnits, 'Amazon DE PDP': `https://www.amazon.de/dp/${p.asin}`, })); const ws = XLSX.utils.json_to_sheet(exportData); const wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, 'DE-Only Top 5'); XLSX.writeFile(wb, `DE_Only_Top5_${effectiveYear}.xlsx`); }, [top5, effectiveYear]); const fmt = (n: number) => `€${n.toLocaleString('de-DE', { minimumFractionDigits: 0, maximumFractionDigits: 0 })}`; return (
{/* Header Card */}

🌍 Market Gap Report

Top 5 productos vendidos en 🇩🇪 Alemania que{' '} nunca se han vendido en{' '} 🇪🇸 España

{/* Year selector */}
{availableYears.map(y => ( ))}
{/* Export */}
{/* Insight banner */} {top5.length > 0 && (
💡 Oportunidad de expansión: Estos {top5.length} productos ya funcionan en DE y podrían tener potencial en el mercado español.
)} {/* Table */}

📊 Top 5 — Solo Alemania ({effectiveYear})

Ranking por Sell-Out (€)
{top5.map((product) => ( {/* Rank */} {/* Product details */} {/* Line */} {/* DE Sell Out */} {/* DE Units */} {/* Amazon PDP Link */} ))} {top5.length === 0 && ( )}
# Producto Línea Sell-Out DE Units DE Link
{product.rank}
{product.title || 'Unknown Title'}
{product.sku && ( SKU: {product.sku} )} ASIN: {product.asin}
{product.line}
{fmt(product.deSellOut)}
{product.deUnits.toLocaleString('de-DE')} uds. Amazon.de ↗
No se encontraron productos exclusivos de DE en {effectiveYear}.
Verifica que los datos contienen registros de Amazon DE y Amazon ES.
{/* Footer note */} {top5.length > 0 && (
* Se excluyen todos los ASINs con cualquier venta histórica en Amazon ES, independientemente del año seleccionado.
)}
); }; export default MarketGapReport;