diff --git a/frontend/src/components/maps/LocationMapCanvas.jsx b/frontend/src/components/maps/LocationMapCanvas.jsx
index c2b985d..673ca0a 100644
--- a/frontend/src/components/maps/LocationMapCanvas.jsx
+++ b/frontend/src/components/maps/LocationMapCanvas.jsx
@@ -20,6 +20,7 @@ export default function LocationMapCanvas({
svgRef,
dragState,
editingLocked = false,
+ onShowZones,
setDragState,
setSelectedObjectKey,
remember,
@@ -27,6 +28,18 @@ export default function LocationMapCanvas({
}) {
const canEditObjects = !editingLocked && mode === "edit" && editorTool === "edit";
const canDragPan = mode === "view" || editorTool === "pan";
+ const hiddenByZonesLayer = objects.length > 0 && !filters.showZones;
+ const visibleObjectCount = filters.showZones
+ ? objects.filter((object) => object.visible).length
+ : 0;
+ const hasNoVisibleObjects = objects.length > 0 && filters.showZones && visibleObjectCount === 0;
+ const emptyCanvasMessage = objects.length === 0
+ ? "No map areas yet"
+ : hiddenByZonesLayer
+ ? "Zones hidden in Layers"
+ : hasNoVisibleObjects
+ ? "No visible map areas"
+ : "";
const scrollRef = useRef(null);
const panDragRef = useRef(null);
const objectDragHistoryCapturedRef = useRef(false);
@@ -113,6 +126,11 @@ export default function LocationMapCanvas({
selectObject(object);
};
+ const handleShowZones = (event) => {
+ event.stopPropagation();
+ onShowZones?.();
+ };
+
const clearSelection = () => {
if (suppressPanClickRef.current) {
suppressPanClickRef.current = false;
@@ -339,9 +357,23 @@ export default function LocationMapCanvas({
) : null}
{objects.map(renderMapObject)}
- {objects.length === 0 ? (
-
- No map areas yet
+ {emptyCanvasMessage ? (
+
+ {emptyCanvasMessage}
+ {hiddenByZonesLayer ? (
+
+ ) : null}
) : null}
diff --git a/frontend/src/pages/LocationMapManager.jsx b/frontend/src/pages/LocationMapManager.jsx
index 0f6e3f3..e2bc22b 100644
--- a/frontend/src/pages/LocationMapManager.jsx
+++ b/frontend/src/pages/LocationMapManager.jsx
@@ -528,6 +528,12 @@ export default function LocationMapManager() {
setSelectedObjectKey={setSelectedObjectKey}
remember={remember}
updateObjects={updateObjects}
+ onShowZones={() =>
+ setFilters((current) => ({
+ ...current,
+ showZones: true,
+ }))
+ }
/>
{
+ await mockMapShell(page);
+
+ const mapState = publishedMapState([
+ {
+ id: 1521,
+ location_map_id: 901,
+ 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 expect(page.getByRole("button", { name: "Map area Bakery" })).toBeVisible();
+
+ await page.getByRole("button", { name: "Layers" }).click();
+ await page.getByLabel("Zones").uncheck();
+
+ await expect(page.getByRole("button", { name: "Map area Bakery" })).toHaveCount(0);
+ await expect(page.getByText("Zones hidden in Layers")).toBeVisible();
+ await expect(page.getByRole("button", { name: "Show Zones" })).toBeVisible();
+ await expect(page.getByRole("button", { name: "Layers, 1 changed" })).toBeVisible();
+
+ await page.getByRole("button", { name: "Show Zones" }).click();
+ await expect(page.getByRole("button", { name: "Map area Bakery" })).toBeVisible();
+ await expect(page.getByText("Zones hidden in Layers")).toHaveCount(0);
+ await expect(page.getByRole("button", { name: "Layers" })).toBeVisible();
+});
+
test("viewer shows a compact overflow cue for long unmapped lists", async ({ page }) => {
await mockMapShell(page);