import { User } from "@nirvana/common/models/user"; import { RefObject, useEffect, useMemo, useRef, useState } from "react"; import { FaPlus, FaRegTimesCircle, FaSearch } from "react-icons/fa"; import { usersIndex } from "../../services/algoliaSearchService"; import SimpleLoadingDot from "../Loading/SimpleLoadingDot"; import SimpleUserDetailsRow from "../UserDetails/SimpleUserDetailsRow"; import { debounce } from "lodash"; import toast from "react-hot-toast"; import { SearchResponse } from "@algolia/client-search"; import Conversation, { ConversationMember, ConversationMemberRole, ConversationMemberState, } from "@nirvana/common/models/conversation"; import { conversationService } from "@nirvana/common/services"; import { QueryRoutes, Routes } from "@nirvana/common/helpers/routes"; import { useRouter } from "next/router"; import { useRecoilState } from "recoil"; import { useAuth } from "../../contexts/authContext"; const searchDebounceMsTime = 3000; export default function CreateConversation() { const { currUser } = useAuth(); const router = useRouter(); const input = useRef(); const [selectedUsers, setSelectedUsers] = useState([] as User[]); const [isLoading, setIsLoading] = useState(false); const [userSearchInput, setUserSearchInput] = useState(""); const [conversationName, setConversationName] = useState(""); // recommendations list: algolio results + cached "relevant users" from all cached conversations currently // options for the select // have a list of 10 max? const [recommendedUsers, setRecommendedUsers] = useState( [] as User[] ); // on loading this page always focus the select field useEffect(() => { input.current?.focus(); }, []); const handleChangeUserSearchInput = async (event) => { const newInput = event?.target?.value; console.log("searching for : " + newInput); setUserSearchInput(newInput); // no search if empty input if (!newInput) { setIsLoading(false); console.warn("no valid input to search...no point searching"); return false; } try { // do the search on the search value const searchedUsers: SearchResponse = await usersIndex.search(newInput); console.log(searchedUsers.hits); if (searchedUsers.hits) { const userHits = searchedUsers.hits.map((returnedUser) => { const recUser = returnedUser as unknown as User; recUser.id = returnedUser.objectID; return recUser; }); setRecommendedUsers(userHits); } } catch (error) { console.log(error); toast.error("Problem in searching"); } // stop showing loading to say that we got results setIsLoading(false); }; const debounceHandler = useMemo( () => debounce(handleChangeUserSearchInput, searchDebounceMsTime), [] ); // Stop the invocation of the debounced function // after unmounting useEffect(() => { return () => { debounceHandler.cancel(); }; }, []); const selectUser = (addUser: User) => { if (addUser.id == currUser!.uid) { toast.error("You cannot add yourself, silly!"); return; } if (selectedUsers.some((currUser) => currUser.id == addUser.id)) { toast("Already added member!"); return; } // also remove from the search set // for now unless they re-search, they will see it again but for now not an issue setRecommendedUsers((prevRecUsers) => prevRecUsers.filter((pU) => pU.id != addUser.id) ); setSelectedUsers((prevUsers) => [addUser, ...prevUsers]); }; const removeUser = (removeUser: User) => { setSelectedUsers((prevUsers) => prevUsers.filter((pUser) => pUser.id != removeUser.id) ); }; const clearSelected = () => { setSelectedUsers([] as User[]); }; const [isSubmitting, setIsSubmitting] = useState(false); const createConversation = async (e) => { e.preventDefault(); setIsSubmitting(true); if (!conversationName) { toast.error("Please put in a conversation name"); setIsSubmitting(false); return; } if (!selectedUsers?.length) { toast.error("You must select members!"); setIsSubmitting(false); return; } try { const arrActiveMembers: string[] = [] as string[]; // create each conversation member based on the selected people const members = selectedUsers.map((selUser) => { arrActiveMembers.push(selUser.id); return new ConversationMember( selUser.id, ConversationMemberState.default, ConversationMemberRole.member ); }); // add myself to this collection of members members.push( new ConversationMember( currUser!.uid, ConversationMemberState.default, ConversationMemberRole.admin ) ); const newConversation = new Conversation( currUser!.uid, conversationName, arrActiveMembers ); console.log(members); console.log(newConversation); // create main conversation object and all of the members associated await conversationService.createConversation(newConversation, members); toast.success("Created Conversation"); router.push({ pathname: Routes.home, query: { page: QueryRoutes.convos }, }); } catch (error) { toast.error("Problem in creating conversation"); } setIsSubmitting(false); }; return (
{/* { setIsLoading(true); debounceHandler(e); }} /> {isLoading && } {/* show search results nicely like tailwind website */} showing {recommendedUsers.length} results Click{" "} here to invite a user to Nirvana. {recommendedUsers?.length > 0 ? (
{recommendedUsers.map((recUser) => { return ( selectUser(recUser)} className="p-2 rounded-full hover:cursor-pointer text-teal-500 hover:bg-slate-200 ml-auto" > } /> ); })}
) : ( <> )} {selectedUsers?.length ? ( <> Selected {/* list of selected people who are nirvana users */} {selectedUsers.map((selectUser) => ( removeUser(selectUser)} className="p-2 rounded-full hover:cursor-pointer text-orange-500 ml-auto" > } /> ))} Name* It can be casual or like an email subject line. setConversationName(e.target.value)} /> {!isSubmitting && ( )} ) : ( <> )} {/* show conversations already with these people */}
); }