From 1bcf4ea6d1a4502a8b7cbc11f94988fe5278a033 Mon Sep 17 00:00:00 2001 From: Nico Date: Wed, 3 Jun 2026 21:09:27 -0700 Subject: [PATCH] fix: preserve cleared map area labels --- frontend/src/lib/locationMapUtils.js | 12 ++++++--- frontend/src/pages/LocationMapManager.jsx | 2 +- frontend/tests/location-map-manager.spec.ts | 29 ++++++++++++++++++++- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/frontend/src/lib/locationMapUtils.js b/frontend/src/lib/locationMapUtils.js index 7bf6bf1..9280dcf 100644 --- a/frontend/src/lib/locationMapUtils.js +++ b/frontend/src/lib/locationMapUtils.js @@ -106,13 +106,17 @@ export function createClientObject(zone, index = 0) { } export function normalizeMapObject(object, index = 0) { + const hasExplicitLabel = Object.prototype.hasOwnProperty.call(object, "label"); + return { ...object, client_id: object.client_id || `object-${object.id || Date.now()}-${index}`, zone_id: object.zone_id ?? null, zone_name: object.zone_name || null, type: MAP_OBJECT_TYPES.includes(object.type) ? object.type : "zone", - label: object.label || object.zone_name || "Map Area", + label: hasExplicitLabel + ? String(object.label ?? "").trim() + : object.zone_name || "Map Area", x: Number(object.x) || 0, y: Number(object.y) || 0, width: Math.max(40, Number(object.width) || 160), @@ -130,8 +134,8 @@ export function getObjectKey(object) { } export function getMapObjectDisplayLabel(object, fallback = "Map Area") { - const label = String(object?.label || "").trim(); - const zoneName = String(object?.zone_name || "").trim(); + const label = String(object?.label ?? "").trim(); + const zoneName = String(object?.zone_name ?? "").trim(); return label || zoneName || fallback; } @@ -139,7 +143,7 @@ export function prepareObjectsForSave(objects) { return objects.map((object, index) => ({ zone_id: object.zone_id || null, type: object.type || "zone", - label: object.label || "", + label: String(object.label ?? "").trim(), x: Number(object.x) || 0, y: Number(object.y) || 0, width: Math.max(40, Number(object.width) || 160), diff --git a/frontend/src/pages/LocationMapManager.jsx b/frontend/src/pages/LocationMapManager.jsx index cdf1c0c..65b79a1 100644 --- a/frontend/src/pages/LocationMapManager.jsx +++ b/frontend/src/pages/LocationMapManager.jsx @@ -380,7 +380,7 @@ export default function LocationMapManager() { ? { ...object, zone_name: zone?.name || null, - label: object.label || zone?.name || "", + label: object.label ?? zone?.name ?? "", } : object ) diff --git a/frontend/tests/location-map-manager.spec.ts b/frontend/tests/location-map-manager.spec.ts index 3003bf2..568458a 100644 --- a/frontend/tests/location-map-manager.spec.ts +++ b/frontend/tests/location-map-manager.spec.ts @@ -599,7 +599,8 @@ test("admin selecting an object does not mark a draft dirty until it changes", a test("admin cleared map area labels keep linked zone action names", async ({ page }) => { await mockMapShell(page); - const mapState = draftMapState([ + let savedPayload: Record | null = null; + let mapState = draftMapState([ { id: 1353, location_map_id: 900, @@ -626,6 +627,22 @@ test("admin cleared map area labels keep linked zone action names", async ({ pag }); }); + await page.route("**/households/1/locations/10/map/draft", async (route) => { + savedPayload = await route.request().postDataJSON(); + const savedObjects = (savedPayload.objects as Array>).map((object, index) => ({ + id: 1360 + index, + location_map_id: 900, + zone_name: object.zone_id === 501 ? "Bakery" : null, + ...object, + })); + mapState = draftMapState(savedObjects, true); + 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(); @@ -636,6 +653,16 @@ test("admin cleared map area labels keep linked zone action names", async ({ pag await expect(page.getByRole("button", { name: "Map area Bakery", exact: true })).toBeVisible(); await expect(page.getByRole("button", { name: "Map area 1", exact: true })).toHaveCount(0); + await page.getByRole("button", { name: "Save Draft" }).click(); + await expect(page.locator(".location-map-status")).toHaveText("Draft"); + expect(savedPayload).not.toBeNull(); + expect((savedPayload?.objects as Array>)[0]).toEqual( + expect.objectContaining({ label: "", zone_id: 501 }) + ); + await expect(page.getByRole("button", { name: "Map area Bakery", exact: true })).toBeVisible(); + await page.getByRole("button", { name: "Map area Bakery", exact: true }).click(); + await expect(page.getByRole("textbox", { name: "Label" })).toHaveValue(""); + await page.getByRole("button", { name: "Delete" }).click(); await expect(page.getByRole("heading", { name: "Delete Bakery?" })).toBeVisible(); await page.getByRole("button", { name: "Cancel" }).click();