diff --git a/frontend/src/components/modals/ConfirmBuyModal.jsx b/frontend/src/components/modals/ConfirmBuyModal.jsx index a9fa1e6..0867759 100644 --- a/frontend/src/components/modals/ConfirmBuyModal.jsx +++ b/frontend/src/components/modals/ConfirmBuyModal.jsx @@ -31,17 +31,17 @@ export default function ConfirmBuyModal({ const hasPrev = currentIndex > 0; const hasNext = currentIndex < allItems.length - 1; - const handleIncrement = () => { - if (!isSubmitting && quantity < maxQuantity) { - setQuantity((prev) => prev + 1); - } - }; + const handleIncrement = useCallback(() => { + if (isSubmitting) return; - const handleDecrement = () => { - if (!isSubmitting && quantity > 1) { - setQuantity((prev) => prev - 1); - } - }; + setQuantity((prev) => Math.min(maxQuantity, prev + 1)); + }, [isSubmitting, maxQuantity]); + + const handleDecrement = useCallback(() => { + if (isSubmitting) return; + + setQuantity((prev) => Math.max(1, prev - 1)); + }, [isSubmitting]); const handleConfirm = async () => { if (isSubmitting) return; @@ -88,12 +88,24 @@ export default function ConfirmBuyModal({ if (event.key === "ArrowRight") { event.preventDefault(); handleNext(); + return; + } + + if (event.key === "ArrowUp") { + event.preventDefault(); + handleIncrement(); + return; + } + + if (event.key === "ArrowDown") { + event.preventDefault(); + handleDecrement(); } }; window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); - }, [handleNext, handlePrev, isSubmitting, onCancel]); + }, [handleDecrement, handleIncrement, handleNext, handlePrev, isSubmitting, onCancel]); const imageUrl = item.item_image && item.image_mime_type ? `data:${item.image_mime_type};base64,${item.item_image}` diff --git a/frontend/tests/location-map-manager.spec.ts b/frontend/tests/location-map-manager.spec.ts index 7fb8dde..f250cb6 100644 --- a/frontend/tests/location-map-manager.spec.ts +++ b/frontend/tests/location-map-manager.spec.ts @@ -3846,9 +3846,14 @@ test("viewer advances map buy modal after partial quantity buys", async ({ page await page.getByRole("button", { name: "Mark flour bought" }).click(); await expect(page.locator(".confirm-buy-item-name")).toHaveText("flour"); - await page.getByRole("button", { name: "Decrease quantity" }).click(); - await page.getByRole("button", { name: "Decrease quantity" }).click(); - await expect(page.getByRole("spinbutton", { name: "Quantity to mark bought" })).toHaveValue("1"); + const quantityInput = page.getByRole("spinbutton", { name: "Quantity to mark bought" }); + await page.keyboard.press("ArrowDown"); + await page.keyboard.press("ArrowDown"); + await expect(quantityInput).toHaveValue("1"); + await page.keyboard.press("ArrowUp"); + await expect(quantityInput).toHaveValue("2"); + await page.keyboard.press("ArrowDown"); + await expect(quantityInput).toHaveValue("1"); await page.getByRole("button", { name: "Mark as Bought" }).click(); await expect.poll(() => boughtPayloads.length).toBe(1);