diff --git a/frontend/e2e/live-updates.spec.ts b/frontend/e2e/live-updates.spec.ts index bbd744cf..a73e07c5 100644 --- a/frontend/e2e/live-updates.spec.ts +++ b/frontend/e2e/live-updates.spec.ts @@ -39,7 +39,7 @@ test('member A comment appears live in member B open event view via SSE', async await pageB.goto(`/events/${event_id}`); const rsvpSectionA = pageA.getByLabel('rsvp'); - await rsvpSectionA.getByRole('button', { name: "i'm going" }).click(); + await rsvpSectionA.getByRole('button', { name: 'rsvp' }).click(); await pageA .getByRole('dialog', { name: 'rsvp' }) .getByRole('button', { name: 'confirm' }) diff --git a/frontend/e2e/rsvp-member.spec.ts b/frontend/e2e/rsvp-member.spec.ts index 18e18970..2e86cbda 100644 --- a/frontend/e2e/rsvp-member.spec.ts +++ b/frontend/e2e/rsvp-member.spec.ts @@ -27,7 +27,7 @@ test('member rsvps to an event from event detail', async ({ page }) => { await expect(page.getByRole('heading', { name: event_title })).toBeVisible(); const rsvpSection = page.getByLabel('rsvp'); - await rsvpSection.getByRole('button', { name: "i'm going" }).click(); + await rsvpSection.getByRole('button', { name: 'rsvp' }).click(); const rsvpDialog = page.getByRole('dialog', { name: 'rsvp' }); await rsvpDialog.getByRole('button', { name: 'confirm' }).click(); diff --git a/frontend/src/components/ui/RsvpStatusPicker.test.tsx b/frontend/src/components/ui/RsvpStatusPicker.test.tsx index e05bade0..a50ebef6 100644 --- a/frontend/src/components/ui/RsvpStatusPicker.test.tsx +++ b/frontend/src/components/ui/RsvpStatusPicker.test.tsx @@ -51,21 +51,6 @@ describe('RsvpStatusPicker', () => { expect(screen.getByRole('button', { name: 'join the waitlist' })).toBeInTheDocument(); }); - it('renders default-size pills unless prominent is set', () => { - render(); - const pill = screen.getByRole('button', { name: "i'm going" }); - expect(pill).toHaveClass('h-10'); - expect(pill).not.toHaveClass('flex-1'); - }); - - it('renders bigger, full-width pills when prominent', () => { - render(); - const pill = screen.getByRole('button', { name: "i'm going" }); - expect(pill).toHaveClass('h-12'); - expect(pill).toHaveClass('flex-1'); - expect(pill).toHaveClass('text-base'); - }); - it('filters to only the given statuses', () => { render(); expect(screen.getByRole('button', { name: "i'm going" })).toBeInTheDocument(); diff --git a/frontend/src/components/ui/RsvpStatusPicker.tsx b/frontend/src/components/ui/RsvpStatusPicker.tsx index 34668243..88382b27 100644 --- a/frontend/src/components/ui/RsvpStatusPicker.tsx +++ b/frontend/src/components/ui/RsvpStatusPicker.tsx @@ -8,17 +8,9 @@ interface Props { disabled?: boolean; labelFor?: (status: RsvpInputStatus, defaultLabel: string) => string; statuses?: RsvpInputStatus[]; - prominent?: boolean; } -export function RsvpStatusPicker({ - value, - onSelect, - disabled = false, - labelFor, - statuses, - prominent = false, -}: Props) { +export function RsvpStatusPicker({ value, onSelect, disabled = false, labelFor, statuses }: Props) { const options = statuses ? RSVP_STATUS_LABELS.filter((p) => statuses.includes(p.status)) : RSVP_STATUS_LABELS; @@ -37,8 +29,7 @@ export function RsvpStatusPicker({ onSelect(p.status); }} className={cn( - 'inline-flex shrink-0 items-center justify-center rounded-full font-medium transition-colors disabled:cursor-not-allowed', - prominent ? 'h-12 flex-1 px-5 text-base' : 'h-10 px-4 text-sm', + 'inline-flex h-10 shrink-0 items-center justify-center rounded-full px-4 text-sm font-medium transition-colors disabled:cursor-not-allowed', active ? 'bg-brand-600 text-brand-on' : 'border-border-strong text-foreground-secondary hover:bg-background border', diff --git a/frontend/src/screens/events/RsvpSection.test.tsx b/frontend/src/screens/events/RsvpSection.test.tsx index d2a82b8f..047ca63a 100644 --- a/frontend/src/screens/events/RsvpSection.test.tsx +++ b/frontend/src/screens/events/RsvpSection.test.tsx @@ -67,29 +67,41 @@ beforeEach(() => { }); describe('RsvpSection — before RSVPing', () => { - it('opens the RSVP box when a pill is tapped (not yet RSVP’d)', () => { + it('opens the RSVP box when the rsvp button is tapped (not yet RSVP’d)', () => { renderSection(makeEvent({ myRsvp: null })); expect(screen.queryByRole('dialog')).not.toBeInTheDocument(); - fireEvent.click(screen.getByRole('button', { name: "i'm going" })); + fireEvent.click(screen.getByRole('button', { name: 'rsvp' })); expect(screen.getByRole('dialog', { name: /RSVP/i })).toBeInTheDocument(); }); - it('shows all three pills and no status line when I have not RSVP’d', () => { + it('shows a single rsvp button and no status line when I have not RSVP’d', () => { renderSection(makeEvent({ myRsvp: null })); - expect(screen.getByRole('button', { name: "i'm going" })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: 'maybe' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: "can't go" })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'rsvp' })).toBeInTheDocument(); + expect(screen.queryByRole('button', { name: "i'm going" })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'maybe' })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: "can't go" })).not.toBeInTheDocument(); expect(screen.queryByRole('button', { name: /edit RSVP/i })).not.toBeInTheDocument(); }); - it('shows "join the waitlist" instead of "i\'m going" when the event is full', () => { + it('shows "join the waitlist" instead of "rsvp" when the event is full', () => { renderSection(makeEvent({ maxAttendees: 2, attendingCount: 2, myRsvp: null })); expect(screen.getByRole('button', { name: 'join the waitlist' })).toBeInTheDocument(); - expect(screen.queryByRole('button', { name: "i'm going" })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'rsvp' })).not.toBeInTheDocument(); + }); + + it('opens the RSVP box defaulted to "going" when the rsvp button is tapped', () => { + renderSection(makeEvent({ myRsvp: null })); + + fireEvent.click(screen.getByRole('button', { name: 'rsvp' })); + + expect(screen.getByRole('button', { name: "i'm going" })).toHaveAttribute( + 'aria-pressed', + 'true', + ); }); }); @@ -271,7 +283,7 @@ describe('RsvpSection — comments in public manage vs member flows', () => { }), ); - fireEvent.click(screen.getByRole('button', { name: /going/i })); + fireEvent.click(screen.getByRole('button', { name: 'rsvp' })); expect(screen.getByTestId('rsvp-comment-field')).toBeInTheDocument(); }); }); diff --git a/frontend/src/screens/events/RsvpSection.tsx b/frontend/src/screens/events/RsvpSection.tsx index 994b1bc1..328dc498 100644 --- a/frontend/src/screens/events/RsvpSection.tsx +++ b/frontend/src/screens/events/RsvpSection.tsx @@ -5,7 +5,6 @@ import { useCancelPublicMyRsvp, useUpdatePublicMyRsvp } from '@/api/publicRsvp'; import { useRemoveRsvp, useSetRsvp } from '@/api/rsvp'; import { useAuthStore } from '@/auth/store'; import { Button } from '@/components/ui/Button'; -import { RsvpStatusPicker } from '@/components/ui/RsvpStatusPicker'; import { type Event, isRsvpInputStatus, @@ -198,15 +197,16 @@ function RsvpControls({ } return ( - { + onOpenCreate(RsvpStatus.Attending); + }} disabled={busy} - prominent - onSelect={onOpenCreate} - labelFor={(status, defaultLabel) => - status === RsvpStatus.Attending && atCapacity ? 'join the waitlist' : defaultLabel - } - /> + className="bg-brand-600 text-brand-on hover:bg-brand-700 mx-auto inline-flex h-12 min-w-28 items-center justify-center rounded-full px-5 text-base font-medium transition-colors disabled:opacity-60" + > + {atCapacity ? 'join the waitlist' : 'rsvp'} + ); }