fix: compact map sheet empty states

This commit is contained in:
Nico 2026-06-04 15:28:43 -07:00
parent 913d458fd6
commit b96cb65d6f
3 changed files with 102 additions and 63 deletions

View File

@ -108,6 +108,20 @@ export function LocationMapOverview({ ariaLabel, rows }) {
);
}
function InlineStateAction({ label, value, actionLabel, actionText = "Show", onAction }) {
return (
<div className="location-map-inline-state">
<span>{label}</span>
<strong>{value}</strong>
{onAction ? (
<button type="button" onClick={onAction} aria-label={actionLabel}>
{actionText}
</button>
) : null}
</div>
);
}
export function SelectedMapObjectForm({
selectedObject,
zones = [],
@ -180,16 +194,16 @@ export function SelectedZoneItemsPanel({
return (
<div className="location-map-zone-items">
<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={onShowSelectedZoneItems}>
Show Zone Items
</button>
) : null}
<InlineStateAction
label="Hidden"
value={hiddenSelectedItemCount}
actionLabel="Show Zone Items"
onAction={onShowSelectedZoneItems}
/>
) : (
<InlineStateAction label="Items" value="0" />
)}
</div>
</div>
);
@ -204,12 +218,13 @@ export function SelectedZoneItemsPanel({
/>
{hasHiddenSelectedItems ? (
<div className="location-map-zone-hidden-note">
<p className="location-map-muted">
{hiddenSelectedItemCount} more hidden by layer filters.
</p>
<button type="button" onClick={onShowSelectedZoneItems}>
Show All Zone Items
</button>
<InlineStateAction
label="Hidden"
value={hiddenSelectedItemCount}
actionLabel="Show All Zone Items"
actionText="Show All"
onAction={onShowSelectedZoneItems}
/>
</div>
) : null}
</div>
@ -228,12 +243,12 @@ export function UnmappedItemsPanel({
<div className="location-map-unmapped-list">
<strong>Unmapped Items</strong>
<div className="location-map-zone-empty">
<p className="location-map-muted">
Unmapped items are hidden by layer filters.
</p>
<button type="button" onClick={onShowUnmappedItems}>
Show Unmapped Items
</button>
<InlineStateAction
label="Hidden"
value={hiddenUnmappedItemCount}
actionLabel="Show Unmapped Items"
onAction={onShowUnmappedItems}
/>
</div>
</div>
);
@ -253,12 +268,13 @@ export function UnmappedItemsPanel({
/>
{hiddenUnmappedItemCount > 0 ? (
<div className="location-map-zone-hidden-note">
<p className="location-map-muted">
{hiddenUnmappedItemCount} more hidden by layer filters.
</p>
<button type="button" onClick={onShowUnmappedItems}>
Show All Unmapped Items
</button>
<InlineStateAction
label="Hidden"
value={hiddenUnmappedItemCount}
actionLabel="Show All Unmapped Items"
actionText="Show All"
onAction={onShowUnmappedItems}
/>
</div>
) : null}
</div>

View File

@ -717,37 +717,45 @@
.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;
gap: 0.35rem;
}
.location-map-zone-hidden-note {
display: grid;
gap: 0.45rem;
margin-top: 0.55rem;
}
.location-map-zone-hidden-note p {
margin: 0;
}
.location-map-zone-hidden-note button {
min-height: 40px;
width: fit-content;
padding: 0.45rem 0.7rem;
.location-map-inline-state {
min-height: 42px;
display: grid;
grid-template-columns: minmax(0, 1fr) auto auto;
align-items: center;
gap: 0.5rem;
padding: 0.25rem 0.35rem 0.25rem 0.55rem;
border: 1px solid var(--color-border-light);
border-radius: 8px;
background: rgba(15, 23, 34, 0.56);
color: #f8fafc;
}
.location-map-inline-state span {
min-width: 0;
color: #9fb3c8;
font-size: 0.82rem;
font-weight: 800;
}
.location-map-inline-state strong {
color: #f8fafc;
font-weight: 900;
white-space: nowrap;
}
.location-map-inline-state button {
min-height: 34px;
min-width: 64px;
padding: 0.35rem 0.6rem;
border: 1px solid var(--color-border-light);
border-radius: 999px;
background: #15283b;
color: #f8fafc;
font-weight: 800;

View File

@ -2914,7 +2914,10 @@ test("viewer can buy selected zone items from the map", async ({ page }) => {
await expect(page.locator(".confirm-buy-modal")).toHaveCount(0);
await expect(page.locator(".location-map-sheet-count")).toHaveText("0 shown");
await expect(bakeryArea.locator(".location-map-count")).toHaveText("0 shown");
await expect(page.getByText("Items are assigned here, but hidden by layer filters.")).toBeVisible();
const hiddenZoneState = page.locator(".location-map-zone-items .location-map-inline-state", { hasText: "Hidden" });
await expect(hiddenZoneState).toContainText("2");
await expect(hiddenZoneState.getByRole("button", { name: "Show Zone Items" })).toHaveText("Show");
await expect(page.getByText("Items are assigned here, but hidden by layer filters.")).toHaveCount(0);
await page.getByRole("button", { name: "Layers" }).click();
await page.getByRole("button", { name: "Bought" }).click();
@ -3196,7 +3199,7 @@ test("viewer shows completed zone items without rebuy actions", async ({ page })
await expect(newlyBoughtRow.locator("small")).toHaveText("Bought");
});
test("viewer explains when unmapped items are hidden by filters", async ({ page }) => {
test("viewer shows compact state when unmapped items are hidden by filters", async ({ page }) => {
await mockMapShell(page);
const mapState = {
@ -3228,13 +3231,15 @@ test("viewer explains when unmapped items are hidden by filters", async ({ page
await page.getByRole("button", { name: "Unmapped" }).click();
await expect(page.getByText("other batteries")).toHaveCount(0);
await expect(page.getByText("Unmapped items are hidden by layer filters.")).toBeVisible();
await expect(page.getByRole("button", { name: "Show Unmapped Items" })).toBeVisible();
const hiddenUnmappedState = page.locator(".location-map-unmapped-list .location-map-inline-state", { hasText: "Hidden" });
await expect(hiddenUnmappedState).toContainText("1");
await expect(hiddenUnmappedState.getByRole("button", { name: "Show Unmapped Items" })).toHaveText("Show");
await expect(page.getByText("Unmapped items are hidden by layer filters.")).toHaveCount(0);
await page.getByRole("button", { name: "Show Unmapped Items" }).click();
await expect(page.getByText("other batteries")).toBeVisible();
await expect(page.getByText("Unmapped items are hidden by layer filters.")).toHaveCount(0);
await expect(hiddenUnmappedState).toHaveCount(0);
await expect(page.getByRole("button", { name: "Layers, 3 changed" })).toBeVisible();
});
@ -3280,16 +3285,18 @@ test("viewer marks partial unmapped counts when filters hide some items", async
await expect(page.getByText("visible batteries")).toBeVisible();
await expect(page.getByText("hidden batteries")).toHaveCount(0);
await expect(page.getByText("1 more hidden by layer filters.")).toBeVisible();
await expect(page.getByRole("button", { name: "Show All Unmapped Items" })).toBeVisible();
const hiddenUnmappedState = page.locator(".location-map-unmapped-list .location-map-inline-state", { hasText: "Hidden" });
await expect(hiddenUnmappedState).toContainText("1");
await expect(hiddenUnmappedState.getByRole("button", { name: "Show All Unmapped Items" })).toHaveText("Show All");
await expect(page.getByText("1 more hidden by layer filters.")).toHaveCount(0);
await page.getByRole("button", { name: "Show All Unmapped Items" }).click();
await expect(page.getByText("hidden batteries")).toBeVisible();
await expect(page.getByText("1 more hidden by layer filters.")).toHaveCount(0);
await expect(hiddenUnmappedState).toHaveCount(0);
});
test("viewer explains when selected zone items are hidden by filters", async ({ page }) => {
test("viewer shows compact state when selected zone items are hidden by filters", async ({ page }) => {
await mockMapShell(page);
const mapState = publishedMapState([
@ -3327,7 +3334,10 @@ test("viewer explains when selected zone items are hidden by filters", async ({
await frozenArea.locator("rect").first().click();
await expect(page.locator(".location-map-sheet-count")).toHaveText("0 shown");
await expect(page.getByText("Items are assigned here, but hidden by layer filters.")).toBeVisible();
const hiddenZoneState = page.locator(".location-map-zone-items .location-map-inline-state", { hasText: "Hidden" });
await expect(hiddenZoneState).toContainText("1");
await expect(hiddenZoneState.getByRole("button", { name: "Show Zone Items" })).toHaveText("Show");
await expect(page.getByText("Items are assigned here, but hidden by layer filters.")).toHaveCount(0);
await expect(page.getByText("frozen salmon")).toHaveCount(0);
await page.getByRole("button", { name: "Show Zone Items" }).click();
@ -3398,8 +3408,10 @@ test("viewer marks partial zone counts when filters hide some items", async ({ p
await expect(page.locator(".location-map-sheet-count")).toHaveText("1 shown");
await expect(page.getByText("visible bread")).toBeVisible();
await expect(page.getByText("hidden baguette")).toHaveCount(0);
await expect(page.getByText("1 more hidden by layer filters.")).toBeVisible();
await expect(page.getByRole("button", { name: "Show All Zone Items" })).toBeVisible();
const hiddenZoneState = page.locator(".location-map-zone-items .location-map-inline-state", { hasText: "Hidden" });
await expect(hiddenZoneState).toContainText("1");
await expect(hiddenZoneState.getByRole("button", { name: "Show All Zone Items" })).toHaveText("Show All");
await expect(page.getByText("1 more hidden by layer filters.")).toHaveCount(0);
await page.getByRole("button", { name: "Show All Zone Items" }).click();
@ -3472,7 +3484,10 @@ test("viewer handles empty and many-item zone panels without default pins", asyn
await page.locator('[data-object-key="1562"]').locator("rect").first().click();
await expect(page.locator(".location-map-sheet-count")).toHaveText("0 items");
await expect(page.getByText("No items assigned to this zone yet.")).toBeVisible();
const emptyZoneState = page.locator(".location-map-zone-items .location-map-inline-state", { hasText: "Items" });
await expect(emptyZoneState).toContainText("0");
await expect(emptyZoneState.getByRole("button")).toHaveCount(0);
await expect(page.getByText("No items assigned to this zone yet.")).toHaveCount(0);
await page.locator('[data-object-key="1561"]').locator("rect").first().click();
await expect(page.locator(".location-map-sheet-count")).toHaveText("14 items");