From 2b534eed6a4796447a2a632ce1b39eb2ab39b7d0 Mon Sep 17 00:00:00 2001 From: Nico Date: Wed, 3 Jun 2026 23:47:24 -0700 Subject: [PATCH] fix: hide draft maps from members --- frontend/src/pages/LocationMapManager.jsx | 25 +++++++++++-- frontend/tests/location-map-manager.spec.ts | 41 +++++++++++++++++++++ 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/frontend/src/pages/LocationMapManager.jsx b/frontend/src/pages/LocationMapManager.jsx index a99506d..034e93f 100644 --- a/frontend/src/pages/LocationMapManager.jsx +++ b/frontend/src/pages/LocationMapManager.jsx @@ -123,6 +123,9 @@ export default function LocationMapManager() { try { const response = await getLocationMap(activeHousehold.id, locationId); const nextState = response.data; + const nextCanManage = Boolean( + nextState.can_manage ?? ["owner", "admin"].includes(activeHousehold?.role) + ); setMapState(nextState); if (!nextState.draft_map && !nextState.published_map) { @@ -143,10 +146,25 @@ export default function LocationMapManager() { setMode("view"); setEditorTool("pan"); setPreviewDraft(false); - } else if (nextState.draft_map) { + } else if (nextState.draft_map && nextCanManage) { setMode("setup"); setEditorTool("pan"); setPreviewDraft(true); + } else { + setMode("setup"); + setEditorTool("pan"); + setPreviewDraft(false); + setObjects([]); + setSelectedObjectKey(null); + setHistory([]); + setFuture([]); + setHasUnsavedChanges(false); + setMapDraft({ + name: "Store Map", + width: DEFAULT_MAP_SIZE.width, + height: DEFAULT_MAP_SIZE.height, + }); + return; } syncMapDraftFromState( @@ -161,7 +179,7 @@ export default function LocationMapManager() { } finally { setLoading(false); } - }, [activeHousehold?.id, locationId, syncMapDraftFromState]); + }, [activeHousehold?.id, activeHousehold?.role, locationId, syncMapDraftFromState]); useEffect(() => { toastRef.current = toast; @@ -506,6 +524,7 @@ export default function LocationMapManager() { } const hasAnyMap = Boolean(mapState?.draft_map || mapState?.published_map); + const hasVisibleOrManageableMap = Boolean(mapState?.published_map || (mapState?.draft_map && canManage)); const status = getMapStatus(mapState, { mode, previewDraft, hasUnsavedChanges }); return ( @@ -532,7 +551,7 @@ export default function LocationMapManager() { {!hasAnyMap || (mode === "setup" && mapState?.draft_map && !mapState?.published_map) ? ( { + await mockMapShell(page, memberHousehold); + + const mapState = draftMapState([ + { + id: 1701, + location_map_id: 900, + zone_id: 501, + zone_name: "Bakery", + type: "zone", + label: "Draft Bakery", + x: 40, + y: 40, + width: 260, + height: 160, + rotation: 0, + locked: false, + visible: true, + sort_order: 1, + }, + ], false); + + 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 expect(page.getByRole("heading", { name: "No Map" })).toBeVisible(); + await expect(page.getByText("A household admin has not published a map yet.")).toBeVisible(); + await expect(page.getByRole("heading", { name: "Draft Map" })).toHaveCount(0); + await expect(page.getByText("A map draft exists for this location")).toHaveCount(0); + await expect(page.getByText("Draft Bakery")).toHaveCount(0); + await expect(page.getByRole("button", { name: "Continue Editing" })).toHaveCount(0); + await expect(page.getByLabel("Map controls")).toHaveCount(0); +});