From f86709f45e956bb91fe960ee5f23bcc612df9443 Mon Sep 17 00:00:00 2001 From: Nico Date: Thu, 4 Jun 2026 06:32:17 -0700 Subject: [PATCH] fix: pan mobile map while editing --- .../src/components/maps/LocationMapCanvas.jsx | 3 +- frontend/tests/location-map-manager.spec.ts | 67 +++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/maps/LocationMapCanvas.jsx b/frontend/src/components/maps/LocationMapCanvas.jsx index c4df4e9..929c50e 100644 --- a/frontend/src/components/maps/LocationMapCanvas.jsx +++ b/frontend/src/components/maps/LocationMapCanvas.jsx @@ -32,7 +32,7 @@ export default function LocationMapCanvas({ updateObjects, }) { const canEditObjects = !editingLocked && mode === "edit" && editorTool === "edit"; - const canDragPan = mode === "view" || editorTool === "pan"; + const canDragPan = mode === "view" || editorTool === "pan" || canEditObjects; const hiddenByZonesLayer = objects.length > 0 && !filters.showZones; const visibleObjectCount = filters.showZones ? objects.filter((object) => object.visible).length @@ -206,6 +206,7 @@ export default function LocationMapCanvas({ const startPan = (event) => { if (!canDragPan || !scrollRef.current || event.button !== 0) return; const objectElement = event.target.closest?.(".location-map-object"); + if (canEditObjects && objectElement) return; event.currentTarget.setPointerCapture?.(event.pointerId); panDragRef.current = { startX: event.clientX, diff --git a/frontend/tests/location-map-manager.spec.ts b/frontend/tests/location-map-manager.spec.ts index eaa1d8e..3a74180 100644 --- a/frontend/tests/location-map-manager.spec.ts +++ b/frontend/tests/location-map-manager.spec.ts @@ -2673,6 +2673,73 @@ test("mobile editor uses bottom sheet controls instead of desktop object toolbar await expect(page.getByRole("textbox", { name: "Label" })).toHaveCount(0); }); +test("mobile editor pans from empty map space without moving areas", async ({ page }) => { + await page.setViewportSize({ width: 390, height: 844 }); + await mockMapShell(page); + + const mapState = draftMapState([ + { + id: 1611, + location_map_id: 900, + zone_id: 501, + zone_name: "Bakery", + type: "zone", + label: "Bakery", + x: 40, + y: 40, + width: 260, + height: 160, + rotation: 0, + locked: false, + visible: true, + sort_order: 1, + }, + ], true); + + await page.route("**/households/1/locations/10/map", async (route) => { + await route.fulfill({ + status: 200, + contentType: "application/json", + body: JSON.stringify(mapState), + }); + }); + + await page.goto("/stores/100/locations/10/map"); + await page.getByRole("button", { name: "Continue Editing" }).click(); + + const scroll = page.locator(".location-map-scroll"); + const scrollBox = await scroll.boundingBox(); + expect(scrollBox).not.toBeNull(); + if (!scrollBox) throw new Error("Mobile edit map scroll area was not measurable"); + + const bakeryArea = page.locator('[data-object-key="1611"]').locator("rect").first(); + await expect(bakeryArea).toHaveAttribute("x", "40"); + await expect(bakeryArea).toHaveAttribute("y", "40"); + + const beforePan = await scroll.evaluate((element) => ({ + left: element.scrollLeft, + top: element.scrollTop, + })); + expect(beforePan).toEqual({ left: 0, top: 0 }); + + const startX = scrollBox.x + scrollBox.width - 48; + const startY = scrollBox.y + scrollBox.height - 48; + await page.mouse.move(startX, startY); + await page.mouse.down(); + await page.mouse.move(startX - 140, startY - 100, { steps: 8 }); + await page.mouse.up(); + + await expect.poll(async () => + scroll.evaluate((element) => element.scrollLeft) + ).toBeGreaterThan(80); + await expect.poll(async () => + scroll.evaluate((element) => element.scrollTop) + ).toBeGreaterThan(50); + await expect(bakeryArea).toHaveAttribute("x", "40"); + await expect(bakeryArea).toHaveAttribute("y", "40"); + await expect(page.locator(".location-map-status")).toHaveText("Draft"); +}); + test("members can view a published map but cannot edit it", async ({ page }) => { await mockMapShell(page, memberHousehold);