diff --git a/src/components/sponsors/reports/ByItemView.js b/src/components/sponsors/reports/ByItemView.js index dce029a0a..1f644ef72 100644 --- a/src/components/sponsors/reports/ByItemView.js +++ b/src/components/sponsors/reports/ByItemView.js @@ -177,10 +177,20 @@ export const groupLinesBySponsorItem = (rows = []) => { purchasedCount: items.filter((it) => it.qty > 0).length }; }); - groups.sort( - (a, b) => - b.totalQty - a.totalQty || a.sponsorName.localeCompare(b.sponsorName) - ); + // Nothing sorts the sponsor accordions explicitly (the column headers reorder + // items WITHIN a group), so they default to alphabetical, unknown bucket last. + // That test keys on the NAME, not sponsorId, because the card title renders as + // `sponsorName || "Unknown sponsor"` — sorting on what the card displays keeps + // every "Unknown sponsor" card together at the end. (The pivot tree keys on + // the id instead, which splits them: a blank-named sponsor shows the unknown + // label but sorts first.) This also decides which sponsors land on which + // client-side page. + groups.sort((a, b) => { + if (!a.sponsorName !== !b.sponsorName) return a.sponsorName ? -1 : 1; + return a.sponsorName + .toLowerCase() + .localeCompare(b.sponsorName.toLowerCase()); + }); return groups; }; @@ -639,7 +649,7 @@ const ByItemView = ({ > itemKey(group, item)} expandedItems={expandedItems} diff --git a/src/components/sponsors/reports/__tests__/ByItemView.test.js b/src/components/sponsors/reports/__tests__/ByItemView.test.js index 46aafdaf6..666df5c5b 100644 --- a/src/components/sponsors/reports/__tests__/ByItemView.test.js +++ b/src/components/sponsors/reports/__tests__/ByItemView.test.js @@ -106,7 +106,7 @@ describe("groupLinesBySponsorItem", () => { expect(group.items.find((i) => i.itemCode === "B").totalCents).toBe(100); }); - it("sorts items qty desc then orders desc, sponsors by totalQty desc", () => { + it("sorts items qty desc then orders desc", () => { const rows = [ line({ sponsor: { id: 1, name: "Small" }, item_code: "A", quantity: 1 }), line({ @@ -124,9 +124,25 @@ describe("groupLinesBySponsorItem", () => { }) ]; const groups = groupLinesBySponsorItem(rows); - expect(groups.map((g) => g.sponsorName)).toEqual(["Big", "Small"]); + const big = groups.find((g) => g.sponsorName === "Big"); // C: qty 9, orders 2 beats B: qty 9, orders 1 - expect(groups[0].items.map((i) => i.itemCode)).toEqual(["C", "B"]); + expect(big.items.map((i) => i.itemCode)).toEqual(["C", "B"]); + }); + + it("sorts sponsor groups alphabetically, not by qty, with unknown last", () => { + const rows = [ + line({ sponsor: { id: 1, name: "zeta" }, quantity: 1 }), + line({ sponsor: null, quantity: 1 }), + // Biggest qty by far — it still sorts on name, not units. + line({ sponsor: { id: 2, name: "Nokia" }, quantity: 99 }), + line({ sponsor: { id: 3, name: "acme" }, quantity: 1 }) + ]; + expect(groupLinesBySponsorItem(rows).map((g) => g.sponsorName)).toEqual([ + "acme", + "Nokia", + "zeta", + "" + ]); }); it("passes canceled lines through as contributors with isCanceled", () => {