From 95fcaaa605c760b8c8b20f0e3ae6917b8d4cf02b Mon Sep 17 00:00:00 2001 From: Preston Mantel Date: Fri, 25 Sep 2026 15:50:28 -0700 Subject: [PATCH] fix(claims): put the wait cursor back on a confirming pill MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #2595 removed two things #2587 had added for the 10-50s a response spends confirming: the note under the claim page's Agree/Disagree pills, and the progress cursor on the pills themselves. The note was the part that made the side look not yet taken, so it stays gone. The cursor was not, and without it the row says nothing at all: presses are dropped for up to 50s with no visible reason, so the pill reads as broken rather than busy. This brings back only the cursor. aria-disabled already covered assistive tech; the pointer had nothing. Tested where the behaviour lives rather than on the claim page, since every surface that renders the pills gets it: position-row.test.tsx now pins the cursor on a pending pill, its absence once the response lands, and — in the same test — that the side still reads as held with no note under it, so the two halves of this decision cannot drift apart. Co-Authored-By: Claude Opus 5 (1M context) --- .../matchmaking/matchmaking-claim-card.tsx | 7 +++- .../debates/matchmaking/position-row.test.tsx | 36 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/apps/web/core/debates/matchmaking/matchmaking-claim-card.tsx b/apps/web/core/debates/matchmaking/matchmaking-claim-card.tsx index f15c3f9f14..a9ca7fcfbd 100644 --- a/apps/web/core/debates/matchmaking/matchmaking-claim-card.tsx +++ b/apps/web/core/debates/matchmaking/matchmaking-claim-card.tsx @@ -1023,7 +1023,8 @@ export function PositionRow({ disabled?: boolean; /** * The viewer's response is still confirming. The pills stay at full strength — the side is drawn - * as taken — but presses are dropped, and the buttons say so to assistive technology. + * as taken — but presses are dropped, and the buttons say so to assistive technology and, on the + * pointer, with a wait cursor. */ pending?: boolean; titleFor?: (position: boolean) => string; @@ -1221,6 +1222,10 @@ function PositionButton({ className={cx( className, 'transition-colors disabled:opacity-60', + // The only sign the press was taken: the pill drops presses for the 10-50s a response + // spends confirming, and nothing else on the page says so. The copy that used to sit + // under the pills read as an unsettled side, so the cue stays on the pointer. + pending && 'cursor-progress', !selected && !disabled && !pending && 'hover:border-text' )} > diff --git a/apps/web/core/debates/matchmaking/position-row.test.tsx b/apps/web/core/debates/matchmaking/position-row.test.tsx index 9ea3bf1201..e769f2b41a 100644 --- a/apps/web/core/debates/matchmaking/position-row.test.tsx +++ b/apps/web/core/debates/matchmaking/position-row.test.tsx @@ -219,4 +219,40 @@ describe('PositionRow', () => { 'bg-divider' ); }); + + // A response confirms for 10-50s, and the pills drop presses for all of it. The wait cursor is + // the only thing left that says so on screen: the note that used to sit under the pills was + // taken out, because it read as a side not yet taken, and `aria-disabled` is heard rather than + // seen. Asserted so the next pass at quieting this row does not take the last cue with it. + describe('while a response is confirming', () => { + const pill = (label: string) => screen.getByText(label).closest('button') as HTMLElement; + + it('puts a wait cursor on both pills', () => { + render( + {}} /> + ); + + expect([...pill('Agree').classList]).toContain('cursor-progress'); + expect([...pill('Disagree').classList]).toContain('cursor-progress'); + }); + + it('leaves the pills looking taken, with no note under them', () => { + render( + {}} /> + ); + + // The side still reads as held: full strength, and nothing announcing a wait. A pressable + // pill carries the fill on the button itself, not on an inner div as the read-only one does. + expect([...pill('Agree').classList]).toContain('bg-divider'); + expect(screen.queryByText(/waiting for confirmation/i)).toBeNull(); + // Dropped presses are still spoken, since a cursor is not. + expect(pill('Agree')).toHaveAttribute('aria-disabled', 'true'); + }); + + it('drops the cursor once the response lands', () => { + render( {}} />); + + expect([...pill('Agree').classList]).not.toContain('cursor-progress'); + }); + }); });