From 10120bc80e37b5063672e1bca07a148f5a349657 Mon Sep 17 00:00:00 2001 From: talksik Date: Fri, 13 May 2022 08:03:03 -0500 Subject: [PATCH] cleaning up so that I can start fresh --- .vscode/settings.json | 4 +- .../src/providers/RealTimeRoomProvider.tsx | 13 +- .../src/tree/protected/terminal/Terminal.tsx | 358 +------------- .../terminal/lines/lineIcon/index.tsx | 68 --- .../terminal/lines/lineRow.tsx/index.tsx | 457 ------------------ 5 files changed, 16 insertions(+), 884 deletions(-) delete mode 100644 packages/desktop/src/tree/protected/terminal/lines/lineIcon/index.tsx delete mode 100644 packages/desktop/src/tree/protected/terminal/lines/lineRow.tsx/index.tsx diff --git a/.vscode/settings.json b/.vscode/settings.json index e2e226e..8711611 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,7 +8,7 @@ "editor.defaultFormatter": "esbenp.prettier-vscode", "workbench.colorTheme": "Default Light+", "javascript.format.semicolons": "insert", - "window.zoomLevel": 2, + "window.zoomLevel": 2 - "eslint.workingDirectories": ["./packages/desktop"] + // "eslint.workingDirectories": ["./packages/desktop"] } diff --git a/packages/desktop/src/providers/RealTimeRoomProvider.tsx b/packages/desktop/src/providers/RealTimeRoomProvider.tsx index 0ffc3cb..3604e46 100644 --- a/packages/desktop/src/providers/RealTimeRoomProvider.tsx +++ b/packages/desktop/src/providers/RealTimeRoomProvider.tsx @@ -26,6 +26,10 @@ type LineIdToMasterLine = { interface IRealTimeRoomProvider { roomsMap: LineIdToMasterLine; + + selectedRoom?: MasterLineData; + // untunes from previous and tunes into new room + handleSelectRoom?: (roomId: string) => void; } const RealTimeRoomContext = React.createContext({ roomsMap: {} }); @@ -260,8 +264,15 @@ export function RealTimeRoomProvider({ children }: { children: React.ReactChild } }, [rooms.value, handleConnectToLine, handleTuneToLine, setRealTimeRoomMap]); + const handleSelectRoom = useCallback( + (roomId: string) => { + return realTimeRoomMap[roomId]; + }, + [realTimeRoomMap], + ); + return ( - + {' '} ); diff --git a/packages/desktop/src/tree/protected/terminal/Terminal.tsx b/packages/desktop/src/tree/protected/terminal/Terminal.tsx index 0c63e82..7cb3a87 100644 --- a/packages/desktop/src/tree/protected/terminal/Terminal.tsx +++ b/packages/desktop/src/tree/protected/terminal/Terminal.tsx @@ -1,17 +1,12 @@ -import { Avatar, Skeleton, Tooltip } from 'antd'; -import React, { useCallback, useMemo, useState } from 'react'; +import React, { useCallback, useState } from 'react'; import useRealTimeRooms from '../../../providers/RealTimeRoomProvider'; import useElectron from '../../../providers/ElectronProvider'; import useAuth from '../../../providers/AuthProvider'; import NavBar from './navbar/Navbar'; -import { FiActivity, FiHeadphones, FiSettings, FiSun } from 'react-icons/fi'; -import { LineMemberState } from '@nirvana/core/models/line.model'; import MasterLineData from '@nirvana/core/models/masterLineData.model'; -import LineRow from './lines/lineRow.tsx'; + import useRooms from '../../../providers/RoomsProvider'; import toast from 'react-hot-toast'; -import { FaPlus } from 'react-icons/fa'; -import LineIcon from './lines/lineIcon'; export default function Terminal() { const { rooms: initialRoomsState } = useRooms(); @@ -22,24 +17,6 @@ export default function Terminal() { const [selectedLine, setSelectedLine] = useState(); - const allLines: MasterLineData[] = useMemo(() => { - const masterLines: MasterLineData[] = Object.values(roomsMap); - - // TODO: sort based on the audio blocks and currentMember lastActiveDate - - return masterLines.filter( - (masterLine) => masterLine.currentUserMember.state === LineMemberState.INBOX, - ); - }, [roomsMap]); - - const toggleTunedLines = useMemo(() => { - const masterLines: MasterLineData[] = Object.values(roomsMap); - - return masterLines.filter( - (masterLine) => masterLine.currentUserMember.state === LineMemberState.TUNED, - ); - }, [roomsMap]); - /** show user line details on click of one line */ const handleSelectLine = useCallback( (newLineIdToSelect: string) => { @@ -51,337 +28,6 @@ export default function Terminal() { return (
- -
-
- {/* tuned in lines block */} -
- {/* tuned in header + general controls */} - - -
- - - -

Rooms

- -

{`${toggleTunedLines?.length || 0}/3`}

-
-
-
- - {/* list of toggle tuned lines */} -
- {toggleTunedLines.map((masterLineData) => ( - { - console.log('asdf'); - }} - /> - ))} -
-
- - {!(allLines.length > 0) && !(toggleTunedLines.length > 0) && ( - - You have no lines!
Create one to connect to your team instantly. -
- )} - - {/* rest of the lines */} -
- {initialRoomsState.loading ? ( - - ) : ( - allLines.map((masterLineData) => ( - - )) - )} -
- -
- -
-
- - {selectedLine ? ( - - ) : ( -
- {`Hi ${user.givenName}!`} - {"You're all set!"} -
- )} -
-
- ); -} - -function LineDetailsTerminal({ selectedLine }: { selectedLine: MasterLineData }) { - const { user } = useAuth(); - - console.log('selected line', selectedLine); - - const isUserToggleTuned = useMemo( - () => selectedLine?.currentUserMember?.state === LineMemberState.TUNED, - [selectedLine], - ); - - // seeing if I am in the list of broadcasters - // the source of truth from the socket connections telling me if my clicking actually made a round trip - const isUserBroadcasting = useMemo( - () => selectedLine?.currentBroadcastersUserIds?.includes(user._id.toString()), - [user, selectedLine], - ); - - // showing all tuned in members...they may not hear me since they might be doing something else - // but feeling of presentness - const tunedProfiles = useMemo(() => { - const pictureSources: { name: string; pictureSrc: string }[] = []; - - selectedLine.tunedInMemberIds?.forEach((tunedInMemberUserId) => { - // don't want to see my own picture - // TODO: don't show myself!? - if (tunedInMemberUserId === user._id.toString()) { - pictureSources.push(); - - pictureSources.push({ - name: user.givenName, - pictureSrc: user.picture, - }); - return; - } - - const otherUserObject = selectedLine.otherUserObjects?.find( - (userObj) => userObj._id.toString() === tunedInMemberUserId, - ); - if (otherUserObject?.picture) - pictureSources.push({ - name: otherUserObject.givenName, - pictureSrc: otherUserObject.picture, - }); - }); - - return pictureSources; - }, [selectedLine, user]); - - // pics for the line icons - const profilePictures = useMemo(() => { - const pictureSources: string[] = []; - - // ?don't add in my image as that's useless contextually? - // if (userData?.user?.picture) pictureSources.push(userData.user.picture); - - selectedLine.otherUserObjects?.forEach((otherUser) => { - if (otherUser.picture) pictureSources.push(otherUser.picture); - }); - - return pictureSources; - }, [selectedLine, user]); - - // TODO get from realtime provider to do this action - - const handleToggleTuneToLine = () => toast('NOT IMPLEMENTATED: toggle tuning'); - - return ( -
- {/* line details */} -
- {profilePictures && } - -
- -

- {selectedLine.lineDetails.name || selectedLine.otherUserObjects[0].givenName} -

- - -
- - - {`${ - selectedLine.otherMembers?.length + 1 ?? 0 - } members`} - - {`${ - selectedLine.tunedInMemberIds?.length ?? 0 - } in this room`} - -
- - {/* TODO: move to on hover of line row */} - - - -
- - {/* line timeline */} -
- load more - - yesterday - -
- {selectedLine.otherUserObjects.map((otherUser) => ( -
- - {otherUser.givenName} - - {`${ - Math.floor(Math.random() * 10) + 1 - }:${Math.floor(Math.random() * 100) + 10}pm |`} - - {`${ - Math.floor(Math.random() * 60) + 1 - } seconds`} -
- ))} - -
- - {'Arjun Patel'} - - {`${ - Math.floor(Math.random() * 10) + 1 - }:${Math.floor(Math.random() * 100) + 10}pm |`} - - {`${ - Math.floor(Math.random() * 60) + 1 - } seconds`} -
-
- - today - -
- {selectedLine.otherUserObjects.map((otherUser) => ( - // TODO: show the shadow if it's unheard -
- - {otherUser.name} - - {`${ - Math.floor(Math.random() * 10) + 1 - }:${Math.floor(Math.random() * 100) + 10}pm |`} - - {`${ - Math.floor(Math.random() * 60) + 1 - } seconds`} -
- ))} -
- - {/* live broadcasters */} - - - right now - -
- {selectedLine.otherUserObjects.map((otherUser) => ( -
- - {otherUser.name} - - - - -
- ))} -
-
- -
); } diff --git a/packages/desktop/src/tree/protected/terminal/lines/lineIcon/index.tsx b/packages/desktop/src/tree/protected/terminal/lines/lineIcon/index.tsx deleted file mode 100644 index 517bd98..0000000 --- a/packages/desktop/src/tree/protected/terminal/lines/lineIcon/index.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { Avatar } from "antd"; -import React from "react"; -import { useMemo } from "react"; - -function LineIcon({ - sourceImages, - grayscale = true, -}: { - sourceImages: string[]; - grayscale: boolean; -}) { - const isMultiple = useMemo(() => { - if (sourceImages?.length > 1) return true; - - return false; - }, [sourceImages]); - - return ( - <> - {isMultiple ? ( -
- {sourceImages.map((avatarSrc, index) => { - if (index === 0) { - return ( - - ); - } else if (index === 1) { - return ( - - ); - } - - // TODO: add third in the frame if we want later - return <>; - })} -
- ) : ( - sourceImages?.map((avatarSrc, index) => ( - - )) - )} - - ); -} - -export default React.memo(LineIcon); diff --git a/packages/desktop/src/tree/protected/terminal/lines/lineRow.tsx/index.tsx b/packages/desktop/src/tree/protected/terminal/lines/lineRow.tsx/index.tsx deleted file mode 100644 index 2a89b9b..0000000 --- a/packages/desktop/src/tree/protected/terminal/lines/lineRow.tsx/index.tsx +++ /dev/null @@ -1,457 +0,0 @@ -import { FiActivity, FiSun } from "react-icons/fi"; -import { - RtcAnswerRequest, - RtcCallRequest, - RtcNewUserResponse, - RtcReceiveAnswerResponse, - ServerResponseChannels, - SomeoneUntunedFromLineResponse, -} from "@nirvana/core/sockets/channels"; -import { useCallback, useEffect, useMemo, useRef, useState } from "react"; - -import { $selectedLineId } from "../../../controller/recoil"; -import { Avatar } from "antd"; -import LineIcon from "../lineIcon"; -import { LineMemberState } from "@nirvana/core/models/line.model"; -import MasterLineData from "@nirvana/core/models/masterLineData.model"; -import Peer from "simple-peer"; -import { ServerRequestChannels } from "../../../../../core/sockets/channels"; -import moment from "moment"; -import toast from "react-hot-toast"; -import { useGetUserDetails } from "../../../controller/index"; -import { useLineDataProvider } from "../../../controller/lineDataProvider"; -import { useRecoilState } from "recoil"; - -// todo: send a much more comprehensive master line object? or just add properties to the -// masterLineData object so that we don't have different models to maintain between client and server - -export default function LineRow({ - masterLineData, - handleSelectLine, -}: { - masterLineData: MasterLineData; - handleSelectLine: (lineId: string) => void; -}) { - const [selectedLineId, setSelectedLineId] = useRecoilState($selectedLineId); - const { data: userData } = useGetUserDetails(); - - useEffect(() => { - console.warn("mounting linerow"); - - return () => console.warn("UNMOUNTING line row"); - }, []); - - // take the source of truth list of memeberIds tuned in, and see if I'm in it - const isUserTunedIn = useMemo( - () => - masterLineData.tunedInMemberIds?.includes(userData?.user?._id.toString()), - [masterLineData.tunedInMemberIds, userData] - ); - - /** - * TODO: slowly add to this and fix based on added features - * */ - const renderActivityIcon = useMemo(() => { - // if there is someone or me broadcasting here - if (masterLineData.currentBroadcastersUserIds?.length > 0) - return ; - - if (isUserTunedIn) - return ; - - // if there is new activity blocks for me - if (masterLineData.currentUserMember.lastVisitDate) - return ( - - ); - - return ( - - ); - }, [masterLineData, isUserTunedIn]); - - const renderRightActivity = useMemo(() => { - // TODO: get the profile pictures of the broadcasters - if (masterLineData.currentBroadcastersUserIds?.length > 0) - return ( - - {masterLineData.otherUserObjects?.map((otherUser, index) => ( - - ))} - - ); - - // if there is new activity/black dot, then show relative time as little bolder? or too much? - - // TODO: compare last visit date to latest audio block - if (false) - return ( - - {moment(masterLineData.currentUserMember.lastVisitDate).fromNow(true)} - - ); - - return ( - - {moment(masterLineData.currentUserMember.lastVisitDate).fromNow(true)} - - ); - }, [masterLineData]); - - const profilePictures = useMemo(() => { - const pictureSources: string[] = []; - - // ?don't add in my image as that's useless contextually? - // if (userData?.user?.picture) pictureSources.push(userData.user.picture); - - masterLineData.otherUserObjects?.forEach((otherUser) => { - if (otherUser.picture) pictureSources.push(otherUser.picture); - }); - - return pictureSources; - }, [masterLineData, userData]); - - return ( - <> -
- handleSelectLine(masterLineData.lineDetails._id.toString()) - } - className={`flex flex-row items-center justify-start gap-2 p-2 px-4 h-14 hover:bg-gray-200 cursor-pointer transition-all - last:border-b-0 border-b border-b-gray-200 relative z-50 rounded ${ - selectedLineId === masterLineData.lineDetails._id.toString() && - "bg-gray-200 scale-110 shadow-2xl translate-x-3" - }`} - > - {/* status dot */} -
{renderActivityIcon}
- - {profilePictures && ( - - )} - -

- {masterLineData.lineDetails.name || - masterLineData.otherUserObjects[0].givenName} -

- -
{renderRightActivity}
-
- - {/* mounts and unmounts based on if in the room or now */} - {/* {isUserTunedIn && ( - - )} */} - - ); -} - -type PeerMap = { [userId: string]: Peer }; - -function StreamRoom({ - lineId, - tunedInUsers, - currentBroadcasters, -}: { - lineId: string; - tunedInUsers?: string[]; - currentBroadcasters?: string[]; -}) { - // ?could move this up the tree and pass it down? or set it in the header? - // local stream specifically for this stream room - const [localStream, setLocalStream] = useState(); - const userStreamTagRef = useRef(null); - const { data: userDetails } = useGetUserDetails(); - - // local peer map of userIds to peers - const [userPeers, setUserPeers] = useState({}); - - // ws listen to events of user disconnecting and such or rely on tunedin members prop - const { $ws } = useLineDataProvider(); - - // todo: get the right constraints based on user settings...audio, video, or none? header selections? make a decision - useEffect(() => { - if (userDetails) { - navigator.mediaDevices - .getUserMedia({ - video: false, - audio: { - echoCancellation: true, - autoGainControl: true, - }, - }) - .then((userStream) => { - setLocalStream(userStream); - - if (userStreamTagRef?.current) - userStreamTagRef.current.srcObject = userStream; - - // alternative to dom element - // const audio = new Audio(); - // audio.autoplay = true; - // audio.srcObject = userStream; - - // !TEST STUFF : removing distortion with headphones in - // test distortion to go away on disabling audio - // setTimeout(() => { - // console.log("stopping audio stream "); - - // userStream.getTracks().forEach((track) => { - // track.enabled = !track.enabled; - - // track.stop(); - // }); - // }, 0); - - // take the initial list of tunedInUsers without my own id - const everyOtherTunedUserId = tunedInUsers.filter( - (tunedUserId) => tunedUserId !== userDetails?.user._id.toString() - ); - - const localPeerConnections: PeerMap = {}; - - everyOtherTunedUserId.forEach((otherTunedInUserId) => { - // create local peer objects for them - const localPeerInitiator = new Peer({ - initiator: true, - stream: userStream, - trickle: false, // prevents the multiple tries on different ice servers and signal from getting called a bunch of times - }); - - // set it for our map that we will iterate through to display streams in other child view - localPeerConnections[otherTunedInUserId] = localPeerInitiator; - - // notify each one with specific signal - localPeerInitiator.on("signal", (signal) => { - $ws.emit( - ServerRequestChannels.RTC_CALL_REQUEST, - new RtcCallRequest(lineId, otherTunedInUserId, signal) - ); - }); - }); - - setUserPeers(localPeerConnections); - - // answer calls - $ws.on( - `${ServerResponseChannels.RTC_NEW_USER_JOINED_RESPONSE_PREFIX}:${lineId}`, - (res: RtcNewUserResponse) => { - // create a local peer connection for this new user - - console.log( - "ooo newbie joined room, I guess I will accept it and send him my signal" - ); - console.log(res); - - var peerForMeAndNewbie = new Peer({ - initiator: false, - trickle: false, // prevents the multiple tries on different ice servers and signal from getting called a bunch of times - stream: userStream, // add in my own stream that I got before - }); - - peerForMeAndNewbie.on("signal", (signal) => { - console.log( - "as the answerer, I am going to send back my signal so that the newbie can update his local peer for me" - ); - $ws.emit( - ServerRequestChannels.RTC_ANSWER_REQUEST, - new RtcAnswerRequest(lineId, res.newUserId, signal) - ); - }); - - peerForMeAndNewbie.signal(res.simplePeerSignal); - - setUserPeers((prevUsersPeers) => { - const newUserPeers = { ...prevUsersPeers }; - - newUserPeers[res.newUserId] = peerForMeAndNewbie; - - return newUserPeers; - }); - } - ); - - // take care of answers recevied - $ws.on( - `${ServerResponseChannels.RTC_RECEIVING_ANSWER_RESPONSE_PREFIX}:${lineId}`, - (res: RtcReceiveAnswerResponse) => { - console.log( - `oooo some master received my call and accepted it ${JSON.stringify( - res - )}` - ); - console.log(res); - - // find the peer we created earlier for this master - // ?is this okay? using the setter to get the current state? - setUserPeers((previousUserPeersMap) => { - const newUserPeerMap = { ...previousUserPeersMap }; - - console.log( - "here is the current peers map", - previousUserPeersMap - ); - - const peerForAnswerer = newUserPeerMap[res.answererUserId]; - - if (peerForAnswerer) { - peerForAnswerer.signal(res.simplePeerSignal); - } else { - console.error( - "could not find the peer we created before for this master" - ); - } - - // note needed to change state so that the peer object that gets iterated in dom isn't the old referenced one/we trigger refresh for the child component - return newUserPeerMap; - }); - } - ); - - $ws.on( - `${ServerResponseChannels.SOMEONE_UNTUNED_FROM_LINE}:${lineId}`, - (res: SomeoneUntunedFromLineResponse) => { - // find the peer object and remove from our userPeers map - // will also cause unmounting the child component which destroys peer object but also can destroy here - } - ); - }) - .catch((error) => { - console.error(error); - - toast.error( - "Make sure that you have permissions enabled and microphone connected" - ); - }); - } - - // TODO: p1 : destroy peers on load - // ! remove ws handlers so that the same channels don't get triggered twice when I retune into this line - return () => { - $ws.removeListener( - `${ServerResponseChannels.RTC_RECEIVING_ANSWER_RESPONSE_PREFIX}:${lineId}` - ); - $ws.removeListener( - `${ServerResponseChannels.RTC_NEW_USER_JOINED_RESPONSE_PREFIX}:${lineId}` - ); - }; - }, [userDetails, setUserPeers]); - - // calculate diff to clean our userPeerMap to unmount and detroy certain peer connections - useEffect(() => {}, [tunedInUsers]); - - useEffect(() => { - console.log("keeping an eye on user peers map"); - console.log(userPeers); - }, [userPeers]); - - // todo, someone tell the main object that I am finally connected after everything...different than tuned in - - // TODO: p1...when the peer map user count > tunedIn.length, then we get rid of the right person from list cuzz they have officially left or disconnected - useEffect(() => { - console.log("change in tuned in users in the streaming room!!!"); - - setUserPeers((prevUserPeersMap) => { - // go through the userIds here - // if tunedIn users doesn't have a userId, this guy prolly disconnected - - const newMap = { ...prevUserPeersMap }; //ensures going through the list of peers again to remove specific ones - - const otherUserIdsPeers = Object.keys(prevUserPeersMap); - - otherUserIdsPeers.forEach((otherUserId) => { - // problem if we are trying to show stream of someone who is not tuned in - if (!tunedInUsers.includes(otherUserId)) { - console.log("user left with id:", otherUserId); - const disconnectedLocalPeer = newMap[otherUserId]; - - if (disconnectedLocalPeer) { - disconnectedLocalPeer.peer?.destroy(); - delete newMap[otherUserId]; - } - } - }); - - return newMap; - }); - }, [tunedInUsers]); - - // todo: when user isUserBroadcasting is false, disable localUserStream in this component - // and also emit, which should already have been done - - // we only loop through peers that are associated to user Ids which exist in the currentBroadcasters array - return ( - <> -