mirror of
https://github.com/christianvidalwolf-prog/Craze-Data-check.git
synced 2026-08-03 15:25:24 +02:00
feat: implement advanced 5-term global search in PricingView
This commit is contained in:
@@ -82,6 +82,7 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
|||||||
const [productTypeFilter, setProductTypeFilter] = useState<string[]>([]);
|
const [productTypeFilter, setProductTypeFilter] = useState<string[]>([]);
|
||||||
const [nameColFilter, setNameColFilter] = useState<{ terms: string[]; op: 'and' | 'or' }>({ terms: [''], op: 'and' });
|
const [nameColFilter, setNameColFilter] = useState<{ terms: string[]; op: 'and' | 'or' }>({ terms: [''], op: 'and' });
|
||||||
const [articleNoColFilter, setArticleNoColFilter] = useState<{ terms: string[]; op: 'and' | 'or' }>({ terms: [''], op: 'and' });
|
const [articleNoColFilter, setArticleNoColFilter] = useState<{ terms: string[]; op: 'and' | 'or' }>({ terms: [''], op: 'and' });
|
||||||
|
const [globalAdvancedFilter, setGlobalAdvancedFilter] = useState<{ terms: string[]; op: 'and' | 'or' }>({ terms: [''], op: 'and' });
|
||||||
const [openFilter, setOpenFilter] = useState<string | null>(null);
|
const [openFilter, setOpenFilter] = useState<string | null>(null);
|
||||||
const [unitsOuterFilter, setUnitsOuterFilter] = useState<string[]>([]);
|
const [unitsOuterFilter, setUnitsOuterFilter] = useState<string[]>([]);
|
||||||
const [outerWFilter, setOuterWFilter] = useState<string[]>([]);
|
const [outerWFilter, setOuterWFilter] = useState<string[]>([]);
|
||||||
@@ -327,6 +328,20 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Global Advanced Filter (Multi-term AND/OR)
|
||||||
|
if (globalAdvancedFilter.terms.some(t => t.trim() !== '')) {
|
||||||
|
result = result.filter(r => {
|
||||||
|
const articleNo = String(r.row[COLUMNS.ARTICLE_NO] || '').toLowerCase();
|
||||||
|
const articleName = String(r.row[COLUMNS.ARTICLE_NAME] || '').toLowerCase();
|
||||||
|
const activeTerms = globalAdvancedFilter.terms.filter(t => t.trim() !== '').map(t => t.toLowerCase());
|
||||||
|
if (activeTerms.length === 0) return true;
|
||||||
|
|
||||||
|
return globalAdvancedFilter.op === 'and'
|
||||||
|
? activeTerms.every(term => articleNo.includes(term) || articleName.includes(term))
|
||||||
|
: activeTerms.some(term => articleNo.includes(term) || articleName.includes(term));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Selected items from search dropdown
|
// Selected items from search dropdown
|
||||||
if (searchMode === 'selected' && selectedSearchItems.size > 0) {
|
if (searchMode === 'selected' && selectedSearchItems.size > 0) {
|
||||||
result = result.filter(r => {
|
result = result.filter(r => {
|
||||||
@@ -400,7 +415,7 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
|||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}, [analyzedRows, filterMode, search, nameColFilter, lineMultiFilter, classificationFilter, productTypeFilter, unitsOuterFilter, outerWFilter, outerLFilter, outerHFilter, dynamicColFilters, weightIssueFilter]);
|
}, [analyzedRows, filterMode, search, nameColFilter, articleNoColFilter, globalAdvancedFilter, lineMultiFilter, classificationFilter, productTypeFilter, unitsOuterFilter, outerWFilter, outerLFilter, outerHFilter, dynamicColFilters, weightIssueFilter, searchMode, selectedSearchItems]);
|
||||||
|
|
||||||
// ── Sorted rows ──────────────────────────────────────────────────────────
|
// ── Sorted rows ──────────────────────────────────────────────────────────
|
||||||
const sortedRows = useMemo(() => {
|
const sortedRows = useMemo(() => {
|
||||||
@@ -796,13 +811,32 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
|||||||
>
|
>
|
||||||
<X className="w-4 h-4" />
|
<X className="w-4 h-4" />
|
||||||
</button>
|
</button>
|
||||||
) : (
|
|
||||||
<div className="absolute right-3 top-1/2 -translate-y-1/2 text-slate-500">
|
|
||||||
<Package className="w-4 h-4" />
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={(e) => { e.stopPropagation(); setOpenFilter(openFilter === 'global' ? null : 'global'); }}
|
||||||
|
className={cn(
|
||||||
|
'absolute -right-10 top-1/2 -translate-y-1/2 p-2 rounded-lg border transition-all active:scale-95',
|
||||||
|
globalAdvancedFilter.terms.some(t => t.trim() !== '')
|
||||||
|
? 'bg-blue-600 border-blue-500 text-white shadow-lg shadow-blue-900/20'
|
||||||
|
: 'bg-slate-800 border-slate-700 text-slate-400 hover:text-white hover:border-slate-600'
|
||||||
|
)}
|
||||||
|
title="Advanced Search"
|
||||||
|
>
|
||||||
|
<Filter className="w-4 h-4" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{openFilter === 'global' && (
|
||||||
|
<div className="absolute top-full left-0 z-[200]">
|
||||||
|
<TextFilterPopover
|
||||||
|
value={globalAdvancedFilter}
|
||||||
|
onChange={setGlobalAdvancedFilter}
|
||||||
|
onClose={() => setOpenFilter(null)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Search Dropdown Panel */}
|
{/* Search Dropdown Panel */}
|
||||||
{isSearchOpen && searchSuggestions.length > 0 && (
|
{isSearchOpen && searchSuggestions.length > 0 && (
|
||||||
<div className="absolute top-full left-0 right-0 mt-1 bg-slate-800 border border-slate-700 rounded-lg shadow-2xl z-[150] overflow-hidden animate-in fade-in slide-in-from-top-2 duration-200">
|
<div className="absolute top-full left-0 right-0 mt-1 bg-slate-800 border border-slate-700 rounded-lg shadow-2xl z-[150] overflow-hidden animate-in fade-in slide-in-from-top-2 duration-200">
|
||||||
|
|||||||
Reference in New Issue
Block a user