From 20a0c2d786cec04066bf4c005b2331c5d5b49b3b Mon Sep 17 00:00:00 2001 From: Christian Vidal Wolf Date: Wed, 8 Apr 2026 17:11:27 +0200 Subject: [PATCH] feat: restrict description column filters to Present/Missing only Long DE, Long EN, Short DE, and Short EN columns now only show Present/Missing filter options instead of all unique values Co-authored-by: Qwen-Coder --- src/components/ProductDescriptions.tsx | 57 +++++++++++++++++--------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/src/components/ProductDescriptions.tsx b/src/components/ProductDescriptions.tsx index 6c9773c..14872be 100644 --- a/src/components/ProductDescriptions.tsx +++ b/src/components/ProductDescriptions.tsx @@ -1,4 +1,4 @@ -import React, { useState, useMemo } from 'react'; +import React, { useState, useMemo, useCallback } from 'react'; import { ExcelRow, COLUMNS } from '../types'; import { Search, Filter, Edit2, ChevronDown, ChevronUp, X } from 'lucide-react'; import { cn } from '../lib/utils'; @@ -11,6 +11,9 @@ interface ProductDescriptionsProps { type TabType = 'all' | 'missingLongDE' | 'missingLongEN' | 'missingLongAny' | 'missingShortDE' | 'missingShortEN' | 'missingShortAny' | 'complete' | 'incomplete'; +// Description columns that should only have Present/Missing filters +const DESCRIPTION_COLUMNS = [COLUMNS.LONG_DE, COLUMNS.LONG_EN, COLUMNS.SHORT_DE, COLUMNS.SHORT_EN]; + export function ProductDescriptions({ data, onEdit }: ProductDescriptionsProps) { const [activeTab, setActiveTab] = useState('all'); const [search, setSearch] = useState(''); @@ -36,20 +39,20 @@ export function ProductDescriptions({ data, onEdit }: ProductDescriptionsProps) if (activeTab === 'missingShortDE') result = result.filter(r => !r.row[COLUMNS.SHORT_DE]); if (activeTab === 'missingShortEN') result = result.filter(r => !r.row[COLUMNS.SHORT_EN]); if (activeTab === 'missingShortAny') result = result.filter(r => !r.row[COLUMNS.SHORT_DE] || !r.row[COLUMNS.SHORT_EN]); - - if (activeTab === 'complete') result = result.filter(r => - r.row[COLUMNS.LONG_DE] && r.row[COLUMNS.LONG_EN] && + + if (activeTab === 'complete') result = result.filter(r => + r.row[COLUMNS.LONG_DE] && r.row[COLUMNS.LONG_EN] && r.row[COLUMNS.SHORT_DE] && r.row[COLUMNS.SHORT_EN] ); - if (activeTab === 'incomplete') result = result.filter(r => - !r.row[COLUMNS.LONG_DE] || !r.row[COLUMNS.LONG_EN] || + if (activeTab === 'incomplete') result = result.filter(r => + !r.row[COLUMNS.LONG_DE] || !r.row[COLUMNS.LONG_EN] || !r.row[COLUMNS.SHORT_DE] || !r.row[COLUMNS.SHORT_EN] ); // Search filter if (search) { const s = search.toLowerCase(); - result = result.filter(r => + result = result.filter(r => String(r.row[COLUMNS.ARTICLE_NO] || '').toLowerCase().includes(s) || String(r.row[COLUMNS.ARTICLE_NAME] || '').toLowerCase().includes(s) ); @@ -61,9 +64,20 @@ export function ProductDescriptions({ data, onEdit }: ProductDescriptionsProps) // Column-specific filters (Excel-like) Object.entries(columnFilters).forEach(([colIdx, selectedValues]) => { + const col = Number(colIdx); const vals = selectedValues as string[]; if (vals.length > 0) { - result = result.filter(r => vals.includes(String(r.row[Number(colIdx)] || ''))); + // For description columns, filter by present/missing + if (DESCRIPTION_COLUMNS.includes(col)) { + result = result.filter(r => { + const hasValue = Boolean(r.row[col]); + const shouldInclude = vals.includes('Present') && hasValue || vals.includes('Missing') && !hasValue; + return shouldInclude; + }); + } else { + // For other columns, use regular value matching + result = result.filter(r => vals.includes(String(r.row[col] || ''))); + } } }); @@ -96,6 +110,11 @@ export function ProductDescriptions({ data, onEdit }: ProductDescriptionsProps) }; const getUniqueValues = (col: number) => { + // For description columns, return only 'Present' and 'Missing' + if (DESCRIPTION_COLUMNS.includes(col)) { + return ['Present', 'Missing']; + } + // For other columns, return actual unique values const values = data.map(r => String(r[col] || '')); return Array.from(new Set(values)).sort(); }; @@ -126,7 +145,7 @@ export function ProductDescriptions({ data, onEdit }: ProductDescriptionsProps) } const fields = [ - row[COLUMNS.LONG_DE], row[COLUMNS.LONG_EN], + row[COLUMNS.LONG_DE], row[COLUMNS.LONG_EN], row[COLUMNS.SHORT_DE], row[COLUMNS.SHORT_EN] ]; const filled = fields.filter(Boolean).length; @@ -137,13 +156,13 @@ export function ProductDescriptions({ data, onEdit }: ProductDescriptionsProps) const Badge = ({ content, row }: { content: any, row: ExcelRow }) => { if (content) return ; - + // EOL Exception: OOC and stock <= 0 const classification = String(row[COLUMNS.CLASSIFICATION] || '').toUpperCase().trim(); const stock = Number(row[COLUMNS.ITEM_AVAILABLE] || 0); - + if (classification === 'OOC' && stock <= 0) { - return EOL not neccessary; + return EOL not neccessary; } return ✗ Missing; @@ -170,8 +189,8 @@ export function ProductDescriptions({ data, onEdit }: ProductDescriptionsProps) onClick={() => { setActiveTab(tab.id); setPage(1); }} className={cn( "px-4 py-2 rounded-md text-sm font-medium transition-colors", - activeTab === tab.id - ? "bg-blue-600 text-white shadow-md" + activeTab === tab.id + ? "bg-blue-600 text-white shadow-md" : "bg-slate-800 text-slate-400 hover:bg-slate-700 hover:text-white" )} > @@ -237,8 +256,8 @@ export function ProductDescriptions({ data, onEdit }: ProductDescriptionsProps) { col: COLUMNS.SHORT_DE, label: 'Short DE' }, { col: COLUMNS.SHORT_EN, label: 'Short EN' }, ].map(({ col, label }) => ( -
@@ -294,8 +313,8 @@ export function ProductDescriptions({ data, onEdit }: ProductDescriptionsProps) {row[COLUMNS.CLASSIFICATION] || '—'} @@ -326,7 +345,7 @@ export function ProductDescriptions({ data, onEdit }: ProductDescriptionsProps)
- +
Showing {Math.min((page - 1) * pageSize + 1, filteredData.length)} to {Math.min(page * pageSize, filteredData.length)} of {filteredData.length} entries