fix: clarify visible map status

This commit is contained in:
Nico 2026-06-03 11:25:20 -07:00
parent 6cddc1f95a
commit 7bb76a8eb4
5 changed files with 108 additions and 4 deletions

View File

@ -1,6 +1,8 @@
import { getLocationName, getStoreName } from "../../lib/locationMapUtils";
export default function LocationMapTopbar({ location, status, onBack }) {
const statusClass = status.toLowerCase().replace(/\s+/g, "-");
return (
<header className="location-map-topbar">
<button type="button" className="location-map-back" onClick={onBack}>
@ -10,7 +12,7 @@ export default function LocationMapTopbar({ location, status, onBack }) {
<h1>{getStoreName(location)}</h1>
<span>{getLocationName(location)}</span>
</div>
<span className={`location-map-status location-map-status-${status.toLowerCase().replace(" ", "-")}`}>
<span className={`location-map-status location-map-status-${statusClass}`}>
{status}
</span>
</header>

View File

@ -40,10 +40,14 @@ export function getLocationName(location) {
return location.location_name;
}
export function getMapStatus(state) {
export function getMapStatus(state, options = {}) {
if (options.hasUnsavedChanges) return "Unsaved Draft";
if (!state?.draft_map && !state?.published_map) return "No Map";
if (options.mode === "edit") return "Draft";
if (options.mode === "view" && options.previewDraft && state?.draft_map) return "Draft Preview";
if (state?.published_map) return "Published";
if (state?.draft_map) return "Draft";
return "Published";
return "No Map";
}
export function objectZoneId(object) {

View File

@ -427,7 +427,7 @@ export default function LocationMapManager() {
}
const hasAnyMap = Boolean(mapState?.draft_map || mapState?.published_map);
const status = hasUnsavedChanges ? "Unsaved Draft" : getMapStatus(mapState);
const status = getMapStatus(mapState, { mode, previewDraft, hasUnsavedChanges });
return (
<div className="location-map-page">

View File

@ -78,6 +78,11 @@
border-color: rgba(245, 158, 11, 0.36);
}
.location-map-status-draft-preview {
background: rgba(14, 165, 233, 0.2);
border-color: rgba(56, 189, 248, 0.4);
}
.location-map-status-unsaved-draft {
background: rgba(244, 114, 182, 0.2);
border-color: rgba(244, 114, 182, 0.42);

View File

@ -113,6 +113,39 @@ function publishedMapState(objects: Array<Record<string, unknown>>, canManage =
};
}
function draftAndPublishedMapState(
draftObjects: Array<Record<string, unknown>>,
publishedObjects: Array<Record<string, unknown>>,
canManage = true
) {
const draft = {
id: 900,
household_id: 1,
store_location_id: 10,
name: "Store Map",
width: 1000,
height: 700,
status: "draft",
version: 3,
};
const published = {
...draft,
id: 901,
status: "published",
version: 2,
};
return {
...noMapState(canManage),
map: draft,
draft_map: draft,
published_map: published,
objects: draftObjects,
draft_objects: draftObjects,
published_objects: publishedObjects,
};
}
async function mockMapShell(page: Page, household = adminHousehold) {
await seedAuthStorage(page, { username: "map-user", role: household.role });
await mockConfig(page);
@ -330,6 +363,66 @@ test("admin creates a map from zones, saves a draft, and publishes it", async ({
await expect(page.getByText("loose batteries")).toBeVisible();
});
test("admin status follows the visible map when a saved draft exists", async ({ page }) => {
await mockMapShell(page);
const publishedObjects = [
{
id: 1201,
location_map_id: 901,
zone_id: 501,
zone_name: "Bakery",
type: "zone",
label: "Live Bakery",
x: 40,
y: 40,
width: 260,
height: 160,
rotation: 0,
locked: false,
visible: true,
sort_order: 1,
},
];
const draftObjects = [
{
...publishedObjects[0],
id: 1301,
location_map_id: 900,
label: "Draft Bakery",
x: 80,
y: 80,
},
];
const mapState = draftAndPublishedMapState(draftObjects, publishedObjects, 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.locator(".location-map-status")).toHaveText("Published");
await expect(page.locator(".location-map-object", { hasText: "Live Bakery" })).toBeVisible();
await expect(page.locator(".location-map-object", { hasText: "Draft Bakery" })).toHaveCount(0);
await page.getByRole("button", { name: "Edit Draft" }).click();
await expect(page.locator(".location-map-status")).toHaveText("Draft");
await expect(page.locator(".location-map-object", { hasText: "Draft Bakery" })).toBeVisible();
await page.getByRole("button", { name: "Preview Draft" }).click();
await expect(page.locator(".location-map-status")).toHaveText("Draft Preview");
await expect(page.locator(".location-map-object", { hasText: "Draft Bakery" })).toBeVisible();
await page.getByRole("button", { name: "View" }).click();
await expect(page.locator(".location-map-status")).toHaveText("Published");
await expect(page.locator(".location-map-object", { hasText: "Live Bakery" })).toBeVisible();
});
test("members can view a published map but cannot edit it", async ({ page }) => {
await mockMapShell(page, memberHousehold);