fix: clarify map zone item empty states
This commit is contained in:
parent
607f74e679
commit
138c3e3aa8
@ -46,7 +46,13 @@ export default function LocationMapBottomSheet({
|
|||||||
onDeleteObject,
|
onDeleteObject,
|
||||||
}) {
|
}) {
|
||||||
const selectedTitle = selectedObject?.label || selectedObject?.zone_name || "Map Area";
|
const selectedTitle = selectedObject?.label || selectedObject?.zone_name || "Map Area";
|
||||||
const selectedItemCountLabel = `${selectedZoneItems.length} item${selectedZoneItems.length === 1 ? "" : "s"}`;
|
const selectedAssignedItems = selectedObject?.zone_id
|
||||||
|
? (mapState?.items || []).filter((item) => String(item.zone_id || "") === objectZoneId(selectedObject))
|
||||||
|
: [];
|
||||||
|
const hasHiddenSelectedItems = selectedAssignedItems.length > 0 && selectedZoneItems.length === 0;
|
||||||
|
const selectedItemCountLabel = hasHiddenSelectedItems
|
||||||
|
? "0 shown"
|
||||||
|
: `${selectedZoneItems.length} item${selectedZoneItems.length === 1 ? "" : "s"}`;
|
||||||
const sheetTitle = mode === "edit"
|
const sheetTitle = mode === "edit"
|
||||||
? selectedObject && editorTool === "edit"
|
? selectedObject && editorTool === "edit"
|
||||||
? "Object Settings"
|
? "Object Settings"
|
||||||
@ -58,6 +64,14 @@ export default function LocationMapBottomSheet({
|
|||||||
: "Map Details";
|
: "Map Details";
|
||||||
const showEditorControls = mode === "edit" && canManage;
|
const showEditorControls = mode === "edit" && canManage;
|
||||||
const showSelectedObjectForm = Boolean(mode === "edit" && editorTool === "edit" && selectedObject);
|
const showSelectedObjectForm = Boolean(mode === "edit" && editorTool === "edit" && selectedObject);
|
||||||
|
const showSelectedZoneItems = () => {
|
||||||
|
setFilters((current) => ({
|
||||||
|
...current,
|
||||||
|
showMyItems: true,
|
||||||
|
showOtherItems: true,
|
||||||
|
showCompleted: true,
|
||||||
|
}));
|
||||||
|
};
|
||||||
const editorActions = showEditorControls ? (
|
const editorActions = showEditorControls ? (
|
||||||
<div className="location-map-editor-actions location-map-primary-actions">
|
<div className="location-map-editor-actions location-map-primary-actions">
|
||||||
<button type="button" onClick={onAddObject}>Add Area</button>
|
<button type="button" onClick={onAddObject}>Add Area</button>
|
||||||
@ -218,7 +232,18 @@ export default function LocationMapBottomSheet({
|
|||||||
<span>{selectedItemCountLabel}</span>
|
<span>{selectedItemCountLabel}</span>
|
||||||
</div>
|
</div>
|
||||||
{selectedZoneItems.length === 0 ? (
|
{selectedZoneItems.length === 0 ? (
|
||||||
<p className="location-map-muted">No visible items assigned to this zone.</p>
|
<div className="location-map-zone-empty">
|
||||||
|
<p className="location-map-muted">
|
||||||
|
{hasHiddenSelectedItems
|
||||||
|
? "Items are assigned here, but hidden by layer filters."
|
||||||
|
: "No items assigned to this zone yet."}
|
||||||
|
</p>
|
||||||
|
{hasHiddenSelectedItems ? (
|
||||||
|
<button type="button" onClick={showSelectedZoneItems}>
|
||||||
|
Show Zone Items
|
||||||
|
</button>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<ul>
|
<ul>
|
||||||
{selectedZoneItems.map((item) => (
|
{selectedZoneItems.map((item) => (
|
||||||
|
|||||||
@ -477,6 +477,23 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.location-map-zone-empty {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.55rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.location-map-zone-empty button {
|
||||||
|
min-height: 40px;
|
||||||
|
width: fit-content;
|
||||||
|
padding: 0.45rem 0.7rem;
|
||||||
|
border: 1px solid var(--color-border-light);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #15283b;
|
||||||
|
color: #f8fafc;
|
||||||
|
font-weight: 800;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.location-map-zone-items ul,
|
.location-map-zone-items ul,
|
||||||
.location-map-unmapped-list ul {
|
.location-map-unmapped-list ul {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
@ -480,6 +480,128 @@ test("viewer wraps long zone labels and keeps item counts visible", async ({ pag
|
|||||||
await expect(produceArea.locator(".location-map-count")).toHaveAttribute("y", "92");
|
await expect(produceArea.locator(".location-map-count")).toHaveAttribute("y", "92");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("viewer explains when selected zone items are hidden by filters", async ({ page }) => {
|
||||||
|
await mockMapShell(page);
|
||||||
|
|
||||||
|
const mapState = publishedMapState([
|
||||||
|
{
|
||||||
|
id: 1551,
|
||||||
|
location_map_id: 901,
|
||||||
|
zone_id: 502,
|
||||||
|
zone_name: "Frozen Foods",
|
||||||
|
type: "zone",
|
||||||
|
label: "Frozen Foods",
|
||||||
|
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");
|
||||||
|
|
||||||
|
const frozenArea = page.locator('[data-object-key="1551"]');
|
||||||
|
await expect(frozenArea.locator(".location-map-count")).toHaveText("0 items");
|
||||||
|
await expect(page.locator(".location-map-pin")).toHaveCount(0);
|
||||||
|
|
||||||
|
await frozenArea.locator("rect").first().click();
|
||||||
|
await expect(page.locator(".location-map-zone-items-title span")).toHaveText("0 shown");
|
||||||
|
await expect(page.getByText("Items are assigned here, but hidden by layer filters.")).toBeVisible();
|
||||||
|
await expect(page.getByText("frozen salmon")).toHaveCount(0);
|
||||||
|
|
||||||
|
await page.getByRole("button", { name: "Show Zone Items" }).click();
|
||||||
|
await expect(page.locator(".location-map-zone-items-title span")).toHaveText("1 item");
|
||||||
|
await expect(page.getByText("frozen salmon")).toBeVisible();
|
||||||
|
await expect(frozenArea.locator(".location-map-count")).toHaveText("1 item");
|
||||||
|
await expect(page.locator(".location-map-pin")).toHaveCount(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("viewer handles empty and many-item zone panels without default pins", async ({ page }) => {
|
||||||
|
await mockMapShell(page);
|
||||||
|
|
||||||
|
const manyItems = Array.from({ length: 14 }, (_, index) => ({
|
||||||
|
id: 3000 + index,
|
||||||
|
item_name: `bulk item ${index + 1}`,
|
||||||
|
quantity: index + 1,
|
||||||
|
bought: false,
|
||||||
|
zone_id: 501,
|
||||||
|
zone: "Bakery",
|
||||||
|
added_by_users: ["map-user"],
|
||||||
|
}));
|
||||||
|
const mapState = {
|
||||||
|
...publishedMapState([
|
||||||
|
{
|
||||||
|
id: 1561,
|
||||||
|
location_map_id: 901,
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1562,
|
||||||
|
location_map_id: 901,
|
||||||
|
zone_id: 502,
|
||||||
|
zone_name: "Frozen Foods",
|
||||||
|
type: "zone",
|
||||||
|
label: "Frozen Foods",
|
||||||
|
x: 340,
|
||||||
|
y: 40,
|
||||||
|
width: 260,
|
||||||
|
height: 160,
|
||||||
|
rotation: 0,
|
||||||
|
locked: false,
|
||||||
|
visible: true,
|
||||||
|
sort_order: 2,
|
||||||
|
},
|
||||||
|
], true),
|
||||||
|
items: manyItems,
|
||||||
|
unmapped_count: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
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-pin")).toHaveCount(0);
|
||||||
|
|
||||||
|
await page.locator('[data-object-key="1562"]').locator("rect").first().click();
|
||||||
|
await expect(page.locator(".location-map-zone-items-title span")).toHaveText("0 items");
|
||||||
|
await expect(page.getByText("No items assigned to this zone yet.")).toBeVisible();
|
||||||
|
|
||||||
|
await page.locator('[data-object-key="1561"]').locator("rect").first().click();
|
||||||
|
await expect(page.locator(".location-map-zone-items-title span")).toHaveText("14 items");
|
||||||
|
await expect(page.locator(".location-map-zone-items li")).toHaveCount(14);
|
||||||
|
await expect(page.locator(".location-map-zone-items li").first()).toContainText("bulk item 1");
|
||||||
|
await expect(page.locator(".location-map-zone-items li").last()).toContainText("bulk item 14");
|
||||||
|
await expect(page.locator(".location-map-pin")).toHaveCount(0);
|
||||||
|
});
|
||||||
|
|
||||||
test("mobile editor uses bottom sheet controls instead of desktop object toolbar", async ({ page }) => {
|
test("mobile editor uses bottom sheet controls instead of desktop object toolbar", async ({ page }) => {
|
||||||
await page.setViewportSize({ width: 390, height: 844 });
|
await page.setViewportSize({ width: 390, height: 844 });
|
||||||
await mockMapShell(page);
|
await mockMapShell(page);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user