mirror of
https://github.com/christianvidalwolf-prog/Craze-Data-check.git
synced 2026-08-03 11:45:24 +02:00
feat(pricing): add EMCO Compliant column next to CategorizationCode
Read-only Yes/No badge sourced from the matrix EmpCO_Compliant column (detected dynamically by header; shows '-' until the new matrix layout is live in Dropbox). Sortable, pinnable and resizable like the rest. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
0d50fce790
commit
0c152a4742
@@ -70,6 +70,7 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
line: 100,
|
||||
classification: 130,
|
||||
productType: 140,
|
||||
empco: 110,
|
||||
itemToLogistic: 160,
|
||||
unitsOuter: 100,
|
||||
outerW: 80,
|
||||
@@ -244,7 +245,7 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
}, [resizingColumn, resizeStartX, resizeStartWidth]);
|
||||
|
||||
// ── Dynamic column detection ──────────────────────────────────────────────
|
||||
const { uvpIdx, srpCols, containerCols, nwIdx, gwIdx, unitsOuterIdx, units40fIdx } = useMemo(() => {
|
||||
const { uvpIdx, srpCols, containerCols, nwIdx, gwIdx, unitsOuterIdx, units40fIdx, empcoIdx } = useMemo(() => {
|
||||
const uvpIdx = findCol(headers, 'uvp');
|
||||
|
||||
// All SRP columns, sorted: INT first, UK second, then alphabetically
|
||||
@@ -273,7 +274,10 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
|
||||
const units40fIdx = findCol(headers, '40f');
|
||||
|
||||
return { uvpIdx, srpCols: srp, containerCols: container, nwIdx, gwIdx, unitsOuterIdx, units40fIdx };
|
||||
// EmpCO_Compliant column from the matrix file (empty until the new layout is live)
|
||||
const empcoIdx = findCol(headers, 'empco');
|
||||
|
||||
return { uvpIdx, srpCols: srp, containerCols: container, nwIdx, gwIdx, unitsOuterIdx, units40fIdx, empcoIdx };
|
||||
}, [headers, COLUMNS]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -616,6 +620,7 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
case 'line': colIndex = COLUMNS.LINE; break;
|
||||
case 'classification': colIndex = COLUMNS.CLASSIFICATION; break;
|
||||
case 'productType': colIndex = COLUMNS.CATEGORIZATION_CODE; break;
|
||||
case 'empco': colIndex = empcoIdx; break;
|
||||
case 'unitsOuter': colIndex = unitsOuterIdx; break;
|
||||
case 'outerW': colIndex = COLUMNS.OUTER_W; break;
|
||||
case 'outerL': colIndex = COLUMNS.OUTER_L; break;
|
||||
@@ -761,6 +766,7 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
{ key: 'line', label: 'Line', index: COLUMNS.LINE },
|
||||
{ key: 'classification', label: 'Classification', index: COLUMNS.CLASSIFICATION },
|
||||
{ key: 'productType', label: 'CategorizationCode', index: COLUMNS.CATEGORIZATION_CODE },
|
||||
{ key: 'empco', label: 'EMCO Compliant', index: empcoIdx },
|
||||
{ key: 'itemToLogistic', label: 'Item to Logistic', index: COLUMNS.ITEM_TO_LOGISTIC },
|
||||
{ key: 'unitsOuter', label: 'Units/Outer', index: unitsOuterIdx },
|
||||
{ key: 'outerW', label: 'Outer W', index: COLUMNS.OUTER_W },
|
||||
@@ -775,7 +781,7 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
cols.push({ key: `con_${col.index}`, label: col.name, index: col.index });
|
||||
});
|
||||
return cols;
|
||||
}, [COLUMNS, unitsOuterIdx, pricingEditableCols, containerCols]);
|
||||
}, [COLUMNS, unitsOuterIdx, empcoIdx, pricingEditableCols, containerCols]);
|
||||
|
||||
const togglePinnedColumn = (key: string) => {
|
||||
setPinnedColumns(prev => {
|
||||
@@ -791,7 +797,7 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
|
||||
// Calculate sticky left position for each pinned column
|
||||
const getStickyLeft = useMemo(() => {
|
||||
const baseOrder = ['articleNo', 'articleName', 'line', 'classification', 'productType', 'itemToLogistic', 'unitsOuter', 'outerW', 'outerL', 'outerH', 'moq'];
|
||||
const baseOrder = ['articleNo', 'articleName', 'line', 'classification', 'productType', 'empco', 'itemToLogistic', 'unitsOuter', 'outerW', 'outerL', 'outerH', 'moq'];
|
||||
const dynamicOrder: string[] = [];
|
||||
pricingEditableCols.forEach(col => dynamicOrder.push(`prc_${col.index}`));
|
||||
containerCols.forEach(col => dynamicOrder.push(`con_${col.index}`));
|
||||
@@ -816,7 +822,7 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
|
||||
// Calculate z-index for sticky columns (so they stack correctly)
|
||||
const getStickyRank = useMemo(() => {
|
||||
const baseOrder = ['articleNo', 'articleName', 'line', 'classification', 'productType', 'itemToLogistic', 'unitsOuter', 'outerW', 'outerL', 'outerH', 'moq'];
|
||||
const baseOrder = ['articleNo', 'articleName', 'line', 'classification', 'productType', 'empco', 'itemToLogistic', 'unitsOuter', 'outerW', 'outerL', 'outerH', 'moq'];
|
||||
const dynamicOrder: string[] = [];
|
||||
pricingEditableCols.forEach(col => dynamicOrder.push(`prc_${col.index}`));
|
||||
containerCols.forEach(col => dynamicOrder.push(`con_${col.index}`));
|
||||
@@ -1545,8 +1551,19 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
<ResizeHandle onMouseDown={e => { e.stopPropagation(); handleResizeStart(e, 'productType', columnWidths.productType); }} />
|
||||
</th>
|
||||
|
||||
<th style={{
|
||||
width: columnWidths.itemToLogistic,
|
||||
<th style={{ width: columnWidths.empco, ...(isPinned('empco') ? { left: getStickyLeft('empco') ?? 0, zIndex: getHeaderStickyRank('empco') ?? 0 } : {}) }} className={cn(
|
||||
"text-left px-3 py-3 text-xs font-semibold text-teal-400 uppercase tracking-wider whitespace-nowrap group cursor-pointer hover:bg-slate-800/50 transition-colors relative",
|
||||
isPinned('empco') && "sticky bg-slate-900"
|
||||
)} onClick={() => handleSort('empco')}>
|
||||
<span className="flex items-center gap-1">
|
||||
{isPinned('empco') && <Pin className="w-3 h-3 text-blue-400 shrink-0" />}
|
||||
EMCO Compliant <SortIcon current={sortConfig.key === 'empco' ? sortConfig.direction : null} />
|
||||
</span>
|
||||
<ResizeHandle onMouseDown={e => { e.stopPropagation(); handleResizeStart(e, 'empco', columnWidths.empco); }} />
|
||||
</th>
|
||||
|
||||
<th style={{
|
||||
width: columnWidths.itemToLogistic,
|
||||
...(isPinned('itemToLogistic')
|
||||
? { left: getStickyLeft('itemToLogistic') ?? 0, zIndex: openFilter === 'logistic' ? 500 : (getHeaderStickyRank('itemToLogistic') ?? 0) }
|
||||
: (openFilter === 'logistic' ? { zIndex: 500, position: 'relative' } : {}))
|
||||
@@ -2111,6 +2128,20 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
)}
|
||||
</td>
|
||||
|
||||
{/* EMCO Compliant cell (read-only, from matrix file) */}
|
||||
<td className={cn("px-3 py-2 relative", isPinned('empco') && "sticky bg-slate-800")} style={isPinned('empco') ? { left: getStickyLeft('empco') ?? 0, zIndex: getStickyRank('empco') ?? 0 } : {}}>
|
||||
{(() => {
|
||||
const raw = empcoIdx >= 0 ? String(row[empcoIdx] ?? '').trim().toLowerCase() : '';
|
||||
if (raw === 'true' || raw === 'yes') {
|
||||
return <span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-teal-500/10 text-teal-300 border border-teal-500/30">Yes</span>;
|
||||
}
|
||||
if (raw === 'false' || raw === 'no') {
|
||||
return <span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-500/10 text-red-300 border border-red-500/30">No</span>;
|
||||
}
|
||||
return <span className="text-xs text-slate-500">-</span>;
|
||||
})()}
|
||||
</td>
|
||||
|
||||
{/* ITEM TO LOGISTIC cell */}
|
||||
<td className={cn("px-3 py-2 overflow-visible relative", isPinned('itemToLogistic') && "sticky bg-slate-800")} style={isPinned('itemToLogistic') ? { left: getStickyLeft('itemToLogistic') ?? 0, zIndex: getStickyRank('itemToLogistic') ?? 0 } : {}}>
|
||||
{editingLogistic?.rowIndex === dataIndex ? (
|
||||
|
||||
Reference in New Issue
Block a user