Claiming This Task
Before you start working, check the Assignees section. If no one is assigned, leave a comment claiming the issue and assign it to yourself. This prevents duplicate work.
See the Community Wiki for contributing guidelines and git workflow.
Problem
The Course Detail Page's "Invite Member" modal currently shows a "coming soon" placeholder. We need a proper UX that lets teachers search for users by name and invite them to a course — not by entering raw user IDs.
Requirements
- User search autocomplete input — debounced text input (300ms) that queries
GET /api/users/search/?q=<query> (min 2 chars) and shows a dropdown of matching users
- Dropdown results — show username, full name (if available) for each match. Paginated results (10 per page), with a "load more" or scroll-to-load option
- User selection — clicking a result selects the user, showing their name in the input
- Role picker — HardLoadSelect for choosing the role (Student, Assistant, Teacher) after selecting a user
- Send invite — calls the existing
inviteMember(courseId, userId, role) API function from coursesApi.ts
- Error handling — show errors inline (user not found, already a member, etc.)
- Dark mode — full dark mode support matching existing glass-morphism styling
- Responsive — works on mobile (dropdown should be touch-friendly)
- Accessibility — keyboard navigation for the dropdown (arrow keys, enter to select, escape to close)
Architecture Context
- The invite modal lives at
src/components/courses/InviteMemberModal.tsx and is rendered from MembersTab.tsx
- It uses
createPortal(... , document.body) to escape the backdrop-blur container
- The existing
coursesApi.ts already has inviteMember() for sending the invite
- Consider building the search autocomplete as a reusable
UserSearchInput component in src/components/common/ since user search may be needed elsewhere (chat, friend requests, etc.)
API Dependencies
Already built and production-ready:
GET /api/users/search/?q=<query> — returns paginated results with id, username, full_name, profile_id
- Privacy-aware: respects user visibility settings
- Min 2 chars required
- Default 10 results per page
POST /api/courses/<id>/members/invite/ — sends an invite (already wired in coursesApi.ts)
Frontend API service needed:
- New function in
src/services/ (e.g. usersApi.ts) for calling the search endpoint
Files to be Altered
src/components/courses/InviteMemberModal.tsx — replace placeholder with search + invite form
src/components/common/UserSearchInput.tsx — new reusable autocomplete component
src/services/usersApi.ts — new API service for user search endpoint
src/types/users.types.ts — TypeScript types for search response (if not existing)
src/i18n/locales/en.json — update invite modal translations
src/i18n/locales/ar.json — Arabic translations
Testing Requirements
- Unit tests for
UserSearchInput component (debounce, dropdown display, selection, keyboard nav)
- Unit tests for
InviteMemberModal (search → select → pick role → submit flow)
- Manual: verify privacy filtering works (hidden users don't appear)
- Manual: verify dark mode and mobile responsiveness
- Manual: verify error states (already a member, network error)
Additional Context (Optional)
- The backend user search API is well-tested (20+ test cases) and handles privacy filtering at the database level
- The search respects 4 visibility levels:
everyone, friends_only, friends_of_friends, nobody
- Consider using
useMemo + AbortController for cancelling stale search requests
Claiming This Task
Before you start working, check the Assignees section. If no one is assigned, leave a comment claiming the issue and assign it to yourself. This prevents duplicate work.
See the Community Wiki for contributing guidelines and git workflow.
Problem
The Course Detail Page's "Invite Member" modal currently shows a "coming soon" placeholder. We need a proper UX that lets teachers search for users by name and invite them to a course — not by entering raw user IDs.
Requirements
GET /api/users/search/?q=<query>(min 2 chars) and shows a dropdown of matching usersinviteMember(courseId, userId, role)API function fromcoursesApi.tsArchitecture Context
src/components/courses/InviteMemberModal.tsxand is rendered fromMembersTab.tsxcreatePortal(... , document.body)to escape thebackdrop-blurcontainercoursesApi.tsalready hasinviteMember()for sending the inviteUserSearchInputcomponent insrc/components/common/since user search may be needed elsewhere (chat, friend requests, etc.)API Dependencies
Already built and production-ready:
GET /api/users/search/?q=<query>— returns paginated results withid,username,full_name,profile_idPOST /api/courses/<id>/members/invite/— sends an invite (already wired incoursesApi.ts)Frontend API service needed:
src/services/(e.g.usersApi.ts) for calling the search endpointFiles to be Altered
src/components/courses/InviteMemberModal.tsx— replace placeholder with search + invite formsrc/components/common/UserSearchInput.tsx— new reusable autocomplete componentsrc/services/usersApi.ts— new API service for user search endpointsrc/types/users.types.ts— TypeScript types for search response (if not existing)src/i18n/locales/en.json— update invite modal translationssrc/i18n/locales/ar.json— Arabic translationsTesting Requirements
UserSearchInputcomponent (debounce, dropdown display, selection, keyboard nav)InviteMemberModal(search → select → pick role → submit flow)Additional Context (Optional)
everyone,friends_only,friends_of_friends,nobodyuseMemo+AbortControllerfor cancelling stale search requests