mirror of
https://github.com/christianvidalwolf-prog/Craze-Data-check.git
synced 2026-08-03 13:35:25 +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,
|
line: 100,
|
||||||
classification: 130,
|
classification: 130,
|
||||||
productType: 140,
|
productType: 140,
|
||||||
|
empco: 110,
|
||||||
itemToLogistic: 160,
|
itemToLogistic: 160,
|
||||||
unitsOuter: 100,
|
unitsOuter: 100,
|
||||||
outerW: 80,
|
outerW: 80,
|
||||||
@@ -244,7 +245,7 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
|||||||
}, [resizingColumn, resizeStartX, resizeStartWidth]);
|
}, [resizingColumn, resizeStartX, resizeStartWidth]);
|
||||||
|
|
||||||
// ── Dynamic column detection ──────────────────────────────────────────────
|
// ── 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');
|
const uvpIdx = findCol(headers, 'uvp');
|
||||||
|
|
||||||
// All SRP columns, sorted: INT first, UK second, then alphabetically
|
// 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');
|
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]);
|
}, [headers, COLUMNS]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -616,6 +620,7 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
|||||||
case 'line': colIndex = COLUMNS.LINE; break;
|
case 'line': colIndex = COLUMNS.LINE; break;
|
||||||
case 'classification': colIndex = COLUMNS.CLASSIFICATION; break;
|
case 'classification': colIndex = COLUMNS.CLASSIFICATION; break;
|
||||||
case 'productType': colIndex = COLUMNS.CATEGORIZATION_CODE; break;
|
case 'productType': colIndex = COLUMNS.CATEGORIZATION_CODE; break;
|
||||||
|
case 'empco': colIndex = empcoIdx; break;
|
||||||
case 'unitsOuter': colIndex = unitsOuterIdx; break;
|
case 'unitsOuter': colIndex = unitsOuterIdx; break;
|
||||||
case 'outerW': colIndex = COLUMNS.OUTER_W; break;
|
case 'outerW': colIndex = COLUMNS.OUTER_W; break;
|
||||||
case 'outerL': colIndex = COLUMNS.OUTER_L; 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: 'line', label: 'Line', index: COLUMNS.LINE },
|
||||||
{ key: 'classification', label: 'Classification', index: COLUMNS.CLASSIFICATION },
|
{ key: 'classification', label: 'Classification', index: COLUMNS.CLASSIFICATION },
|
||||||
{ key: 'productType', label: 'CategorizationCode', index: COLUMNS.CATEGORIZATION_CODE },
|
{ 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: 'itemToLogistic', label: 'Item to Logistic', index: COLUMNS.ITEM_TO_LOGISTIC },
|
||||||
{ key: 'unitsOuter', label: 'Units/Outer', index: unitsOuterIdx },
|
{ key: 'unitsOuter', label: 'Units/Outer', index: unitsOuterIdx },
|
||||||
{ key: 'outerW', label: 'Outer W', index: COLUMNS.OUTER_W },
|
{ 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 });
|
cols.push({ key: `con_${col.index}`, label: col.name, index: col.index });
|
||||||
});
|
});
|
||||||
return cols;
|
return cols;
|
||||||
}, [COLUMNS, unitsOuterIdx, pricingEditableCols, containerCols]);
|
}, [COLUMNS, unitsOuterIdx, empcoIdx, pricingEditableCols, containerCols]);
|
||||||
|
|
||||||
const togglePinnedColumn = (key: string) => {
|
const togglePinnedColumn = (key: string) => {
|
||||||
setPinnedColumns(prev => {
|
setPinnedColumns(prev => {
|
||||||
@@ -791,7 +797,7 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
|||||||
|
|
||||||
// Calculate sticky left position for each pinned column
|
// Calculate sticky left position for each pinned column
|
||||||
const getStickyLeft = useMemo(() => {
|
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[] = [];
|
const dynamicOrder: string[] = [];
|
||||||
pricingEditableCols.forEach(col => dynamicOrder.push(`prc_${col.index}`));
|
pricingEditableCols.forEach(col => dynamicOrder.push(`prc_${col.index}`));
|
||||||
containerCols.forEach(col => dynamicOrder.push(`con_${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)
|
// Calculate z-index for sticky columns (so they stack correctly)
|
||||||
const getStickyRank = useMemo(() => {
|
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[] = [];
|
const dynamicOrder: string[] = [];
|
||||||
pricingEditableCols.forEach(col => dynamicOrder.push(`prc_${col.index}`));
|
pricingEditableCols.forEach(col => dynamicOrder.push(`prc_${col.index}`));
|
||||||
containerCols.forEach(col => dynamicOrder.push(`con_${col.index}`));
|
containerCols.forEach(col => dynamicOrder.push(`con_${col.index}`));
|
||||||
@@ -1545,6 +1551,17 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
|||||||
<ResizeHandle onMouseDown={e => { e.stopPropagation(); handleResizeStart(e, 'productType', columnWidths.productType); }} />
|
<ResizeHandle onMouseDown={e => { e.stopPropagation(); handleResizeStart(e, 'productType', columnWidths.productType); }} />
|
||||||
</th>
|
</th>
|
||||||
|
|
||||||
|
<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={{
|
<th style={{
|
||||||
width: columnWidths.itemToLogistic,
|
width: columnWidths.itemToLogistic,
|
||||||
...(isPinned('itemToLogistic')
|
...(isPinned('itemToLogistic')
|
||||||
@@ -2111,6 +2128,20 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
|||||||
)}
|
)}
|
||||||
</td>
|
</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 */}
|
{/* 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 } : {}}>
|
<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 ? (
|
{editingLogistic?.rowIndex === dataIndex ? (
|
||||||
|
|||||||
Reference in New Issue
Block a user