fix: hide unavailable map draft actions

This commit is contained in:
Nico 2026-06-04 19:29:17 -07:00
parent 15324c25f2
commit 0c8f18e1e5
2 changed files with 84 additions and 27 deletions

View File

@ -121,6 +121,10 @@ export default function LocationMapBottomSheet({
showEditorControls && hiddenAreaCount > 0 && filters.showZones && !hasNoVisibleAreas;
const saveDraftLabel = savingAction === "save" ? "Saving..." : "Save Draft";
const publishLabel = savingAction === "publish" ? "Publishing..." : "Publish";
const canPublishDraft = Boolean(mapState?.draft_map || hasUnsavedChanges);
const showSaveDraftAction = Boolean(savingAction === "save" || hasUnsavedChanges);
const showPublishAction = Boolean(savingAction === "publish" || canPublishDraft);
const showPreviewDraftAction = Boolean((mapState?.draft_map || hasUnsavedChanges) && !showSelectedObjectForm);
const mappedItemSummary = assignedItemCount === visibleAssignedItemCount
? String(assignedItemCount)
: `${visibleAssignedItemCount} shown`;
@ -152,25 +156,29 @@ export default function LocationMapBottomSheet({
showCompleted: true,
}));
};
const primaryDraftActions = showEditorControls ? (
const primaryDraftActions = showEditorControls && (showSaveDraftAction || showPublishAction) ? (
<div className="location-map-editor-actions location-map-primary-actions">
<button type="button" className="primary" onClick={onSaveDraft} disabled={saving || !hasUnsavedChanges}>
{saveDraftLabel}
</button>
<button
type="button"
className="primary"
onClick={onPublish}
disabled={saving || (!mapState?.draft_map && !hasUnsavedChanges)}
>
{publishLabel}
</button>
{showSaveDraftAction ? (
<button type="button" className="primary" onClick={onSaveDraft} disabled={saving || !hasUnsavedChanges}>
{saveDraftLabel}
</button>
) : null}
{showPublishAction ? (
<button
type="button"
className="primary"
onClick={onPublish}
disabled={saving || !canPublishDraft}
>
{publishLabel}
</button>
) : null}
</div>
) : null;
const secondaryDraftActions = showEditorControls ? (
<div className="location-map-editor-actions location-map-secondary-actions">
<button type="button" onClick={onAddObject} disabled={saving}>Add Area</button>
{!showSelectedObjectForm ? (
{showPreviewDraftAction ? (
<button type="button" onClick={onPreviewDraft} aria-label="Preview Draft" disabled={saving}>
Preview
</button>
@ -236,14 +244,16 @@ export default function LocationMapBottomSheet({
<LocationMapLayerPanel filters={filters} setFilters={setFilters} />
) : null}
{showSelectedObjectForm && primaryDraftActions ? (
<div
className="location-map-editor-action-stack location-map-selected-primary-actions"
role="group"
aria-label="Map draft actions"
>
{primaryDraftActions}
</div>
{showSelectedObjectForm ? (
primaryDraftActions ? (
<div
className="location-map-editor-action-stack location-map-selected-primary-actions"
role="group"
aria-label="Map draft actions"
>
{primaryDraftActions}
</div>
) : null
) : editorActions}
{showHiddenAreaAction ? (

View File

@ -1229,6 +1229,53 @@ test("admin status follows the visible map when a saved draft exists", async ({
await expect(page.locator(".location-map-object", { hasText: "Live Bakery" })).toBeVisible();
});
test("admin edit mode hides unavailable draft actions until changes exist", async ({ page }) => {
await mockMapShell(page);
const mapState = publishedMapState([
{
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,
},
], 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 page.getByRole("button", { name: "Edit Draft" }).click();
const secondaryActions = page.locator(".location-map-secondary-actions");
await expect(page.locator(".location-map-primary-actions")).toHaveCount(0);
await expect(secondaryActions.getByRole("button", { name: "Add Area" })).toBeVisible();
await expect(secondaryActions.getByRole("button", { name: "Preview Draft" })).toHaveCount(0);
await expect(page.getByRole("button", { name: "Save Draft" })).toHaveCount(0);
await expect(page.getByRole("button", { name: "Publish", exact: true })).toHaveCount(0);
await secondaryActions.getByRole("button", { name: "Add Area" }).click();
await expect(page.locator(".location-map-status")).toHaveText("Unsaved Draft");
await expect(page.getByRole("button", { name: "Save Draft" })).toBeEnabled();
await expect(page.getByRole("button", { name: "Publish", exact: true })).toBeEnabled();
});
test("mode switches close open map layers without resetting filters", async ({ page }) => {
await mockMapShell(page);
@ -1561,7 +1608,7 @@ test("admin selecting an object does not mark a draft dirty until it changes", a
await expect(page.getByRole("textbox", { name: "Label" })).toBeVisible();
await expect(page.locator(".location-map-status")).toHaveText("Draft");
await expect(page.getByRole("button", { name: "Save Draft" })).toBeDisabled();
await expect(page.getByRole("button", { name: "Save Draft" })).toHaveCount(0);
await expect(page.getByRole("button", { name: "Undo" })).toBeDisabled();
const objectBox = await bakeryObject.boundingBox();
@ -2098,7 +2145,7 @@ test("admin save progress locks draft controls", async ({ page }) => {
releaseSave();
await expect(page.locator(".location-map-status")).toHaveText("Draft");
await expect(page.getByRole("button", { name: "Save Draft" })).toBeDisabled();
await expect(page.getByRole("button", { name: "Save Draft" })).toHaveCount(0);
await expect(page.getByRole("textbox", { name: "Label" })).toBeEnabled();
await expect(page.getByRole("textbox", { name: "Label" })).toHaveValue("Saving Bakery");
await expect(page.getByRole("button", { name: "Map area Saving Bakery" })).toHaveAttribute("aria-pressed", "true");
@ -2611,7 +2658,7 @@ test("admin publish failure keeps successfully saved pending edits", async ({ pa
])
);
await expect(page.locator(".location-map-status")).toHaveText("Draft");
await expect(page.getByRole("button", { name: "Save Draft" })).toBeDisabled();
await expect(page.getByRole("button", { name: "Save Draft" })).toHaveCount(0);
await expect(page.getByRole("button", { name: "Map area Saved Draft Bakery" })).toBeVisible();
await expect(page.getByRole("button", { name: "Map area Live Bakery" })).toHaveCount(0);
});
@ -3957,7 +4004,7 @@ test("mobile editor uses bottom sheet controls instead of desktop object toolbar
await expect(historyActions.getByRole("button", { name: "Redo" })).toBeDisabled();
const primaryActions = page.locator(".location-map-primary-actions");
const secondaryActions = page.locator(".location-map-secondary-actions");
await expect(primaryActions.getByRole("button", { name: "Save Draft" })).toBeVisible();
await expect(primaryActions.getByRole("button", { name: "Save Draft" })).toHaveCount(0);
await expect(primaryActions.getByRole("button", { name: "Publish" })).toBeVisible();
await expect(secondaryActions.getByRole("button", { name: "Add Area" })).toBeVisible();
await expect(secondaryActions.getByRole("button", { name: "Preview Draft" })).toBeVisible();
@ -4017,7 +4064,7 @@ test("mobile editor uses bottom sheet controls instead of desktop object toolbar
await expect(page.getByRole("button", { name: "Locked" })).toHaveAttribute("aria-pressed", "false");
const selectedPrimaryActions = page.locator(".location-map-selected-primary-actions");
const selectedSecondaryActions = page.locator(".location-map-selected-secondary-actions");
await expect(selectedPrimaryActions.getByRole("button", { name: "Save Draft" })).toBeVisible();
await expect(selectedPrimaryActions.getByRole("button", { name: "Save Draft" })).toHaveCount(0);
await expect(selectedPrimaryActions.getByRole("button", { name: "Publish" })).toBeVisible();
await expect(selectedSecondaryActions.getByRole("button", { name: "Add Area" })).toBeVisible();
await expect(selectedSecondaryActions.getByRole("button", { name: "Preview Draft" })).toHaveCount(0);
@ -4049,7 +4096,7 @@ test("mobile editor uses bottom sheet controls instead of desktop object toolbar
await closeSelectedButton.click();
await expect(page.getByRole("textbox", { name: "Label" })).toHaveCount(0);
await expect(page.locator(".location-map-sheet-header strong")).toHaveText("Edit Areas");
await expect(page.getByRole("button", { name: "Save Draft" })).toBeDisabled();
await expect(page.getByRole("button", { name: "Save Draft" })).toHaveCount(0);
await page.getByRole("button", { name: "View", exact: true }).click();
await expect(page.getByRole("textbox", { name: "Label" })).toHaveCount(0);
});