import { useContext , useEffect , useRef , useState } from 'react' ; import { AppContext } from '../context/AppContext' ; import type { UserFilters , UserResponse } from 'stream-chat' ; import type { LocalUserType } from '../types' ; export type PaginatedUsers = { clearText : ( ) => void ; initialResults : UserResponse < LocalUserType > [ ] | null ; loading : boolean ; loadMore : ( ) => void ; onChangeSearchText : ( newText : string ) => void ; onFocusInput : ( ) => void ; removeUser : ( index : number ) => void ; reset : ( ) => void ; results : UserResponse < LocalUserType > [ ] ; searchText : string ; selectedUserIds : string [ ] ; selectedUsers : UserResponse < LocalUserType > [ ] ; setInitialResults : React . Dispatch < React . SetStateAction < UserResponse < LocalUserType > [ ] | null > > ; setResults : React . Dispatch < React . SetStateAction < UserResponse < LocalUserType > [ ] > > ; setSearchText : React . Dispatch < React . SetStateAction < string > > ; setSelectedUsers : React . Dispatch < React . SetStateAction < UserResponse < LocalUserType > [ ] > > ; toggleUser : ( user : UserResponse < LocalUserType > ) => void ; } ; export const usePaginatedUsers = ( ) : PaginatedUsers => { const { chatClient } = useContext ( AppContext ) ; const [ initialResults , setInitialResults ] = useState < UserResponse < LocalUserType > [ ] | null > ( null ) ; const [ loading , setLoading ] = useState ( true ) ; const [ results , setResults ] = useState < UserResponse < LocalUserType > [ ] > ( [ ] ) ; const [ searchText , setSearchText ] = useState ( '' ) ; const [ selectedUserIds , setSelectedUserIds ] = useState < string [ ] > ( [ ] ) ; const [ selectedUsers , setSelectedUsers ] = useState < UserResponse < LocalUserType > [ ] > ( [ ] ) ; const hasMoreResults = useRef ( true ) ; const offset = useRef ( 0 ) ; const queryInProgress = useRef ( false ) ; const reset = ( ) => { setSearchText ( '' ) ; fetchUsers ( '' ) ; setSelectedUserIds ( [ ] ) ; setSelectedUsers ( [ ] ) ; } ; const addUser = ( user ) => { setSelectedUsers ( [ ... selectedUsers , user ] ) ; setSelectedUserIds ( ( prevSelectedUserIds ) => { prevSelectedUserIds . push ( user . id ) ; return prevSelectedUserIds ; } ) ; setSearchText ( '' ) ; setResults ( initialResults || [ ] ) ; } ; const removeUser = ( index ) => { if ( index < 0 ) { return ; } setSelectedUserIds ( ( prevSelectedUserIds ) => { const newSelectedUserIds = prevSelectedUserIds . slice ( ) ; newSelectedUserIds . splice ( index , 1 ) ; return newSelectedUserIds ; } ) ; setSelectedUsers ( ( prevSelectedUsers ) => { const newSelectedUsers = prevSelectedUsers . slice ( ) ; newSelectedUsers . splice ( index , 1 ) ; return newSelectedUsers ; } ) ; } ; const toggleUser = ( user ) => { if ( ! user . id ) { return ; } const existingIndex = selectedUserIds . indexOf ( user . id ) ; if ( existingIndex > - 1 ) { removeUser ( existingIndex ) ; } else { addUser ( user ) ; } } ; const onFocusInput = ( ) => { if ( ! searchText ) { setResults ( initialResults || [ ] ) ; setLoading ( false ) ; } else { fetchUsers ( searchText ) ; } } ; const onChangeSearchText = ( newText ) => { setSearchText ( newText ) ; if ( ! newText ) { setResults ( initialResults || [ ] ) ; setLoading ( false ) ; } else { fetchUsers ( newText ) ; } } ; const fetchUsers = async ( query = '' ) => { if ( queryInProgress . current || ! chatClient ?. userID ) return ; setLoading ( true ) ; try { queryInProgress . current = true ; const filter = { id : { $nin : [ chatClient ?. userID ] , } , role : 'user' , } ; if ( query ) { filter . name = { $autocomplete : query } ; } if ( query !== searchText ) { offset . current = 0 ; hasMoreResults . current = true ; } else { offset . current = offset . current + results . length ; } if ( ! hasMoreResults . current ) { queryInProgress . current = false ; return ; } const res = await chatClient ?. queryUsers ( filter , { name : 1 } , { limit : 10 , offset : offset . current , presence : true , } ) ; if ( ! res ?. users ) { queryInProgress . current = false ; return ; } if ( query === searchText && results . findIndex ( ( r ) => res ?. users [ 0 ] . id === r . id ) > - 1 ) { queryInProgress . current = false ; return ; } setResults ( ( r ) => { if ( query !== searchText ) { return res ?. users ; } return r . concat ( res ?. users || [ ] ) ; } ) ; if ( res ?. users . length < 10 && ( offset . current === 0 || query === searchText ) ) { hasMoreResults . current = false ; } if ( ! query && offset . current === 0 ) { setInitialResults ( res ?. users || [ ] ) ; } } catch ( e ) { } queryInProgress . current = false ; setLoading ( false ) ; } ; const loadMore = ( ) => { fetchUsers ( searchText ) ; } ; useEffect ( ( ) => { fetchUsers ( ) ; } , [ ] ) ; return { clearText : ( ) => { setSearchText ( '' ) ; fetchUsers ( '' ) ; } , initialResults , loading , loadMore , onChangeSearchText , onFocusInput , removeUser , reset , results , searchText , selectedUserIds , selectedUsers , setInitialResults , setResults , setSearchText , setSelectedUsers , toggleUser , } ; } ;