mirror of
https://github.com/christianvidalwolf-prog/CrazeAnalytix.git
synced 2026-08-03 12:25:22 +02:00
Implement Excel-style filters (SKU, ASIN, Title, Line) across GRID, WEEKLY SALES, and FC26 tabs
This commit is contained in:
+60
-12
@@ -2,13 +2,14 @@ import React, { useState, useMemo, useEffect, useRef } from 'react';
|
||||
import {
|
||||
LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer
|
||||
} from 'recharts';
|
||||
import { SalesRecord, PivotRow, AdsRecord, CombinedKPIs } from '../types';
|
||||
import { pivotSalesData, generateXLSX, aggregateForTimeSeries, aggregateForComparisonTimeSeries, applyPanEUGrouping } from '../services/dataProcessor';
|
||||
import { SalesRecord, PivotRow, AdsRecord, CombinedKPIs, ColumnFilterCondition } from '../types';
|
||||
import { pivotSalesData, generateXLSX, aggregateForTimeSeries, aggregateForComparisonTimeSeries, applyPanEUGrouping, filterData } from '../services/dataProcessor';
|
||||
import { DownloadIcon, FunnelIcon, CloseIcon, ChartIcon, TrendingIcon } from './Icons';
|
||||
import { StockBadge } from './StockBadge';
|
||||
import { Top50Badge } from './Top50Badge';
|
||||
import { VendorStockBadge } from './VendorStockBadge';
|
||||
import { BuyBoxWarningBadge } from './BuyBoxWarningBadge';
|
||||
import { ExcelFilter } from './ExcelFilter';
|
||||
|
||||
interface DataGridProps {
|
||||
data: SalesRecord[] | CombinedKPIs[];
|
||||
@@ -297,6 +298,19 @@ const DataGrid: React.FC<DataGridProps> = ({ data, hasCustomerFilter, adsData, s
|
||||
const [newFilterOperator, setNewFilterOperator] = useState<'gt' | 'lt'>('gt');
|
||||
const [newFilterValue, setNewFilterValue] = useState<string>('');
|
||||
|
||||
// State for Column Filters
|
||||
const [columnFilters, setColumnFilters] = useState<Record<string, ColumnFilterCondition>>({});
|
||||
|
||||
const handleColumnFilterChange = (columnKey: string, condition: ColumnFilterCondition | undefined) => {
|
||||
setColumnFilters(prev => {
|
||||
const next = { ...prev };
|
||||
if (condition) next[columnKey] = condition;
|
||||
else delete next[columnKey];
|
||||
return next;
|
||||
});
|
||||
setCurrentPage(1);
|
||||
};
|
||||
|
||||
// Effective dimensions for rendering
|
||||
const effectiveDimensions = useMemo(() =>
|
||||
selectedDimensions.length > 0 ? selectedDimensions : ['customer'],
|
||||
@@ -307,10 +321,28 @@ const DataGrid: React.FC<DataGridProps> = ({ data, hasCustomerFilter, adsData, s
|
||||
// Apply Pan-EU grouping when no customer filter is applied
|
||||
const processedData = applyPanEUGrouping(data as SalesRecord[], hasCustomerFilter);
|
||||
|
||||
// Apply our comprehensive filters (includes Column Filters now)
|
||||
const filterState: any = {
|
||||
customer: [],
|
||||
year: [],
|
||||
month: [],
|
||||
line: [],
|
||||
asin: [],
|
||||
sku: [],
|
||||
title: [],
|
||||
week: [],
|
||||
stock: [],
|
||||
vendorStock: [],
|
||||
woc: [],
|
||||
bulkSearch: searchTerm,
|
||||
columnFilters
|
||||
};
|
||||
const filteredFlatData = filterData(processedData, filterState, stockMap, vendorStockMap, top50Mode);
|
||||
|
||||
// pivotSalesData now handles ads aggregation correctly because it receives CombinedKPIs
|
||||
const { rows } = pivotSalesData(processedData, effectiveDimensions);
|
||||
const { rows } = pivotSalesData(filteredFlatData, effectiveDimensions);
|
||||
return rows;
|
||||
}, [data, effectiveDimensions, hasCustomerFilter]);
|
||||
}, [data, effectiveDimensions, hasCustomerFilter, columnFilters, searchTerm, stockMap, vendorStockMap, top50Mode]);
|
||||
|
||||
const { years } = useMemo(() => {
|
||||
// We still need unique years for columns
|
||||
@@ -452,13 +484,9 @@ const DataGrid: React.FC<DataGridProps> = ({ data, hasCustomerFilter, adsData, s
|
||||
|
||||
// 1. Filter
|
||||
if (rowFilters.length > 0) {
|
||||
const latestYear = years[0];
|
||||
const prevYear = years[1];
|
||||
|
||||
result = result.filter(row => {
|
||||
return rowFilters.every(filter => {
|
||||
let rowValue = 0;
|
||||
|
||||
if (filter.metric.startsWith('total_sellOut_')) {
|
||||
const y = filter.metric.split('_')[2];
|
||||
rowValue = row.totalsByYear[y]?.sellOut || 0;
|
||||
@@ -468,6 +496,8 @@ const DataGrid: React.FC<DataGridProps> = ({ data, hasCustomerFilter, adsData, s
|
||||
rowValue = row.totalsByYear[y]?.units || 0;
|
||||
}
|
||||
else if (filter.metric === 'growth_sellOut') {
|
||||
const latestYear = years[0];
|
||||
const prevYear = years[1];
|
||||
if (!prevYear) return true;
|
||||
const curr = row.totalsByYear[latestYear]?.sellOut || 0;
|
||||
const prev = row.totalsByYear[prevYear]?.sellOut || 0;
|
||||
@@ -475,6 +505,8 @@ const DataGrid: React.FC<DataGridProps> = ({ data, hasCustomerFilter, adsData, s
|
||||
rowValue = ((curr - prev) / prev) * 100;
|
||||
}
|
||||
else if (filter.metric === 'growth_units') {
|
||||
const latestYear = years[0];
|
||||
const prevYear = years[1];
|
||||
if (!prevYear) return true;
|
||||
const curr = row.totalsByYear[latestYear]?.units || 0;
|
||||
const prev = row.totalsByYear[prevYear]?.units || 0;
|
||||
@@ -1186,14 +1218,30 @@ const DataGrid: React.FC<DataGridProps> = ({ data, hasCustomerFilter, adsData, s
|
||||
{/* Dynamic Dimension Headers */}
|
||||
{effectiveDimensions.map(dim => {
|
||||
const label = DIMENSION_OPTIONS.find(d => d.value === dim)?.label || dim;
|
||||
// Extract unique values for this dimension from ALL pivot rows (pre-filter)
|
||||
const uniqueValues = Array.from(new Set(pivotRows.map(r => String((r as any)[dim] || ''))))
|
||||
.filter(Boolean)
|
||||
.sort();
|
||||
|
||||
return (
|
||||
<th
|
||||
key={dim}
|
||||
className={`px-4 py-3 border-b border-border cursor-pointer hover:text-white group bg-slate-950 ${dim === 'title' ? 'min-w-[450px]' : 'min-w-[150px]'}`}
|
||||
onClick={() => requestSort(dim)}
|
||||
className={`px-4 py-3 border-b border-border group bg-slate-950 ${dim === 'title' ? 'min-w-[450px]' : 'min-w-[150px]'}`}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
{label} {getSortIcon(dim)}
|
||||
<div className="flex items-center justify-between">
|
||||
<div
|
||||
className="flex items-center cursor-pointer hover:text-white"
|
||||
onClick={() => requestSort(dim)}
|
||||
>
|
||||
{label} {getSortIcon(dim)}
|
||||
</div>
|
||||
<ExcelFilter
|
||||
columnKey={dim}
|
||||
title={label}
|
||||
uniqueValues={uniqueValues}
|
||||
currentFilter={columnFilters[dim]}
|
||||
onFilterChange={handleColumnFilterChange}
|
||||
/>
|
||||
</div>
|
||||
</th>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user