feat: mostrar detalles del producto en Vendor tab cuando hay un solo ASIN

- Agregar tarjeta con SKU, ASIN y título al inicio de los gráficos
- Incluir Buy Box Warning Badge si el producto tiene issues
- Solo se muestra cuando hay un único ASIN seleccionado

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
Christian Vidal Wolf
2026-03-03 11:21:14 +01:00
co-authored by Qwen-Coder
parent 32a7de8aea
commit 2814d68716
2 changed files with 58 additions and 3 deletions
+57 -2
View File
@@ -1,6 +1,7 @@
import React, { useMemo } from 'react';
import React, { useMemo, useState } from 'react';
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
import { BSRRecord } from '../types';
import { BuyBoxWarningBadge } from './BuyBoxWarningBadge';
const MARKET_COLORS: Record<string, string> = {
DE: '#3b82f6',
@@ -12,6 +13,8 @@ const MARKET_COLORS: Record<string, string> = {
interface VendorDataViewProps {
bsrData: BSRRecord[];
asinMetadata?: Map<string, { sku: string; title: string; line: string }>;
buyBoxLostMap?: Map<string, { countries: string[]; reasons: Record<string, string> }>;
}
interface ChartPoint {
@@ -20,7 +23,7 @@ interface ChartPoint {
[key: string]: number | string | null;
}
const VendorDataView: React.FC<VendorDataViewProps> = ({ bsrData = [] }) => {
const VendorDataView: React.FC<VendorDataViewProps> = ({ bsrData = [], asinMetadata, buyBoxLostMap }) => {
// Determine active markets in filtered data for series generation
const activeMarkets = useMemo(() => {
const m = new Set(bsrData.map(r => r.market));
@@ -33,6 +36,26 @@ const VendorDataView: React.FC<VendorDataViewProps> = ({ bsrData = [] }) => {
return withDate > bsrData.length / 2;
}, [bsrData]);
// Get unique ASINs in filtered data
const uniqueAsins = useMemo(() => {
const asinSet = new Set(bsrData.map(r => r.asin.trim().toUpperCase()));
return Array.from(asinSet);
}, [bsrData]);
// Get product info when single ASIN is selected
const productInfo = useMemo(() => {
if (uniqueAsins.length !== 1) return null;
const asin = uniqueAsins[0];
const metadata = asinMetadata?.get(asin);
if (!metadata) return null;
return {
asin,
sku: metadata.sku,
title: metadata.title,
line: metadata.line,
};
}, [uniqueAsins, asinMetadata]);
// Aggregate Data for Charts — daily if dates available, else weekly
const { topBsrChartData, detailBsrChartData, ratingChartData } = useMemo(() => {
// Group by date string (YYYY-MM-DD) or by week number
@@ -121,6 +144,38 @@ const VendorDataView: React.FC<VendorDataViewProps> = ({ bsrData = [] }) => {
<span className="text-slate-500 text-xs ml-auto">{bsrData.length.toLocaleString()} records filtered</span>
</div>
{/* Product Info Card - Only shown when single ASIN is selected */}
{productInfo && (
<div className="bg-gradient-to-r from-indigo-500/10 to-purple-500/10 border border-indigo-500/30 rounded-xl p-4 animate-fade-in">
<div className="flex items-start gap-4">
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-2">
<span className="text-[10px] font-black text-indigo-400 uppercase tracking-widest bg-indigo-500/20 px-2 py-0.5 rounded">
Product Details
</span>
</div>
<div className="space-y-1.5">
<div className="flex items-center gap-2 flex-wrap">
<span className="text-xs text-slate-500 font-bold uppercase tracking-wider">SKU:</span>
<span className="text-sm font-mono font-bold text-slate-200">{productInfo.sku}</span>
</div>
<div className="flex items-center gap-2 flex-wrap">
<span className="text-xs text-slate-500 font-bold uppercase tracking-wider">ASIN:</span>
<span className="text-sm font-mono font-bold text-indigo-400">{productInfo.asin}</span>
</div>
<div className="flex items-start gap-2">
<span className="text-xs text-slate-500 font-bold uppercase tracking-wider mt-0.5">Title:</span>
<span className="text-sm font-medium text-slate-300">{productInfo.title}</span>
</div>
</div>
</div>
<div className="flex-shrink-0">
<BuyBoxWarningBadge asin={productInfo.asin} buyBoxLostMap={buyBoxLostMap} />
</div>
</div>
</div>
)}
{/* Top Level BSR Trend Chart */}
<div className="bg-slate-900/50 border border-slate-800 rounded-xl p-4">
<h3 className="text-lg font-bold text-slate-200 mb-4">Top Level BSR Trend ({resolutionLabel})</h3>