fix: keep bought map items in layer state

This commit is contained in:
Nico 2026-06-04 13:01:22 -07:00
parent e0417783e9
commit 8510c1180a
2 changed files with 49 additions and 10 deletions

View File

@ -51,6 +51,13 @@ function getLocallyReducedMapItem(item, quantity) {
}; };
} }
function getLocallyBoughtMapItem(item) {
return {
...item,
bought: true,
};
}
export default function LocationMapManager() { export default function LocationMapManager() {
const { storeId, locationId } = useParams(); const { storeId, locationId } = useParams();
const navigate = useNavigate(); const navigate = useNavigate();
@ -129,7 +136,7 @@ export default function LocationMapManager() {
[filters, mapItems, username] [filters, mapItems, username]
); );
const buyModalItems = useMemo( const buyModalItems = useMemo(
() => (selectedObject ? selectedZoneItems : visibleUnmappedItems), () => (selectedObject ? selectedZoneItems : visibleUnmappedItems).filter((item) => !item.bought),
[selectedObject, selectedZoneItems, visibleUnmappedItems] [selectedObject, selectedZoneItems, visibleUnmappedItems]
); );
const { visibleAssignedItemCount, unmappedItemCount } = useMemo(() => { const { visibleAssignedItemCount, unmappedItemCount } = useMemo(() => {
@ -190,7 +197,11 @@ export default function LocationMapManager() {
let nextBuyModalItems = buyModalItems; let nextBuyModalItems = buyModalItems;
if (quantity >= item.quantity) { if (quantity >= item.quantity) {
nextBuyModalItems = buyModalItems.filter((candidate) => candidate.id !== item.id); nextBuyModalItems = buyModalItems.filter((candidate) => candidate.id !== item.id);
updateMapItems((currentItems) => currentItems.filter((candidate) => candidate.id !== item.id)); updateMapItems((currentItems) =>
currentItems.map((candidate) => (
candidate.id === item.id ? getLocallyBoughtMapItem(candidate) : candidate
))
);
} else { } else {
let updatedItem; let updatedItem;
try { try {

View File

@ -2339,8 +2339,8 @@ test("viewer can buy selected zone items from the map", async ({ page }) => {
quantity_bought: 1, quantity_bought: 1,
}); });
await expect(page.locator(".confirm-buy-item-name")).toHaveText("sourdough"); await expect(page.locator(".confirm-buy-item-name")).toHaveText("sourdough");
await expect(page.locator(".location-map-sheet-count")).toHaveText("1 item"); await expect(page.locator(".location-map-sheet-count")).toHaveText("1 shown");
await expect(bakeryArea.locator(".location-map-count")).toHaveText("1 item"); await expect(bakeryArea.locator(".location-map-count")).toHaveText("1 shown");
await expect(page.locator(".location-map-zone-items")).not.toContainText("french bread"); await expect(page.locator(".location-map-zone-items")).not.toContainText("french bread");
await page.getByRole("button", { name: "Mark as Bought" }).click(); await page.getByRole("button", { name: "Mark as Bought" }).click();
@ -2352,9 +2352,15 @@ test("viewer can buy selected zone items from the map", async ({ page }) => {
quantity_bought: 1, quantity_bought: 1,
}); });
await expect(page.locator(".confirm-buy-modal")).toHaveCount(0); await expect(page.locator(".confirm-buy-modal")).toHaveCount(0);
await expect(page.locator(".location-map-sheet-count")).toHaveText("0 items"); await expect(page.locator(".location-map-sheet-count")).toHaveText("0 shown");
await expect(bakeryArea.locator(".location-map-count")).toHaveText("0 items"); await expect(bakeryArea.locator(".location-map-count")).toHaveText("0 shown");
await expect(page.getByText("No items assigned to this zone yet.")).toBeVisible(); await expect(page.getByText("Items are assigned here, but hidden by layer filters.")).toBeVisible();
await page.getByRole("button", { name: "Layers" }).click();
await page.getByRole("button", { name: "Bought" }).click();
await expect(page.locator(".location-map-sheet-count")).toHaveText("2 items");
await expect(page.getByRole("button", { name: "french bread bought" })).toBeDisabled();
await expect(page.getByRole("button", { name: "sourdough bought" })).toBeDisabled();
}); });
test("viewer advances map buy modal after partial quantity buys", async ({ page }) => { test("viewer advances map buy modal after partial quantity buys", async ({ page }) => {
@ -2571,9 +2577,10 @@ test("viewer shows completed zone items without rebuy actions", async ({ page })
...items[0], ...items[0],
bought: true, bought: true,
}, },
items[1],
], ],
}; };
let boughtRequestCount = 0; const boughtPayloads: Array<Record<string, unknown>> = [];
await page.route("**/households/1/locations/10/map", async (route) => { await page.route("**/households/1/locations/10/map", async (route) => {
await route.fulfill({ await route.fulfill({
@ -2584,7 +2591,12 @@ test("viewer shows completed zone items without rebuy actions", async ({ page })
}); });
await page.route("**/households/1/locations/10/list/item", async (route) => { await page.route("**/households/1/locations/10/list/item", async (route) => {
boughtRequestCount += 1; if (route.request().method() !== "PATCH") {
await route.fulfill({ status: 404, contentType: "application/json", body: "{}" });
return;
}
boughtPayloads.push(await route.request().postDataJSON());
await route.fulfill({ await route.fulfill({
status: 200, status: 200,
contentType: "application/json", contentType: "application/json",
@ -2605,7 +2617,23 @@ test("viewer shows completed zone items without rebuy actions", async ({ page })
await boughtRow.click({ force: true }); await boughtRow.click({ force: true });
await expect(page.locator(".confirm-buy-modal")).toHaveCount(0); await expect(page.locator(".confirm-buy-modal")).toHaveCount(0);
expect(boughtRequestCount).toBe(0); expect(boughtPayloads).toHaveLength(0);
await page.getByRole("button", { name: "Mark sourdough bought" }).click();
await expect(page.locator(".confirm-buy-item-name")).toHaveText("sourdough");
await page.getByRole("button", { name: "Mark as Bought" }).click();
await expect.poll(() => boughtPayloads.length).toBe(1);
expect(boughtPayloads[0]).toMatchObject({
item_name: "sourdough",
bought: true,
quantity_bought: 1,
});
await expect(page.locator(".confirm-buy-modal")).toHaveCount(0);
const newlyBoughtRow = page.getByRole("button", { name: "sourdough bought" });
await expect(newlyBoughtRow).toBeVisible();
await expect(newlyBoughtRow).toBeDisabled();
await expect(newlyBoughtRow.locator("small")).toHaveText("Bought");
}); });
test("viewer explains when unmapped items are hidden by filters", async ({ page }) => { test("viewer explains when unmapped items are hidden by filters", async ({ page }) => {