fix: lock canvas recovery while saving

This commit is contained in:
Nico 2026-06-03 22:52:51 -07:00
parent ba48ece884
commit e2128a4ad7
3 changed files with 87 additions and 1 deletions

View File

@ -39,7 +39,7 @@ export default function LocationMapCanvas({
: 0;
const hasNoVisibleObjects = objects.length > 0 && filters.showZones && visibleObjectCount === 0;
const canAddFirstArea =
!editingLocked && mode === "edit" && objects.length === 0 && typeof onAddObject === "function";
mode === "edit" && objects.length === 0 && typeof onAddObject === "function";
const canRecoverHiddenAreas =
mode === "edit" && hasNoVisibleObjects && hiddenAreaCount > 0 && typeof onShowHiddenAreas === "function";
const hasEmptyCanvasAction = canAddFirstArea || hiddenByZonesLayer || canRecoverHiddenAreas;
@ -165,11 +165,13 @@ export default function LocationMapCanvas({
const handleAddObject = (event) => {
event.stopPropagation();
if (editingLocked) return;
onAddObject?.();
};
const handleShowHiddenAreas = (event) => {
event.stopPropagation();
if (editingLocked) return;
onShowHiddenAreas?.();
};
@ -417,6 +419,7 @@ export default function LocationMapCanvas({
{canAddFirstArea ? (
<button
type="button"
disabled={editingLocked}
onPointerDown={(event) => event.stopPropagation()}
onClick={handleAddObject}
>
@ -433,6 +436,7 @@ export default function LocationMapCanvas({
) : canRecoverHiddenAreas ? (
<button
type="button"
disabled={editingLocked}
onPointerDown={(event) => event.stopPropagation()}
onClick={handleShowHiddenAreas}
>

View File

@ -345,6 +345,11 @@
cursor: pointer;
}
.location-map-empty-canvas button:disabled {
cursor: not-allowed;
opacity: 0.55;
}
.location-map-bottom-sheet {
max-height: 43vh;
overflow-y: auto;

View File

@ -1049,6 +1049,83 @@ test("admin save progress locks draft controls", async ({ page }) => {
await expect(page.getByRole("button", { name: "Save Draft" })).toBeDisabled();
});
test("admin save progress locks empty-canvas recovery actions", async ({ page }) => {
await mockMapShell(page);
let mapState = draftMapState([
{
id: 1362,
location_map_id: 900,
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);
let releaseSave: () => void = () => {};
let saveStarted = false;
const saveGate = new Promise<void>((resolve) => {
releaseSave = resolve;
});
await page.route("**/households/1/locations/10/map", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify(mapState),
});
});
await page.route("**/households/1/locations/10/map/draft", async (route) => {
saveStarted = true;
const payload = await route.request().postDataJSON();
await saveGate;
const savedObjects = (payload.objects as Array<Record<string, unknown>>).map((object, index) => ({
...(mapState.draft_objects[index] || {}),
...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();
await page.getByRole("button", { name: "Edit Objects" }).click();
await page.locator(".location-map-object", { hasText: "Bakery" }).locator("rect").first().click();
await page.getByLabel("Visible").click();
await expect(page.getByText("No visible map areas")).toBeVisible();
await expect(
page.locator(".location-map-empty-canvas").getByRole("button", { name: "Show Hidden" })
).toBeEnabled();
await expect(page.getByRole("button", { name: "Show Hidden Areas (1)" })).toBeEnabled();
await page.getByRole("button", { name: "Save Draft" }).click();
await expect.poll(() => saveStarted).toBe(true);
await expect(
page.locator(".location-map-empty-canvas").getByRole("button", { name: "Show Hidden" })
).toBeDisabled();
await expect(page.getByRole("button", { name: "Show Hidden Areas (1)" })).toBeDisabled();
releaseSave();
await expect(page.locator(".location-map-status")).toHaveText("Draft");
await expect(
page.locator(".location-map-empty-canvas").getByRole("button", { name: "Show Hidden" })
).toBeEnabled();
});
test("admin hard navigation warns when draft edits are unsaved", async ({ page }) => {
await mockMapShell(page);