fix: explain hidden map zones
This commit is contained in:
parent
aaf0876b63
commit
e09a95e172
@ -20,6 +20,7 @@ export default function LocationMapCanvas({
|
|||||||
svgRef,
|
svgRef,
|
||||||
dragState,
|
dragState,
|
||||||
editingLocked = false,
|
editingLocked = false,
|
||||||
|
onShowZones,
|
||||||
setDragState,
|
setDragState,
|
||||||
setSelectedObjectKey,
|
setSelectedObjectKey,
|
||||||
remember,
|
remember,
|
||||||
@ -27,6 +28,18 @@ export default function LocationMapCanvas({
|
|||||||
}) {
|
}) {
|
||||||
const canEditObjects = !editingLocked && mode === "edit" && editorTool === "edit";
|
const canEditObjects = !editingLocked && mode === "edit" && editorTool === "edit";
|
||||||
const canDragPan = mode === "view" || editorTool === "pan";
|
const canDragPan = mode === "view" || editorTool === "pan";
|
||||||
|
const hiddenByZonesLayer = objects.length > 0 && !filters.showZones;
|
||||||
|
const visibleObjectCount = filters.showZones
|
||||||
|
? objects.filter((object) => object.visible).length
|
||||||
|
: 0;
|
||||||
|
const hasNoVisibleObjects = objects.length > 0 && filters.showZones && visibleObjectCount === 0;
|
||||||
|
const emptyCanvasMessage = objects.length === 0
|
||||||
|
? "No map areas yet"
|
||||||
|
: hiddenByZonesLayer
|
||||||
|
? "Zones hidden in Layers"
|
||||||
|
: hasNoVisibleObjects
|
||||||
|
? "No visible map areas"
|
||||||
|
: "";
|
||||||
const scrollRef = useRef(null);
|
const scrollRef = useRef(null);
|
||||||
const panDragRef = useRef(null);
|
const panDragRef = useRef(null);
|
||||||
const objectDragHistoryCapturedRef = useRef(false);
|
const objectDragHistoryCapturedRef = useRef(false);
|
||||||
@ -113,6 +126,11 @@ export default function LocationMapCanvas({
|
|||||||
selectObject(object);
|
selectObject(object);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleShowZones = (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
onShowZones?.();
|
||||||
|
};
|
||||||
|
|
||||||
const clearSelection = () => {
|
const clearSelection = () => {
|
||||||
if (suppressPanClickRef.current) {
|
if (suppressPanClickRef.current) {
|
||||||
suppressPanClickRef.current = false;
|
suppressPanClickRef.current = false;
|
||||||
@ -339,9 +357,23 @@ export default function LocationMapCanvas({
|
|||||||
) : null}
|
) : null}
|
||||||
{objects.map(renderMapObject)}
|
{objects.map(renderMapObject)}
|
||||||
</svg>
|
</svg>
|
||||||
{objects.length === 0 ? (
|
{emptyCanvasMessage ? (
|
||||||
<div className="location-map-empty-canvas">
|
<div
|
||||||
No map areas yet
|
className={[
|
||||||
|
"location-map-empty-canvas",
|
||||||
|
hiddenByZonesLayer ? "has-action" : "",
|
||||||
|
].filter(Boolean).join(" ")}
|
||||||
|
>
|
||||||
|
<span>{emptyCanvasMessage}</span>
|
||||||
|
{hiddenByZonesLayer ? (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onPointerDown={(event) => event.stopPropagation()}
|
||||||
|
onClick={handleShowZones}
|
||||||
|
>
|
||||||
|
Show Zones
|
||||||
|
</button>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -528,6 +528,12 @@ export default function LocationMapManager() {
|
|||||||
setSelectedObjectKey={setSelectedObjectKey}
|
setSelectedObjectKey={setSelectedObjectKey}
|
||||||
remember={remember}
|
remember={remember}
|
||||||
updateObjects={updateObjects}
|
updateObjects={updateObjects}
|
||||||
|
onShowZones={() =>
|
||||||
|
setFilters((current) => ({
|
||||||
|
...current,
|
||||||
|
showZones: true,
|
||||||
|
}))
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<LocationMapBottomSheet
|
<LocationMapBottomSheet
|
||||||
mode={mode}
|
mode={mode}
|
||||||
|
|||||||
@ -325,6 +325,25 @@
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.location-map-empty-canvas.has-action {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.55rem;
|
||||||
|
padding: 0.4rem 0.45rem 0.4rem 0.7rem;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.location-map-empty-canvas button {
|
||||||
|
min-height: 40px;
|
||||||
|
padding: 0 0.75rem;
|
||||||
|
border: 1px solid rgba(96, 165, 250, 0.52);
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(59, 130, 246, 0.24);
|
||||||
|
color: #f8fafc;
|
||||||
|
font-weight: 900;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.location-map-bottom-sheet {
|
.location-map-bottom-sheet {
|
||||||
max-height: 43vh;
|
max-height: 43vh;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|||||||
@ -924,6 +924,53 @@ test("viewer wraps long zone labels and keeps item counts visible", async ({ pag
|
|||||||
await expect(produceArea.locator(".location-map-count")).toHaveAttribute("y", "116");
|
await expect(produceArea.locator(".location-map-count")).toHaveAttribute("y", "116");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("viewer explains when the zones layer hides the map", async ({ page }) => {
|
||||||
|
await mockMapShell(page);
|
||||||
|
|
||||||
|
const mapState = publishedMapState([
|
||||||
|
{
|
||||||
|
id: 1521,
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
], 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");
|
||||||
|
await expect(page.getByRole("button", { name: "Map area Bakery" })).toBeVisible();
|
||||||
|
|
||||||
|
await page.getByRole("button", { name: "Layers" }).click();
|
||||||
|
await page.getByLabel("Zones").uncheck();
|
||||||
|
|
||||||
|
await expect(page.getByRole("button", { name: "Map area Bakery" })).toHaveCount(0);
|
||||||
|
await expect(page.getByText("Zones hidden in Layers")).toBeVisible();
|
||||||
|
await expect(page.getByRole("button", { name: "Show Zones" })).toBeVisible();
|
||||||
|
await expect(page.getByRole("button", { name: "Layers, 1 changed" })).toBeVisible();
|
||||||
|
|
||||||
|
await page.getByRole("button", { name: "Show Zones" }).click();
|
||||||
|
await expect(page.getByRole("button", { name: "Map area Bakery" })).toBeVisible();
|
||||||
|
await expect(page.getByText("Zones hidden in Layers")).toHaveCount(0);
|
||||||
|
await expect(page.getByRole("button", { name: "Layers" })).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
test("viewer shows a compact overflow cue for long unmapped lists", async ({ page }) => {
|
test("viewer shows a compact overflow cue for long unmapped lists", async ({ page }) => {
|
||||||
await mockMapShell(page);
|
await mockMapShell(page);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user