feat: Add Team Members & Organization Directory page#88
Conversation
- Add API endpoint GET /api/organization/members to fetch organization members - Create TeamMembers page with member list, search, and filters - Implement member details modal with profile information - Add role-based filtering (Admin/Member) - Add search functionality for name, email, and role - Add sorting by name, join date, and role - Implement loading, empty, and error states - Add quick actions (copy email) - Add Team Members link to navigation bar - Follow MeetOnMemory design language with responsive layout
|
@mrunmayeekokitkar is attempting to deploy a commit to the Shiv Raj Singh's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Warning Review limit reached
Next review available in: 53 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughAdds a Team Members directory feature: a backend endpoint retrieving organization members with populated fields, a new frontend ChangesTeam Members Feature
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant TeamMembersPage
participant OrganizationRoutes
participant OrganizationController
participant Database
User->>TeamMembersPage: Navigate to /team-members
TeamMembersPage->>OrganizationRoutes: GET /api/organization/members
OrganizationRoutes->>OrganizationController: getOrganizationMembers(req, res)
OrganizationController->>Database: Fetch user, verify organization
OrganizationController->>Database: Fetch organization, populate members
Database-->>OrganizationController: organization + members
OrganizationController-->>TeamMembersPage: 200 { members, organizationName }
TeamMembersPage->>TeamMembersPage: applyFiltersAndSort(search, role, sort)
TeamMembersPage-->>User: Render filtered member cards
User->>TeamMembersPage: Click member card
TeamMembersPage-->>User: Show member details modal
Compact metadata:
🐰 A rabbit hopped through org charts wide, 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…ion declarations - Add apiLimiter to organizationRoutes.js to fix CodeQL security alerts - Fix duplicate updateMeeting function declaration in meetingController.js - Fix duplicate updateMeeting import in meetingRoutes.js - Fix malformed getMeetingById function in meetingController.js
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (3)
server/controllers/organizationController.js (1)
193-216: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winRedundant DB round-trip:
req.useralready hasorganization.
userAuthmiddleware already loads the user viafindById(decoded.id).select("-password")and assigns it toreq.user. Re-queryinguserModel.findById(req.user.id)here just to read.organizationadds an unnecessary DB call on every request to this endpoint.⚡ Proposed fix
- const user = await userModel.findById(req.user.id); - if (!user || !user.organization) { + if (!req.user.organization) { return res .status(400) .json({ success: false, message: "User is not part of an organization.", }); } const organization = await Organization.findById( - user.organization, + req.user.organization, ).populate({🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@server/controllers/organizationController.js` around lines 193 - 216, `getOrganizationMembers` is doing an unnecessary `userModel.findById(req.user.id)` lookup even though `userAuth` already populated `req.user` with the authenticated user record. Update this handler to read `req.user.organization` directly after the auth check, and keep the existing guard for missing organization before calling `Organization.findById(...).populate(...)`.client/src/pages/TeamMembers.jsx (2)
70-109: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider
useMemoinstead of state+effect forfilteredMembers.
applyFiltersAndSortrecomputes and callssetFilteredMembers, triggering an extra render each time inputs change. AuseMemoon the derived list would avoid the redundant state/effect indirection.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@client/src/pages/TeamMembers.jsx` around lines 70 - 109, The filtered member list in TeamMembers should be derived data instead of stored via state updates in applyFiltersAndSort, since calling setFilteredMembers causes an extra render whenever members, searchQuery, roleFilter, sortBy, or sortOrder changes. Refactor the TeamMembers component to compute the final list with useMemo using the same filtering and sorting logic, and remove the extra state/effect indirection tied to filteredMembers and applyFiltersAndSort.
324-437: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueModal has no keyboard (Escape) dismissal or focus trap.
Closing only works via click on the overlay/X/Close button; keyboard-only users can't dismiss it with Escape, and focus isn't trapped inside the dialog.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@client/src/pages/TeamMembers.jsx` around lines 324 - 437, The member details modal in TeamMembers.jsx only closes via mouse interactions and does not support keyboard dismissal or focus containment. Update the selectedMember modal block to add an Escape key handler that clears selectedMember, and add proper focus trapping/initial focus management while the modal is open, ensuring focus returns to the triggering element when it closes. Use the modal wrapper and close handlers around selectedMember, setSelectedMember, and the existing Close/X actions as the integration points.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@client/src/pages/TeamMembers.jsx`:
- Around line 41-42: The TeamMembers sorting state is hardcoded because `sortBy`
and `sortOrder` are created without setters, so `applyFiltersAndSort` can only
ever use the default name/ascending path. Update `TeamMembers.jsx` to use state
setters for these values, then add a sort control in the existing filter UI near
the role filter that lets users choose `name`, `role`, or `joined` and toggle
ascending/descending order, wiring those controls to `setSortBy` and
`setSortOrder` so the sort logic becomes reachable.
- Around line 111-114: The handleCopyEmail helper in TeamMembers.jsx shows a
success toast without checking whether navigator.clipboard.writeText actually
succeeds. Update handleCopyEmail to handle the returned promise from writeText,
and only call toast.success after it resolves; if it rejects, handle the failure
path instead of reporting success.
- Around line 49-54: The TeamMembers fetch is calling the wrong members endpoint
path and will 404 because the organization router is mounted under the plural
base route. Update the axios.get call in TeamMembers.jsx to use the correct
organizations members URL that matches the server.js mount path, and keep the
rest of the request options unchanged. Use the existing TeamMembers component
and its members-loading request as the place to fix the route.
---
Nitpick comments:
In `@client/src/pages/TeamMembers.jsx`:
- Around line 70-109: The filtered member list in TeamMembers should be derived
data instead of stored via state updates in applyFiltersAndSort, since calling
setFilteredMembers causes an extra render whenever members, searchQuery,
roleFilter, sortBy, or sortOrder changes. Refactor the TeamMembers component to
compute the final list with useMemo using the same filtering and sorting logic,
and remove the extra state/effect indirection tied to filteredMembers and
applyFiltersAndSort.
- Around line 324-437: The member details modal in TeamMembers.jsx only closes
via mouse interactions and does not support keyboard dismissal or focus
containment. Update the selectedMember modal block to add an Escape key handler
that clears selectedMember, and add proper focus trapping/initial focus
management while the modal is open, ensuring focus returns to the triggering
element when it closes. Use the modal wrapper and close handlers around
selectedMember, setSelectedMember, and the existing Close/X actions as the
integration points.
In `@server/controllers/organizationController.js`:
- Around line 193-216: `getOrganizationMembers` is doing an unnecessary
`userModel.findById(req.user.id)` lookup even though `userAuth` already
populated `req.user` with the authenticated user record. Update this handler to
read `req.user.organization` directly after the auth check, and keep the
existing guard for missing organization before calling
`Organization.findById(...).populate(...)`.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: c6d18423-598a-4990-a1bc-66af2342f4af
📒 Files selected for processing (5)
client/src/App.jsxclient/src/components/Navbar.jsxclient/src/pages/TeamMembers.jsxserver/controllers/organizationController.jsserver/routes/organizationRoutes.js
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
@mrunmayeekokitkar Thank you once again for another excellent contribution to MeetOnMemory! 🚀 I really appreciate the consistent effort you've put into implementing the Team Members & Organization Directory feature. The implementation is well organized, responsive, and integrates nicely with the existing project architecture. Thank you as well for proactively addressing the review feedback and ensuring all CI checks passed before review. I'm happy to have merged your PR! 🎉 If you found MeetOnMemory helpful, please consider ⭐ starring the repository. Looking forward to your future contributions—happy coding! 💙 |
Pull Request
Description
Implements a dedicated Team Members & Organization Directory page for MeetOnMemory, allowing users to browse organization members, search and filter the directory, view member details, and quickly copy contact information. This update also adds the required backend API, navigation entry, and responsive UI while following the existing MeetOnMemory design language.
Type of Change
Related Issue
Closes #86
Changes
Backend
GET /api/organization/membersendpoint.getOrganizationMemberscontroller inorganizationController.js.createdAt)isAccountVerified)Team Members Page
Created a dedicated
TeamMemberspage featuring:Member List
Displays each organization member with:
Search
Implemented real-time search across:
Filters
Added expandable filtering panel with:
Sorting
Supports sorting by:
with both ascending and descending order.
Member Details
Added a detailed member modal displaying profile information when a member is selected.
Quick Actions
Added quick action for:
Displays a toast notification after copying successfully.
Navigation
/team-membersroute inApp.jsx.Design
Implementation Summary
Backend Changes
getOrganizationMemberscontroller inorganizationController.js.GET /api/organization/membersroute inorganizationRoutes.js.Frontend Changes
Created
TeamMembers.jsxwith:Navigation
/team-membersroute inApp.jsx.Navbar.jsx.Features Implemented
Testing
Verification
Screenshots
N/A
Checklist
Summary by CodeRabbit
New Features
Bug Fixes