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'}
+
);
}