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 <qwen-coder@alibabacloud.com>
This commit is contained in:
Christian Vidal Wolf
2026-04-08 17:11:27 +02:00
co-authored by Qwen-Coder
parent 976f38eef8
commit 20a0c2d786
+38 -19
View File
@@ -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<TabType>('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 <span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-500/20 text-green-400 border border-green-500/30"></span>;
// 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 <span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-yellow-500/20 text-yellow-400 border border-yellow-500/30">EOL not neccessary</span>;
return <span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-yellow-500/20 text-yellow-400 border border-yellow-500/30">EOL not neccessary</span>;
}
return <span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-500/20 text-red-400 border border-red-500/30"> Missing</span>;
@@ -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 }) => (
<th
key={col}
<th
key={col}
className="px-4 py-3 font-medium transition-colors select-none group relative"
>
<div className="flex items-center justify-between gap-1">
@@ -294,8 +313,8 @@ export function ProductDescriptions({ data, onEdit }: ProductDescriptionsProps)
<td className="px-4 py-3">
<span className={cn(
"px-2 py-0.5 rounded text-[10px] font-bold border",
String(row[COLUMNS.CLASSIFICATION]).includes('OOC')
? "bg-amber-500/10 text-amber-500 border-amber-500/20"
String(row[COLUMNS.CLASSIFICATION]).includes('OOC')
? "bg-amber-500/10 text-amber-500 border-amber-500/20"
: "bg-slate-700/50 text-slate-400 border-slate-600/50"
)}>
{row[COLUMNS.CLASSIFICATION] || '—'}
@@ -326,7 +345,7 @@ export function ProductDescriptions({ data, onEdit }: ProductDescriptionsProps)
</tbody>
</table>
</div>
<div className="bg-slate-900 border-t border-slate-700 p-4 flex items-center justify-between text-sm text-slate-400">
<div className="flex items-center gap-4">
<span>Showing {Math.min((page - 1) * pageSize + 1, filteredData.length)} to {Math.min(page * pageSize, filteredData.length)} of {filteredData.length} entries</span>