Compare commits
No commits in common. "a2db8cd65503973b91fb9443a7cc3505d16de756" and "85061b93d1f197c4088c0990c2ea920ad9f6de32" have entirely different histories.
a2db8cd655
...
85061b93d1
@ -55,21 +55,6 @@ export default function LocationMapCanvas({
|
|||||||
const objectDragHistoryCapturedRef = useRef(false);
|
const objectDragHistoryCapturedRef = useRef(false);
|
||||||
const suppressPanClickRef = useRef(false);
|
const suppressPanClickRef = useRef(false);
|
||||||
const [isPanning, setIsPanning] = useState(false);
|
const [isPanning, setIsPanning] = useState(false);
|
||||||
const orderedObjects = useMemo(() => {
|
|
||||||
if (!selectedObjectKey) return objects;
|
|
||||||
|
|
||||||
const selectedObjects = [];
|
|
||||||
const remainingObjects = [];
|
|
||||||
objects.forEach((object) => {
|
|
||||||
if (getObjectKey(object) === selectedObjectKey) {
|
|
||||||
selectedObjects.push(object);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
remainingObjects.push(object);
|
|
||||||
});
|
|
||||||
|
|
||||||
return [...remainingObjects, ...selectedObjects];
|
|
||||||
}, [objects, selectedObjectKey]);
|
|
||||||
const zoneItemSummary = useMemo(() => {
|
const zoneItemSummary = useMemo(() => {
|
||||||
const assignedCounts = new Map();
|
const assignedCounts = new Map();
|
||||||
const visibleItemsByZone = new Map();
|
const visibleItemsByZone = new Map();
|
||||||
@ -339,7 +324,13 @@ export default function LocationMapCanvas({
|
|||||||
{mode === "edit" ? (
|
{mode === "edit" ? (
|
||||||
<rect className="location-map-grid" width={mapSize.width} height={mapSize.height} />
|
<rect className="location-map-grid" width={mapSize.width} height={mapSize.height} />
|
||||||
) : null}
|
) : null}
|
||||||
{orderedObjects.map(renderMapObject)}
|
{(selectedObjectKey
|
||||||
|
? [
|
||||||
|
...objects.filter((object) => getObjectKey(object) !== selectedObjectKey),
|
||||||
|
...objects.filter((object) => getObjectKey(object) === selectedObjectKey),
|
||||||
|
]
|
||||||
|
: objects
|
||||||
|
).map(renderMapObject)}
|
||||||
</svg>
|
</svg>
|
||||||
{emptyCanvasMessage ? (
|
{emptyCanvasMessage ? (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@ -11,9 +11,13 @@ export function LocationMapMessageState({ message, location, status = "Loading",
|
|||||||
<main className="location-map-workspace location-map-message-workspace">
|
<main className="location-map-workspace location-map-message-workspace">
|
||||||
<section className="location-map-setup location-map-message-card" aria-live="polite">
|
<section className="location-map-setup location-map-message-card" aria-live="polite">
|
||||||
<h2>{status}</h2>
|
<h2>{status}</h2>
|
||||||
<div className="location-map-setup-rows" role="group" aria-label="Map message details">
|
<div className="location-map-setup-rows" role="group" aria-label="Map message status">
|
||||||
<div className="location-map-setup-row">
|
<div className="location-map-setup-row">
|
||||||
<span>Message</span>
|
<span>Status</span>
|
||||||
|
<strong>{status}</strong>
|
||||||
|
</div>
|
||||||
|
<div className="location-map-setup-row">
|
||||||
|
<span>Detail</span>
|
||||||
<strong>{message}</strong>
|
<strong>{message}</strong>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -30,9 +34,13 @@ export function LocationMapLoadErrorState({ location, loadError, onBack, onRetry
|
|||||||
<main className="location-map-workspace">
|
<main className="location-map-workspace">
|
||||||
<section className="location-map-setup location-map-load-error" role="alert" aria-live="polite">
|
<section className="location-map-setup location-map-load-error" role="alert" aria-live="polite">
|
||||||
<h2>Map Unavailable</h2>
|
<h2>Map Unavailable</h2>
|
||||||
<div className="location-map-setup-rows" role="group" aria-label="Map load details">
|
<div className="location-map-setup-rows" role="group" aria-label="Map load status">
|
||||||
<div className="location-map-setup-row">
|
<div className="location-map-setup-row">
|
||||||
<span>Error</span>
|
<span>Status</span>
|
||||||
|
<strong>Load failed</strong>
|
||||||
|
</div>
|
||||||
|
<div className="location-map-setup-row">
|
||||||
|
<span>Detail</span>
|
||||||
<strong>{loadError}</strong>
|
<strong>{loadError}</strong>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -104,7 +104,6 @@ export default function LocationMapToolbar({
|
|||||||
<div
|
<div
|
||||||
className={`location-map-history-buttons ${canUseHistoryControls ? "" : "is-inactive"}`}
|
className={`location-map-history-buttons ${canUseHistoryControls ? "" : "is-inactive"}`}
|
||||||
aria-label="Edit history"
|
aria-label="Edit history"
|
||||||
aria-hidden={!canUseHistoryControls}
|
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@ -184,11 +184,6 @@
|
|||||||
gap: 0.3rem;
|
gap: 0.3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.location-map-history-buttons.is-inactive {
|
|
||||||
visibility: hidden;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.location-map-history-buttons button {
|
.location-map-history-buttons button {
|
||||||
min-width: 40px;
|
min-width: 40px;
|
||||||
padding-inline: 0.55rem;
|
padding-inline: 0.55rem;
|
||||||
|
|||||||
@ -465,10 +465,9 @@ test("map message prompts for a household with compact status rows", async ({ pa
|
|||||||
await page.goto("/stores/100/locations/10/map");
|
await page.goto("/stores/100/locations/10/map");
|
||||||
|
|
||||||
await expect(page.getByRole("heading", { name: "Select Household" })).toBeVisible();
|
await expect(page.getByRole("heading", { name: "Select Household" })).toBeVisible();
|
||||||
const messageDetails = page.getByRole("group", { name: "Map message details" });
|
const messageStatus = page.getByRole("group", { name: "Map message status" });
|
||||||
await expect(messageDetails.locator(".location-map-setup-row")).toHaveCount(1);
|
await expect(messageStatus.locator(".location-map-setup-row", { hasText: "Status" })).toContainText("Select Household");
|
||||||
await expect(messageDetails.locator(".location-map-setup-row", { hasText: "Message" })).toContainText("Select a household to manage maps.");
|
await expect(messageStatus.locator(".location-map-setup-row", { hasText: "Detail" })).toContainText("Select a household to manage maps.");
|
||||||
await expect(messageDetails.locator(".location-map-setup-row", { hasText: "Status" })).toHaveCount(0);
|
|
||||||
await expect(page.locator(".location-map-message-card p")).toHaveCount(0);
|
await expect(page.locator(".location-map-message-card p")).toHaveCount(0);
|
||||||
await expect(page.getByLabel("Map controls")).toHaveCount(0);
|
await expect(page.getByLabel("Map controls")).toHaveCount(0);
|
||||||
});
|
});
|
||||||
@ -518,10 +517,9 @@ test("load failure shows retryable error instead of no-map setup", async ({ page
|
|||||||
|
|
||||||
const errorCard = page.locator(".location-map-load-error");
|
const errorCard = page.locator(".location-map-load-error");
|
||||||
await expect(errorCard.getByRole("heading", { name: "Map Unavailable" })).toBeVisible();
|
await expect(errorCard.getByRole("heading", { name: "Map Unavailable" })).toBeVisible();
|
||||||
const loadDetails = errorCard.getByRole("group", { name: "Map load details" });
|
const loadStatus = errorCard.getByRole("group", { name: "Map load status" });
|
||||||
await expect(loadDetails.locator(".location-map-setup-row")).toHaveCount(1);
|
await expect(loadStatus.locator(".location-map-setup-row", { hasText: "Status" })).toContainText("Load failed");
|
||||||
await expect(loadDetails.locator(".location-map-setup-row", { hasText: "Error" })).toContainText("Map service unavailable");
|
await expect(loadStatus.locator(".location-map-setup-row", { hasText: "Detail" })).toContainText("Map service unavailable");
|
||||||
await expect(loadDetails.locator(".location-map-setup-row", { hasText: "Status" })).toHaveCount(0);
|
|
||||||
await expect(errorCard.locator("p")).toHaveCount(0);
|
await expect(errorCard.locator("p")).toHaveCount(0);
|
||||||
await expect(page.getByText("Load Error")).toBeVisible();
|
await expect(page.getByText("Load Error")).toBeVisible();
|
||||||
await expect(page.getByRole("heading", { name: "No Map" })).toHaveCount(0);
|
await expect(page.getByRole("heading", { name: "No Map" })).toHaveCount(0);
|
||||||
@ -587,10 +585,9 @@ test("loading map keeps location context visible", async ({ page }) => {
|
|||||||
await expect(page.getByText("Eastvale")).toBeVisible();
|
await expect(page.getByText("Eastvale")).toBeVisible();
|
||||||
await expect(page.getByRole("button", { name: "Back to grocery list" })).toBeVisible();
|
await expect(page.getByRole("button", { name: "Back to grocery list" })).toBeVisible();
|
||||||
await expect(page.locator(".location-map-status")).toHaveText("Loading");
|
await expect(page.locator(".location-map-status")).toHaveText("Loading");
|
||||||
const messageDetails = page.getByRole("group", { name: "Map message details" });
|
const messageStatus = page.getByRole("group", { name: "Map message status" });
|
||||||
await expect(messageDetails.locator(".location-map-setup-row")).toHaveCount(1);
|
await expect(messageStatus.locator(".location-map-setup-row", { hasText: "Status" })).toContainText("Loading");
|
||||||
await expect(messageDetails.locator(".location-map-setup-row", { hasText: "Message" })).toContainText("Loading map...");
|
await expect(messageStatus.locator(".location-map-setup-row", { hasText: "Detail" })).toContainText("Loading map...");
|
||||||
await expect(messageDetails.locator(".location-map-setup-row", { hasText: "Status" })).toHaveCount(0);
|
|
||||||
await expect(page.locator(".location-map-message-card p")).toHaveCount(0);
|
await expect(page.locator(".location-map-message-card p")).toHaveCount(0);
|
||||||
|
|
||||||
releaseMapResponse();
|
releaseMapResponse();
|
||||||
@ -1394,15 +1391,15 @@ test("mobile keeps draft preview status compact in the topbar", async ({ page })
|
|||||||
expect(modeBox.width).toBeLessThanOrEqual(126);
|
expect(modeBox.width).toBeLessThanOrEqual(126);
|
||||||
expect(reservedHistoryBox.width).toBeGreaterThanOrEqual(82);
|
expect(reservedHistoryBox.width).toBeGreaterThanOrEqual(82);
|
||||||
expect(reservedHistoryBox.x).toBeGreaterThan(modeBox.x + modeBox.width - 1);
|
expect(reservedHistoryBox.x).toBeGreaterThan(modeBox.x + modeBox.width - 1);
|
||||||
await expect(historyActions).toHaveCSS("visibility", "hidden");
|
await expect(historyActions.getByRole("button", { name: "Undo" })).toBeVisible();
|
||||||
await expect(historyActions.locator('button[aria-label="Undo"]')).toBeDisabled();
|
await expect(historyActions.getByRole("button", { name: "Redo" })).toBeVisible();
|
||||||
await expect(historyActions.locator('button[aria-label="Redo"]')).toBeDisabled();
|
await expect(historyActions.getByRole("button", { name: "Undo" })).toBeDisabled();
|
||||||
|
await expect(historyActions.getByRole("button", { name: "Redo" })).toBeDisabled();
|
||||||
expect(zoomBox.y).toBeLessThan(modeBox.y + modeBox.height);
|
expect(zoomBox.y).toBeLessThan(modeBox.y + modeBox.height);
|
||||||
expect(zoomBox.x).toBeGreaterThan(reservedHistoryBox.x + reservedHistoryBox.width - 1);
|
expect(zoomBox.x).toBeGreaterThan(reservedHistoryBox.x + reservedHistoryBox.width - 1);
|
||||||
expect(zoomBox.x + zoomBox.width).toBeLessThanOrEqual(toolbarBox.x + toolbarBox.width + 1);
|
expect(zoomBox.x + zoomBox.width).toBeLessThanOrEqual(toolbarBox.x + toolbarBox.width + 1);
|
||||||
|
|
||||||
await page.getByRole("button", { name: "Edit Draft" }).click();
|
await page.getByRole("button", { name: "Edit Draft" }).click();
|
||||||
await expect(historyActions).toHaveCSS("visibility", "visible");
|
|
||||||
await expect(historyActions.getByRole("button", { name: "Undo" })).toBeVisible();
|
await expect(historyActions.getByRole("button", { name: "Undo" })).toBeVisible();
|
||||||
await expect(historyActions.getByRole("button", { name: "Redo" })).toBeVisible();
|
await expect(historyActions.getByRole("button", { name: "Redo" })).toBeVisible();
|
||||||
const editToolbarBox = await toolbar.boundingBox();
|
const editToolbarBox = await toolbar.boundingBox();
|
||||||
@ -1781,68 +1778,6 @@ test("admin locked map areas hide resize affordances", async ({ page }) => {
|
|||||||
await expect(page.locator(".location-map-resize-handle")).toBeVisible();
|
await expect(page.locator(".location-map-resize-handle")).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("admin selected overlapping map area renders above other areas", async ({ page }) => {
|
|
||||||
await mockMapShell(page);
|
|
||||||
|
|
||||||
const mapState = draftMapState([
|
|
||||||
{
|
|
||||||
id: 1311,
|
|
||||||
location_map_id: 900,
|
|
||||||
zone_id: 501,
|
|
||||||
zone_name: "Bakery",
|
|
||||||
type: "zone",
|
|
||||||
label: "Bakery",
|
|
||||||
x: 40,
|
|
||||||
y: 40,
|
|
||||||
width: 260,
|
|
||||||
height: 180,
|
|
||||||
rotation: 0,
|
|
||||||
locked: false,
|
|
||||||
visible: true,
|
|
||||||
sort_order: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1312,
|
|
||||||
location_map_id: 900,
|
|
||||||
zone_id: 502,
|
|
||||||
zone_name: "Frozen Foods",
|
|
||||||
type: "zone",
|
|
||||||
label: "Frozen Foods",
|
|
||||||
x: 120,
|
|
||||||
y: 90,
|
|
||||||
width: 260,
|
|
||||||
height: 180,
|
|
||||||
rotation: 0,
|
|
||||||
locked: false,
|
|
||||||
visible: true,
|
|
||||||
sort_order: 2,
|
|
||||||
},
|
|
||||||
], 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 page.getByRole("button", { name: "Continue Editing" }).click();
|
|
||||||
|
|
||||||
const bakeryArea = page.getByRole("button", { name: "Map area Bakery" });
|
|
||||||
await bakeryArea.focus();
|
|
||||||
await page.keyboard.press("Enter");
|
|
||||||
await expect(bakeryArea).toHaveAttribute("aria-pressed", "true");
|
|
||||||
|
|
||||||
await expect.poll(async () =>
|
|
||||||
page.locator(".location-map-object").evaluateAll((nodes) =>
|
|
||||||
nodes.map((node) => node.getAttribute("data-object-key"))
|
|
||||||
)
|
|
||||||
).toEqual(["1312", "1311"]);
|
|
||||||
await expect(page.locator('[data-object-key="1311"] .location-map-resize-handle')).toBeVisible();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("admin cleared map area labels keep linked zone action names", async ({ page }) => {
|
test("admin cleared map area labels keep linked zone action names", async ({ page }) => {
|
||||||
await mockMapShell(page);
|
await mockMapShell(page);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user