import React, { useMemo } from 'react'; import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts'; import { BSRRecord } from '../types'; import { BuyBoxWarningBadge } from './BuyBoxWarningBadge'; interface VendorDataViewProps { bsrData: BSRRecord[]; asinMetadata?: Map; buyBoxLostMap?: Map }>; } interface ChartPoint { label: string; sortKey: string; [key: string]: number | string | null; } const CATEGORY_TRANSLATIONS: Record = { // === TOP-LEVEL (DE) === 'Spielzeug': 'Toys & Games', 'Küche, Haushalt & Wohnen': 'Kitchen & Home', 'Baby': 'Baby', 'Bürobedarf & Schreibwaren': 'Stationery & Office Supplies', 'Baumarkt': 'DIY & Tools', 'Drogerie & Körperpflage': 'Health & Beauty', 'Drogerie & Körperpflege': 'Health & Beauty', 'Garten': 'Garden', 'Kosmetik': 'Beauty', 'Musik-CDs & Vinyl': 'Music CDs & Vinyl', 'Bücher': 'Books', 'Küche & Haushalt': 'Kitchen & Home', // === TOP-LEVEL (FR) === 'Jeux et Jouets': 'Toys & Games', 'Bébé et Puériculture': 'Baby', 'Beauté et Parfum': 'Beauty', 'Cuisine et Maison': 'Kitchen & Home', 'Fournitures de bureau': 'Office Supplies', 'Hygiène et Santé': 'Health & Hygiene', 'Jeux vidéo': 'Video Games', 'Mode': 'Fashion', 'Livres': 'Books', // === TOP-LEVEL (IT) === 'Giochi e giocattoli': 'Toys & Games', 'Prima infanzia': 'Baby', 'Bellezza': 'Beauty', 'Casa e cucina': 'Kitchen & Home', 'Cancelleria e prodotti per ufficio': 'Stationery & Office Supplies', 'Videogiochi': 'Video Games', 'Moda': 'Fashion', 'Informatica': 'Computers', 'Salute e cura della persona': 'Health & Personal Care', 'CD e Vinili': 'Music CDs & Vinyl', 'Altro': 'Other', // === TOP-LEVEL (ES) === 'Juguetes y juegos': 'Toys & Games', 'Bebé': 'Baby', 'Belleza': 'Beauty', 'Hogar y cocina': 'Kitchen & Home', 'Oficina y papelería': 'Office Supplies', 'Deportes y aire libre': 'Sports & Outdoors', 'Salud y cuidado personal': 'Health & Personal Care', // === DETAIL (DE) === 'Badebomben': 'Bath Bombs', 'Badesalz': 'Bath Salts', 'Badesalze': 'Bath Salts', 'Badezusätze': 'Bath Additives', 'Badewannenspielzeug': 'Bath Toys', 'Adventskalender': 'Advent Calendars', 'Dekorative Adventskalender': 'Decorative Advent Calendars', 'Kinder-Bastelsets': 'Kids Craft Sets', 'Kinderknete': 'Kids Clay & Dough', 'Basteln, Malen & Handarbeiten': 'Arts, Crafts & Sewing', 'Experimentierkästen': 'Science Kits', 'Puzzles': 'Puzzles', 'Klassische Puzzles': 'Classic Puzzles', 'Brettspiele': 'Board Games', 'Spielzeugfiguren': 'Toy Figures', 'Plüsch-Spielzeug': 'Plush Toys', 'Stofftiere & Teddybären': 'Stuffed Animals & Teddy Bears', 'Puppen': 'Dolls', 'Figuren': 'Figures', 'Actionfiguren': 'Action Figures', 'Wasserpistolen': 'Water Guns', 'Schaumstoff-Blaster': 'Foam Blasters', 'Kreisel': 'Spinning Tops', 'Handkreisel': 'Hand Spinners', 'Haargummis': 'Hair Ties', 'Haarclips': 'Hair Clips', 'Haarspangen': 'Hair Clips', 'Haarschmuck': 'Hair Accessories', 'Schmuck-Sets': 'Jewellery Sets', 'Schmucksets': 'Jewellery Sets', 'Armbänder': 'Bracelets', 'Ohrringe': 'Earrings', 'Gummibänder & -ringe': 'Rubber Bands', 'Bügelperlen': 'Fuse Beads', 'Perlen': 'Beads', 'Malen nach Zahlen': 'Paint by Numbers', 'Malsets': 'Painting Sets', 'Mosaik': 'Mosaic', 'Kinder Schmuckkästchen': 'Kids Jewellery Boxes', 'Slime & Putty Spielzeuge': 'Slime & Putty Toys', 'Pop Fidget-Spielzeug': 'Pop Fidget Toys', 'Gesichtsfarben': 'Face Paints', 'Schminke': 'Makeup', 'Masken für Erwachsene': 'Adult Masks', 'Tattoos': 'Tattoos', 'Tiere': 'Animals', 'Dinosaurier & prähistorische Kreaturen': 'Dinosaurs & Prehistoric Creatures', 'Fantastische Kreaturen': 'Fantasy Creatures', 'Spielsets': 'Play Sets', 'Reise- & Kompaktspiele': 'Travel & Compact Games', 'Party- & Scherzartikel': 'Party & Novelty Items', 'Partygeschenk-Packs mit verschiedenen Artikeln': 'Party Gift Packs', 'Lernuhren': 'Teaching Clocks', 'Grußkarten': 'Greeting Cards', 'Saisonale Deko': 'Seasonal Decorations', 'Werkzeuge & Zubehör': 'Tools & Accessories', 'Sticker': 'Stickers', 'Papeterie & Sticker': 'Stationery & Stickers', 'Drucken & Stempeln': 'Printing & Stamping', 'Zeichnen': 'Drawing', 'Wachsmalstifte': 'Wax Crayons', 'Zierschmuck': 'Decorative Jewellery', 'Armband-Packs': 'Bracelet Packs', 'Bausätze für Diamantmalerei': 'Diamond Painting Kits', 'Schlüsselringe & Schlüsselbänder für Damen': 'Key Rings & Lanyards', 'Geschenktaschen': 'Gift Bags', 'Sortier- & Stapelspielzeug': 'Sorting & Stacking Toys', 'Lernspiele': 'Educational Games', 'Spieluhren': 'Music Boxes', 'Trinkspiele': 'Drinking Games', // === DETAIL (FR) === 'Boules effervescentes': 'Bath Bombs', 'Sels de bain': 'Bath Salts', 'Bains moussants': 'Bubble Baths', 'Produits de bain': 'Bath Products', 'Jouets de bain': 'Bath Toys', 'Calendriers de l\'Avent': 'Advent Calendars', 'Jouets anti-stress': 'Stress Relief Toys', 'Poupées': 'Dolls', 'Figurines d\'action': 'Action Figures', 'Figurines étirables': 'Stretchy Figures', 'Animaux en peluche': 'Stuffed Animals', 'Peluches': 'Plush Toys', 'Jeux de plateau': 'Board Games', 'Puzzles classiques': 'Classic Puzzles', 'Bracelets': 'Bracelets', 'Boucles d\'oreilles': 'Earrings', 'Bijoux et perles': 'Jewellery & Beads', 'Perles à repasser': 'Fuse Beads', 'Kits de broderie diamant': 'Diamond Painting Kits', 'Kits pour bijoux': 'Jewellery Making Kits', 'Slime et mastic': 'Slime & Putty', 'Toupies': 'Spinning Tops', 'Toupies d\'éveil': 'Baby Spinning Tops', 'Pistolets': 'Toy Guns', 'Pistolets et fusils à eau': 'Water Guns', 'Animaux': 'Animals', 'Créatures fantastiques': 'Fantasy Creatures', 'Dinosaures': 'Dinosaurs', 'Décorations de cheveux': 'Hair Accessories', 'Barrettes': 'Hair Clips', 'Pinces': 'Hair Clips', 'Élastiques': 'Elastic Bands', 'Sacs cadeaux': 'Gift Bags', 'Coffrets cadeaux': 'Gift Sets', 'Masques': 'Masks', 'Tampons à imprimer': 'Printing Stamps', 'Maisons de poupées': 'Dollhouses', 'Boîtes à bijoux pour enfants': 'Kids Jewellery Boxes', 'Boîtes à musique et figurines': 'Music Boxes & Figurines', 'Parure de bijoux': 'Jewellery Sets', 'Parures': 'Jewellery Sets', 'Ensembles': 'Sets', 'Coffrets': 'Gift Boxes', 'Pochettes-surprises': 'Mystery Bags', // === DETAIL (IT) === 'Bombe da bagno': 'Bath Bombs', 'Sali da bagno': 'Bath Salts', 'Schiuma da bagno': 'Bubble Bath', 'Prodotti per il bagno': 'Bath Products', 'Set di accessori bagno': 'Bath Accessory Sets', 'Giochi per il bagnetto': 'Bath Toys', 'Calendari dell\'avvento': 'Advent Calendars', 'Giochi di società': 'Board Games', 'Puzzle classici': 'Classic Puzzles', 'Bambole': 'Dolls', 'Set di bambole e accessori': 'Doll & Accessory Sets', 'Animali di peluche': 'Stuffed Animals', 'Animali': 'Animals', 'Creature fantastiche': 'Fantasy Creatures', 'Dinosauri e creature preistoriche': 'Dinosaurs & Prehistoric Creatures', 'Personaggi d\'azione': 'Action Figures', 'Personaggi giocattolo': 'Toy Characters', 'Personaggi di gomma': 'Rubber Characters', 'Argilla e pasta modellabile': 'Clay & Modelling Dough', 'Lavoretti con la sabbia': 'Sand Art', 'Kit per pittura diamante': 'Diamond Painting Kits', 'Kit per creazione gioielli': 'Jewellery Making Kits', 'Perline a fusione': 'Fuse Beads', 'Mosaici': 'Mosaics', 'Braccialetti': 'Bracelets', 'Orecchini': 'Earrings', 'Gioielli': 'Jewellery', 'Portagioie per bambini': 'Kids Jewellery Boxes', 'Mollette': 'Hair Clips', 'Mollette per capelli': 'Hair Clips', 'Decorazioni per capelli': 'Hair Accessories', 'Unghie finte': 'Fake Nails', 'Unghie a pressione': 'Press-on Nails', 'Set trucco e gioielli': 'Makeup & Jewellery Sets', 'Parure di gioielli': 'Jewellery Sets', 'Elastici': 'Elastic Bands', 'Slime': 'Slime', 'Giochi da schiacciare': 'Squeeze Toys', 'Pop fidget toys antistress': 'Pop Fidget Toys', 'Cubi fidget': 'Fidget Cubes', 'Fidget toys semplici': 'Simple Fidget Toys', 'Trottole': 'Spinning Tops', 'Trottole da combattimento': 'Battle Spinning Tops', 'Pistole d\'acqua': 'Water Guns', 'Pistole in gommapiuma': 'Foam Blasters', 'Giocattoli prima infanzia': 'Early Childhood Toys', 'Giochi per attività motorie': 'Motor Activity Toys', 'Giochi': 'Games', 'Giochi alcolici': 'Drinking Games', 'Stampini e timbri': 'Stamps', 'Maschere': 'Masks', 'Altro': 'Other', 'Miniature': 'Miniatures', 'Carillon e carillon con statuetta': 'Music Boxes', 'Articoli per giochi di magia': 'Magic Trick Items', 'Sabbiere e giocattoli da spiaggia': 'Sand & Beach Toys', 'Uova di Pasqua giocattolo': 'Toy Easter Eggs', // === DETAIL (ES) === 'Bombas de baño': 'Bath Bombs', 'Sales de baño': 'Bath Salts', 'Aditivos para el baño': 'Bath Additives', 'Aceite perfumado': 'Perfumed Oil', 'Aceites de masaje': 'Massage Oils', 'Juguetes de baño': 'Bath Toys', 'Calendarios de adviento': 'Advent Calendars', 'Calendarios de pared': 'Wall Calendars', 'Juegos de estrategia': 'Strategy Games', 'Juegos de misterio': 'Mystery Games', 'Juegos de cartas con baraja específica': 'Specific Card Games', 'Juegos de bebida': 'Drinking Games', 'Juguetes antiestrés': 'Stress Relief Toys', 'Muñecas': 'Dolls', 'Muñecas y accesorios': 'Dolls & Accessories', 'Muñecos y figuras de acción': 'Action Figures', 'Muñecos cabezones': 'Bobblehead Figures', 'Animales de peluche': 'Stuffed Animals', 'Animales': 'Animals', 'Animales y figuras': 'Animals & Figures', 'Criaturas fantásticas': 'Fantasy Creatures', 'Dinosaurios y criaturas prehistóricas': 'Dinosaurs & Prehistoric Creatures', 'Personas': 'People', 'Arcilla y plastilina': 'Clay & Modelling Dough', 'Manualidades con arena': 'Sand Art', 'Arte y manualidades': 'Arts & Crafts', 'Kits para pintura con diamantes': 'Diamond Painting Kits', 'Kits para hacer bisutería': 'Jewellery Making Kits', 'Cuentas para planchar': 'Fuse Beads', 'Mosaicos': 'Mosaics', 'Pulseras': 'Bracelets', 'Pendientes': 'Earrings', 'Joyería': 'Jewellery', 'Joyeros para niños': 'Kids Jewellery Boxes', 'Clips de pelo': 'Hair Clips', 'Horquillas': 'Hair Pins', 'Adornos para el pelo': 'Hair Accessories', 'Uñas adhesivas': 'Press-on Nails', 'Puntas de uñas': 'Nail Tips', 'Sets de uñas': 'Nail Sets', 'Conjuntos de maquillaje y bisutería': 'Makeup & Jewellery Sets', 'Conjuntos': 'Sets', 'Sets de accesorios': 'Accessory Sets', 'Gomas elásticas': 'Elastic Bands', 'Pegatinas': 'Stickers', 'Masas viscosas': 'Slime', 'Peonzas': 'Spinning Tops', 'Peonzas de batalla': 'Battle Spinning Tops', 'Novedades en peonzas': 'Novelty Spinning Tops', 'Pistolas de agua': 'Water Guns', 'Lanzadores de espuma': 'Foam Blasters', 'Grabados y sellos': 'Printing & Stamping', 'Pintura': 'Painting', 'Mascarillas': 'Masks/Face Masks', 'Cromos coleccionables': 'Collectible Cards', 'Pack de artículos para fiestas': 'Party Item Packs', 'Paquetes multielementos de cotillones': 'Multi-item Party Packs', 'Bolsas para regalo': 'Gift Bags', 'Decoración original': 'Original Decorations', 'Llaveros': 'Key Rings', 'Varitas': 'Wands', 'Relojes de aprendizaje': 'Teaching Clocks', 'Patines': 'Skates', 'Monopatines': 'Skateboards', 'Gafas': 'Glasses', 'Miniaturas': 'Miniatures', }; const translateCategory = (name: string): string => CATEGORY_TRANSLATIONS[name] ?? name; const VendorDataView: React.FC = ({ bsrData = [], asinMetadata, buyBoxLostMap }) => { const activeMarkets = useMemo(() => { const m = new Set(bsrData.map(r => r.market)); return Array.from(m).sort(); }, [bsrData]); const useDailyResolution = useMemo(() => { const withDate = bsrData.filter(r => r.date).length; return withDate > bsrData.length / 2; }, [bsrData]); const uniqueAsins = useMemo(() => { const asinSet = new Set(bsrData.map(r => r.asin.trim().toUpperCase())); return Array.from(asinSet); }, [bsrData]); const productInfo = useMemo(() => { if (uniqueAsins.length !== 1) return null; const asin = uniqueAsins[0]; const metadata = asinMetadata?.get(asin); if (!metadata) return null; let topCategory = ''; let detailCategory = ''; for (const r of bsrData) { if (!topCategory && r.topLevelName) topCategory = r.topLevelName; if (!detailCategory && r.detailLevelName) detailCategory = r.detailLevelName; if (topCategory && detailCategory) break; } return { asin, sku: metadata.sku, title: metadata.title, line: metadata.line, topCategory, detailCategory }; }, [uniqueAsins, asinMetadata, bsrData]); const { topBsrChartData, detailBsrChartData, ratingChartData } = useMemo(() => { const byBucket = new Map(); bsrData.forEach(r => { const key = useDailyResolution && r.date ? r.date : `W${String(r.week).padStart(2, '0')}`; if (!byBucket.has(key)) byBucket.set(key, []); byBucket.get(key)!.push(r); }); const sortedKeys = Array.from(byBucket.keys()).sort(); const topBsrChartData: ChartPoint[] = []; const detailBsrChartData: ChartPoint[] = []; const ratingChartData: ChartPoint[] = []; sortedKeys.forEach(key => { const rows = byBucket.get(key)!; let label: string; if (useDailyResolution && key.includes('-')) { const d = new Date(key + 'T12:00:00Z'); label = d.toLocaleDateString('en-GB', { day: '2-digit', month: 'short' }); } else { label = key; } const topPoint: ChartPoint = { label, sortKey: key }; const detailPoint: ChartPoint = { label, sortKey: key }; const ratingPoint: ChartPoint = { label, sortKey: key }; activeMarkets.forEach(m => { const marketRows = rows.filter(r => r.market === m); const topBsrRows = marketRows.filter(r => r.topLevelBSR != null); topPoint[`${m}_bsr`] = topBsrRows.length > 0 ? Math.round(topBsrRows.reduce((sum, r) => sum + r.topLevelBSR!, 0) / topBsrRows.length) : null; const detailBsrRows = marketRows.filter(r => r.detailLevelBSR != null); detailPoint[`${m}_bsr`] = detailBsrRows.length > 0 ? Math.round(detailBsrRows.reduce((sum, r) => sum + r.detailLevelBSR!, 0) / detailBsrRows.length) : null; const ratingRows = marketRows.filter(r => r.avgRating != null); ratingPoint[`${m}_rating`] = ratingRows.length > 0 ? Math.round((ratingRows.reduce((sum, r) => sum + r.avgRating!, 0) / ratingRows.length) * 10) / 10 : null; }); topBsrChartData.push(topPoint); detailBsrChartData.push(detailPoint); ratingChartData.push(ratingPoint); }); return { topBsrChartData, detailBsrChartData, ratingChartData }; }, [bsrData, activeMarkets, useDailyResolution]); if (bsrData.length === 0) { return (

No BSR Data Yet

Ensure BSR.xlsx is present and loading to see Top Level BSR, Detail Level BSR, and Average Rating trends.

); } // Exact color values based on the screenshot const cardBg = '#161b24'; const orangeHex = '#f37526'; const cyanHex = '#2acbd6'; const purpleHex = '#7950f2'; const gridLineColor = '#ffffff'; return (
{/* Product Details Header Card */} {productInfo && (
PRODUCT DETAILS

{productInfo.title}

SKU: {productInfo.sku}
ASIN: {productInfo.asin}
)} {/* Top Level BSR Trend Chart */}

Top Level BSR Trend

{productInfo?.topCategory && ( {translateCategory(productInfo.topCategory)} )}

Weekly Average Rank • Lower is better

{activeMarkets.map((m) => ( ))}
{/* Exact Legend matching screenshot */}
{activeMarkets.length > 0 && (
{activeMarkets[0]} BSR
)}
{/* Detail Level BSR Trend Chart */}

Detail Level BSR Trend

{productInfo?.detailCategory && ( {translateCategory(productInfo.detailCategory)} )}

Sub-category Performance • Filtered ASINs

{activeMarkets.map((m) => ( ))}
{/* Exact Legend matching screenshot */}
Category Rank
{/* Average Rating Chart */}

Average Rating

Weekly Average (1.0 - 5.0)

{activeMarkets.map((m) => ( ))}
{/* Exact Legend matching screenshot */}
Star Rating
); }; export default VendorDataView;