mirror of
https://github.com/christianvidalwolf-prog/Craze-Data-check.git
synced 2026-08-03 16:25:24 +02:00
Add column filters for Units/Outer and Outer W/L/H in Pricing tab
Add dropdown filters to filter by specific values in Units/Outer, Outer W, Outer L, Outer H columns
This commit is contained in:
+130
-10
@@ -55,7 +55,15 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
|||||||
const [lineMultiFilter, setLineMultiFilter] = useState<string[]>([]);
|
const [lineMultiFilter, setLineMultiFilter] = useState<string[]>([]);
|
||||||
const [classificationFilter, setClassificationFilter] = useState<string[]>([]);
|
const [classificationFilter, setClassificationFilter] = useState<string[]>([]);
|
||||||
const [nameColFilter, setNameColFilter] = useState('');
|
const [nameColFilter, setNameColFilter] = useState('');
|
||||||
const [openFilter, setOpenFilter] = useState<'name' | 'line' | 'classification' | null>(null);
|
const [openFilter, setOpenFilter] = useState<'name' | 'line' | 'classification' | 'unitsOuter' | 'outerW' | 'outerL' | 'outerH' | 'srp' | 'container' | 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[]>([]);
|
||||||
|
|
||||||
// ── Dynamic column detection ──────────────────────────────────────────────
|
// ── Dynamic column detection ──────────────────────────────────────────────
|
||||||
const { uvpIdx, srpCols, containerCols } = useMemo(() => {
|
const { uvpIdx, srpCols, containerCols } = useMemo(() => {
|
||||||
@@ -146,6 +154,22 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
|||||||
Array.from(new Set(data.map(r => String(r[COLUMNS.CLASSIFICATION] || '')))).sort(),
|
Array.from(new Set(data.map(r => String(r[COLUMNS.CLASSIFICATION] || '')))).sort(),
|
||||||
[data]);
|
[data]);
|
||||||
|
|
||||||
|
const uniqueUnitsOuter = useMemo(() =>
|
||||||
|
Array.from(new Set(data.map(r => String(r[COLUMNS.UNITS_OUTER] || '')))).filter(v => v).sort(),
|
||||||
|
[data]);
|
||||||
|
|
||||||
|
const uniqueOuterW = useMemo(() =>
|
||||||
|
Array.from(new Set(data.map(r => String(r[COLUMNS.OUTER_W] || '')))).filter(v => v).sort((a, b) => Number(a) - Number(b)),
|
||||||
|
[data]);
|
||||||
|
|
||||||
|
const uniqueOuterL = useMemo(() =>
|
||||||
|
Array.from(new Set(data.map(r => String(r[COLUMNS.OUTER_L] || '')))).filter(v => v).sort((a, b) => Number(a) - Number(b)),
|
||||||
|
[data]);
|
||||||
|
|
||||||
|
const uniqueOuterH = useMemo(() =>
|
||||||
|
Array.from(new Set(data.map(r => String(r[COLUMNS.OUTER_H] || '')))).filter(v => v).sort((a, b) => Number(a) - Number(b)),
|
||||||
|
[data]);
|
||||||
|
|
||||||
// ── Filtered rows ─────────────────────────────────────────────────────────
|
// ── Filtered rows ─────────────────────────────────────────────────────────
|
||||||
const filteredRows = useMemo(() => {
|
const filteredRows = useMemo(() => {
|
||||||
let result = analyzedRows;
|
let result = analyzedRows;
|
||||||
@@ -177,9 +201,21 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
|||||||
if (classificationFilter.length > 0) {
|
if (classificationFilter.length > 0) {
|
||||||
result = result.filter(r => classificationFilter.includes(String(r.row[COLUMNS.CLASSIFICATION] || '')));
|
result = result.filter(r => classificationFilter.includes(String(r.row[COLUMNS.CLASSIFICATION] || '')));
|
||||||
}
|
}
|
||||||
|
if (unitsOuterFilter.length > 0) {
|
||||||
|
result = result.filter(r => unitsOuterFilter.includes(String(r.row[COLUMNS.UNITS_OUTER] || '')));
|
||||||
|
}
|
||||||
|
if (outerWFilter.length > 0) {
|
||||||
|
result = result.filter(r => outerWFilter.includes(String(r.row[COLUMNS.OUTER_W] || '')));
|
||||||
|
}
|
||||||
|
if (outerLFilter.length > 0) {
|
||||||
|
result = result.filter(r => outerLFilter.includes(String(r.row[COLUMNS.OUTER_L] || '')));
|
||||||
|
}
|
||||||
|
if (outerHFilter.length > 0) {
|
||||||
|
result = result.filter(r => outerHFilter.includes(String(r.row[COLUMNS.OUTER_H] || '')));
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}, [analyzedRows, filterMode, search, nameColFilter, lineMultiFilter, classificationFilter]);
|
}, [analyzedRows, filterMode, search, nameColFilter, lineMultiFilter, classificationFilter, unitsOuterFilter, outerWFilter, outerLFilter, outerHFilter]);
|
||||||
|
|
||||||
// ── Inline edit helpers ───────────────────────────────────────────────────
|
// ── Inline edit helpers ───────────────────────────────────────────────────
|
||||||
const startEdit = (rowIndex: number, colIndex: number, currentValue: string) => {
|
const startEdit = (rowIndex: number, colIndex: number, currentValue: string) => {
|
||||||
@@ -441,23 +477,107 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
|||||||
))}
|
))}
|
||||||
|
|
||||||
{/* Units/Outer */}
|
{/* Units/Outer */}
|
||||||
<th className="text-left px-3 py-3 text-xs font-semibold text-slate-400 uppercase tracking-wider border-b border-slate-700 whitespace-nowrap">
|
<th className="text-left px-3 py-3 text-xs font-semibold text-slate-400 uppercase tracking-wider border-b border-slate-700 whitespace-nowrap group relative">
|
||||||
Units/Outer
|
<div className="flex items-center gap-1">
|
||||||
|
<span>Units/Outer</span>
|
||||||
|
<button
|
||||||
|
onClick={() => setOpenFilter(openFilter === 'unitsOuter' ? null : 'unitsOuter')}
|
||||||
|
className={cn(
|
||||||
|
'p-0.5 rounded hover:bg-slate-700 transition-colors',
|
||||||
|
unitsOuterFilter.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 === 'unitsOuter' && (
|
||||||
|
<ColumnFilterPopover
|
||||||
|
uniqueValues={uniqueUnitsOuter}
|
||||||
|
selectedValues={unitsOuterFilter}
|
||||||
|
onToggle={val => setUnitsOuterFilter(prev => prev.includes(val) ? prev.filter(v => v !== val) : [...prev, val])}
|
||||||
|
onSelectAll={vals => setUnitsOuterFilter(vals)}
|
||||||
|
onClear={() => { setUnitsOuterFilter([]); setOpenFilter(null); }}
|
||||||
|
onClose={() => setOpenFilter(null)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</th>
|
</th>
|
||||||
|
|
||||||
{/* Outer W */}
|
{/* Outer W */}
|
||||||
<th className="text-left px-3 py-3 text-xs font-semibold text-slate-400 uppercase tracking-wider border-b border-slate-700 whitespace-nowrap">
|
<th className="text-left px-3 py-3 text-xs font-semibold text-slate-400 uppercase tracking-wider border-b border-slate-700 whitespace-nowrap group relative">
|
||||||
Outer W
|
<div className="flex items-center gap-1">
|
||||||
|
<span>Outer W</span>
|
||||||
|
<button
|
||||||
|
onClick={() => setOpenFilter(openFilter === 'outerW' ? null : 'outerW')}
|
||||||
|
className={cn(
|
||||||
|
'p-0.5 rounded hover:bg-slate-700 transition-colors',
|
||||||
|
outerWFilter.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 === 'outerW' && (
|
||||||
|
<ColumnFilterPopover
|
||||||
|
uniqueValues={uniqueOuterW}
|
||||||
|
selectedValues={outerWFilter}
|
||||||
|
onToggle={val => setOuterWFilter(prev => prev.includes(val) ? prev.filter(v => v !== val) : [...prev, val])}
|
||||||
|
onSelectAll={vals => setOuterWFilter(vals)}
|
||||||
|
onClear={() => { setOuterWFilter([]); setOpenFilter(null); }}
|
||||||
|
onClose={() => setOpenFilter(null)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</th>
|
</th>
|
||||||
|
|
||||||
{/* Outer L */}
|
{/* Outer L */}
|
||||||
<th className="text-left px-3 py-3 text-xs font-semibold text-slate-400 uppercase tracking-wider border-b border-slate-700 whitespace-nowrap">
|
<th className="text-left px-3 py-3 text-xs font-semibold text-slate-400 uppercase tracking-wider border-b border-slate-700 whitespace-nowrap group relative">
|
||||||
Outer L
|
<div className="flex items-center gap-1">
|
||||||
|
<span>Outer L</span>
|
||||||
|
<button
|
||||||
|
onClick={() => setOpenFilter(openFilter === 'outerL' ? null : 'outerL')}
|
||||||
|
className={cn(
|
||||||
|
'p-0.5 rounded hover:bg-slate-700 transition-colors',
|
||||||
|
outerLFilter.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 === 'outerL' && (
|
||||||
|
<ColumnFilterPopover
|
||||||
|
uniqueValues={uniqueOuterL}
|
||||||
|
selectedValues={outerLFilter}
|
||||||
|
onToggle={val => setOuterLFilter(prev => prev.includes(val) ? prev.filter(v => v !== val) : [...prev, val])}
|
||||||
|
onSelectAll={vals => setOuterLFilter(vals)}
|
||||||
|
onClear={() => { setOuterLFilter([]); setOpenFilter(null); }}
|
||||||
|
onClose={() => setOpenFilter(null)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</th>
|
</th>
|
||||||
|
|
||||||
{/* Outer H */}
|
{/* Outer H */}
|
||||||
<th className="text-left px-3 py-3 text-xs font-semibold text-slate-400 uppercase tracking-wider border-b border-slate-700 whitespace-nowrap">
|
<th className="text-left px-3 py-3 text-xs font-semibold text-slate-400 uppercase tracking-wider border-b border-slate-700 whitespace-nowrap group relative">
|
||||||
Outer H
|
<div className="flex items-center gap-1">
|
||||||
|
<span>Outer H</span>
|
||||||
|
<button
|
||||||
|
onClick={() => setOpenFilter(openFilter === 'outerH' ? null : 'outerH')}
|
||||||
|
className={cn(
|
||||||
|
'p-0.5 rounded hover:bg-slate-700 transition-colors',
|
||||||
|
outerHFilter.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 === 'outerH' && (
|
||||||
|
<ColumnFilterPopover
|
||||||
|
uniqueValues={uniqueOuterH}
|
||||||
|
selectedValues={outerHFilter}
|
||||||
|
onToggle={val => setOuterHFilter(prev => prev.includes(val) ? prev.filter(v => v !== val) : [...prev, val])}
|
||||||
|
onSelectAll={vals => setOuterHFilter(vals)}
|
||||||
|
onClear={() => { setOuterHFilter([]); setOpenFilter(null); }}
|
||||||
|
onClose={() => setOpenFilter(null)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</th>
|
</th>
|
||||||
|
|
||||||
{/* Container columns */}
|
{/* Container columns */}
|
||||||
|
|||||||
Reference in New Issue
Block a user