You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat(meetings): load the viewer's own rsvp on the v2 page - #3344
Closes#2880 · epic #1765 · targets the integration branch feat/meeting-details-v2
Summary
E2-04 loads the viewer's own RSVP on the V2 page (FR-023). The public payload doesn't carry it.
MeetingDetailsStateService.myRsvp holds the viewer's answer for the selected occurrence:
RsvpResponse once answered, null when not answered yet, undefined while unknown.
It's fetched only for a signed-in viewer on the invite list of an upcoming or live meeting with RSVP tracking on.
It's scoped to the selected occurrence through resolveRsvpOccurrenceId, as V1 scopes it.
It feeds three places:
Status pill and identity bar (resolveMeetingStatus): going / maybe / cant-attend, or awaiting-rsvp when not answered.
Header data-my-rsvp (testid contract): accepted / maybe / declined / none, and absent while unknown.
The rsvp slot's line: until E2-05's card replaces it, it names the answer ("You're going.", "You replied maybe.", "You can't attend.", "…You haven't replied yet."). It carries the same data-my-rsvp.
A failed fetch reads as unknown, never as "not answered" (#2880: "degrades to no chip"):
The pill shows the time state, not "Awaiting your RSVP".
MeetingService.getMeetingRsvpForCurrentUser turns failures into null, so this PR adds a strict sibling, getMeetingRsvpForCurrentUserOrFail, that logs and rethrows.
The original keeps its exact behaviour (log, then null) by delegating to it, so V1 and the RSVP button group are unchanged. Specs pin both behaviours.
BFF (added in review): the server's getMeetingRsvpForCurrentUser used to catch every failure and answer 200 null, which made failures indistinguishable from "not answered" before they ever reached the client.
It now lets a failed registrant or RSVP lookup propagate to apiErrorHandler, which returns an error status.
null still means no identity or no registrant row.
Its only caller is the /rsvp/me controller. V1's client still reads any error as null, so V1 is unchanged.
setMyRsvp(meetingId, occurrenceId, rsvp) is for E2-05's card to apply a just-saved RSVP ahead of the indexer:
It switches out any fetch in flight. V1's rsvpUpdateCounter guarded the same race, but inside a switchMap its filter could never fire, so it isn't ported.
The request key is deduplicated, so the 30s clock tick and re-lookups never refetch over the saved answer.
A save that lands after the page moved to another occurrence or meeting is dropped. This is checked synchronously against the route.
A failed fetch is retried once at once, then on each 30s clock tick until it succeeds.
V1's "bind (rsvpChanged) on the attendee branch" maps to setMyRsvp, which E2-05's card will call. No other component has to wire it.
Validation
Tests: V2 page specs 215 (meetings 931 before the review fixes); MeetingService 20. yarn build, a forced check-types, lint:check (0 errors) and format:check are green.
New coverage:
each answer → status and attribute;
occurrence scoping;
failure → unknown;
no fetch for outsiders, tracking off, anonymous, or ended;
a saved answer beats an in-flight fetch and survives a re-lookup;
changing the occurrence refetches;
stale saves are dropped.
Pre-PR review: one round with the general, repo-code and learnings reviewers. Fixed in 372b79e:
setMyRsvp scoped to the meeting and occurrence the RSVP was saved for;
dedupe and refetch tests;
the slot attribute assertion.
/lfx-self-serve-pr-readiness (against the integration branch) READY; /preflight passes.
Medium Risk
Changes BFF /rsvp/me error handling and meeting-details state/fetch logic; V1 keeps the tolerant client path, but V2 status and RSVP messaging depend on the new strict contract.
Overview Loads the signed-in invitee's own RSVP on the V2 meeting details page (E2-04 / FR-023), since the public meeting payload does not include it.
MeetingDetailsStateService now fetches /rsvp/me (occurrence-scoped for series), exposes myRsvp / myRsvpAttr, feeds resolveMeetingStatus (going / maybe / awaiting-rsvp, etc.), and adds setMyRsvp for E2-05 optimistic saves with deduped requests, retries on failure, and stale-save guards when the route or occurrence changes. Fetch failures stay unknown (undefined) so the status pill does not show "Awaiting your RSVP".
The header pill and rsvp action slot bind data-my-rsvp and show confirmation copy ("You're going.", etc.) until the RSVP card lands in E2-05.
API semantics: client getMeetingRsvpForCurrentUserOrFail rethrows after logging; the lenient method still returns null on error for V1/RSVP buttons. The BFFgetMeetingRsvpForCurrentUser no longer swallows lookup failures as 200 null—errors propagate so V2 can distinguish load failure from no answer—and uses a strict raw RSVP page walk.
Specs and testid-contract.md document the attribute behavior.
Reviewed by Cursor Bugbot for commit 1d272fe. Bugbot is set up for automated code reviews on this repo. Configure here.
Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Essentials
Run ID: 298b0e45-de3f-4531-88d6-fba462b3965a
You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.
Use the checkbox below for a quick retry:
🔍 Trigger review
Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Comment @coderabbitai help to get the list of available commands.
@nunoeufrasio I'm starting review 1 of this pull request now (started 2026-10-07 09:25 UTC). This usually takes a few minutes — I'll update this comment with the summary when I'm done.
The change loads the viewer's own RSVP on the V2 meeting page and feeds it to the status pill, the header and the rsvp slot. A failed fetch reads as unknown rather than "not answered". The strict OrFail sibling keeps V1 behaviour unchanged. setMyRsvp is scoped to the meeting and occurrence, and a save beats an in-flight fetch. The new specs cover each of these paths.
⚪ Nit: 1 issue: A failed RSVP fetch is never retried
✅ Approved
➡️ This auto-review agent is a preview. Please send feedback to @dealako.
This registrant lookup is still partial-tolerant: getMeetingRegistrantsForUser calls fetchAllQueryResources without failOnPartial: true. Because this path intentionally supports multiple occurrence-specific/re-registration rows, a later-page failure can omit the row carrying the applicable RSVP and return 200 with null or an older answer instead of the required unknown/error state. Add a strict option/sibling for this complete-set lookup and use it here.
This registrant lookup is still partial-tolerant: getMeetingRegistrantsForUser calls fetchAllQueryResources without failOnPartial: true, so a later-page failure returns a partial prefix instead of rejecting. That can make this endpoint return 200 null or select an RSVP from an incomplete registrant-ID set—the exact failure/“not answered” ambiguity this strict path is intended to remove. Add a strict option to getMeetingRegistrantsForUser, enable it here, and cover a second-page registrant failure.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2880 · epic #1765 · targets the integration branch
feat/meeting-details-v2Summary
E2-04 loads the viewer's own RSVP on the V2 page (FR-023). The public payload doesn't carry it.
MeetingDetailsStateService.myRsvpholds the viewer's answer for the selected occurrence:RsvpResponseonce answered,nullwhen not answered yet,undefinedwhile unknown.resolveRsvpOccurrenceId, as V1 scopes it.It feeds three places:
resolveMeetingStatus):going/maybe/cant-attend, orawaiting-rsvpwhen not answered.data-my-rsvp(testid contract):accepted/maybe/declined/none, and absent while unknown.rsvpslot's line: until E2-05's card replaces it, it names the answer ("You're going.", "You replied maybe.", "You can't attend.", "…You haven't replied yet."). It carries the samedata-my-rsvp.A failed fetch reads as unknown, never as "not answered" (#2880: "degrades to no chip"):
MeetingService.getMeetingRsvpForCurrentUserturns failures intonull, so this PR adds a strict sibling,getMeetingRsvpForCurrentUserOrFail, that logs and rethrows.null) by delegating to it, so V1 and the RSVP button group are unchanged. Specs pin both behaviours.getMeetingRsvpForCurrentUserused to catch every failure and answer200 null, which made failures indistinguishable from "not answered" before they ever reached the client.apiErrorHandler, which returns an error status.nullstill means no identity or no registrant row./rsvp/mecontroller. V1's client still reads any error asnull, so V1 is unchanged.setMyRsvp(meetingId, occurrenceId, rsvp)is for E2-05's card to apply a just-saved RSVP ahead of the indexer:rsvpUpdateCounterguarded the same race, but inside aswitchMapits filter could never fire, so it isn't ported.V1's "bind
(rsvpChanged)on the attendee branch" maps tosetMyRsvp, which E2-05's card will call. No other component has to wire it.Validation
MeetingService20.yarn build, a forcedcheck-types,lint:check(0 errors) andformat:checkare green.setMyRsvpscoped to the meeting and occurrence the RSVP was saved for;/lfx-self-serve-pr-readiness(against the integration branch) READY;/preflightpasses.🤖 Generated with Claude Code