feat(vendor): update to modern bar charts

- Use BarChart with rounded corners for modern look
- Remove vertical grid lines for cleaner appearance
- Add hover cursor effect on tooltip
- Y-axis reversed for BSR charts (lower = better)
- Normal Y-axis for Rating chart (higher = better)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
Christian Vidal Wolf
2026-03-03 16:21:08 +01:00
co-authored by Qwen-Coder
parent 4fa8b0f45e
commit 0a2b15615d
+24 -54
View File
@@ -1,5 +1,5 @@
import React, { useMemo, useState } from 'react'; import React, { useMemo, useState } from 'react';
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, AreaChart, Area } from 'recharts'; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, Cell } from 'recharts';
import { BSRRecord } from '../types'; import { BSRRecord } from '../types';
import { BuyBoxWarningBadge } from './BuyBoxWarningBadge'; import { BuyBoxWarningBadge } from './BuyBoxWarningBadge';
@@ -181,36 +181,26 @@ const VendorDataView: React.FC<VendorDataViewProps> = ({ bsrData = [], asinMetad
<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>
<p className="text-xs text-slate-500 mb-3">Lower rank = better position. Averaged across filtered ASINs per market.</p> <p className="text-xs text-slate-500 mb-3">Lower rank = better position. Averaged across filtered ASINs per market.</p>
<ResponsiveContainer width="100%" height={350}> <ResponsiveContainer width="100%" height={350}>
<AreaChart data={topBsrChartData}> <BarChart data={topBsrChartData} barGap={4} barCategoryGap="20%">
<defs> <CartesianGrid strokeDasharray="3 3" stroke="#334155" vertical={false} />
{activeMarkets.map(m => (
<linearGradient key={m} id={`colorTop${m}`} x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor={MARKET_COLORS[m] || '#6b7280'} stopOpacity={0.4} />
<stop offset="95%" stopColor={MARKET_COLORS[m] || '#6b7280'} stopOpacity={0} />
</linearGradient>
))}
</defs>
<CartesianGrid strokeDasharray="3 3" stroke="#334155" />
<XAxis dataKey="label" tick={{ fill: '#94a3b8', fontSize: 11 }} interval="preserveStartEnd" /> <XAxis dataKey="label" tick={{ fill: '#94a3b8', fontSize: 11 }} interval="preserveStartEnd" />
<YAxis reversed tick={{ fill: '#94a3b8', fontSize: 11 }} /> <YAxis reversed tick={{ fill: '#94a3b8', fontSize: 11 }} domain={['auto', 'auto']} />
<Tooltip <Tooltip
contentStyle={{ backgroundColor: '#1e293b', border: '1px solid #334155', borderRadius: '8px' }} contentStyle={{ backgroundColor: '#1e293b', border: '1px solid #334155', borderRadius: '8px' }}
labelStyle={{ color: '#e2e8f0' }} labelStyle={{ color: '#e2e8f0' }}
cursor={{ fill: 'rgba(255,255,255,0.05)' }}
/> />
<Legend /> <Legend />
{activeMarkets.map(m => ( {activeMarkets.map(m => (
<Area <Bar
key={m} key={m}
type="monotone"
dataKey={`${m}_bsr`} dataKey={`${m}_bsr`}
name={`${m} BSR`} name={`${m} BSR`}
stroke={MARKET_COLORS[m] || '#6b7280'} fill={MARKET_COLORS[m] || '#6b7280'}
strokeWidth={2} radius={[4, 4, 0, 0]}
fill={`url(#colorTop${m})`}
connectNulls
/> />
))} ))}
</AreaChart> </BarChart>
</ResponsiveContainer> </ResponsiveContainer>
</div> </div>
@@ -219,36 +209,26 @@ const VendorDataView: React.FC<VendorDataViewProps> = ({ bsrData = [], asinMetad
<h3 className="text-lg font-bold text-slate-200 mb-4">Detail Level BSR Trend ({resolutionLabel})</h3> <h3 className="text-lg font-bold text-slate-200 mb-4">Detail Level BSR Trend ({resolutionLabel})</h3>
<p className="text-xs text-slate-500 mb-3">Lower rank = better position. Averaged across filtered ASINs per market.</p> <p className="text-xs text-slate-500 mb-3">Lower rank = better position. Averaged across filtered ASINs per market.</p>
<ResponsiveContainer width="100%" height={350}> <ResponsiveContainer width="100%" height={350}>
<AreaChart data={detailBsrChartData}> <BarChart data={detailBsrChartData} barGap={4} barCategoryGap="20%">
<defs> <CartesianGrid strokeDasharray="3 3" stroke="#334155" vertical={false} />
{activeMarkets.map(m => (
<linearGradient key={m} id={`colorDetail${m}`} x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor={MARKET_COLORS[m] || '#6b7280'} stopOpacity={0.4} />
<stop offset="95%" stopColor={MARKET_COLORS[m] || '#6b7280'} stopOpacity={0} />
</linearGradient>
))}
</defs>
<CartesianGrid strokeDasharray="3 3" stroke="#334155" />
<XAxis dataKey="label" tick={{ fill: '#94a3b8', fontSize: 11 }} interval="preserveStartEnd" /> <XAxis dataKey="label" tick={{ fill: '#94a3b8', fontSize: 11 }} interval="preserveStartEnd" />
<YAxis reversed tick={{ fill: '#94a3b8', fontSize: 11 }} /> <YAxis reversed tick={{ fill: '#94a3b8', fontSize: 11 }} domain={['auto', 'auto']} />
<Tooltip <Tooltip
contentStyle={{ backgroundColor: '#1e293b', border: '1px solid #334155', borderRadius: '8px' }} contentStyle={{ backgroundColor: '#1e293b', border: '1px solid #334155', borderRadius: '8px' }}
labelStyle={{ color: '#e2e8f0' }} labelStyle={{ color: '#e2e8f0' }}
cursor={{ fill: 'rgba(255,255,255,0.05)' }}
/> />
<Legend /> <Legend />
{activeMarkets.map(m => ( {activeMarkets.map(m => (
<Area <Bar
key={m} key={m}
type="monotone"
dataKey={`${m}_bsr`} dataKey={`${m}_bsr`}
name={`${m} BSR`} name={`${m} BSR`}
stroke={MARKET_COLORS[m] || '#6b7280'} fill={MARKET_COLORS[m] || '#6b7280'}
strokeWidth={2} radius={[4, 4, 0, 0]}
fill={`url(#colorDetail${m})`}
connectNulls
/> />
))} ))}
</AreaChart> </BarChart>
</ResponsiveContainer> </ResponsiveContainer>
</div> </div>
@@ -257,36 +237,26 @@ const VendorDataView: React.FC<VendorDataViewProps> = ({ bsrData = [], asinMetad
<h3 className="text-lg font-bold text-slate-200 mb-4">Average Rating ({resolutionLabel})</h3> <h3 className="text-lg font-bold text-slate-200 mb-4">Average Rating ({resolutionLabel})</h3>
<p className="text-xs text-slate-500 mb-3">Averaged across filtered ASINs per market.</p> <p className="text-xs text-slate-500 mb-3">Averaged across filtered ASINs per market.</p>
<ResponsiveContainer width="100%" height={350}> <ResponsiveContainer width="100%" height={350}>
<AreaChart data={ratingChartData}> <BarChart data={ratingChartData} barGap={4} barCategoryGap="20%">
<defs> <CartesianGrid strokeDasharray="3 3" stroke="#334155" vertical={false} />
{activeMarkets.map(m => (
<linearGradient key={m} id={`colorRating${m}`} x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor={MARKET_COLORS[m] || '#6b7280'} stopOpacity={0.4} />
<stop offset="95%" stopColor={MARKET_COLORS[m] || '#6b7280'} stopOpacity={0} />
</linearGradient>
))}
</defs>
<CartesianGrid strokeDasharray="3 3" stroke="#334155" />
<XAxis dataKey="label" tick={{ fill: '#94a3b8', fontSize: 11 }} interval="preserveStartEnd" /> <XAxis dataKey="label" tick={{ fill: '#94a3b8', fontSize: 11 }} interval="preserveStartEnd" />
<YAxis domain={[0, 5]} tick={{ fill: '#94a3b8', fontSize: 11 }} /> <YAxis domain={[0, 5]} tick={{ fill: '#94a3b8', fontSize: 11 }} />
<Tooltip <Tooltip
contentStyle={{ backgroundColor: '#1e293b', border: '1px solid #334155', borderRadius: '8px' }} contentStyle={{ backgroundColor: '#1e293b', border: '1px solid #334155', borderRadius: '8px' }}
labelStyle={{ color: '#e2e8f0' }} labelStyle={{ color: '#e2e8f0' }}
cursor={{ fill: 'rgba(255,255,255,0.05)' }}
/> />
<Legend /> <Legend />
{activeMarkets.map(m => ( {activeMarkets.map(m => (
<Area <Bar
key={m} key={m}
type="monotone"
dataKey={`${m}_rating`} dataKey={`${m}_rating`}
name={`${m} Rating`} name={`${m} Rating`}
stroke={MARKET_COLORS[m] || '#6b7280'} fill={MARKET_COLORS[m] || '#6b7280'}
strokeWidth={2} radius={[4, 4, 0, 0]}
fill={`url(#colorRating${m})`}
connectNulls
/> />
))} ))}
</AreaChart> </BarChart>
</ResponsiveContainer> </ResponsiveContainer>
</div> </div>
</div> </div>