import React, { useState, useCallback, useRef, useEffect } from 'react'; import { FiPlusSquare, FiUsers, FiX, FiXSquare } from 'react-icons/fi'; import { useAsyncFn, useDebounce, useKeyPressEvent } from 'react-use'; import { createLine, userSearch } from '../../../../api/NirvanaApi'; import toast from 'react-hot-toast'; import { Avatar, Divider, Skeleton, Spin } from 'antd'; import { User } from '@nirvana/core/models/user.model'; import CreateLineRequest from '@nirvana/core/requests/createLine.request'; import { maxChannelUserCount } from '../rules'; export default function NewChannelForm({ handleClose }: { handleClose: () => void }) { const [peopleSearchQuery, setPeopleSearchQuery] = useState(''); const [userSearchRes, fetchUsers] = useAsyncFn(userSearch); const [selectedUsers, setSelectedUsers] = useState([]); const [isSearchingUsers, setSearchingUsers] = useState(false); const searchInputRef = useRef(null); const [createChannelRes, triggerCreateChannel] = useAsyncFn(createLine); useEffect(() => { if (searchInputRef) searchInputRef.current.focus(); }, [searchInputRef]); const [_, cancel] = useDebounce( async () => { if (!peopleSearchQuery) { return; } try { await fetchUsers(peopleSearchQuery); setSearchingUsers(false); } catch (error) { toast.error('Problem in searching users!'); console.error(error); } }, 200, [peopleSearchQuery, setSearchingUsers, fetchUsers], ); const handleSearchChange = useCallback( async (e) => { setSearchingUsers(true); setPeopleSearchQuery(e.target.value); }, [setPeopleSearchQuery, setSearchingUsers], ); // ensuring that we haven't already selected this user // changing search results so that we don't see the selected user in the search results anymore const addUser = useCallback( (newUser: User) => { setSelectedUsers((prevUsers) => { if (prevUsers.find((currUser) => currUser.email === newUser.email)) { return prevUsers; } if (prevUsers.length === maxChannelUserCount - 1) { toast.error('you can only have 8 people per channel!'); return prevUsers; } return [...prevUsers, newUser]; }); if (userSearchRes.value?.users) { userSearchRes.value.users = userSearchRes.value.users.filter( (currUser) => currUser._id !== newUser._id, ); } }, [setSelectedUsers, userSearchRes.value], ); const removeUser = useCallback((userIdToRemove: string) => { setSelectedUsers((prevUsers) => prevUsers.filter((currentUser) => currentUser._id.toString() !== userIdToRemove), ); }, []); // TODO: prevent creating one-on-one line if already exists with x person? // ensure that we don't have a one on one chat already with x person if it's one person selected // upon success, // make sure that the list of lines updates for this client and others so that it shows this new line // select the line so that it shows up in the line details for this client const handleCreateChannel = useCallback(async () => { console.log('trying to create line now!'); try { if (!selectedUsers?.length) { toast.error('you must select at least one person'); return; } if (selectedUsers.length === maxChannelUserCount - 1) { toast.error(`Max ${maxChannelUserCount} people per channel including you!`); return; } const selectedMemberIds = selectedUsers.map((selectedPerson) => selectedPerson._id.toString(), ); await triggerCreateChannel(new CreateLineRequest(selectedMemberIds)); toast.success('created channel!'); // handle close once the new line is created handleClose(); } catch (error) { toast.error(error); console.error(error); } finally { console.log('done'); } }, [handleClose, selectedUsers, triggerCreateChannel]); useKeyPressEvent('Enter', handleCreateChannel); useKeyPressEvent('Escape', handleClose); return (
`esc`
{/* people search */} People
{/* dropdown search results */}
{(userSearchRes.loading || isSearchingUsers) && } {(!userSearchRes.value || userSearchRes.value?.users.length === 0) && selectedUsers?.length === 0 && ( {`Can't find someone? Invite them and tell them the secret passcode!`} )} {userSearchRes.value?.users.map((searchedUser) => { return (
addUser(searchedUser)} role={'presentation'} key={searchedUser.email} className="flex flex-row gap-2 items-center p-2 border border-gray-200 hover:bg-gray-100 cursor-pointer" > {searchedUser.name} {searchedUser.email}
); })}
{/* selected people */} {`Selected`} {selectedUsers.length}/${maxChannelUserCount - 1} {selectedUsers.map((selectedUser) => { return (
removeUser(selectedUser._id.toString())} role={'presentation'} key={selectedUser.email} className="flex flex-row gap-2 items-center p-2 border border-gray-200 hover:bg-gray-100 cursor-pointer group" > {selectedUser.name} {selectedUser.email}
); })}
`enter`
); }