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,
|
||||
}) {
|
||||
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"
|
||||
? selectedObject && editorTool === "edit"
|
||||
? "Object Settings"
|
||||
@ -58,6 +64,14 @@ export default function LocationMapBottomSheet({
|
||||
: "Map Details";
|
||||
const showEditorControls = mode === "edit" && canManage;
|
||||
const showSelectedObjectForm = Boolean(mode === "edit" && editorTool === "edit" && selectedObject);
|
||||
const showSelectedZoneItems = () => {
|
||||
setFilters((current) => ({
|
||||
...current,
|
||||
showMyItems: true,
|
||||
showOtherItems: true,
|
||||
showCompleted: true,
|
||||
}));
|
||||
};
|
||||
const editorActions = showEditorControls ? (
|
||||
<div className="location-map-editor-actions location-map-primary-actions">
|
||||
<button type="button" onClick={onAddObject}>Add Area</button>
|
||||
@ -218,7 +232,18 @@ export default function LocationMapBottomSheet({
|
||||
<span>{selectedItemCountLabel}</span>
|
||||
</div>
|
||||
{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>
|
||||
{selectedZoneItems.map((item) => (
|
||||
|
||||
@ -477,6 +477,23 @@
|
||||
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-unmapped-list ul {
|
||||
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");
|
||||
});
|
||||
|
||||
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 }) => {
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
await mockMapShell(page);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user