From 2b994e3c86c94db0a17f8403f46a0becc1e0ef58 Mon Sep 17 00:00:00 2001 From: Christian Vidal Wolf Date: Tue, 21 Apr 2026 09:03:01 +0200 Subject: [PATCH] feat: implement resizable columns in Pricing Units tab --- src/components/PricingView.tsx | 290 +++++++++++++++++++-------------- 1 file changed, 164 insertions(+), 126 deletions(-) diff --git a/src/components/PricingView.tsx b/src/components/PricingView.tsx index 492ab5e..20c986c 100644 --- a/src/components/PricingView.tsx +++ b/src/components/PricingView.tsx @@ -56,6 +56,12 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit, articleName: 220, line: 100, classification: 130, + unitsOuter: 100, + outerW: 80, + outerL: 80, + outerH: 80, + check: 100, + actions: 60, }); const [resizingColumn, setResizingColumn] = useState(null); const [resizeStartX, setResizeStartX] = useState(null); @@ -135,7 +141,7 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit, const handleMouseMove = (e: MouseEvent) => { const delta = e.clientX - resizeStartX; - const newWidth = Math.max(50, Math.min(400, resizeStartWidth + delta)); + const newWidth = Math.max(40, Math.min(800, resizeStartWidth + delta)); setColumnWidths(prev => ({ ...prev, [resizingColumn]: newWidth })); }; @@ -659,26 +665,22 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,

All products are correctly configured.

) : ( - +
- - - - - {pricingEditableCols.map(col => ( - - ))} + {pricingEditableCols.map(col => { + const colKey = `prc_${col.index}`; + const width = columnWidths[colKey] ?? 100; + return ( + + ); + })} - - - - - {containerCols.map(col => ( - - ))} + {containerCols.map(col => { + const colKey = `con_${col.index}`; + const width = columnWidths[colKey] ?? 110; + return ( + + ); + })} - {/* Validation Check Column */} - - {/* All remaining Matrix columns */} - {matrixCols.map(col => ( - - ))} + {matrixCols.map(col => { + const colKey = `mat_${col.index}`; + const width = columnWidths[colKey] ?? 120; + return ( + + ); + })} - {/* Actions */} - @@ -953,7 +977,7 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit, )} > {/* Art. No. */} - @@ -965,14 +989,14 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit, {/* Line */} - {/* Classification */} - - - - + + + {/* Container units columns */} {containerCols.map(col => ( - ))} @@ -1139,6 +1163,20 @@ function TextFilterPopover({ value, onChange, onClose }: { ); } +// ── Resize Handle Component ───────────────────────────────────────────── +function ResizeHandle({ onMouseDown }: { onMouseDown: (e: React.MouseEvent) => void }) { + return ( +
e.stopPropagation()} + className="absolute right-0 top-0 bottom-0 w-1.5 hover:bg-blue-500/50 cursor-col-resize group/resizer flex items-center justify-center z-20" + title="Drag to resize" + > +
+
+ ); +} + // ── Stat card ───────────────────────────────────────────────────────────────── function StatCard({ label,
-
+
+
Art. No. -
handleResizeStart(e, 'articleNo', columnWidths.articleNo || 100)} - onClick={(e) => e.stopPropagation()} - className="w-1.5 h-4 bg-slate-600 hover:bg-blue-500 cursor-col-resize rounded-sm ml-1 shrink-0 pointer-events-auto" - title="Drag to resize" - />
+ handleResizeStart(e, 'articleNo', columnWidths.articleNo)} />
-
Article Name +
+
+ Article Name
+
- Line + Line
+
- Classification + Classification
-
- {col.name} - -
- {openFilter === `prc_${col.index}` && ( - setDynamicColFilters(prev => { - const current = prev[col.index] || []; - return current.includes(val) - ? { ...prev, [col.index]: current.filter(v => v !== val) } - : { ...prev, [col.index]: [...current, val] }; - })} - onSelectAll={vals => setDynamicColFilters(prev => ({ ...prev, [col.index]: vals }))} - onClear={() => { setDynamicColFilters(prev => { const next = { ...prev }; delete next[col.index]; return next; }); setOpenFilter(null); }} - onClose={() => setOpenFilter(null)} - /> - )} -
+
+ {col.name} + +
+ {openFilter === `prc_${col.index}` && ( + setDynamicColFilters(prev => { + const current = prev[col.index] || []; + return current.includes(val) + ? { ...prev, [col.index]: current.filter(v => v !== val) } + : { ...prev, [col.index]: [...current, val] }; + })} + onSelectAll={vals => setDynamicColFilters(prev => ({ ...prev, [col.index]: vals }))} + onClear={() => { setDynamicColFilters(prev => { const next = { ...prev }; delete next[col.index]; return next; }); setOpenFilter(null); }} + onClose={() => setOpenFilter(null)} + /> + )} + handleResizeStart(e, colKey, width)} /> +
+
- Units/Outer + Units/Outer
+
- Outer W + Outer W
+
- Outer L + Outer L
+
- Outer H + Outer H
-
- {col.name} - -
- {openFilter === `con_${col.index}` && ( - setDynamicColFilters(prev => { - const current = prev[col.index] || []; - return current.includes(val) - ? { ...prev, [col.index]: current.filter(v => v !== val) } - : { ...prev, [col.index]: [...current, val] }; - })} - onSelectAll={vals => setDynamicColFilters(prev => ({ ...prev, [col.index]: vals }))} - onClear={() => { setDynamicColFilters(prev => { const next = { ...prev }; delete next[col.index]; return next; }); setOpenFilter(null); }} - onClose={() => setOpenFilter(null)} - /> - )} -
+
+ {col.name} + +
+ {openFilter === `con_${col.index}` && ( + setDynamicColFilters(prev => { + const current = prev[col.index] || []; + return current.includes(val) + ? { ...prev, [col.index]: current.filter(v => v !== val) } + : { ...prev, [col.index]: [...current, val] }; + })} + onSelectAll={vals => setDynamicColFilters(prev => ({ ...prev, [col.index]: vals }))} + onClear={() => { setDynamicColFilters(prev => { const next = { ...prev }; delete next[col.index]; return next; }); setOpenFilter(null); }} + onClose={() => setOpenFilter(null)} + /> + )} + handleResizeStart(e, colKey, width)} /> +
+ Check + handleResizeStart(e, 'check', columnWidths.check)} /> - {col.name} - + {col.name} + handleResizeStart(e, colKey, width)} /> + + + handleResizeStart(e, 'actions', columnWidths.actions)} /> +
+ {row[COLUMNS.ARTICLE_NO]} + {row[COLUMNS.LINE] || '—'} + + {isEditing ? (
setEditingCell(prev => prev ? { ...prev, value: e.target.value } : null)} onKeyDown={handleKeyDown} onBlur={commitEdit} - className="w-24 bg-slate-900 border border-blue-500 rounded px-2 py-1 text-sm text-white focus:outline-none focus:ring-1 focus:ring-blue-500" + className="w-full bg-slate-900 border border-blue-500 rounded px-2 py-1 text-sm text-white focus:outline-none focus:ring-1 focus:ring-blue-500" /> -
) : ( )} @@ -1033,13 +1057,13 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit, {/* Units columns */}
{unitOuterBadge(row[COLUMNS.UNITS_OUTER])}{row[COLUMNS.OUTER_W] ?? '-'}{row[COLUMNS.OUTER_L] ?? '-'}{row[COLUMNS.OUTER_H] ?? '-'}{row[COLUMNS.OUTER_W] ?? '-'}{row[COLUMNS.OUTER_L] ?? '-'}{row[COLUMNS.OUTER_H] ?? '-'} + {unitBadge(row[col.index], col.name)}