mirror of
https://github.com/christianvidalwolf-prog/CrazeAnalytix.git
synced 2026-08-03 21:25:24 +02:00
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:
co-authored by
Qwen-Coder
parent
32a7de8aea
commit
2814d68716
@@ -924,7 +924,7 @@ const App: React.FC = () => {
|
|||||||
|
|
||||||
<Suspense fallback={<LoadingSpinner />}>
|
<Suspense fallback={<LoadingSpinner />}>
|
||||||
<div className={view === 'vendor' ? '' : 'hidden'}>
|
<div className={view === 'vendor' ? '' : 'hidden'}>
|
||||||
<VendorDataView bsrData={filteredBsrData} />
|
<VendorDataView bsrData={filteredBsrData} asinMetadata={globalAsinMetadata} buyBoxLostMap={buyBoxLostMap} />
|
||||||
</div>
|
</div>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
|
||||||
|
|||||||
@@ -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 { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
|
||||||
import { BSRRecord } from '../types';
|
import { BSRRecord } from '../types';
|
||||||
|
import { BuyBoxWarningBadge } from './BuyBoxWarningBadge';
|
||||||
|
|
||||||
const MARKET_COLORS: Record<string, string> = {
|
const MARKET_COLORS: Record<string, string> = {
|
||||||
DE: '#3b82f6',
|
DE: '#3b82f6',
|
||||||
@@ -12,6 +13,8 @@ const MARKET_COLORS: Record<string, string> = {
|
|||||||
|
|
||||||
interface VendorDataViewProps {
|
interface VendorDataViewProps {
|
||||||
bsrData: BSRRecord[];
|
bsrData: BSRRecord[];
|
||||||
|
asinMetadata?: Map<string, { sku: string; title: string; line: string }>;
|
||||||
|
buyBoxLostMap?: Map<string, { countries: string[]; reasons: Record<string, string> }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ChartPoint {
|
interface ChartPoint {
|
||||||
@@ -20,7 +23,7 @@ interface ChartPoint {
|
|||||||
[key: string]: number | string | null;
|
[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
|
// Determine active markets in filtered data for series generation
|
||||||
const activeMarkets = useMemo(() => {
|
const activeMarkets = useMemo(() => {
|
||||||
const m = new Set(bsrData.map(r => r.market));
|
const m = new Set(bsrData.map(r => r.market));
|
||||||
@@ -33,6 +36,26 @@ const VendorDataView: React.FC<VendorDataViewProps> = ({ bsrData = [] }) => {
|
|||||||
return withDate > bsrData.length / 2;
|
return withDate > bsrData.length / 2;
|
||||||
}, [bsrData]);
|
}, [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
|
// Aggregate Data for Charts — daily if dates available, else weekly
|
||||||
const { topBsrChartData, detailBsrChartData, ratingChartData } = useMemo(() => {
|
const { topBsrChartData, detailBsrChartData, ratingChartData } = useMemo(() => {
|
||||||
// Group by date string (YYYY-MM-DD) or by week number
|
// 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>
|
<span className="text-slate-500 text-xs ml-auto">{bsrData.length.toLocaleString()} records filtered</span>
|
||||||
</div>
|
</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 */}
|
{/* Top Level BSR Trend Chart */}
|
||||||
<div className="bg-slate-900/50 border border-slate-800 rounded-xl p-4">
|
<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>
|
<h3 className="text-lg font-bold text-slate-200 mb-4">Top Level BSR Trend ({resolutionLabel})</h3>
|
||||||
|
|||||||
Reference in New Issue
Block a user