-
Notifications
You must be signed in to change notification settings - Fork 0
feat(meetings): add registrants management with rsvp details #145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Implemented comprehensive guest/registrant management capabilities with enhanced UI components and backend API support. New Components: - MeetingRegistrantsComponent: List view with add/edit capabilities for registrants - MeetingRsvpDetailsComponent: RSVP statistics, attendance tracking with progress bars UI Enhancements: - Meeting join page: Added "View Guests" button for organizers, improved layout - Meeting card: Replaced inline attendees section with new modular components - Added toggle functionality for showing/hiding registrant lists Backend API: - New endpoints for registrant CRUD operations (GET, POST, DELETE) - Added project_slug field to meeting responses - Service methods for registrant management Type Safety: - Updated Meeting interface with project_slug and registrants fields - New Registrant interface in shared package Generated with [Claude Code](https://claude.ai/code) Signed-off-by: Asitha de Silva <asithade@gmail.com>
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughRefactors meeting UI by extracting registrant and RSVP logic into new standalone components, enriches meeting payload with Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Join as MeetingJoin
participant Card as MeetingCard
participant Registrants as MeetingRegistrants
participant Rsvp as MeetingRsvpDetails
participant API as MeetingService
participant Controller as PublicMeetingController
User->>Join: Open meeting page
Join->>Controller: request public meeting
Controller->>API: fetch meeting (M2M)
Controller->>Controller: access check (if authenticated)
Controller-->>Join: return meeting { ..., project_slug, organizer }
alt Organizer or Viewer with RSVP
Join->>Rsvp: provide meeting
Rsvp->>API: getMeetingRsvps(meeting.uid)
API-->>Rsvp: RSVP list
Rsvp->>Rsvp: compute counts & UI state
Rsvp-->>Join: render RSVP summary
end
opt Show registrants
Join->>Registrants: request registrants (visible)
Registrants->>API: fetch registrants / past participants
API-->>Registrants: registrants list
Registrants->>Registrants: sort, compute additional count
Registrants-->>Join: render list, emit count
end
User->>Card: View meeting card
Card->>Rsvp: embed RSVP details (if applicable)
Card->>Registrants: embed registrants list (if applicable)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Suggested labels
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements comprehensive guest/registrant management capabilities for meetings, including new reusable UI components for displaying RSVP details and managing registrants, along with backend support for adding project_slug to meeting responses and enhanced organizer access checks.
- Refactored attendee/registrant management into standalone reusable components
- Added organizer status check to public meeting endpoint for authenticated users
- Enhanced meeting join page with improved layout and organizer-specific features
Reviewed Changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/shared/src/interfaces/meeting.interface.ts | Added project_slug field to Meeting interface |
| apps/lfx-one/src/server/services/meeting.service.ts | Updated meeting service to include project slug in response |
| apps/lfx-one/src/server/controllers/public-meeting.controller.ts | Added organizer access check for authenticated users on public meeting endpoint |
| apps/lfx-one/src/app/shared/components/meeting-rsvp-details/* | New component for displaying RSVP statistics and attendance tracking |
| apps/lfx-one/src/app/shared/components/meeting-registrants/* | New component for managing meeting registrants with add/edit capabilities |
| apps/lfx-one/src/app/shared/components/meeting-card/* | Refactored to use new modular components, removed inline registrant logic |
| apps/lfx-one/src/app/modules/meetings/meeting-join/* | Added organizer-specific UI elements and improved alert banner positioning |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
apps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.ts
Outdated
Show resolved
Hide resolved
apps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.ts
Show resolved
Hide resolved
apps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.html
Show resolved
Hide resolved
apps/lfx-one/src/app/modules/meetings/meeting-join/meeting-join.component.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/lfx-one/src/server/controllers/public-meeting.controller.ts (1)
86-131: Organizer flag never set for public meetingsLine 87 returns for public, unrestricted meetings before the organizer check executes, so authenticated organizers receive responses without
meeting.organizer, breaking the new UI paths that depend on it. Run the organizer augmentation before any response path so all callers get the flag populated.@@ - if (meeting.visibility === MeetingVisibility.PUBLIC && !meeting.restricted) { + if (req.oidc?.isAuthenticated()) { + if (originalToken !== undefined) { + req.bearerToken = originalToken; + } + + Logger.start(req, 'get_public_meeting_by_id_check_organizer', { meeting_uid: id }); + try { + meeting = await this.accessCheckService.addAccessToResource(req, meeting, 'meeting', 'organizer'); + Logger.success(req, 'get_public_meeting_by_id_check_organizer', startTime, { + meeting_uid: id, + is_organizer: meeting.organizer, + }); + } catch (error) { + req.log.warn( + { + error: error instanceof Error ? error.message : error, + meeting_uid: id, + }, + 'Failed to check organizer status, continuing with organizer = false' + ); + meeting.organizer = false; + } + } else { + meeting.organizer = false; + } + + if (meeting.visibility === MeetingVisibility.PUBLIC && !meeting.restricted) { // Only get join URL if within allowed join time window if (this.isWithinJoinWindow(meeting)) { await this.handleJoinUrlForPublicMeeting(req, meeting, id); } res.json({ meeting, project: { name: project.name, slug: project.slug, logo_url: project.logo_url } }); return; } @@ - // Check if user is authenticated and add organizer field - if (req.oidc?.isAuthenticated()) { - // Restore user's original token before organizer check - if (originalToken !== undefined) { - req.bearerToken = originalToken; - } - - Logger.start(req, 'get_public_meeting_by_id_check_organizer', { meeting_uid: id }); - try { - meeting = await this.accessCheckService.addAccessToResource(req, meeting, 'meeting', 'organizer'); - Logger.success(req, 'get_public_meeting_by_id_check_organizer', startTime, { - meeting_uid: id, - is_organizer: meeting.organizer, - }); - } catch (error) { - // If organizer check fails, log but continue with organizer = false - req.log.warn( - { - error: error instanceof Error ? error.message : error, - meeting_uid: id, - }, - 'Failed to check organizer status, continuing with organizer = false' - ); - meeting.organizer = false; - } - } else { - // User is not authenticated, set organizer to false - meeting.organizer = false; - }
🧹 Nitpick comments (4)
apps/lfx-one/src/app/shared/components/meeting-rsvp-details/meeting-rsvp-details.component.ts (1)
53-67: Consider using structured logging instead of console.error.Line 59 uses
console.errorfor logging RSVP fetch failures. In production environments, consider using a proper logging service (like the one available in the backend at@services/logger.service) for better observability, error tracking, and integration with monitoring systems.apps/lfx-one/src/app/shared/components/meeting-registrants/meeting-registrants.component.ts (3)
93-117: Improve null handling in sorting logic.The current sorting logic may produce inconsistent results when
first_nameis null or undefined:
- Line 104:
a.first_name?.localeCompare(b.first_name ?? '') ?? 0When
a.first_nameis null/undefined, the optional chaining returns undefined, then the nullish coalescing returns 0 (no sort). However,b.first_nameis normalized to an empty string, creating asymmetric comparison behavior.Apply this diff for more consistent sorting:
- map((registrants) => registrants.sort((a, b) => a.first_name?.localeCompare(b.first_name ?? '') ?? 0) as MeetingRegistrant[]), + map((registrants) => registrants.sort((a, b) => (a.first_name ?? '').localeCompare(b.first_name ?? ''))),This ensures both sides are normalized to empty strings when null/undefined, providing predictable sort order. Also removes unnecessary type cast since
mapalready infers the correct type.
93-137: Consider adding error logging for failed data fetches.Both
initRegistrantsList(line 102) andinitPastMeetingParticipantsList(line 128) usecatchError(() => of([]))to silently fall back to empty arrays. While this prevents crashes, it provides no visibility into why data might be missing.Consider logging errors or providing user feedback when API calls fail:
.pipe(catchError((error) => { console.error('Failed to load registrants:', error); // Optionally: show toast/message to user return of([]); }))This helps with debugging and improves user experience by explaining why no data appears.
93-137: Optional: Consider consolidating initialization logic.The two initialization methods (
initRegistrantsListandinitPastMeetingParticipantsList) share significant structural similarity, differing mainly in the service method called and post-processing logic. While keeping them separate maintains clarity, consolidating into a single method with conditional branches could reduce duplication.However, given the different return types and processing requirements, the current separation may be more maintainable. This is a stylistic choice.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (11)
apps/lfx-one/src/app/modules/meetings/meeting-join/meeting-join.component.html(3 hunks)apps/lfx-one/src/app/modules/meetings/meeting-join/meeting-join.component.ts(4 hunks)apps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.html(4 hunks)apps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.ts(6 hunks)apps/lfx-one/src/app/shared/components/meeting-registrants/meeting-registrants.component.html(1 hunks)apps/lfx-one/src/app/shared/components/meeting-registrants/meeting-registrants.component.ts(1 hunks)apps/lfx-one/src/app/shared/components/meeting-rsvp-details/meeting-rsvp-details.component.html(1 hunks)apps/lfx-one/src/app/shared/components/meeting-rsvp-details/meeting-rsvp-details.component.ts(1 hunks)apps/lfx-one/src/server/controllers/public-meeting.controller.ts(4 hunks)apps/lfx-one/src/server/services/meeting.service.ts(1 hunks)packages/shared/src/interfaces/meeting.interface.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
packages/shared/src/interfaces/**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Place all TypeScript interfaces in the shared package at packages/shared/src/interfaces
Files:
packages/shared/src/interfaces/meeting.interface.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Use TypeScript interfaces instead of union types for better maintainability
When defining PrimeNG-related types, reference the official PrimeNG component interfaces
Files:
packages/shared/src/interfaces/meeting.interface.tsapps/lfx-one/src/app/shared/components/meeting-rsvp-details/meeting-rsvp-details.component.tsapps/lfx-one/src/server/services/meeting.service.tsapps/lfx-one/src/app/shared/components/meeting-registrants/meeting-registrants.component.tsapps/lfx-one/src/server/controllers/public-meeting.controller.tsapps/lfx-one/src/app/modules/meetings/meeting-join/meeting-join.component.tsapps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.ts
**/*.{ts,tsx,js,jsx,mjs,cjs,html,css,scss}
📄 CodeRabbit inference engine (CLAUDE.md)
Include required license headers on all source files
Files:
packages/shared/src/interfaces/meeting.interface.tsapps/lfx-one/src/app/shared/components/meeting-rsvp-details/meeting-rsvp-details.component.tsapps/lfx-one/src/server/services/meeting.service.tsapps/lfx-one/src/app/shared/components/meeting-registrants/meeting-registrants.component.tsapps/lfx-one/src/app/modules/meetings/meeting-join/meeting-join.component.htmlapps/lfx-one/src/app/shared/components/meeting-registrants/meeting-registrants.component.htmlapps/lfx-one/src/server/controllers/public-meeting.controller.tsapps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.htmlapps/lfx-one/src/app/shared/components/meeting-rsvp-details/meeting-rsvp-details.component.htmlapps/lfx-one/src/app/modules/meetings/meeting-join/meeting-join.component.tsapps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not nest ternary expressions
Files:
packages/shared/src/interfaces/meeting.interface.tsapps/lfx-one/src/app/shared/components/meeting-rsvp-details/meeting-rsvp-details.component.tsapps/lfx-one/src/server/services/meeting.service.tsapps/lfx-one/src/app/shared/components/meeting-registrants/meeting-registrants.component.tsapps/lfx-one/src/server/controllers/public-meeting.controller.tsapps/lfx-one/src/app/modules/meetings/meeting-join/meeting-join.component.tsapps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.ts
apps/lfx-one/src/**/*.html
📄 CodeRabbit inference engine (CLAUDE.md)
apps/lfx-one/src/**/*.html: Always add data-testid attributes when creating new Angular components for reliable test targeting
Use data-testid naming convention [section]-[component]-[element]
Files:
apps/lfx-one/src/app/modules/meetings/meeting-join/meeting-join.component.htmlapps/lfx-one/src/app/shared/components/meeting-registrants/meeting-registrants.component.htmlapps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.htmlapps/lfx-one/src/app/shared/components/meeting-rsvp-details/meeting-rsvp-details.component.html
🧠 Learnings (3)
📚 Learning: 2025-10-21T21:19:13.599Z
Learnt from: andrest50
Repo: linuxfoundation/lfx-v2-ui PR: 125
File: apps/lfx-one/src/app/modules/project/meetings/components/meeting-card/meeting-card.component.ts:345-350
Timestamp: 2025-10-21T21:19:13.599Z
Learning: In the Angular meeting card component (apps/lfx-one/src/app/modules/project/meetings/components/meeting-card/meeting-card.component.ts), when selecting between `summary.summary_data.edited_content` and `summary.summary_data.content`, the logical OR operator (`||`) is intentionally used instead of nullish coalescing (`??`) because empty string edited_content should fall back to the original content rather than being displayed as empty.
Applied to files:
apps/lfx-one/src/app/shared/components/meeting-rsvp-details/meeting-rsvp-details.component.tsapps/lfx-one/src/server/services/meeting.service.tsapps/lfx-one/src/app/modules/meetings/meeting-join/meeting-join.component.htmlapps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.htmlapps/lfx-one/src/app/shared/components/meeting-rsvp-details/meeting-rsvp-details.component.htmlapps/lfx-one/src/app/modules/meetings/meeting-join/meeting-join.component.tsapps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.ts
📚 Learning: 2025-09-16T03:32:46.518Z
Learnt from: CR
Repo: linuxfoundation/lfx-v2-ui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T03:32:46.518Z
Learning: Applies to apps/lfx-one/src/**/*.html : Always add data-testid attributes when creating new Angular components for reliable test targeting
Applied to files:
apps/lfx-one/src/app/shared/components/meeting-registrants/meeting-registrants.component.html
📚 Learning: 2025-09-16T03:32:46.518Z
Learnt from: CR
Repo: linuxfoundation/lfx-v2-ui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T03:32:46.518Z
Learning: All PrimeNG components are wrapped in LFX components to keep UI library independence
Applied to files:
apps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.ts
🧬 Code graph analysis (2)
apps/lfx-one/src/app/shared/components/meeting-rsvp-details/meeting-rsvp-details.component.ts (2)
packages/shared/src/interfaces/meeting.interface.ts (5)
Meeting(75-152)PastMeeting(523-536)MeetingOccurrence(158-171)MeetingRsvp(752-773)RsvpCounts(737-746)packages/shared/src/utils/rsvp-calculator.util.ts (1)
calculateRsvpCounts(15-60)
apps/lfx-one/src/app/shared/components/meeting-registrants/meeting-registrants.component.ts (3)
apps/lfx-one/src/app/modules/meetings/meeting-join/meeting-join.component.ts (1)
Component(40-449)apps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.ts (1)
Component(69-742)packages/shared/src/interfaces/meeting.interface.ts (4)
Meeting(75-152)PastMeeting(523-536)MeetingRegistrant(279-322)PastMeetingParticipant(542-569)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Agent
🔇 Additional comments (13)
packages/shared/src/interfaces/meeting.interface.ts (1)
150-151: LGTM!The addition of the
project_slugfield to theMeetinginterface is straightforward and well-documented. This change aligns with the UI updates that utilize project slugs for routing.apps/lfx-one/src/server/services/meeting.service.ts (1)
900-903: LGTM!The addition of
project_slugto the meeting response follows the same pattern asproject_namewith appropriate fallback handling. This change correctly enriches the meeting data to support slug-based routing in the UI.apps/lfx-one/src/app/shared/components/meeting-registrants/meeting-registrants.component.html (1)
1-82: LGTM!The template follows Angular best practices with proper license headers, appropriate data-testid attributes for testing, and clear conditional logic for rendering past/upcoming meeting states. The invite acceptance status logic correctly handles three states (declined, pending, accepted).
apps/lfx-one/src/app/modules/meetings/meeting-join/meeting-join.component.ts (1)
17-18: LGTM!The changes properly integrate the new
MeetingRegistrantsComponentandMeetingRsvpDetailsComponent:
- Imports are correctly added to both the import statement and the component's imports array
- The new
showRegistrantssignal follows Angular 19 zoneless patterns- The
formValuesvisibility change to public is appropriate if the template requires access- The
onRegistrantsToggle()method correctly toggles the registrants visibility stateAlso applies to: 51-52, 93-93, 96-96, 128-130
apps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.html (2)
84-93: Verify project_slug empty string handling.The condition at line 84 now checks
meeting().project_sluginstead ofproject()?.slug. Since the backend returns an empty string as a fallback when the project is not found (apps/lfx-one/src/server/services/meeting.service.ts:902), the condition will correctly prevent the edit button from rendering when no valid project slug exists. Ensure this behavior is intentional.
277-327: LGTM!The component integration is well-structured:
MeetingRsvpDetailsComponentproperly receives all required inputs and emits events correctly- The "View Guests" / "Add Guest" button label logic provides good UX by adapting to the registrant count
- The
registrantsCountChangeevent creates proper reactive data flow between the registrants component and RSVP details component- All signal bindings follow Angular 19 patterns correctly
apps/lfx-one/src/app/modules/meetings/meeting-join/meeting-join.component.html (2)
164-196: Verify hardcoded additionalRegistrantsCount for meeting-join page.Line 173 passes
additionalRegistrantsCount="0"to the RSVP details component. Unlike the meeting-card component which tracks dynamic registrant count changes, this hardcoded value means the RSVP statistics won't update if registrants are added during the session. Verify this is the intended behavior for the meeting-join page context.
266-390: LGTM!The footer authentication section is well-structured:
- Signed-in state properly displays user information with a sensible fallback for empty names
- Signed-out state provides clear CTAs for both authenticated login and guest joining
- Guest form includes proper validation, required field indicators, and appropriate disabled states
- Accessibility is maintained with proper labels and required field markers
- returnTo parameters correctly preserve navigation context
apps/lfx-one/src/app/shared/components/meeting-registrants/meeting-registrants.component.ts (2)
38-45: LGTM: Visibility-based loading pattern.The effect correctly triggers data loading when the component becomes visible, which is an efficient pattern for conditionally rendered components.
47-87: LGTM: Modal handling with proper cleanup.Both modal methods correctly use
take(1)to auto-unsubscribe and trigger refresh after changes, ensuring data consistency.apps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.ts (3)
196-203: LGTM: Simplified toggle logic with child component delegation.The refactored
onRegistrantsTogglecorrectly delegates data loading responsibilities to the childMeetingRegistrantsComponent, simplifying parent logic while maintaining the UX pattern of opening the add modal when no registrants exist.
205-217: Verify registrant state synchronization after modal close.The simplified
openAddRegistrantModalno longer subscribes toregistrantSavedor callsrefreshMeeting(). While the childMeetingRegistrantsComponenthandles its own refresh and emitsregistrantsCountChange, ensure that all necessary parent state updates occur through this event binding in the template.If you find that meeting-level counts or other properties aren't updating correctly after adding registrants via this modal, you may need to restore the onClose subscription:
.onClose.pipe(take(1)) .subscribe((saved) => { if (saved) { this.registrantsComponent.refresh(); } });
488-499: LGTM: Cleaner separation of concerns.Removing the
finalize(() => this.refresh$.next(true))call is appropriate now that registrant management is delegated to the child component. The parent focuses on meeting-level data while the child handles registrant-specific state.
apps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.ts
Outdated
Show resolved
Hide resolved
apps/lfx-one/src/app/shared/components/meeting-rsvp-details/meeting-rsvp-details.component.html
Show resolved
Hide resolved
apps/lfx-one/src/app/shared/components/meeting-rsvp-details/meeting-rsvp-details.component.ts
Outdated
Show resolved
Hide resolved
Signed-off-by: Asitha de Silva <asithade@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
apps/lfx-one/src/app/shared/components/meeting-rsvp-details/meeting-rsvp-details.component.ts (1)
53-67: Consider structured logging for error handling.The error handling gracefully returns an empty array on failure, which is good. However, using
console.error(line 59) is less than ideal for production environments. Consider using a structured logging service for better observability and debugging.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (3)
apps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.html(4 hunks)apps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.ts(6 hunks)apps/lfx-one/src/app/shared/components/meeting-rsvp-details/meeting-rsvp-details.component.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Use TypeScript interfaces instead of union types for better maintainability
When defining PrimeNG-related types, reference the official PrimeNG component interfaces
Files:
apps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.tsapps/lfx-one/src/app/shared/components/meeting-rsvp-details/meeting-rsvp-details.component.ts
**/*.{ts,tsx,js,jsx,mjs,cjs,html,css,scss}
📄 CodeRabbit inference engine (CLAUDE.md)
Include required license headers on all source files
Files:
apps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.tsapps/lfx-one/src/app/shared/components/meeting-rsvp-details/meeting-rsvp-details.component.tsapps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.html
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not nest ternary expressions
Files:
apps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.tsapps/lfx-one/src/app/shared/components/meeting-rsvp-details/meeting-rsvp-details.component.ts
apps/lfx-one/src/**/*.html
📄 CodeRabbit inference engine (CLAUDE.md)
apps/lfx-one/src/**/*.html: Always add data-testid attributes when creating new Angular components for reliable test targeting
Use data-testid naming convention [section]-[component]-[element]
Files:
apps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.html
🧠 Learnings (2)
📚 Learning: 2025-10-21T21:19:13.599Z
Learnt from: andrest50
Repo: linuxfoundation/lfx-v2-ui PR: 125
File: apps/lfx-one/src/app/modules/project/meetings/components/meeting-card/meeting-card.component.ts:345-350
Timestamp: 2025-10-21T21:19:13.599Z
Learning: In the Angular meeting card component (apps/lfx-one/src/app/modules/project/meetings/components/meeting-card/meeting-card.component.ts), when selecting between `summary.summary_data.edited_content` and `summary.summary_data.content`, the logical OR operator (`||`) is intentionally used instead of nullish coalescing (`??`) because empty string edited_content should fall back to the original content rather than being displayed as empty.
Applied to files:
apps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.tsapps/lfx-one/src/app/shared/components/meeting-rsvp-details/meeting-rsvp-details.component.tsapps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.html
📚 Learning: 2025-09-16T03:32:46.518Z
Learnt from: CR
Repo: linuxfoundation/lfx-v2-ui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T03:32:46.518Z
Learning: All PrimeNG components are wrapped in LFX components to keep UI library independence
Applied to files:
apps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.ts
🧬 Code graph analysis (1)
apps/lfx-one/src/app/shared/components/meeting-rsvp-details/meeting-rsvp-details.component.ts (2)
packages/shared/src/interfaces/meeting.interface.ts (5)
Meeting(75-152)PastMeeting(523-536)MeetingOccurrence(158-171)MeetingRsvp(752-773)RsvpCounts(737-746)packages/shared/src/utils/rsvp-calculator.util.ts (1)
calculateRsvpCounts(15-60)
🔇 Additional comments (9)
apps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.html (4)
84-93: LGTM! Simplified project slug access.The change from
project()?.slugtomeeting().project_slugsimplifies data access by sourcing the slug directly from the meeting object. This eliminates the dependency on the separate project signal and aligns with the Meeting interface enhancement that now includesproject_slug.
277-290: LGTM! Clean delegation to specialized components.The replacement of inline RSVP markup with
<lfx-meeting-rsvp-details>for organizers and<lfx-rsvp-button-group>for non-organizers successfully modularizes the UI. All required inputs are properly bound, and theaddParticipantevent is correctly wired toopenAddRegistrantModal().
294-305: LGTM! Organizer-specific guest management.The conditional rendering of the "View Guests"/"Add Guest" button for organizers is correctly implemented with appropriate guards and dynamic labeling based on registrant count. The
data-testidattribute is properly included per coding guidelines.
322-328: LGTM! Registrants component properly integrated.The
<lfx-meeting-registrants>component is correctly bound with all necessary inputs. TheshowAddRegistrantinput binding (line 326) addresses the previous review comment, and theregistrantsCountChangeevent properly updates the parent'sadditionalRegistrantsCountsignal.apps/lfx-one/src/app/shared/components/meeting-card/meeting-card.component.ts (3)
7-7: LGTM! Import updates align with refactoring.The import changes correctly support the new component delegation pattern:
- Added
MeetingRegistrantsComponentandMeetingRsvpDetailsComponentimports (lines 20-21, 73-74)- Updated rxjs-interop and rxjs imports (lines 7, 53) to match the refactored reactive patterns
Also applies to: 20-21, 53-53, 73-74
472-483: LGTM! Clean refresh implementation.The
refreshMeetingmethod correctly fetches the updated meeting data, resets theadditionalRegistrantsCountsignal, and updates themeetingsignal. The implementation is clean and follows reactive patterns.
189-201: The review comment is incorrect.The
openAddRegistrantModal()method in meeting-card.component.ts doesn't need to subscribe to refresh events.MeetingRegistrantsComponentalready handles its own state refresh—it subscribes toregistrantSavedin itsonAddRegistrantClick()method and callsthis.refresh(), which triggers therefresh$BehaviorSubject to fetch updated registrant data. This is proper component architecture where the component displaying the data is responsible for managing its own state updates.Likely an incorrect or invalid review comment.
apps/lfx-one/src/app/shared/components/meeting-rsvp-details/meeting-rsvp-details.component.ts (2)
22-32: LGTM! Well-structured component inputs and outputs.The component correctly uses Angular 19's signal-based APIs with
InputSignalandOutputEmitterRef. Input defaults are appropriate, and the type annotations are clear and correct.
132-140: LGTM! Null project guard properly implemented.The
editLinkcomputed signal now correctly guards against null/undefined project by checking the slug before constructing the URL and providing a fallback. This addresses the previous review concern about malformed URLs.
Summary
Implemented comprehensive guest/registrant management capabilities for meetings with enhanced UI components and backend API support.
Changes
New Reusable Components
UI Enhancements
Backend API
GET /meeting/:uid/registrants- Fetch registrants listPOST /meeting/:uid/registrants- Add registrantDELETE /meeting/:uid/registrants/:registrantId- Delete registrantproject_slugfield to meeting response objectsType Safety
project_slugandregistrantsfieldsTechnical Details
Testing
Related Issues
Files Changed