From 932033682de708c063a1342ee9a0e6df2b89eeb6 Mon Sep 17 00:00:00 2001 From: Nico Date: Thu, 4 Jun 2026 23:21:07 -0700 Subject: [PATCH] fix: ignore no-op map edge edits --- .../src/components/maps/LocationMapCanvas.jsx | 58 +++++++++++++------ frontend/tests/location-map-manager.spec.ts | 8 ++- 2 files changed, 46 insertions(+), 20 deletions(-) diff --git a/frontend/src/components/maps/LocationMapCanvas.jsx b/frontend/src/components/maps/LocationMapCanvas.jsx index d44a568..62ee76b 100644 --- a/frontend/src/components/maps/LocationMapCanvas.jsx +++ b/frontend/src/components/maps/LocationMapCanvas.jsx @@ -38,6 +38,31 @@ function clampResizedObjectToMap(object, mapSize) { }; } +function hasObjectBoundsChanged(object, nextObject) { + return ( + object.x !== nextObject.x || + object.y !== nextObject.y || + object.width !== nextObject.width || + object.height !== nextObject.height + ); +} + +function getDraggedObjectUpdate(object, dragState, deltaX, deltaY, mapSize) { + if (dragState.type === "resize") { + return clampResizedObjectToMap({ + ...object, + width: Math.max(40, dragState.startObject.width + deltaX), + height: Math.max(40, dragState.startObject.height + deltaY), + }, mapSize); + } + + return clampObjectToMap({ + ...object, + x: dragState.startObject.x + deltaX, + y: dragState.startObject.y + deltaY, + }, mapSize); +} + export default function LocationMapCanvas({ mode, objects, @@ -198,6 +223,11 @@ export default function LocationMapCanvas({ Math.abs(deltaY) >= DRAG_CHANGE_THRESHOLD; if (!hasMeaningfulChange) return; + const draggedObject = objects.find((object) => getObjectKey(object) === dragState.key); + if (!draggedObject) return; + const nextDraggedObject = getDraggedObjectUpdate(draggedObject, dragState, deltaX, deltaY, mapSize); + if (!hasObjectBoundsChanged(draggedObject, nextDraggedObject)) return; + if (!objectDragHistoryCapturedRef.current) { remember(); objectDragHistoryCapturedRef.current = true; @@ -206,18 +236,7 @@ export default function LocationMapCanvas({ updateObjects((currentObjects) => currentObjects.map((object) => { if (getObjectKey(object) !== dragState.key) return object; - if (dragState.type === "resize") { - return clampResizedObjectToMap({ - ...object, - width: Math.max(40, dragState.startObject.width + deltaX), - height: Math.max(40, dragState.startObject.height + deltaY), - }, mapSize); - } - return clampObjectToMap({ - ...object, - x: dragState.startObject.x + deltaX, - y: dragState.startObject.y + deltaY, - }, mapSize); + return getDraggedObjectUpdate(object, dragState, deltaX, deltaY, mapSize); }) ); }; @@ -264,17 +283,20 @@ export default function LocationMapCanvas({ const nudgeAmount = event.shiftKey ? 25 : 10; const deltaX = event.key === "ArrowLeft" ? -nudgeAmount : event.key === "ArrowRight" ? nudgeAmount : 0; const deltaY = event.key === "ArrowUp" ? -nudgeAmount : event.key === "ArrowDown" ? nudgeAmount : 0; + const nextObject = clampObjectToMap({ + ...object, + x: object.x + deltaX, + y: object.y + deltaY, + }, mapSize); + + setSelectedObjectKey(getObjectKey(object)); + if (!hasObjectBoundsChanged(object, nextObject)) return; remember(); - setSelectedObjectKey(getObjectKey(object)); updateObjects((currentObjects) => currentObjects.map((candidate) => getObjectKey(candidate) === getObjectKey(object) - ? clampObjectToMap({ - ...candidate, - x: candidate.x + deltaX, - y: candidate.y + deltaY, - }, mapSize) + ? nextObject : candidate ) ); diff --git a/frontend/tests/location-map-manager.spec.ts b/frontend/tests/location-map-manager.spec.ts index c244d0c..5b90566 100644 --- a/frontend/tests/location-map-manager.spec.ts +++ b/frontend/tests/location-map-manager.spec.ts @@ -2131,7 +2131,9 @@ test("admin cannot nudge map areas outside the canvas", async ({ page }) => { await expect(bakeryArea).toHaveAttribute("x", "740"); await expect(bakeryArea).toHaveAttribute("y", "540"); - await expect(page.locator(".location-map-status")).toHaveText("Unsaved Draft"); + await expect(page.locator(".location-map-status")).toHaveText("Draft"); + await expect(page.getByRole("button", { name: "Save Draft" })).toHaveCount(0); + await expect(page.getByRole("button", { name: "Undo" })).toBeDisabled(); }); test("admin cannot resize map areas beyond the canvas", async ({ page }) => { @@ -2191,7 +2193,9 @@ test("admin cannot resize map areas beyond the canvas", async ({ page }) => { await expect(bakeryArea).toHaveAttribute("y", "580"); await expect(bakeryArea).toHaveAttribute("width", "180"); await expect(bakeryArea).toHaveAttribute("height", "120"); - await expect(page.locator(".location-map-status")).toHaveText("Unsaved Draft"); + await expect(page.locator(".location-map-status")).toHaveText("Draft"); + await expect(page.getByRole("button", { name: "Save Draft" })).toHaveCount(0); + await expect(page.getByRole("button", { name: "Undo" })).toBeDisabled(); }); test("admin selected map area uses compact editable fields", async ({ page }) => {