Skip to content

Commit 007a02f

Browse files
committed
Show progress for cut and paste
1 parent 9c18497 commit 007a02f

2 files changed

Lines changed: 43 additions & 13 deletions

File tree

frontend/src/components/Canvas.js

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2369,7 +2369,8 @@ function Canvas({
23692369
setUndoAvailable,
23702370
setRedoAvailable,
23712371
auth,
2372-
roomType
2372+
roomType,
2373+
showLocalSnack
23732374
);
23742375

23752376
// Draw a preview of a shape (for shape mode)
@@ -2545,6 +2546,7 @@ function Canvas({
25452546
setRedoStack([]);
25462547

25472548
const pasteRecordId = generateId();
2549+
showLocalSnack(`Pasting ${newDrawings.length} item(s)... Please wait.`);
25482550
console.log("[handlePaste] Starting paste operation:", {
25492551
pasteRecordId,
25502552
drawingCount: newDrawings.length,
@@ -2561,10 +2563,11 @@ function Canvas({
25612563
console.log("[handlePaste] Attached parentPasteId to all drawings:", pasteRecordId);
25622564

25632565
// Submit all pasted drawings as replacement/child strokes but DO NOT add each to the undo stack
2566+
let submittedCount = 0;
25642567
for (const newDrawing of newDrawings) {
25652568
try {
25662569
userData.addDrawing(newDrawing);
2567-
// skipUndoStack=true so these individual strokes don't create separate undo entries
2570+
25682571
await submitToDatabase(
25692572
newDrawing,
25702573
auth,
@@ -2573,6 +2576,9 @@ function Canvas({
25732576
setRedoAvailable
25742577
);
25752578
pastedDrawings.push(newDrawing);
2579+
submittedCount++;
2580+
2581+
showLocalSnack(`Pasting... ${submittedCount}/${newDrawings.length} items saved.`);
25762582
} catch (error) {
25772583
console.error("Failed to save drawing:", newDrawing, error);
25782584
handleAuthError(error);
@@ -2629,8 +2635,9 @@ function Canvas({
26292635
drawAllDrawings();
26302636
setCutImageData([]);
26312637
setDrawMode("freehand");
2638+
showLocalSnack(`Paste completed! ${pastedDrawings.length} item(s) pasted successfully.`);
26322639
} else {
2633-
showLocalSnack("Some strokes may not have been saved. Please try again.");
2640+
showLocalSnack(`Paste partially completed. ${pastedDrawings.length}/${newDrawings.length} items pasted.`);
26342641
}
26352642
};
26362643

@@ -3949,17 +3956,26 @@ function Canvas({
39493956
showLocalSnack("Cut is disabled in view-only mode.");
39503957
return;
39513958
}
3952-
const result = await handleCutSelection();
3953-
if (result && result.compositeCutAction) {
3954-
setUndoStack((prev) => [...prev, result.compositeCutAction]);
3955-
}
3956-
setIsRefreshing(true);
3959+
showLocalSnack("Cutting selection... This may take a moment.");
39573960
try {
3958-
await mergedRefreshCanvas();
3961+
const result = await handleCutSelection();
3962+
if (result && result.compositeCutAction) {
3963+
setUndoStack((prev) => [...prev, result.compositeCutAction]);
3964+
}
3965+
setIsRefreshing(true);
3966+
showLocalSnack("Syncing cut operation...");
3967+
try {
3968+
await mergedRefreshCanvas();
3969+
showLocalSnack("Cut completed successfully!");
3970+
} catch (e) {
3971+
console.error("Error syncing cut with server:", e);
3972+
showLocalSnack("Cut completed, but sync failed. Try refreshing.");
3973+
} finally {
3974+
setIsRefreshing(false);
3975+
}
39593976
} catch (e) {
3960-
console.error("Error syncing cut with server:", e);
3961-
} finally {
3962-
setIsRefreshing(false);
3977+
console.error("Error during cut:", e);
3978+
showLocalSnack("Cut operation failed. Please try again.");
39633979
}
39643980
}}
39653981
cutImageData={cutImageData}

frontend/src/hooks/useCanvasSelection.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import ClipperLib from 'clipper-lib';
33
import { submitToDatabase } from '../services/canvasBackendJWT';
44
import { Drawing } from '../lib/drawing';
55

6-
export function useCanvasSelection(canvasRef, currentUser, userData, generateId, drawAllDrawings, currentRoomId, setUndoAvailable, setRedoAvailable, auth, roomType) {
6+
export function useCanvasSelection(canvasRef, currentUser, userData, generateId, drawAllDrawings, currentRoomId, setUndoAvailable, setRedoAvailable, auth, roomType, showLocalSnack) {
77
const [selectionStart, setSelectionStart] = useState(null);
88
const [selectionRect, setSelectionRect] = useState(null);
99
const [cutImageData, setCutImageData] = useState(null);
@@ -172,7 +172,15 @@ export function useCanvasSelection(canvasRef, currentUser, userData, generateId,
172172
const newCutOriginalIds = new Set();
173173
const newCutStrokesMap = {};
174174

175+
const totalDrawings = userData.drawings.length;
176+
let processedCount = 0;
177+
175178
userData.drawings.forEach((drawing) => {
179+
processedCount++;
180+
181+
if (showLocalSnack) {
182+
showLocalSnack(`Processing cut... ${processedCount}/${totalDrawings} strokes analyzed.`);
183+
}
176184
if (Array.isArray(drawing.pathData)) {
177185
const points = drawing.pathData;
178186

@@ -533,9 +541,15 @@ export function useCanvasSelection(canvasRef, currentUser, userData, generateId,
533541
const allReplacementSegments = Object.values(newCutStrokesMap).flat();
534542
const replacementSegmentIds = allReplacementSegments.map(seg => seg.drawingId);
535543

544+
let savedSegmentCount = 0;
536545
for (const segment of allReplacementSegments) {
537546
try {
538547
await submitToDatabase(segment, auth, { roomId: currentRoomId, roomType, skipUndoCheck: true, skipUndoStack: true }, setUndoAvailable, setRedoAvailable);
548+
savedSegmentCount++;
549+
550+
if (showLocalSnack && allReplacementSegments.length > 0) {
551+
showLocalSnack(`Saving cut segments... ${savedSegmentCount}/${allReplacementSegments.length} saved.`);
552+
}
539553
} catch (error) {
540554
console.error("Failed to submit replacement segment:", segment, error);
541555
}

0 commit comments

Comments
 (0)