Add store location map manager #20

Open
nalalangan wants to merge 206 commits from feature/location-map-manager into feature/store-selector-modal
4 changed files with 12 additions and 17 deletions
Showing only changes of commit 8ad160196c - Show all commits

View File

@ -37,7 +37,6 @@ export default function LocationMapBottomSheet({
onAddObject, onAddObject,
onSaveDraft, onSaveDraft,
onPublish, onPublish,
onPreviewDraft,
onObjectField, onObjectField,
onZoneLinkChange, onZoneLinkChange,
onDuplicateObject, onDuplicateObject,
@ -124,7 +123,6 @@ export default function LocationMapBottomSheet({
const canPublishDraft = Boolean(mapState?.draft_map || hasUnsavedChanges); const canPublishDraft = Boolean(mapState?.draft_map || hasUnsavedChanges);
const showSaveDraftAction = Boolean(savingAction === "save" || hasUnsavedChanges); const showSaveDraftAction = Boolean(savingAction === "save" || hasUnsavedChanges);
const showPublishAction = Boolean(savingAction === "publish" || canPublishDraft); const showPublishAction = Boolean(savingAction === "publish" || canPublishDraft);
const showPreviewDraftAction = Boolean((mapState?.draft_map || hasUnsavedChanges) && !showSelectedObjectForm);
const mappedItemSummary = assignedItemCount === visibleAssignedItemCount const mappedItemSummary = assignedItemCount === visibleAssignedItemCount
? String(assignedItemCount) ? String(assignedItemCount)
: `${visibleAssignedItemCount} shown`; : `${visibleAssignedItemCount} shown`;
@ -178,11 +176,6 @@ export default function LocationMapBottomSheet({
const secondaryDraftActions = showEditorControls ? ( const secondaryDraftActions = showEditorControls ? (
<div className="location-map-editor-actions location-map-secondary-actions"> <div className="location-map-editor-actions location-map-secondary-actions">
<button type="button" onClick={onAddObject} disabled={saving}>Add Area</button> <button type="button" onClick={onAddObject} disabled={saving}>Add Area</button>
{showPreviewDraftAction ? (
<button type="button" onClick={onPreviewDraft} disabled={saving}>
View Draft
</button>
) : null}
</div> </div>
) : null; ) : null;
const editorActions = showEditorControls ? ( const editorActions = showEditorControls ? (

View File

@ -87,7 +87,7 @@ export default function useLocationMapViewControls({
setMode("view"); setMode("view");
setEditorTool("pan"); setEditorTool("pan");
setLayersOpen(false); setLayersOpen(false);
if (hasUnsavedChanges) { if ((mode === "edit" || previewDraft) && (hasUnsavedChanges || mapState?.draft_map)) {
setPreviewDraft(true); setPreviewDraft(true);
setSelectedObjectKey(null); setSelectedObjectKey(null);
return; return;
@ -99,6 +99,8 @@ export default function useLocationMapViewControls({
}, [ }, [
hasUnsavedChanges, hasUnsavedChanges,
mapState, mapState,
mode,
previewDraft,
setEditorTool, setEditorTool,
setLayersOpen, setLayersOpen,
setMode, setMode,

View File

@ -359,7 +359,6 @@ export default function LocationMapManager() {
onAddObject={handleAddObject} onAddObject={handleAddObject}
onSaveDraft={handleSaveDraft} onSaveDraft={handleSaveDraft}
onPublish={handlePublish} onPublish={handlePublish}
onPreviewDraft={handlePreviewDraft}
onObjectField={handleObjectField} onObjectField={handleObjectField}
onZoneLinkChange={handleZoneLinkChange} onZoneLinkChange={handleZoneLinkChange}
onDuplicateObject={handleDuplicateObject} onDuplicateObject={handleDuplicateObject}

View File

@ -364,7 +364,7 @@ test("admin creates a map from zones, saves a draft, and publishes it", async ({
await expect(page).toHaveURL(/\/stores\/100\/locations\/10\/map$/); await expect(page).toHaveURL(/\/stores\/100\/locations\/10\/map$/);
await expect(page.locator(".location-map-status")).toHaveText("Unsaved Draft"); await expect(page.locator(".location-map-status")).toHaveText("Unsaved Draft");
await page.getByRole("button", { name: "View Draft" }).click(); await page.getByRole("button", { name: "View", exact: true }).click();
await expect(page.locator(".location-map-object", { hasText: "Bread Wall" })).toBeVisible(); await expect(page.locator(".location-map-object", { hasText: "Bread Wall" })).toBeVisible();
await expect(page.locator(".location-map-status")).toHaveText("Unsaved Draft"); await expect(page.locator(".location-map-status")).toHaveText("Unsaved Draft");
@ -1172,7 +1172,7 @@ test("admin can add the first area from a blank map canvas", async ({ page }) =>
await expect(page.getByRole("button", { name: "Save Draft" })).toBeEnabled(); await expect(page.getByRole("button", { name: "Save Draft" })).toBeEnabled();
}); });
test("admin status follows the visible map when a saved draft exists", async ({ page }) => { test("admin view mode previews the edited draft when a saved draft exists", async ({ page }) => {
await mockMapShell(page); await mockMapShell(page);
const publishedObjects = [ const publishedObjects = [
@ -1223,13 +1223,13 @@ test("admin status follows the visible map when a saved draft exists", async ({
await expect(page.locator(".location-map-status")).toHaveText("Draft"); await expect(page.locator(".location-map-status")).toHaveText("Draft");
await expect(page.locator(".location-map-object", { hasText: "Draft Bakery" })).toBeVisible(); await expect(page.locator(".location-map-object", { hasText: "Draft Bakery" })).toBeVisible();
await page.getByRole("button", { name: "View Draft" }).click(); await page.getByRole("button", { name: "View", exact: true }).click();
await expect(page.locator(".location-map-status")).toHaveText("Viewing Draft"); await expect(page.locator(".location-map-status")).toHaveText("Viewing Draft");
await expect(page.locator(".location-map-object", { hasText: "Draft Bakery" })).toBeVisible(); await expect(page.locator(".location-map-object", { hasText: "Draft Bakery" })).toBeVisible();
await page.getByRole("button", { name: "View" }).click(); await page.getByRole("button", { name: "View" }).click();
await expect(page.locator(".location-map-status")).toHaveText("Published"); await expect(page.locator(".location-map-status")).toHaveText("Viewing Draft");
await expect(page.locator(".location-map-object", { hasText: "Live Bakery" })).toBeVisible(); await expect(page.locator(".location-map-object", { hasText: "Draft Bakery" })).toBeVisible();
}); });
test("admin edit mode hides unavailable draft actions until changes exist", async ({ page }) => { test("admin edit mode hides unavailable draft actions until changes exist", async ({ page }) => {
@ -1341,7 +1341,7 @@ test("mode switches close open map layers without resetting filters", async ({ p
await page.getByRole("button", { name: "Edit Draft" }).click(); await page.getByRole("button", { name: "Edit Draft" }).click();
await page.getByRole("button", { name: "Layers, 1 changed" }).click(); await page.getByRole("button", { name: "Layers, 1 changed" }).click();
await expect(page.locator(".location-map-display-panel")).toBeVisible(); await expect(page.locator(".location-map-display-panel")).toBeVisible();
await page.getByRole("button", { name: "View Draft" }).click(); await page.getByRole("button", { name: "View", exact: true }).click();
await expect(page.getByRole("button", { name: "Layers, 1 changed" })).toHaveAttribute("aria-expanded", "false"); await expect(page.getByRole("button", { name: "Layers, 1 changed" })).toHaveAttribute("aria-expanded", "false");
await expect(page.locator(".location-map-display-panel")).toHaveCount(0); await expect(page.locator(".location-map-display-panel")).toHaveCount(0);
@ -1390,7 +1390,7 @@ test("mobile keeps viewing draft status compact in the topbar", async ({ page })
await page.goto("/stores/100/locations/10/map"); await page.goto("/stores/100/locations/10/map");
await page.getByRole("button", { name: "Edit Draft" }).click(); await page.getByRole("button", { name: "Edit Draft" }).click();
await page.getByRole("button", { name: "View Draft" }).click(); await page.getByRole("button", { name: "View", exact: true }).click();
const topbar = page.locator(".location-map-topbar"); const topbar = page.locator(".location-map-topbar");
const backButton = page.getByRole("button", { name: "Back to grocery list" }); const backButton = page.getByRole("button", { name: "Back to grocery list" });
@ -4073,7 +4073,8 @@ test("mobile editor uses bottom sheet controls instead of desktop object toolbar
await expect(primaryActions.getByRole("button", { name: "Save Draft" })).toHaveCount(0); await expect(primaryActions.getByRole("button", { name: "Save Draft" })).toHaveCount(0);
await expect(primaryActions.getByRole("button", { name: "Publish" })).toBeVisible(); await expect(primaryActions.getByRole("button", { name: "Publish" })).toBeVisible();
await expect(secondaryActions.getByRole("button", { name: "Add Area" })).toBeVisible(); await expect(secondaryActions.getByRole("button", { name: "Add Area" })).toBeVisible();
await expect(secondaryActions.getByRole("button", { name: "View Draft" })).toBeVisible(); await expect(secondaryActions.getByRole("button", { name: "View Draft" })).toHaveCount(0);
await expect(page.getByRole("button", { name: "View", exact: true })).toBeVisible();
const primaryActionBox = await primaryActions.boundingBox(); const primaryActionBox = await primaryActions.boundingBox();
const secondaryActionBox = await secondaryActions.boundingBox(); const secondaryActionBox = await secondaryActions.boundingBox();
expect(primaryActionBox).not.toBeNull(); expect(primaryActionBox).not.toBeNull();