feat: sync vendor tab filters with global header filters

This commit is contained in:
Christian Vidal Wolf
2026-03-03 10:52:35 +01:00
parent a6b7503c82
commit 98ba0d1708
3 changed files with 88 additions and 99 deletions
+10 -97
View File
@@ -1,6 +1,5 @@
import React, { useState, useMemo } from 'react';
import React, { useMemo } from 'react';
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
import MultiSelectDropdown from './MultiSelectDropdown';
import { BSRRecord } from '../types';
const MARKET_COLORS: Record<string, string> = {
@@ -21,73 +20,25 @@ interface ChartPoint {
[key: string]: number | string | null;
}
const VendorDataView: React.FC<VendorDataViewProps> = ({ bsrData }) => {
// Filters
const [selectedMarkets, setSelectedMarkets] = useState<string[]>([]);
const [selectedAsins, setSelectedAsins] = useState<string[]>([]);
const [selectedTopCats, setSelectedTopCats] = useState<string[]>([]);
const [selectedDetailCats, setSelectedDetailCats] = useState<string[]>([]);
// Extract available filter options from the dataset
const { availableMarkets, availableAsins, availableTopCats, availableDetailCats } = useMemo(() => {
const markets = new Set<string>();
const asins = new Set<string>();
const topCats = new Set<string>();
const detailCats = new Set<string>();
bsrData.forEach(r => {
if (r.market) markets.add(r.market);
if (r.asin) asins.add(r.asin);
if (r.topLevelName) topCats.add(r.topLevelName);
if (r.detailLevelName) detailCats.add(r.detailLevelName);
});
return {
availableMarkets: Array.from(markets).sort(),
availableAsins: Array.from(asins).sort(),
availableTopCats: Array.from(topCats).sort(),
availableDetailCats: Array.from(detailCats).sort()
};
}, [bsrData]);
// Apply filters
const filteredData = useMemo(() => {
let result = bsrData;
if (selectedMarkets.length > 0) {
result = result.filter(r => selectedMarkets.includes(r.market));
}
if (selectedAsins.length > 0) {
result = result.filter(r => selectedAsins.includes(r.asin));
}
if (selectedTopCats.length > 0) {
result = result.filter(r => r.topLevelName && selectedTopCats.includes(r.topLevelName));
}
if (selectedDetailCats.length > 0) {
result = result.filter(r => r.detailLevelName && selectedDetailCats.includes(r.detailLevelName));
}
return result;
}, [bsrData, selectedMarkets, selectedAsins, selectedTopCats, selectedDetailCats]);
const VendorDataView: React.FC<VendorDataViewProps> = ({ bsrData = [] }) => {
// Determine active markets in filtered data for series generation
const activeMarkets = useMemo(() => {
const m = new Set(filteredData.map(r => r.market));
const m = new Set(bsrData.map(r => r.market));
return Array.from(m).sort();
}, [filteredData]);
}, [bsrData]);
// Determine if daily resolution is available (>= half the records have a date)
const useDailyResolution = useMemo(() => {
const withDate = filteredData.filter(r => r.date).length;
return withDate > filteredData.length / 2;
}, [filteredData]);
const withDate = bsrData.filter(r => r.date).length;
return withDate > bsrData.length / 2;
}, [bsrData]);
// 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
const byBucket = new Map<string, BSRRecord[]>();
filteredData.forEach(r => {
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);
@@ -144,7 +95,7 @@ const VendorDataView: React.FC<VendorDataViewProps> = ({ bsrData }) => {
});
return { topBsrChartData, detailBsrChartData, ratingChartData };
}, [filteredData, activeMarkets, useDailyResolution]);
}, [bsrData, activeMarkets, useDailyResolution]);
if (bsrData.length === 0) {
return (
@@ -166,46 +117,8 @@ const VendorDataView: React.FC<VendorDataViewProps> = ({ bsrData }) => {
return (
<div className="space-y-6 p-4 pb-24 md:pb-4">
{/* Filters */}
<div className="flex flex-wrap gap-3 items-center">
<MultiSelectDropdown
label="Market"
options={availableMarkets}
selected={selectedMarkets}
onChange={setSelectedMarkets}
/>
<MultiSelectDropdown
label="ASIN"
options={availableAsins}
selected={selectedAsins}
onChange={setSelectedAsins}
/>
<MultiSelectDropdown
label="Top Level Category"
options={availableTopCats}
selected={selectedTopCats}
onChange={setSelectedTopCats}
/>
<MultiSelectDropdown
label="Detail Level Category"
options={availableDetailCats}
selected={selectedDetailCats}
onChange={setSelectedDetailCats}
/>
{(selectedMarkets.length > 0 || selectedAsins.length > 0 || selectedTopCats.length > 0 || selectedDetailCats.length > 0) && (
<button
onClick={() => {
setSelectedMarkets([]);
setSelectedAsins([]);
setSelectedTopCats([]);
setSelectedDetailCats([]);
}}
className="text-xs text-slate-400 hover:text-white underline"
>
Clear filters
</button>
)}
<span className="text-slate-500 text-xs ml-auto">{filteredData.length.toLocaleString()} records filtered</span>
<span className="text-slate-500 text-xs ml-auto">{bsrData.length.toLocaleString()} records filtered</span>
</div>
{/* Top Level BSR Trend Chart */}