diff --git a/packages/desktop/src/providers/RealTimeRoomProvider.tsx b/packages/desktop/src/providers/RealTimeRoomProvider.tsx index 711dda4..66425bb 100644 --- a/packages/desktop/src/providers/RealTimeRoomProvider.tsx +++ b/packages/desktop/src/providers/RealTimeRoomProvider.tsx @@ -55,10 +55,15 @@ interface IRealTimeRoomProvider { handleSelectLine?: (newLineId: string) => void; handleUpdateLineMemberState?: (lineId: string, newState: LineMemberState) => void; + + showNewChannelForm: boolean; + handleShowNewChannelForm?: (showOrHide: 'show' | 'hide') => void; } const RealTimeRoomContext = React.createContext({ roomsMap: {}, + + showNewChannelForm: false, }); /** @@ -109,6 +114,7 @@ export function RealTimeRoomProvider({ children }: { children: React.ReactChild const [selectedLineId, setSelectedLineId] = useState(); const [moveLineState, moveLine] = useAsyncFn(updateLineMemberState); + const [showNewChannelForm, setShowNewChannelForm] = useState(false); /** All line listeners */ useEffect(() => { @@ -309,9 +315,24 @@ export function RealTimeRoomProvider({ children }: { children: React.ReactChild [setSelectedLineId, handleUntuneFromLine, roomMap, user, handleTuneIntoLine], ); + const handleShowNewChannelForm = useCallback( + (showOrHide: 'show' | 'hide' = 'show') => { + setSelectedLineId(undefined); + setShowNewChannelForm(showOrHide === 'show'); + }, + [setShowNewChannelForm, setSelectedLineId], + ); + return ( {children} diff --git a/packages/desktop/src/tree/protected/terminal/compose/NewChannelForm.tsx b/packages/desktop/src/tree/protected/terminal/compose/NewChannelForm.tsx new file mode 100644 index 0000000..eaabb15 --- /dev/null +++ b/packages/desktop/src/tree/protected/terminal/compose/NewChannelForm.tsx @@ -0,0 +1,119 @@ +import React, { useState, useCallback } from 'react'; +import { FiUsers, FiXSquare } from 'react-icons/fi'; +import { useAsyncFn, useDebounce } from 'react-use'; +import { userSearch } from '../../../../api/NirvanaApi'; +import toast from 'react-hot-toast'; +import { Avatar, Skeleton } from 'antd'; +import { User } from '@nirvana/core/models/user.model'; + +export default function NewChannelForm() { + const [peopleSearchQuery, setPeopleSearchQuery] = useState(''); + + const [userSearchRes, fetchUsers] = useAsyncFn(userSearch); + + const [isReady, cancel] = useDebounce( + async () => { + try { + await fetchUsers(peopleSearchQuery); + } catch (error) { + toast.error('Problem in searching users!'); + console.error(error); + } + }, + 2000, + [peopleSearchQuery], + ); + + const [selectedUsers, setSelectedUsers] = useState([]); + + const addUser = useCallback( + (newUser: User) => { + setSelectedUsers((prevUsers) => [...prevUsers, newUser]); + }, + [setSelectedUsers], + ); + + const removeUser = useCallback((userIdToRemove: string) => { + setSelectedUsers((prevUsers) => + prevUsers.filter((currentUser) => !currentUser._id.equals(userIdToRemove)), + ); + }, []); + + const handleSearchChange = useCallback( + async (e) => { + setPeopleSearchQuery(e.target.value); + }, + [setPeopleSearchQuery], + ); + + return ( +
+
+ {/* people search */} + People +
+ + +
+ + {/* dropdown search results */} +
+ {(userSearchRes.loading || !isReady) && } + + {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-200 cursor-pointer" + > + + + {searchedUser.name} + {searchedUser.email} + +
+ ); + })} +
+ + {/* selected people */} + + {`Selected`} + + {selectedUsers.length}/7 + + + {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-200 cursor-pointer group" + > + + + {selectedUser.name} + {selectedUser.email} + + + +
+ ); + })} +
+
+ ); +} diff --git a/packages/desktop/src/tree/protected/terminal/panels/MainPanel.tsx b/packages/desktop/src/tree/protected/terminal/panels/MainPanel.tsx index 47ffdac..65a56c3 100644 --- a/packages/desktop/src/tree/protected/terminal/panels/MainPanel.tsx +++ b/packages/desktop/src/tree/protected/terminal/panels/MainPanel.tsx @@ -18,16 +18,19 @@ import { import { Avatar, Tooltip } from 'antd'; import useStreams from '../../../../providers/StreamProvider'; import Peer from 'simple-peer'; +import NewChannelForm from '../compose/NewChannelForm'; export default function MainPanel() { const { user } = useAuth(); - const { selectedLineId } = useRealTimeRooms(); + const { selectedLineId, showNewChannelForm } = useRealTimeRooms(); // already won't see stuff for overlay only mode as per parent configuration // TODO: if there is stuff in search, show that first + if (showNewChannelForm) return ; + // if selected line, show line details if (selectedLineId) return ; @@ -107,89 +110,6 @@ function LineDetails() { return pictureSources; }, [selectedLine]); - const [peopleSearch, setPeopleSearch] = useState(''); - - const showCreateChannel = false; - if (showCreateChannel) - return ( -
-
- {/* people search */} - People -
- - setPeopleSearch(e.target.value)} - value={peopleSearch} - /> -
- - {/* dropdown search results */} -
- {selectedLine.otherUserObjects.map((otherUser) => { - return ( -
- - - {otherUser.name} - {otherUser.email} - -
- ); - })} - - {selectedLine.otherUserObjects.map((otherUser) => { - return ( -
- - - {otherUser.name} - {otherUser.email} - -
- ); - })} -
- - {/* selected people */} - - {`Selected`} - - {selectedLine.otherMembers.length}/7 - - - {selectedLine.otherUserObjects.map((otherUser) => { - return ( -
- - - {otherUser.name} - {otherUser.email} - -
- ); - })} -
-
- ); - return (
{/* line details */} diff --git a/packages/desktop/src/tree/protected/terminal/panels/SidePanel.tsx b/packages/desktop/src/tree/protected/terminal/panels/SidePanel.tsx index 519cf5c..55a855c 100644 --- a/packages/desktop/src/tree/protected/terminal/panels/SidePanel.tsx +++ b/packages/desktop/src/tree/protected/terminal/panels/SidePanel.tsx @@ -3,7 +3,7 @@ import MasterLineData from '@nirvana/core/models/masterLineData.model'; import { Avatar, Skeleton, Tooltip } from 'antd'; import React, { useCallback, useMemo, useEffect, useState } from 'react'; import { FaPlus, FaSearch } from 'react-icons/fa'; -import { FiActivity, FiSearch, FiSun } from 'react-icons/fi'; +import { FiActivity, FiPlus, FiSearch, FiSun } from 'react-icons/fi'; import useRealTimeRooms from '../../../../providers/RealTimeRoomProvider'; import useRooms from '../../../../providers/RoomsProvider'; import useAuth from '../../../../providers/AuthProvider'; @@ -16,7 +16,8 @@ export default function SidePanel() { // using merely for loading state...better to add to realtimeroom context? const { rooms: initialRoomsFetch } = useRooms(); - const { roomsMap, handleSelectLine, selectedLineId } = useRealTimeRooms(); + const { roomsMap, handleSelectLine, selectedLineId, handleShowNewChannelForm } = + useRealTimeRooms(); const [toggleTunedLines, allLines] = useMemo(() => { const masterLines: MasterLineData[] = Object.values(roomsMap); @@ -34,6 +35,10 @@ export default function SidePanel() { const [searchQuery, setSearchQuery] = useState(''); + const handleCreateNewChannel = useCallback(() => { + handleShowNewChannelForm('show'); + }, [handleShowNewChannelForm]); + return (
@@ -49,12 +54,15 @@ export default function SidePanel() { />
- + > + + +
{/* tuned in lines block */}