From 567d4b6088a708b4bee8853bd8478f1e47be3732 Mon Sep 17 00:00:00 2001 From: Nico Date: Mon, 15 Jun 2026 16:27:14 -0700 Subject: [PATCH] fix: close map buy modal with escape --- .../src/components/modals/ConfirmBuyModal.jsx | 11 ++++ frontend/tests/location-map-manager.spec.ts | 50 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/frontend/src/components/modals/ConfirmBuyModal.jsx b/frontend/src/components/modals/ConfirmBuyModal.jsx index 0cfadf0..a626b4a 100644 --- a/frontend/src/components/modals/ConfirmBuyModal.jsx +++ b/frontend/src/components/modals/ConfirmBuyModal.jsx @@ -26,6 +26,17 @@ export default function ConfirmBuyModal({ setIsSubmitting(false); }, [item.id, item.quantity]); + useEffect(() => { + const handleKeyDown = (event) => { + if (event.key === "Escape" && !isSubmitting) { + onCancel(); + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [isSubmitting, onCancel]); + const currentIndex = allItems.findIndex((listItem) => listItem.id === item.id); const hasPrev = currentIndex > 0; const hasNext = currentIndex < allItems.length - 1; diff --git a/frontend/tests/location-map-manager.spec.ts b/frontend/tests/location-map-manager.spec.ts index cb71d68..e4a0637 100644 --- a/frontend/tests/location-map-manager.spec.ts +++ b/frontend/tests/location-map-manager.spec.ts @@ -3611,6 +3611,56 @@ test("viewer can buy selected zone items from the map", async ({ page }) => { await expect(page.getByRole("button", { name: "sourdough bought" })).toBeDisabled(); }); +test("viewer can close map buy modal with Escape", async ({ page }) => { + await mockMapShell(page); + + const mapState = publishedMapState([ + { + id: 1533, + 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); + const boughtPayloads: Array> = []; + + await page.route("**/households/1/locations/10/map", async (route) => { + await route.fulfill({ + status: 200, + contentType: "application/json", + body: JSON.stringify(mapState), + }); + }); + + await page.route("**/households/1/locations/10/list/item", async (route) => { + if (route.request().method() === "PATCH") { + boughtPayloads.push(await route.request().postDataJSON()); + } + await route.fulfill({ status: 404, contentType: "application/json", body: "{}" }); + }); + + await page.goto("/stores/100/locations/10/map"); + await page.locator('[data-object-key="1533"]').locator("rect").first().click(); + await page.getByRole("button", { name: "Mark french bread bought" }).click(); + await expect(page.locator(".confirm-buy-modal")).toBeVisible(); + + await page.keyboard.press("Escape"); + + await expect(page.locator(".confirm-buy-modal")).toHaveCount(0); + expect(boughtPayloads).toEqual([]); + await expect(page.getByRole("button", { name: "Mark french bread bought" })).toBeVisible(); +}); + test("viewer advances map buy modal after partial quantity buys", async ({ page }) => { await mockMapShell(page);