From e7631b2da15d91791c7842907e7b86ebae135940 Mon Sep 17 00:00:00 2001 From: smarcet Date: Mon, 10 Aug 2026 09:39:58 -0300 Subject: [PATCH] fix: send order line_id instead of item type id when cancelling a sponsor order line mapOrderData() built each SponsorOrderGrid row's id from it.type?.id, so onCancelForm/onUndoCancelForm handed consumers the item type id instead of the order line's real identifier (it.line_id). Consumers that forward row.id straight into a cancel API call (e.g. summit-admin's cancelSponsorForm/undoCancelSponsorForm) ended up cancelling by the wrong id. Use it.line_id as the row identity, falling back to `${form.id}-${i}` only when line_id is absent. This also fixes a latent collision: two rows sharing the same item type across different forms previously produced duplicate React keys and duplicate #item- DOM anchors. --- .../__tests__/SponsorOrderGrid.test.js | 49 ++++++++++++++++++- src/components/mui/SponsorOrderGrid/index.js | 2 +- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/components/mui/SponsorOrderGrid/__tests__/SponsorOrderGrid.test.js b/src/components/mui/SponsorOrderGrid/__tests__/SponsorOrderGrid.test.js index b4422a86..2579de42 100644 --- a/src/components/mui/SponsorOrderGrid/__tests__/SponsorOrderGrid.test.js +++ b/src/components/mui/SponsorOrderGrid/__tests__/SponsorOrderGrid.test.js @@ -35,11 +35,11 @@ import "@testing-library/jest-dom"; import SponsorOrderGrid from "../index"; const makeItem = (overrides = {}) => ({ - line_id: 1, + line_id: 841, quantity: 1, amount: 10000, canceled_by_id: null, - type: { name: "Booth", code: "BOOTH" }, + type: { id: 146, name: "Booth", code: "BOOTH" }, meta_fields: [], ...overrides }); @@ -147,6 +147,51 @@ describe("SponsorOrderGrid", () => { expect(onUndoCancelForm).toHaveBeenCalledTimes(1); }); + test("passes the order line id to onCancelForm", () => { + const onCancelForm = jest.fn(); + render( + + ); + const button = document.querySelector("tbody button"); + fireEvent.click(button); + expect(onCancelForm).toHaveBeenCalledWith(expect.objectContaining({ id: 841 })); + }); + + test("passes the order line id to onUndoCancelForm", () => { + const onUndoCancelForm = jest.fn(); + const order = { + forms: [makeForm({ items: [makeItem({ line_id: 841, canceled_by_id: 99 })] })], + total: 0 + }; + render( + + ); + const button = document.querySelector("tbody button"); + fireEvent.click(button); + expect(onUndoCancelForm).toHaveBeenCalledWith(expect.objectContaining({ id: 841 })); + }); + + test("gives rows from different forms with the same item type distinct ids", () => { + const order = { + forms: [ + makeForm({ id: 10, items: [makeItem({ line_id: 841, type: { id: 146, name: "Booth", code: "BOOTH" } })] }), + makeForm({ id: 11, items: [makeItem({ line_id: 900, type: { id: 146, name: "Booth", code: "BOOTH" } })] }) + ], + total: 0 + }; + render(); + expect(document.getElementById("item-841")).toBeInTheDocument(); + expect(document.getElementById("item-900")).toBeInTheDocument(); + }); + test("renders amount_due label in total row", () => { render(); expect(screen.getByText("sponsor_order_grid.amount_due")).toBeInTheDocument(); diff --git a/src/components/mui/SponsorOrderGrid/index.js b/src/components/mui/SponsorOrderGrid/index.js index 0e0878f5..5069ba3f 100644 --- a/src/components/mui/SponsorOrderGrid/index.js +++ b/src/components/mui/SponsorOrderGrid/index.js @@ -45,7 +45,7 @@ const mapOrderData = (forms) => { .filter((it) => it.quantity) .map((it, i) => { const amount = currencyAmountFromCents(it.amount || 0); - const itemId = it.type?.id || `${form.id}-${i}`; + const itemId = it.line_id ?? `${form.id}-${i}`; const cancelled = !!it.canceled_by_id; const type = cancelled ? SPONSOR_ORDER_GRID_ITEM_TYPES.CANCELLED : SPONSOR_ORDER_GRID_ITEM_TYPES.CHARGE;