Add store location map manager #20
@ -1,6 +1,7 @@
|
|||||||
export default function LocationMapSetupPanel({
|
export default function LocationMapSetupPanel({
|
||||||
hasAnyMap,
|
hasAnyMap,
|
||||||
canManage,
|
canManage,
|
||||||
|
zoneCount = 0,
|
||||||
saving,
|
saving,
|
||||||
onContinue,
|
onContinue,
|
||||||
onPreview,
|
onPreview,
|
||||||
@ -15,6 +16,10 @@ export default function LocationMapSetupPanel({
|
|||||||
: canManage
|
: canManage
|
||||||
? "Create a rough map for this store location."
|
? "Create a rough map for this store location."
|
||||||
: "A household admin has not published a map yet.";
|
: "A household admin has not published a map yet.";
|
||||||
|
const hasZones = zoneCount > 0;
|
||||||
|
const createFromZonesLabel = hasZones
|
||||||
|
? `Create From ${zoneCount} Zone${zoneCount === 1 ? "" : "s"}`
|
||||||
|
: "Create From Zones";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="location-map-setup">
|
<section className="location-map-setup">
|
||||||
@ -22,28 +27,29 @@ export default function LocationMapSetupPanel({
|
|||||||
<p>{description}</p>
|
<p>{description}</p>
|
||||||
{hasAnyMap && canManage ? (
|
{hasAnyMap && canManage ? (
|
||||||
<div className="location-map-setup-actions">
|
<div className="location-map-setup-actions">
|
||||||
<>
|
<button type="button" className="btn-primary" onClick={onContinue}>
|
||||||
<button type="button" className="btn-primary" onClick={onContinue}>
|
Continue Editing
|
||||||
Continue Editing
|
</button>
|
||||||
</button>
|
<button type="button" className="btn-secondary" onClick={onPreview}>
|
||||||
<button type="button" className="btn-secondary" onClick={onPreview}>
|
Preview Map
|
||||||
Preview Map
|
</button>
|
||||||
</button>
|
<button type="button" className="btn-primary" onClick={onPublish} disabled={saving || !canManage}>
|
||||||
<button type="button" className="btn-primary" onClick={onPublish} disabled={saving || !canManage}>
|
Publish Map
|
||||||
Publish Map
|
</button>
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
</div>
|
</div>
|
||||||
) : !hasAnyMap && canManage ? (
|
) : !hasAnyMap && canManage ? (
|
||||||
<div className="location-map-setup-actions">
|
<div className="location-map-setup-actions">
|
||||||
<>
|
{!hasZones ? (
|
||||||
<button type="button" className="btn-primary" onClick={onCreateFromZones} disabled={saving}>
|
<p className="location-map-setup-note">
|
||||||
Create Map From Existing Zones
|
No zones are available yet. Create a blank map now, or add zones first for an automatic starter layout.
|
||||||
</button>
|
</p>
|
||||||
<button type="button" className="btn-secondary" onClick={onCreateBlank} disabled={saving}>
|
) : null}
|
||||||
Create Blank Map
|
<button type="button" className="btn-primary" onClick={onCreateFromZones} disabled={saving || !hasZones}>
|
||||||
</button>
|
{createFromZonesLabel}
|
||||||
</>
|
</button>
|
||||||
|
<button type="button" className="btn-secondary" onClick={onCreateBlank} disabled={saving}>
|
||||||
|
Create Blank Map
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@ -475,6 +475,7 @@ export default function LocationMapManager() {
|
|||||||
<LocationMapSetupPanel
|
<LocationMapSetupPanel
|
||||||
hasAnyMap={hasAnyMap}
|
hasAnyMap={hasAnyMap}
|
||||||
canManage={canManage}
|
canManage={canManage}
|
||||||
|
zoneCount={mapState?.zones?.length || 0}
|
||||||
saving={saving}
|
saving={saving}
|
||||||
onContinue={() => setMode("edit")}
|
onContinue={() => setMode("edit")}
|
||||||
onPreview={handlePreviewDraft}
|
onPreview={handlePreviewDraft}
|
||||||
|
|||||||
@ -553,6 +553,17 @@
|
|||||||
gap: 0.6rem;
|
gap: 0.6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.location-map-setup-note {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0.6rem 0.7rem;
|
||||||
|
border: 1px solid rgba(245, 158, 11, 0.28);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: rgba(245, 158, 11, 0.1);
|
||||||
|
color: #f8fafc;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
.location-map-loading {
|
.location-map-loading {
|
||||||
margin: 3rem auto;
|
margin: 3rem auto;
|
||||||
color: #9fb3c8;
|
color: #9fb3c8;
|
||||||
|
|||||||
@ -262,10 +262,10 @@ test("admin creates a map from zones, saves a draft, and publishes it", async ({
|
|||||||
await expect(page.getByRole("heading", { name: "Costco" })).toBeVisible();
|
await expect(page.getByRole("heading", { name: "Costco" })).toBeVisible();
|
||||||
await expect(page.getByText("Eastvale")).toBeVisible();
|
await expect(page.getByText("Eastvale")).toBeVisible();
|
||||||
await expect(page.getByRole("heading", { name: "No Map" })).toBeVisible();
|
await expect(page.getByRole("heading", { name: "No Map" })).toBeVisible();
|
||||||
await expect(page.getByRole("button", { name: "Create Map From Existing Zones" })).toBeVisible();
|
await expect(page.getByRole("button", { name: "Create From 2 Zones" })).toBeVisible();
|
||||||
await expect(page.getByLabel("Map controls")).toHaveCount(0);
|
await expect(page.getByLabel("Map controls")).toHaveCount(0);
|
||||||
|
|
||||||
await page.getByRole("button", { name: "Create Map From Existing Zones" }).click();
|
await page.getByRole("button", { name: "Create From 2 Zones" }).click();
|
||||||
await expect(page.getByText("Bakery")).toBeVisible();
|
await expect(page.getByText("Bakery")).toBeVisible();
|
||||||
await expect(page.getByText("Frozen Foods")).toBeVisible();
|
await expect(page.getByText("Frozen Foods")).toBeVisible();
|
||||||
await expect(page.getByRole("button", { name: "Pan Mode" })).toBeVisible();
|
await expect(page.getByRole("button", { name: "Pan Mode" })).toBeVisible();
|
||||||
@ -373,6 +373,31 @@ test("admin creates a map from zones, saves a draft, and publishes it", async ({
|
|||||||
await expect(page.getByText("loose batteries")).toBeVisible();
|
await expect(page.getByText("loose batteries")).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("admin setup explains when no zones exist yet", async ({ page }) => {
|
||||||
|
await mockMapShell(page);
|
||||||
|
|
||||||
|
await page.route("**/households/1/locations/10/map", async (route) => {
|
||||||
|
await route.fulfill({
|
||||||
|
status: 200,
|
||||||
|
contentType: "application/json",
|
||||||
|
body: JSON.stringify({
|
||||||
|
...noMapState(true),
|
||||||
|
zones: [],
|
||||||
|
items: [],
|
||||||
|
unmapped_count: 0,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.goto("/stores/100/locations/10/map");
|
||||||
|
|
||||||
|
await expect(page.getByRole("heading", { name: "No Map" })).toBeVisible();
|
||||||
|
await expect(page.getByText("No zones are available yet.")).toBeVisible();
|
||||||
|
await expect(page.getByRole("button", { name: "Create From Zones" })).toBeDisabled();
|
||||||
|
await expect(page.getByRole("button", { name: "Create Blank Map" })).toBeEnabled();
|
||||||
|
await expect(page.getByLabel("Map controls")).toHaveCount(0);
|
||||||
|
});
|
||||||
|
|
||||||
test("admin status follows the visible map when a saved draft exists", async ({ page }) => {
|
test("admin status follows the visible map when a saved draft exists", async ({ page }) => {
|
||||||
await mockMapShell(page);
|
await mockMapShell(page);
|
||||||
|
|
||||||
@ -857,7 +882,7 @@ test("members see a clean empty state when no map is published", async ({ page }
|
|||||||
await expect(page.getByRole("heading", { name: "No Map" })).toBeVisible();
|
await expect(page.getByRole("heading", { name: "No Map" })).toBeVisible();
|
||||||
await expect(page.getByText("A household admin has not published a map yet.")).toBeVisible();
|
await expect(page.getByText("A household admin has not published a map yet.")).toBeVisible();
|
||||||
await expect(page.getByText("Create a rough map for this store location.")).toHaveCount(0);
|
await expect(page.getByText("Create a rough map for this store location.")).toHaveCount(0);
|
||||||
await expect(page.getByRole("button", { name: "Create Map From Existing Zones" })).toHaveCount(0);
|
await expect(page.getByRole("button", { name: /Create From/ })).toHaveCount(0);
|
||||||
await expect(page.getByRole("button", { name: "Create Blank Map" })).toHaveCount(0);
|
await expect(page.getByRole("button", { name: "Create Blank Map" })).toHaveCount(0);
|
||||||
await expect(page.getByLabel("Map controls")).toHaveCount(0);
|
await expect(page.getByLabel("Map controls")).toHaveCount(0);
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user