Implement premium Confirmation Modal for all data-modifying actions

This commit is contained in:
Christian Vidal Wolf
2026-03-29 18:26:20 +02:00
parent 7a86a8e64b
commit 99825af08c
3 changed files with 148 additions and 35 deletions
+34 -34
View File
@@ -2,6 +2,7 @@ import React, { useState, useMemo } from 'react';
import { ExcelRow, COLUMNS } from '../types';
import { AlertTriangle, CheckCircle2, ChevronDown, ChevronRight, Edit2, Package, Boxes, Scale, Loader2, RefreshCw, Layers } from 'lucide-react';
import { cn } from '../lib/utils';
import { ConfirmModal } from './ConfirmModal';
interface DimensionsViewProps {
data: ExcelRow[];
@@ -27,6 +28,11 @@ export function DimensionsView({ data, headers, onEdit, onSaveRow, onCaptureStat
const [expandedGroups, setExpandedGroups] = useState<Set<string>>(new Set());
const [showOnlyInconsistent, setShowOnlyInconsistent] = useState(true);
const [syncing, setSyncing] = useState<{ key: string, field: string } | null>(null);
const [pendingAction, setPendingAction] = useState<{
group: DimensionGroup,
sourceRow: ExcelRow,
fieldType: 'outer' | 'units' | 'moq' | 'all'
} | null>(null);
const groups = useMemo(() => {
const groupMap = new Map<string, { row: ExcelRow; index: number }[]>();
@@ -98,13 +104,21 @@ export function DimensionsView({ data, headers, onEdit, onSaveRow, onCaptureStat
};
const handleSyncField = async (group: DimensionGroup, sourceRow: ExcelRow, fieldType: 'outer' | 'units' | 'moq') => {
const fieldLabel = fieldType === 'outer' ? 'Outer Box Dimensions' : fieldType === 'units' ? 'Units per Outer' : 'MOQ';
if (!window.confirm(`Sync ALL products in this group to match "${fieldLabel}" from product ${sourceRow[COLUMNS.ARTICLE_NO]}?`)) {
return;
}
setPendingAction({ group, sourceRow, fieldType });
};
const handleFullSync = async (group: DimensionGroup, sourceRow: ExcelRow) => {
setPendingAction({ group, sourceRow, fieldType: 'all' });
};
const executeSync = async () => {
if (!pendingAction) return;
const { group, sourceRow, fieldType } = pendingAction;
const fieldLabel = fieldType === 'outer' ? 'Outer Box Dimensions' : fieldType === 'units' ? 'Units per Outer' : fieldType === 'moq' ? 'MOQ' : 'Full Packaging Data';
onCaptureState(`Bulk synced ${fieldLabel} in group ${group.innerDims}`);
setSyncing({ key: group.key, field: fieldType });
setPendingAction(null);
try {
const outerL = sourceRow[COLUMNS.OUTER_L];
@@ -125,6 +139,12 @@ export function DimensionsView({ data, headers, onEdit, onSaveRow, onCaptureStat
updatedRow[COLUMNS.UNITS_OUTER] = unitsOuter;
} else if (fieldType === 'moq') {
updatedRow[COLUMNS.MOQ] = moq;
} else if (fieldType === 'all') {
updatedRow[COLUMNS.OUTER_L] = outerL;
updatedRow[COLUMNS.OUTER_W] = outerW;
updatedRow[COLUMNS.OUTER_H] = outerH;
updatedRow[COLUMNS.UNITS_OUTER] = unitsOuter;
updatedRow[COLUMNS.MOQ] = moq;
}
await onSaveRow(index, updatedRow);
@@ -134,36 +154,6 @@ export function DimensionsView({ data, headers, onEdit, onSaveRow, onCaptureStat
}
};
const handleFullSync = async (group: DimensionGroup, sourceRow: ExcelRow) => {
if (!window.confirm(`Sync ALL Packaging & MOQ data in this group to match product ${sourceRow[COLUMNS.ARTICLE_NO]}?`)) {
return;
}
onCaptureState(`Full sync of packaging data in group ${group.innerDims}`);
setSyncing({ key: group.key, field: 'all' });
try {
const outerL = sourceRow[COLUMNS.OUTER_L];
const outerW = sourceRow[COLUMNS.OUTER_W];
const outerH = sourceRow[COLUMNS.OUTER_H];
const unitsOuter = sourceRow[COLUMNS.UNITS_OUTER];
const moq = sourceRow[COLUMNS.MOQ];
for (const { row, index } of group.rows) {
if (row === sourceRow) continue;
const updatedRow = [...row];
updatedRow[COLUMNS.OUTER_L] = outerL;
updatedRow[COLUMNS.OUTER_W] = outerW;
updatedRow[COLUMNS.OUTER_H] = outerH;
updatedRow[COLUMNS.UNITS_OUTER] = unitsOuter;
updatedRow[COLUMNS.MOQ] = moq;
await onSaveRow(index, updatedRow);
}
} finally {
setSyncing(null);
}
};
return (
<div className="space-y-6">
<div className="flex items-center justify-between bg-slate-800/50 p-4 rounded-lg border border-slate-700">
@@ -363,6 +353,16 @@ export function DimensionsView({ data, headers, onEdit, onSaveRow, onCaptureStat
</div>
)}
</div>
<ConfirmModal
isOpen={!!pendingAction}
onConfirm={executeSync}
onCancel={() => setPendingAction(null)}
title="Sync Group Data"
message={`Are you sure you want to sync ${pendingAction?.fieldType === 'all' ? 'ALL packaging data' : pendingAction?.fieldType} for the whole group using product ${pendingAction?.sourceRow[COLUMNS.ARTICLE_NO]} as the template?`}
type="warning"
confirmText="Sync Group"
/>
</div>
);
}