mirror of
https://github.com/christianvidalwolf-prog/Craze-Data-check.git
synced 2026-08-03 11:55:23 +02:00
Add dynamic column filters to all pricing columns
Add filter dropdowns to SRP, UVP, and container columns in Pricing tab
This commit is contained in:
@@ -55,15 +55,12 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
const [lineMultiFilter, setLineMultiFilter] = useState<string[]>([]);
|
||||
const [classificationFilter, setClassificationFilter] = useState<string[]>([]);
|
||||
const [nameColFilter, setNameColFilter] = useState('');
|
||||
const [openFilter, setOpenFilter] = useState<'name' | 'line' | 'classification' | 'unitsOuter' | 'outerW' | 'outerL' | 'outerH' | 'srp' | 'container' | null>(null);
|
||||
const [openFilter, setOpenFilter] = useState<string | null>(null);
|
||||
const [unitsOuterFilter, setUnitsOuterFilter] = useState<string[]>([]);
|
||||
const [outerWFilter, setOuterWFilter] = useState<string[]>([]);
|
||||
const [outerLFilter, setOuterLFilter] = useState<string[]>([]);
|
||||
const [outerHFilter, setOuterHFilter] = useState<string[]>([]);
|
||||
const [srpFilter, setSrpFilter] = useState<string[]>([]);
|
||||
const [containerFilter, setContainerFilter] = useState<string[]>([]);
|
||||
const [srpColFilter, setSrpColFilter] = useState<string[]>([]);
|
||||
const [containerColFilter, setContainerColFilter] = useState<string[]>([]);
|
||||
const [dynamicColFilters, setDynamicColFilters] = useState<Record<number, string[]>>({});
|
||||
|
||||
// ── Dynamic column detection ──────────────────────────────────────────────
|
||||
const { uvpIdx, srpCols, containerCols } = useMemo(() => {
|
||||
@@ -214,8 +211,17 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
result = result.filter(r => outerHFilter.includes(String(r.row[COLUMNS.OUTER_H] || '')));
|
||||
}
|
||||
|
||||
// Dynamic column filters (SRP, container)
|
||||
(Object.keys(dynamicColFilters) as string[]).forEach(colIdx => {
|
||||
const filterVals = dynamicColFilters[Number(colIdx)];
|
||||
if (filterVals && filterVals.length > 0) {
|
||||
const col = Number(colIdx);
|
||||
result = result.filter(r => filterVals.includes(String(r.row[col] || '')));
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}, [analyzedRows, filterMode, search, nameColFilter, lineMultiFilter, classificationFilter, unitsOuterFilter, outerWFilter, outerLFilter, outerHFilter]);
|
||||
}, [analyzedRows, filterMode, search, nameColFilter, lineMultiFilter, classificationFilter, unitsOuterFilter, outerWFilter, outerLFilter, outerHFilter, dynamicColFilters]);
|
||||
|
||||
// ── Inline edit helpers ───────────────────────────────────────────────────
|
||||
const startEdit = (rowIndex: number, colIndex: number, currentValue: string) => {
|
||||
@@ -249,6 +255,18 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
...srpCols,
|
||||
];
|
||||
|
||||
// ═ Unique values for dynamic pricing columns ═════════════════════════════
|
||||
const dynamicColUniqueValues = useMemo(() => {
|
||||
const result: Record<number, string[]> = {};
|
||||
pricingEditableCols.forEach(col => {
|
||||
result[col.index] = Array.from(new Set(data.map(r => String(r[col.index] || '')))).filter(v => v).sort();
|
||||
});
|
||||
containerCols.forEach(col => {
|
||||
result[col.index] = Array.from(new Set(data.map(r => String(r[col.index] || '')))).filter(v => v).sort();
|
||||
});
|
||||
return result;
|
||||
}, [data, uvpIdx, srpCols, containerCols, headers]);
|
||||
|
||||
const formatPrice = (val: any) => {
|
||||
if (val === undefined || val === null || val === '') return '';
|
||||
const n = parseFloat(String(val).replace(',', '.'));
|
||||
@@ -468,11 +486,37 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
|
||||
{/* Editable pricing columns */}
|
||||
{pricingEditableCols.map(col => (
|
||||
<th key={col.index} className="text-left px-3 py-3 text-xs font-semibold text-blue-400 uppercase tracking-wider border-b border-slate-700 whitespace-nowrap">
|
||||
<span className="flex items-center gap-1">
|
||||
<Edit2 className="w-3 h-3" />
|
||||
{col.name}
|
||||
</span>
|
||||
<th key={col.index} className="text-left px-3 py-3 text-xs font-semibold text-blue-400 uppercase tracking-wider border-b border-slate-700 whitespace-nowrap group relative">
|
||||
<div className="flex items-center gap-1">
|
||||
<span>{col.name}</span>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setOpenFilter(openFilter === `prc_${col.index}` ? null : `prc_${col.index}`);
|
||||
}}
|
||||
className={cn(
|
||||
'p-0.5 rounded hover:bg-slate-700 transition-colors',
|
||||
dynamicColFilters[col.index]?.length > 0 ? 'text-blue-400 bg-blue-400/10' : 'text-slate-500 opacity-0 group-hover:opacity-100'
|
||||
)}
|
||||
>
|
||||
<Filter className="w-3 h-3" />
|
||||
</button>
|
||||
</div>
|
||||
{openFilter === `prc_${col.index}` && (
|
||||
<ColumnFilterPopover
|
||||
uniqueValues={dynamicColUniqueValues[col.index] || []}
|
||||
selectedValues={dynamicColFilters[col.index] || []}
|
||||
onToggle={val => setDynamicColFilters(prev => {
|
||||
const current = prev[col.index] || [];
|
||||
return current.includes(val)
|
||||
? { ...prev, [col.index]: current.filter(v => v !== val) }
|
||||
: { ...prev, [col.index]: [...current, val] };
|
||||
})}
|
||||
onSelectAll={vals => setDynamicColFilters(prev => ({ ...prev, [col.index]: vals }))}
|
||||
onClear={() => { setDynamicColFilters(prev => { const next = { ...prev }; delete next[col.index]; return next; }); setOpenFilter(null); }}
|
||||
onClose={() => setOpenFilter(null)}
|
||||
/>
|
||||
)}
|
||||
</th>
|
||||
))}
|
||||
|
||||
@@ -582,8 +626,37 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
|
||||
{/* Container columns */}
|
||||
{containerCols.map(col => (
|
||||
<th key={col.index} className="text-left px-3 py-3 text-xs font-semibold text-orange-400 uppercase tracking-wider border-b border-slate-700 whitespace-nowrap">
|
||||
{col.name}
|
||||
<th key={col.index} className="text-left px-3 py-3 text-xs font-semibold text-orange-400 uppercase tracking-wider border-b border-slate-700 whitespace-nowrap group relative">
|
||||
<div className="flex items-center gap-1">
|
||||
<span>{col.name}</span>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setOpenFilter(openFilter === `con_${col.index}` ? null : `con_${col.index}`);
|
||||
}}
|
||||
className={cn(
|
||||
'p-0.5 rounded hover:bg-slate-700 transition-colors',
|
||||
dynamicColFilters[col.index]?.length > 0 ? 'text-blue-400 bg-blue-400/10' : 'text-slate-500 opacity-0 group-hover:opacity-100'
|
||||
)}
|
||||
>
|
||||
<Filter className="w-3 h-3" />
|
||||
</button>
|
||||
</div>
|
||||
{openFilter === `con_${col.index}` && (
|
||||
<ColumnFilterPopover
|
||||
uniqueValues={dynamicColUniqueValues[col.index] || []}
|
||||
selectedValues={dynamicColFilters[col.index] || []}
|
||||
onToggle={val => setDynamicColFilters(prev => {
|
||||
const current = prev[col.index] || [];
|
||||
return current.includes(val)
|
||||
? { ...prev, [col.index]: current.filter(v => v !== val) }
|
||||
: { ...prev, [col.index]: [...current, val] };
|
||||
})}
|
||||
onSelectAll={vals => setDynamicColFilters(prev => ({ ...prev, [col.index]: vals }))}
|
||||
onClear={() => { setDynamicColFilters(prev => { const next = { ...prev }; delete next[col.index]; return next; }); setOpenFilter(null); }}
|
||||
onClose={() => setOpenFilter(null)}
|
||||
/>
|
||||
)}
|
||||
</th>
|
||||
))}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user