Skip to content

[FRONTEND] Build Invite Member UX with User Search Autocomplete #261

Description

@smattymatty

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

  1. 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
  2. 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
  3. User selection — clicking a result selects the user, showing their name in the input
  4. Role picker — HardLoadSelect for choosing the role (Student, Assistant, Teacher) after selecting a user
  5. Send invite — calls the existing inviteMember(courseId, userId, role) API function from coursesApi.ts
  6. Error handling — show errors inline (user not found, already a member, etc.)
  7. Dark mode — full dark mode support matching existing glass-morphism styling
  8. Responsive — works on mobile (dropdown should be touch-friendly)
  9. 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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions