throwing away bunch of garbage

This commit is contained in:
talksik
2022-06-10 05:29:30 -05:00
parent 7af1c1ceb0
commit 445d1ef522
32 changed files with 120 additions and 2471 deletions
@@ -2,7 +2,7 @@ import NirvanaApi, { getUserDetails } from '../api/NirvanaApi';
import React, { useCallback, useContext, useEffect, useState } from 'react';
import { STORE_ITEMS } from '../electron/constants';
import { User } from '@nirvana/core/models/user.model';
import User from '@nirvana/core/models/user.model';
import toast from 'react-hot-toast';
import { useAsyncFn } from 'react-use';
@@ -1,7 +1,7 @@
import React, { useCallback, useContext, useEffect, useState } from 'react';
import { Socket, io } from 'socket.io-client';
import FlowState from '../tree/protected/FlowState';
import FlowState from '../tree/FlowState';
import toast from 'react-hot-toast';
import useAuth from './AuthProvider';
@@ -1,6 +1,6 @@
import React, { useState, useEffect, useContext } from 'react';
import React, { useContext, useEffect, useState } from 'react';
import { useAsyncFn, useAsyncRetry } from 'react-use';
import { serverCheck } from '../api/NirvanaApi';
interface IStabilityContext {
@@ -1,368 +0,0 @@
import React, { useEffect, useContext, useState, useRef, useMemo, useCallback } from 'react';
import Peer from 'simple-peer';
import useAuth from './AuthProvider';
import { useImmer } from 'use-immer';
import useSockets from './SocketProvider';
import {
RtcAnswerSomeoneRequest,
RtcCallRequest,
RtcNewUserJoinedResponse,
RtcReceiveAnswerResponse,
ServerRequestChannels,
ServerResponseChannels,
} from '@nirvana/core/sockets/channels';
import toast from 'react-hot-toast';
import useTerminalProvider from './TerminalProvider';
import MasterLineData from '@nirvana/core/models/masterLineData.model';
import { useEffectOnce } from 'react-use';
const videoConstraints = false;
// {
// frameRate: 30,
// width: { max: 100 },
// height: { max: 200 },
// };
const iceServers = [
// { urls: 'stun:stun.l.google.com:19302' },
// { urls: 'stun:stun.l.google.com:19302' },
// { urls: 'stun:stun1.l.google.com:19302' },
{ urls: 'stun:stun2.l.google.com:19302' },
// { urls: 'stun:stun3.l.google.com:19302' },
// { urls: 'stun:stun4.l.google.com:19302' },
// { urls: 'stun:global.stun.twilio.com:3478?transport=udp' },
// {
// url: 'turn:numb.viagenie.ca',
// credential: 'muazkh',
// username: '[email protected]',
// },
// {
// url: 'turn:192.158.29.39:3478?transport=udp',
// credential: 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
// username: '28224511:1379330808',
// },
// {
// url: 'turn:turn.bistri.com:80',
// credential: 'homeo',
// username: 'homeo',
// },
// {
// url: 'turn:turn.anyfirewall.com:443?transport=tcp',
// credential: 'webrtc',
// username: 'webrtc',
// },
{
url: 'turn:openrelay.metered.ca:80',
credential: 'openrelayproject',
username: 'openrelayproject',
},
];
type LineStreamData = {
localStreamForLine?: MediaStream;
peerRelations: {
userId: string;
peer: Peer;
peerMediaStream?: MediaStream;
}[];
};
type LinePeerMap = {
[lineId: string]: LineStreamData;
};
interface IStreamProvider {
peerMap: LinePeerMap;
userLocalStream?: MediaStream;
}
const StreamProviderContext = React.createContext<IStreamProvider>({
peerMap: {},
});
export function StreamProvider({ children }: { children: React.ReactChild }) {
const { roomsMap } = useTerminalProvider();
const { user } = useAuth();
const { $ws } = useSockets();
const [peerMap, updatePeerMap] = useImmer<LinePeerMap>({});
const [userLocalStream, setUserLocalStream] = useState<MediaStream>();
const handleGotPeerRemoteStream = useCallback(
(lineId: string, userId: string, remoteStream: MediaStream) => {
updatePeerMap((draft) => {
// for trickling, if we already have a peer for this line and user, then just replace
const existingUserLinePeerRelation = draft[lineId]?.peerRelations?.find(
(currPeerRelation) => currPeerRelation.userId === userId,
);
if (existingUserLinePeerRelation) {
existingUserLinePeerRelation.peerMediaStream = remoteStream;
}
});
},
[updatePeerMap],
);
const setLocalStreamForLine = useCallback(
(lineId: string, localStreamForLine: MediaStream) => {
updatePeerMap((draft) => {
draft[lineId] = { ...draft[lineId], localStreamForLine };
});
},
[updatePeerMap],
);
const handleAddPeer = useCallback(
(lineId: string, userId: string, peerObj: Peer) => {
updatePeerMap((draft) => {
// for trickling, if we already have a peer for this line and user, then just replace
const existingUserLinePeerRelation = draft[lineId]?.peerRelations?.find(
(currPeerRelation) => currPeerRelation.userId === userId,
);
if (existingUserLinePeerRelation) {
return draft;
}
if (draft[lineId]?.peerRelations) {
draft[lineId].peerRelations.push({ userId, peer: peerObj });
} else {
draft[lineId] = { ...draft[lineId], peerRelations: [{ userId, peer: peerObj }] };
}
});
},
[updatePeerMap],
);
useEffect(() => {
$ws.on(ServerResponseChannels.RTC_NEW_USER_JOINED, (res: RtcNewUserJoinedResponse) => {
toast.success('NEWBIE JOINED!!!');
console.log('someone calling me', res);
const peerForMeAndNewbie = new Peer({
initiator: false,
trickle: true, // prevents the multiple tries on different ice servers and signal from getting called a bunch of times
stream: peerMap[res.lineId]?.localStreamForLine,
config: {
iceServers,
},
});
peerForMeAndNewbie.signal(res.simplePeerSignal);
handleAddPeer(res.lineId, res.userWhoCalled, peerForMeAndNewbie);
// make sure this peer gets destroyed to remove this listener
peerForMeAndNewbie.on('signal', (signal) => {
console.log('sending an answer to the slave', res);
$ws.emit(
ServerRequestChannels.RTC_ANSWER_SOMEONE_FOR_LINE,
new RtcAnswerSomeoneRequest(res.userWhoCalled, res.lineId, signal),
);
});
peerForMeAndNewbie.on('stream', (remoteStream: MediaStream) => {
handleGotPeerRemoteStream(res.lineId, res.userWhoCalled, remoteStream);
});
});
$ws.on(ServerResponseChannels.RTC_RECEIVING_MASTER_ANSWER, (res: RtcReceiveAnswerResponse) => {
toast.success('MASTER gave me an answer!!!');
console.log('master gave me this answer: ', res);
// find this person in peer map
updatePeerMap((draft) => {
const localPeerForMasterAndMe = draft[res.lineId]?.peerRelations?.find(
(currPeerRelationship) => currPeerRelationship.userId === res.masterUserId,
);
if (localPeerForMasterAndMe) localPeerForMasterAndMe.peer.signal(res.simplePeerSignal);
});
});
return () => {
$ws.removeAllListeners(ServerResponseChannels.RTC_NEW_USER_JOINED);
$ws.removeAllListeners(ServerResponseChannels.RTC_RECEIVING_MASTER_ANSWER);
};
}, [updatePeerMap, $ws, userLocalStream, peerMap, handleGotPeerRemoteStream, handleAddPeer]);
useEffect(() => {
navigator.mediaDevices.enumerateDevices().then((devices) => {
const uniqueDevices = [];
const uniqueGroupIds = [];
devices.forEach((device) => {
if (!uniqueGroupIds.includes(device.groupId)) {
uniqueDevices.push(device);
uniqueGroupIds.push(device.groupId);
}
});
console.log(uniqueDevices);
});
// navigator.mediaDevices
// .getUserMedia({
// video: videoConstraints,
// audio: true,
// })
// .then((localMediaStream: MediaStream) => {
// setUserLocalStream(localMediaStream);
// });
}, []);
console.log(`peer map: `, peerMap);
// manage untuning including myself
useEffect(() => {
const tunedUsersForLines: { [lineId: string]: string[] } = {};
Object.values(roomsMap).map((currentLine) => {
if (currentLine.tunedInMemberIds)
tunedUsersForLines[currentLine.lineDetails._id.toString()] = currentLine.tunedInMemberIds;
});
updatePeerMap((draft) => {
// go through peer map
// if there is someone in it who is not in a tuned in line, then destroy peer and remove
Object.entries(draft).map(([lineId, lineStreamData]) => {
// if I left this channel, then I want to make sure to destroy and delete all relations
if (
roomsMap[lineId]?.tunedInMemberIds &&
!roomsMap[lineId]?.tunedInMemberIds.includes(user._id.toString())
) {
lineStreamData?.peerRelations?.forEach((peerRelation) => {
peerRelation.peer.destroy();
});
delete draft[lineId];
return;
}
const usersToRemove = [];
lineStreamData?.peerRelations?.forEach((peerRelation) => {
if (!tunedUsersForLines[lineId].includes(peerRelation.userId)) {
peerRelation.peer.destroy();
usersToRemove.push(peerRelation.userId);
}
});
draft[lineId].peerRelations = draft[lineId]?.peerRelations?.filter(
(peerRelation) => !usersToRemove.includes(peerRelation.userId),
);
});
});
}, [roomsMap, updatePeerMap, user]);
return (
<StreamProviderContext.Provider value={{ peerMap, userLocalStream }}>
{/* handles stream connections */}
{/* {Object.values(roomsMap).map((line) => {
if (line.tunedInMemberIds?.includes(user._id.toString()))
return (
<MemoLineConnector
key={`streamConnector-${line.lineDetails._id.toString()}`}
lineId={line.lineDetails._id.toString()}
handleAddPeer={handleAddPeer}
membersToCall={line.tunedInMemberIds.filter(
(currMemberId) => currMemberId !== user._id.toString(),
)}
handleGotPeerRemoteStream={handleGotPeerRemoteStream}
setLocalStreamForLine={setLocalStreamForLine}
/>
);
})} */}
{children}
</StreamProviderContext.Provider>
);
}
export default function useStreams() {
return useContext(StreamProviderContext);
}
const MemoLineConnector = React.memo(LineConnector);
// handle managing stream connections for one line
function LineConnector({
lineId,
membersToCall,
handleAddPeer,
handleGotPeerRemoteStream,
setLocalStreamForLine,
}: {
lineId: string;
membersToCall: string[];
handleAddPeer: (lineId: string, userId: string, peerObj: Peer) => void;
setLocalStreamForLine: (lineId: string, localStreamForLine: MediaStream) => void;
handleGotPeerRemoteStream: (lineId: string, userId: string, remoteStream: MediaStream) => void;
}) {
const { $ws } = useSockets();
console.log('rendering this piece of shit');
useEffectOnce(() => {
console.log('got initial list for this channel that I am tuned into');
console.log(membersToCall);
// todo get the user media selections
// todo check if already in peer map? keeping it simple for now
// a peer relationship between me and someone for this particular channel so that I can just enable or disable this particular stream
// object instead of managing different ones
// bandwidth wise, would be uploading stream to one room at a time but downloading a x b streams but someone can't
// stream in two at same time anyway
navigator.mediaDevices
.getUserMedia({ video: videoConstraints, audio: true })
.then((localMediaStream: MediaStream) => {
setLocalStreamForLine(lineId, localMediaStream);
toast.success('CALLING bunch of people!!!');
console.log('Calling these folks', membersToCall);
console.log('for line', lineId);
// todo...call in parallel
membersToCall.map((memberId) => {
const connectingToast = toast.loading('calling peer for a snappy experience');
// make sure this peer gets destroyed when it's time to remove this listener
const localPeerConnection = new Peer({
initiator: true,
stream: localMediaStream,
trickle: true, // prevents the multiple tries on different ice servers and signal from getting called a bunch of times,
config: {
iceServers,
},
});
localPeerConnection.on('signal', (signal) => {
console.log('have a signal to make call to someone ');
$ws.emit(
ServerRequestChannels.RTC_CALL_SOMEONE_FOR_LINE,
new RtcCallRequest(memberId, lineId, signal),
);
toast.dismiss(connectingToast);
// sending back the connection to the parent
// so that we can accept the answer later on
handleAddPeer(lineId, memberId, localPeerConnection);
});
localPeerConnection.on('stream', (remoteStream: MediaStream) => {
handleGotPeerRemoteStream(lineId, memberId, remoteStream);
});
});
});
});
return <></>;
}
@@ -1,494 +0,0 @@
import React, { useEffect, useState, useContext, useCallback, useMemo } from 'react';
import useRooms from './RoomsProvider';
import useSockets from './SocketProvider';
import MasterLineData from '@nirvana/core/models/masterLineData.model';
import {
ServerRequestChannels,
ServerResponseChannels,
SomeoneConnectedResponse,
SomeoneDisconnectedResponse,
SomeoneTunedResponse,
SomeoneUntunedFromLineResponse,
TuneToLineRequest,
UserStartedBroadcastingResponse,
UserStoppedBroadcastingResponse,
ConnectToLineRequest,
UntuneFromLineRequest,
} from '@nirvana/core/sockets/channels';
import toast from 'react-hot-toast';
import { useImmer } from 'use-immer';
import { LineMemberState } from '@nirvana/core/models/line.model';
import { useAsyncFn, useKeyPressEvent } from 'react-use';
import { updateLineMemberState } from '../api/NirvanaApi';
import UpdateLineMemberState from '@nirvana/core/requests/updateLineMemberState.request';
import useAuth from './AuthProvider';
import { User } from '@nirvana/core/models/user.model';
import SidePanel from '../tree/protected/terminal/panels/SidePanel';
import MainPanel from '../tree/protected/terminal/panels/MainPanel';
import useElectron from './ElectronProvider';
import { StreamProvider } from './StreamProvider';
type LineIdToMasterLine = {
[lineId: string]: MasterLineData;
};
// TODO: implement the below to save renders
type TunedMembersMap = {
[lineId: string]: string[];
};
type ConnectedMembesMap = {
[lineId: string]: string[];
};
type UserMap = {
[userId: string]: User;
};
type BroadcastersMap = {
[lineId: string]: string[];
};
interface ITerminalProvider {
roomsMap: LineIdToMasterLine;
allChannels: MasterLineData[];
selectedLineId?: string;
handleSelectLine?: (newLineId: string) => void;
handleUpdateLineMemberState?: (lineId: string, newState: LineMemberState) => void;
showNewChannelForm: boolean;
handleShowNewChannelForm?: (showOrHide: 'show' | 'hide') => void;
tunedChannelsCount: number;
}
const TerminalContext = React.createContext<ITerminalProvider>({
roomsMap: {},
allChannels: [],
tunedChannelsCount: 0,
showNewChannelForm: false,
});
/**
*
* handles reads of new data
* keeps listening to incoming socket events to make sure that the realtime rooms map is highly available
*
* on load, we want to grab all of the rooms we are in
* put them in a map
*
* fetch more audio clips, fire off async function to fetch more and add to the room map
*
* Socket Rooms:
* - all people online for a line
* - all tuned in folks on a line...have it selected or toggle tuned
*
* Socket Events:
* - someone connected
* - someone tuned in
* - someone started broadcasting
* - someone stopped broadcasting
*
* - someone disconnected...take them out of the necessary lists
* - someone left x room
* - someone joined x room
*
* - someone added me to line
*
* - someone went into flow state their status
*
* Socket Emissions:
* - join a line
* - tune into a line
* - send audio clip
* - create a line -> send to specific people
*
* REST endpoints:
* - toggle tune or untoggle tune
* - fetch content blocks for line history - react query
*/
// TODO: many of this can be done in a HOC like <Terminal /> but it doesn't matter, they both just
// re-render, just make sure to pass in lighter props to children like main panel or lineRow
export function TerminalProvider({ children }: { children: React.ReactChild }) {
const { rooms } = useRooms();
const { user } = useAuth();
const { $ws } = useSockets();
const [roomMap, updateRoomMap] = useImmer<LineIdToMasterLine>({});
const { desktopMode } = useElectron();
const [selectedLineId, setSelectedLineId] = useState<string>();
const [moveLineState, moveLine] = useAsyncFn(updateLineMemberState);
const [showNewChannelForm, setShowNewChannelForm] = useState<boolean>(false);
/** All line listeners */
useEffect(() => {
// when me or anyone just initially connects to line
$ws.on(ServerResponseChannels.SOMEONE_CONNECTED_TO_LINE, (res: SomeoneConnectedResponse) => {
console.log(`${res.userId} connected to room ${res.lineId}`);
updateRoomMap((draft) => {
if (!draft[res.lineId]) {
toast.error('there was a problem updating rooms!!!');
return;
}
draft[res.lineId].connectedMemberIds = res.allUsers;
});
});
// someone tuning in, including perhaps me | either toggled in or just temporary
$ws.on(ServerResponseChannels.SOMEONE_TUNED_INTO_LINE, (res: SomeoneTunedResponse) => {
console.log(`${res.userId} tuned into line ${res.lineId}`);
updateRoomMap((draft) => {
if (!draft[res.lineId]) {
toast.error('there was a problem updating rooms!!!');
return;
}
draft[res.lineId].tunedInMemberIds = res.allUsers;
});
});
$ws.on(
ServerResponseChannels.SOMEONE_UNTUNED_FROM_LINE,
(res: SomeoneUntunedFromLineResponse) => {
console.log(`${res.userId} untuned from ${res.lineId}`);
updateRoomMap((draft) => {
if (!draft[res.lineId]) {
toast.error('there was a problem updating rooms!!!');
return;
}
if (draft[res.lineId].tunedInMemberIds) {
draft[res.lineId].tunedInMemberIds = draft[res.lineId].tunedInMemberIds.filter(
(userId) => userId !== res.userId,
);
}
});
},
);
// remove them from the line connected list and tuned list if they are there
$ws.on(
ServerResponseChannels.SOMEONE_DISCONNECTED_FROM_LINE,
(res: SomeoneDisconnectedResponse) => {
updateRoomMap((draft) => {
if (!draft[res.lineId]) {
toast.error('there was a problem updating rooms!!!');
return;
}
draft[res.lineId].connectedMemberIds = draft[res.lineId].connectedMemberIds?.filter(
(userId) => userId !== res.userId,
);
draft[res.lineId].tunedInMemberIds = draft[res.lineId].tunedInMemberIds?.filter(
(userId) => userId !== res.userId,
);
});
},
);
$ws.on(
ServerResponseChannels.SOMEONE_STARTED_BROADCASTING,
(res: UserStartedBroadcastingResponse) => {
console.log(`${res.userId} is starting to broadcast in ${res.lineId}`);
updateRoomMap((draft) => {
if (!draft[res.lineId]) {
toast.error('there was a problem updating rooms!!!');
return;
}
if (draft[res.lineId].currentBroadcastersUserIds) {
draft[res.lineId].currentBroadcastersUserIds.push(res.userId);
} else {
draft[res.lineId].currentBroadcastersUserIds = [res.userId];
}
});
},
);
$ws.on(
ServerResponseChannels.SOMEONE_STOPPED_BROADCASTING,
(res: UserStoppedBroadcastingResponse) => {
console.log(`${res.userId} is STOPPED BROADCASTING in ${res.lineId}`);
updateRoomMap((draft) => {
if (!draft[res.lineId]) {
toast.error('there was a problem updating rooms!!!');
return;
}
if (draft[res.lineId].currentBroadcastersUserIds) {
draft[res.lineId].currentBroadcastersUserIds = draft[
res.lineId
].currentBroadcastersUserIds.filter((userId) => userId !== res.userId);
}
});
},
);
return () => {
// ?perhaps only remove specific ones?
// !this will remove all listeners across the app and we want it to?
$ws.removeAllListeners();
};
}, [$ws, updateRoomMap]);
const handleConnectToLine = useCallback(
(lineId: string) => {
$ws.emit(ServerRequestChannels.CONNECT_TO_LINE, new ConnectToLineRequest(lineId));
},
[$ws],
);
const handleTuneIntoLine = useCallback(
(lineId: string) => {
$ws.emit(ServerRequestChannels.TUNE_INTO_LINE, new TuneToLineRequest(lineId));
},
[$ws],
);
const handleUntuneFromLine = useCallback(
(lineId: string) => {
$ws.emit(ServerRequestChannels.UNTUNE_FROM_LINE, new UntuneFromLineRequest(lineId));
},
[$ws],
);
// converts the initial rooms fetch to a map
useEffect(() => {
if (rooms.value?.data?.masterLines?.length > 0) {
updateRoomMap((draft) => {
rooms.value.data.masterLines.forEach((masterLine) => {
const lineId = masterLine.lineDetails._id.toString();
draft[lineId] = masterLine;
handleConnectToLine(lineId);
if (masterLine.currentUserMember.state === LineMemberState.TUNED) {
handleTuneIntoLine(lineId);
}
});
});
}
}, [rooms.value, updateRoomMap, handleConnectToLine, handleTuneIntoLine]);
// "subscribe" to a channel
const handleAddChannel = useCallback(
(channelId: string) => {
// get the details of the channel
// get my association with it
// get other members in it
// add to map
// connect/join the socket room for it
},
[handleConnectToLine, updateRoomMap],
);
// persist whether I want it toggle tuned or not
const handleUpdateLineMemberState = useCallback(
(lineId: string, newState: LineMemberState) => {
moveLine(new UpdateLineMemberState(newState), lineId)
.then((_res) => {
updateRoomMap((draft) => {
draft[lineId].currentUserMember.state = newState;
});
})
.catch((error) => {
toast.error('problem in updating line member state');
console.error(error);
});
},
[moveLine, updateRoomMap],
);
/**
* selection globally
* tune into socket room and tell everyone else
*/
const handleSelectLine = useCallback(
(newLineIdToSelect: string) => {
setSelectedLineId((prevLineId) => {
if (newLineIdToSelect === prevLineId) {
return prevLineId;
}
// untune from the last line if it was just a temporary tuned one
if (roomMap[prevLineId]?.currentUserMember.state === LineMemberState.INBOX) {
handleUntuneFromLine(prevLineId);
}
// tune in if not already tuned into this line
if (!roomMap[newLineIdToSelect].tunedInMemberIds?.includes(user._id.toString())) {
handleTuneIntoLine(newLineIdToSelect);
}
return newLineIdToSelect;
});
setShowNewChannelForm(false);
},
[
setSelectedLineId,
handleUntuneFromLine,
roomMap,
user,
handleTuneIntoLine,
setShowNewChannelForm,
],
);
const handleShowNewChannelForm = useCallback(
(showOrHide: 'show' | 'hide' = 'show') => {
setSelectedLineId(undefined);
setShowNewChannelForm(showOrHide === 'show');
},
[setShowNewChannelForm, setSelectedLineId],
);
// handle shortcuts
const clearMind = useCallback(() => {
setSelectedLineId((prevLineId) => {
// untune from the last line if it was just a temporary tuned one
if (roomMap[prevLineId]?.currentUserMember.state === LineMemberState.INBOX) {
handleUntuneFromLine(prevLineId);
}
return undefined;
});
setShowNewChannelForm(false);
}, [setSelectedLineId, setShowNewChannelForm, handleUntuneFromLine, roomMap]);
useKeyPressEvent('Escape', clearMind);
// todo: sort based on content blocks and my last activity date
const allChannels = useMemo(() => {
let channels: MasterLineData[] = Object.values(roomMap);
channels = channels.map((currChann) => Object.assign({}, currChann, MasterLineData));
if (desktopMode === 'overlayOnly') {
channels = channels.filter((currentChannel) =>
currentChannel.tunedInMemberIds?.includes(user._id.toString()),
);
}
channels.sort((channelA, channelB) => {
if (
channelA.currentUserMember.state === LineMemberState.TUNED &&
channelB.currentUserMember.state === LineMemberState.INBOX
)
return -1;
if (
channelB.currentUserMember.state === LineMemberState.TUNED &&
channelA.currentUserMember.state === LineMemberState.INBOX
)
return 1;
if (channelA.lineDetails.createdDate > channelB.lineDetails.createdDate) return 1;
// sort also by activity
return -1;
});
channels.forEach((currChannel) => {
currChannel.isUserTunedIn = currChannel.tunedInMemberIds?.includes(user._id.toString())
? true
: false;
currChannel.isUserToggleTuned = currChannel.currentUserMember.state === LineMemberState.TUNED;
const allMembers: string[] = [];
const allMembersWithoutMe: string[] = [];
const tunedMembers: string[] = [];
const broadcastMembers: string[] = [];
const untunedMembers: string[] = [];
// ?don't add in my image as that's useless contextually?
if (user.picture) allMembers.push(user.picture);
currChannel.otherUserObjects?.forEach((otherUser) => {
if (otherUser.picture) {
allMembers.push(otherUser.picture);
allMembersWithoutMe.push(otherUser.picture);
if (currChannel.tunedInMemberIds?.includes(otherUser._id.toString())) {
tunedMembers.push(otherUser.picture);
return;
}
if (currChannel.currentBroadcastersUserIds?.includes(otherUser._id.toString())) {
broadcastMembers.push(otherUser.picture);
return;
}
untunedMembers.push(otherUser.picture);
}
});
currChannel.profilePictures = {
untunedMembers,
allMembers,
tunedMembers,
broadcastMembers,
allMembersWithoutMe,
};
});
return channels;
}, [roomMap, desktopMode, user]);
const tunedChannelsCount = useMemo(
() =>
allChannels?.filter(
(currChannel) => currChannel.currentUserMember.state === LineMemberState.TUNED,
)?.length,
[allChannels],
);
// !Caution: the roommap won't have the additional properties as allChannels does
return (
<TerminalContext.Provider
value={{
roomsMap: roomMap,
allChannels,
tunedChannelsCount,
handleSelectLine,
selectedLineId,
handleUpdateLineMemberState,
showNewChannelForm,
handleShowNewChannelForm,
}}
>
<StreamProvider>
<>
<div className="flex flex-row flex-1 h-full w-full">
<SidePanel />
{desktopMode === 'mainApp' && <MainPanel />}
</div>
{children}
</>
</StreamProvider>
</TerminalContext.Provider>
);
}
export default function useTerminalProvider() {
return useContext(TerminalContext);
}
@@ -0,0 +1 @@
// handle the flow state and other things