Features
User Search & Invite Flow
The template includes a user search feature that allows users to find and invite others to chat rooms. This section explains how search works and how the invite flow is implemented.
Search Functionality
How It Works
User search is implemented via searchUserByEmailSmart from user-search.service.ts:
- Searches the
userscollection in Firestore - Uses Firestore query with
where("email", ">=", query)andwhere("email", ">=", query + "\uf8ff")for prefix matching - Limits results to a reasonable number (e.g., 10) to avoid excessive reads
- Returns user info including
displayName,avatarURL, andemail
Note: This is a simple prefix search. For more advanced search (full-text, fuzzy matching), you would need to integrate a search service like Algolia or Elasticsearch.
Debounced Search
The search is debounced to avoid excessive Firestore queries while the user is typing:
- Uses
SEARCH_DEBOUNCE_MSconstant (default: 300ms) fromchat.constants.ts - Search query is executed only after the user stops typing for the debounce duration
- Each keystroke resets the timer, so search only runs when the user pauses
- Empty queries return no results immediately (no API call)
Using the Search Hook
useUserSearch Hook
Components use useUserSearch hook to manage search state:
const {
query,
loading,
matchedUsers,
handleSearchChange,
clearQuery
} = useUserSearch(currentUid, selectedUsers);
// matchedUsers automatically excludes:
// - Current user
// - Already selected usersquery– Current search query stringloading– Whether search is in progressmatchedUsers– Filtered search results (excludes current user and already selected users)handleSearchChange– Callback to update search query (debounced internally)clearQuery– Clears search query and results
Search User Dialog
SearchUserDialog Component
The template includes a SearchUserDialog component that provides the full search and invite UI:
- Opens when user clicks "Create Group" or starts a new private chat
- Contains a search input that uses
useUserSearchhook - Displays search results as a list of user cards with avatar, name, and email
- Allows selecting multiple users (for group chats) or a single user (for private chats)
- Shows selected users in a preview section with ability to remove them
- Has "Create" button that triggers room creation with selected users
User Selector Component
The UserSelector component handles the search input and results display:
- Renders a search input with loading indicator
- Shows "No results" message when search returns empty
- Displays user cards that can be clicked to select/deselect
- Highlights selected users visually
Invite Flow
Creating Private Chat
When creating a private chat:
- User searches for and selects a single user
- Clicks "Create" button
- System calls
ensureCreatePrivateChat(currentUid, recipientUid) - If a private room already exists between these users, it opens that room
- If no room exists, creates a new private room and opens it
Creating Group Chat
When creating a group chat:
- User searches for and selects multiple users (minimum 1)
- Optionally enters a group name
- Clicks "Create" button
- System calls
createGroupChat(creatorUid, participantUids, groupName, groupAvatarURL) - Creates a new group room with all selected participants
- Creates a system message: "created the group"
- Opens the newly created group room
State Management
The search dialog state is managed via dialog.store.ts:
isOpen– Whether the dialog is visibleselectedUsers– Array of selected user objectsroomType– "private" or "group" (determines if single or multiple selection)
The store provides actions to open/close the dialog, add/remove selected users, and reset state.
Implementation Details
Key files for user search:
features/chat/services/user-search.service.ts– searchUserByEmailSmart functionfeatures/chat/hooks/use-user-search.ts– React hook for managing search statefeatures/chat/components/dialog/search-user-dialog.tsx– Main dialog componentfeatures/chat/components/dialog/user-selector.tsx– Search input and results displayfeatures/chat/components/dialog/selected-user-preview.tsx– Preview of selected usersfeatures/chat/stores/dialog.store.ts– Zustand store for dialog state