From 306812d692f5e3d0ef4334e0195862d629087098 Mon Sep 17 00:00:00 2001 From: Nico Date: Wed, 3 Jun 2026 20:43:52 -0700 Subject: [PATCH] fix: reuse map area display names --- .../src/components/maps/LocationMapBottomSheet.jsx | 8 ++++++-- frontend/src/components/maps/LocationMapCanvas.jsx | 11 +++-------- frontend/src/lib/locationMapUtils.js | 6 ++++++ frontend/src/pages/LocationMapManager.jsx | 6 ++++-- frontend/tests/location-map-manager.spec.ts | 11 ++++++++++- 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/frontend/src/components/maps/LocationMapBottomSheet.jsx b/frontend/src/components/maps/LocationMapBottomSheet.jsx index 1ecdbe0..2a283b2 100644 --- a/frontend/src/components/maps/LocationMapBottomSheet.jsx +++ b/frontend/src/components/maps/LocationMapBottomSheet.jsx @@ -1,4 +1,8 @@ -import { DEFAULT_MAP_FILTERS, MAP_OBJECT_TYPES } from "../../lib/locationMapUtils"; +import { + DEFAULT_MAP_FILTERS, + MAP_OBJECT_TYPES, + getMapObjectDisplayLabel, +} from "../../lib/locationMapUtils"; function objectZoneId(object) { return object?.zone_id ? String(object.zone_id) : ""; @@ -48,7 +52,7 @@ export default function LocationMapBottomSheet({ onDuplicateObject, onDeleteObject, }) { - const selectedTitle = selectedObject?.label || selectedObject?.zone_name || "Map Area"; + const selectedTitle = getMapObjectDisplayLabel(selectedObject); const selectedAssignedItems = selectedObject?.zone_id ? (mapState?.items || []).filter((item) => String(item.zone_id || "") === objectZoneId(selectedObject)) : []; diff --git a/frontend/src/components/maps/LocationMapCanvas.jsx b/frontend/src/components/maps/LocationMapCanvas.jsx index af8fc67..29b84ec 100644 --- a/frontend/src/components/maps/LocationMapCanvas.jsx +++ b/frontend/src/components/maps/LocationMapCanvas.jsx @@ -1,6 +1,7 @@ import { useRef, useState } from "react"; import { clientPointToMap, + getMapObjectDisplayLabel, getObjectKey, itemsForZone, } from "../../lib/locationMapUtils"; @@ -8,12 +9,6 @@ import { const DRAG_CHANGE_THRESHOLD = 2; const NUDGE_KEYS = new Set(["ArrowUp", "ArrowRight", "ArrowDown", "ArrowLeft"]); -function mapObjectDisplayLabel(object, fallback) { - const label = String(object.label || "").trim(); - const zoneName = String(object.zone_name || "").trim(); - return label || zoneName || fallback; -} - export default function LocationMapCanvas({ mode, editorTool, @@ -218,7 +213,7 @@ export default function LocationMapCanvas({ }; const fittedLabelLines = (object, fallback) => { - const rawLabel = mapObjectDisplayLabel(object, fallback); + const rawLabel = getMapObjectDisplayLabel(object, fallback); const maxCharacters = Math.max(8, Math.floor((Number(object.width) - 28) / 13)); const canUseTwoLines = Number(object.height) >= 92 && rawLabel.length > maxCharacters; if (!canUseTwoLines) return [truncateLabel(rawLabel, maxCharacters)]; @@ -301,7 +296,7 @@ export default function LocationMapCanvas({ height={object.height} rx="12" role="button" - aria-label={`Map area ${mapObjectDisplayLabel(object, index + 1)}`} + aria-label={`Map area ${getMapObjectDisplayLabel(object, index + 1)}`} aria-pressed={isSelected} tabIndex={mode === "view" || canEditObjects ? 0 : -1} onPointerDown={(event) => startDrag(event, object, "move")} diff --git a/frontend/src/lib/locationMapUtils.js b/frontend/src/lib/locationMapUtils.js index 794d5f8..7bf6bf1 100644 --- a/frontend/src/lib/locationMapUtils.js +++ b/frontend/src/lib/locationMapUtils.js @@ -129,6 +129,12 @@ export function getObjectKey(object) { return String(object.id || object.client_id); } +export function getMapObjectDisplayLabel(object, fallback = "Map Area") { + const label = String(object?.label || "").trim(); + const zoneName = String(object?.zone_name || "").trim(); + return label || zoneName || fallback; +} + export function prepareObjectsForSave(objects) { return objects.map((object, index) => ({ zone_id: object.zone_id || null, diff --git a/frontend/src/pages/LocationMapManager.jsx b/frontend/src/pages/LocationMapManager.jsx index 778139b..cdf1c0c 100644 --- a/frontend/src/pages/LocationMapManager.jsx +++ b/frontend/src/pages/LocationMapManager.jsx @@ -24,6 +24,7 @@ import { clampMapZoom, clampObjectToMap, createClientObject, + getMapObjectDisplayLabel, getMapStatus, getObjectKey, itemsForZone, @@ -322,11 +323,12 @@ export default function LocationMapManager() { const handleDuplicateObject = () => { if (!selectedObject) return; remember(); + const displayLabel = getMapObjectDisplayLabel(selectedObject, "Area"); const nextObject = { ...selectedObject, id: undefined, client_id: `copy-${Date.now()}`, - label: `${selectedObject.label || "Area"} Copy`, + label: `${displayLabel} Copy`, x: selectedObject.x + 28, y: selectedObject.y + 28, sort_order: objects.length + 1, @@ -584,7 +586,7 @@ export default function LocationMapManager() { setPendingDeleteObject(null)} diff --git a/frontend/tests/location-map-manager.spec.ts b/frontend/tests/location-map-manager.spec.ts index fcea9d0..3003bf2 100644 --- a/frontend/tests/location-map-manager.spec.ts +++ b/frontend/tests/location-map-manager.spec.ts @@ -596,7 +596,7 @@ test("admin selecting an object does not mark a draft dirty until it changes", a await expect(page.getByRole("button", { name: "Undo" })).toBeEnabled(); }); -test("admin cleared map area labels keep linked zone accessible names", async ({ page }) => { +test("admin cleared map area labels keep linked zone action names", async ({ page }) => { await mockMapShell(page); const mapState = draftMapState([ @@ -635,6 +635,15 @@ test("admin cleared map area labels keep linked zone accessible names", async ({ 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: "Delete" }).click(); + await expect(page.getByRole("heading", { name: "Delete Bakery?" })).toBeVisible(); + await page.getByRole("button", { name: "Cancel" }).click(); + + await page.getByRole("button", { name: "Duplicate" }).click(); + await expect(page.getByRole("textbox", { name: "Label" })).toHaveValue("Bakery Copy"); + await expect(page.getByRole("button", { name: "Map area Bakery Copy" })).toBeVisible(); + await expect(page.getByRole("button", { name: "Map area Area Copy" })).toHaveCount(0); }); test("admin nudges selected map areas with arrow keys", async ({ page }) => {