diff --git a/src/App.tsx b/src/App.tsx index fd9addd..2d84c14 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -126,7 +126,8 @@ export default function App() { COLUMNS.UNITS_OUTER, COLUMNS.MOQ, COLUMNS.VERIFIED_DIMS, COLUMNS.VALIDATED_CHECK, - COLUMNS.VALIDATED_NOTE + COLUMNS.VALIDATED_NOTE, + COLUMNS.PRODUCT_TYPE ]); headers.forEach((h: any, i: number) => { diff --git a/src/components/PricingView.tsx b/src/components/PricingView.tsx index 20c986c..3e48717 100644 --- a/src/components/PricingView.tsx +++ b/src/components/PricingView.tsx @@ -56,6 +56,7 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit, articleName: 220, line: 100, classification: 130, + productType: 140, unitsOuter: 100, outerW: 80, outerL: 80, @@ -79,6 +80,9 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit, const [outerLFilter, setOuterLFilter] = useState([]); const [outerHFilter, setOuterHFilter] = useState([]); const [dynamicColFilters, setDynamicColFilters] = useState>({}); + const [editingType, setEditingType] = useState<{ rowIndex: number; value: string } | null>(null); + const [typeSuggestions, setTypeSuggestions] = useState([]); + const typeInputRef = useRef(null); const [isSearchOpen, setIsSearchOpen] = useState(false); const [selectedSearchItems, setSelectedSearchItems] = useState>(new Set()); @@ -354,6 +358,35 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit, if (e.key === 'Escape') cancelEdit(); }; + // ── All unique product types (for autocomplete) ─────────────────────────── + const allProductTypes = useMemo(() => + Array.from(new Set(data.map(r => String(r[COLUMNS.PRODUCT_TYPE] || '')).filter(Boolean))).sort() + , [data]); + + const startEditType = (rowIndex: number, currentValue: string) => { + setEditingType({ rowIndex, value: currentValue }); + setTypeSuggestions(allProductTypes); + setTimeout(() => typeInputRef.current?.focus(), 0); + }; + + const commitTypeEdit = useCallback(async (rowIndex: number, value: string) => { + setEditingType(null); + setTypeSuggestions([]); + const original = data[rowIndex]; + const newRow = [...original]; + newRow[COLUMNS.PRODUCT_TYPE] = value; + onCaptureState(`Updated type for ${original[COLUMNS.ARTICLE_NO]}`); + await onSaveRow(rowIndex, newRow); + }, [data, onSaveRow, onCaptureState]); + + const handleTypeInputChange = (value: string) => { + setEditingType(prev => prev ? { ...prev, value } : null); + const lower = value.toLowerCase(); + setTypeSuggestions( + lower ? allProductTypes.filter(t => t.toLowerCase().includes(lower)) : allProductTypes + ); + }; + // ── Column helpers ──────────────────────────────────────────────────────── const pricingEditableCols: DetectedCol[] = [ ...(uvpIdx >= 0 ? [{ index: uvpIdx, name: headers[uvpIdx] || 'UVP' }] : []), @@ -747,6 +780,11 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit, handleResizeStart(e, 'classification', columnWidths.classification)} /> + + Type + handleResizeStart(e, 'productType', columnWidths.productType)} /> + + {pricingEditableCols.map(col => { const colKey = `prc_${col.index}`; const width = columnWidths[colKey] ?? 100; @@ -1007,6 +1045,52 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit, + {/* TYPE cell */} + + {editingType?.rowIndex === dataIndex ? ( +
+ handleTypeInputChange(e.target.value)} + onKeyDown={e => { + if (e.key === 'Enter') commitTypeEdit(dataIndex, editingType.value); + if (e.key === 'Escape') { setEditingType(null); setTypeSuggestions([]); } + }} + onBlur={() => setTimeout(() => { commitTypeEdit(dataIndex, editingType?.value ?? ''); }, 150)} + className="w-full bg-slate-900 border border-purple-500 rounded px-2 py-1 text-sm text-white focus:outline-none focus:ring-1 focus:ring-purple-500" + /> + {typeSuggestions.length > 0 && ( +
    + {typeSuggestions.map(t => ( +
  • { e.preventDefault(); commitTypeEdit(dataIndex, t); }} + className="px-3 py-1.5 text-xs text-slate-200 hover:bg-purple-500/20 cursor-pointer truncate" + > + {t} +
  • + ))} +
+ )} +
+ ) : ( + + )} + + {/* Pricing editable cells */} {pricingEditableCols.map(col => { const isEditing = editingCell?.rowIndex === dataIndex && editingCell?.colIndex === col.index; diff --git a/src/types.ts b/src/types.ts index 71aa9d0..7689fe2 100644 --- a/src/types.ts +++ b/src/types.ts @@ -38,5 +38,6 @@ export const COLUMNS = { OUTER_H: 49, VERIFIED_DIMS: 100, VALIDATED_CHECK: 101, - VALIDATED_NOTE: 102 + VALIDATED_NOTE: 102, + PRODUCT_TYPE: 103 }; \ No newline at end of file