From a4919691b2cf9ed45f8e2a2ef92781b974cdf3f8 Mon Sep 17 00:00:00 2001 From: Christian Vidal Wolf Date: Fri, 20 Feb 2026 14:01:05 +0100 Subject: [PATCH] Fix Vendor filters: add year, date range, and ASIN search - Add year filter with multi-select dropdown - Add date range pickers (from/to) - Fix tags filter using ilike for partial matching - Add clear filters button - Update supabase service with proper year filtering Co-authored-by: Qwen-Coder --- components/VendorDataView.tsx | 52 ++++++++++++++++++++++++++++++++++- services/supabase.ts | 19 ++++++++++++- 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/components/VendorDataView.tsx b/components/VendorDataView.tsx index 7bbb61e..c8d5e83 100644 --- a/components/VendorDataView.tsx +++ b/components/VendorDataView.tsx @@ -109,11 +109,15 @@ const VendorDataView: React.FC = () => { // Filter options const [availableMarkets, setAvailableMarkets] = useState([]); const [availableTags, setAvailableTags] = useState([]); + const [availableYears, setAvailableYears] = useState([]); // Selected filters const [selectedMarkets, setSelectedMarkets] = useState([]); const [selectedTags, setSelectedTags] = useState([]); + const [selectedYears, setSelectedYears] = useState([]); const [asinSearch, setAsinSearch] = useState(''); + const [dateFrom, setDateFrom] = useState(''); + const [dateTo, setDateTo] = useState(''); // Load filter options on mount useEffect(() => { @@ -122,6 +126,14 @@ const VendorDataView: React.FC = () => { const opts = await fetchVendorFilterOptions(); setAvailableMarkets(opts.markets); setAvailableTags(opts.tags); + // Extract years from date range + if (opts.dateRange) { + const minYear = new Date(opts.dateRange.min).getFullYear(); + const maxYear = new Date(opts.dateRange.max).getFullYear(); + const years: number[] = []; + for (let y = minYear; y <= maxYear; y++) years.push(y); + setAvailableYears(years); + } } catch (e: any) { console.error('Failed to load vendor filter options', e); } @@ -138,6 +150,9 @@ const VendorDataView: React.FC = () => { markets: selectedMarkets.length > 0 ? selectedMarkets : undefined, tags: selectedTags.length > 0 ? selectedTags : undefined, asins: asinSearch.trim() ? asinSearch.split(',').map(a => a.trim()).filter(Boolean) : undefined, + dateFrom: dateFrom || undefined, + dateTo: dateTo || undefined, + years: selectedYears.length > 0 ? selectedYears : undefined, }); setVendorRows(data); } catch (e: any) { @@ -145,7 +160,7 @@ const VendorDataView: React.FC = () => { } finally { setLoading(false); } - }, [selectedMarkets, selectedTags, asinSearch]); + }, [selectedMarkets, selectedTags, selectedYears, asinSearch, dateFrom, dateTo]); useEffect(() => { loadData(); @@ -197,6 +212,26 @@ const VendorDataView: React.FC = () => { selected={selectedTags} onChange={setSelectedTags} /> + setSelectedYears(vals.map(v => parseInt(v)))} + /> + setDateFrom(e.target.value)} + className="bg-slate-900 border border-slate-700 rounded-lg px-3 py-2 text-sm text-slate-200 placeholder-slate-500 focus:outline-none focus:ring-1 focus:ring-indigo-500" + placeholder="From date" + /> + setDateTo(e.target.value)} + className="bg-slate-900 border border-slate-700 rounded-lg px-3 py-2 text-sm text-slate-200 placeholder-slate-500 focus:outline-none focus:ring-1 focus:ring-indigo-500" + placeholder="To date" + /> { onChange={e => setAsinSearch(e.target.value)} className="bg-slate-900 border border-slate-700 rounded-lg px-3 py-2 text-sm text-slate-200 placeholder-slate-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 w-64" /> + {(selectedMarkets.length > 0 || selectedTags.length > 0 || selectedYears.length > 0 || dateFrom || dateTo || asinSearch) && ( + + )} {loading && (
diff --git a/services/supabase.ts b/services/supabase.ts index 086fb55..78dce18 100644 --- a/services/supabase.ts +++ b/services/supabase.ts @@ -23,6 +23,7 @@ export interface VendorFilters { asins?: string[]; dateFrom?: string; dateTo?: string; + years?: number[]; } export const fetchVendorData = async (filters: VendorFilters): Promise => { @@ -42,7 +43,8 @@ export const fetchVendorData = async (filters: VendorFilters): Promise `tags.ilike.%${t}%`).join(',')); } if (filters.asins?.length) { query = query.in('asin', filters.asins); @@ -53,6 +55,21 @@ export const fetchVendorData = async (filters: VendorFilters): Promise ({ + from: `${y}-01-01`, + to: `${y}-12-31` + })); + const dateConditions = yearFilters.flatMap(f => [ + `date.gte.${f.from}`, + `date.lte.${f.to}` + ]); + // Build OR condition for multiple years + query = query.or( + filters.years.map(y => `and(date.gte.${y}-01-01,date.lte.${y}-12-31)`).join(',') + ); + } const { data, error } = await query; if (error) throw error;