diff --git a/README.md b/README.md index ab9bf155..ba455914 100644 --- a/README.md +++ b/README.md @@ -10,16 +10,101 @@ ## TEAM ๐Ÿ”ฅFIRE๐Ÿ”ฅ ์†Œ๊ฐœ -|์œค์˜๊ธฐ : FE|๊ณ ์ฃผํ˜• : BE|์ดํ•˜๋ น : FE| -|:--:|:--:|:---:| -| | | | -|[@071yoon](https://github.com/071yoon)|[@IamGroooooot](https://github.com/IamGroooooot)|[@halang](https://github.com/haryung-lee)| -| [![wakatime](https://wakatime.com/badge/user/4292264a-e9dd-4cc1-8ab6-1ada6ddb177a/project/79b7e168-b8e8-41f9-a790-c41967365f78.svg)](https://wakatime.com/badge/user/4292264a-e9dd-4cc1-8ab6-1ada6ddb177a/project/79b7e168-b8e8-41f9-a790-c41967365f78) |[![wakatime](https://wakatime.com/badge/user/95486c3b-017e-41e8-8d9c-20de1b876bf5/project/dabe2a55-4c66-49ab-ae59-8eba6b898e6f.svg)](https://wakatime.com/badge/user/95486c3b-017e-41e8-8d9c-20de1b876bf5/project/dabe2a55-4c66-49ab-ae59-8eba6b898e6f)|[![wakatime](https://wakatime.com/badge/user/02d79381-005e-489b-b7f0-5fdf9dc2a088/project/d5dd888b-da07-4723-bc9d-f7c07c44307a.svg)](https://wakatime.com/badge/user/02d79381-005e-489b-b7f0-5fdf9dc2a088/project/d5dd888b-da07-4723-bc9d-f7c07c44307a)| +| ์œค์˜๊ธฐ : FE | ๊ณ ์ฃผํ˜• : BE | ์ดํ•˜๋ น : FE | +| :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +| | | | +| [@071yoon](https://github.com/071yoon) | [@IamGroooooot](https://github.com/IamGroooooot) | [@halang](https://github.com/haryung-lee) | +| [![wakatime](https://wakatime.com/badge/user/4292264a-e9dd-4cc1-8ab6-1ada6ddb177a/project/79b7e168-b8e8-41f9-a790-c41967365f78.svg)](https://wakatime.com/badge/user/4292264a-e9dd-4cc1-8ab6-1ada6ddb177a/project/79b7e168-b8e8-41f9-a790-c41967365f78) | [![wakatime](https://wakatime.com/badge/user/95486c3b-017e-41e8-8d9c-20de1b876bf5/project/dabe2a55-4c66-49ab-ae59-8eba6b898e6f.svg)](https://wakatime.com/badge/user/95486c3b-017e-41e8-8d9c-20de1b876bf5/project/dabe2a55-4c66-49ab-ae59-8eba6b898e6f) | [![wakatime](https://wakatime.com/badge/user/02d79381-005e-489b-b7f0-5fdf9dc2a088/project/d5dd888b-da07-4723-bc9d-f7c07c44307a.svg)](https://wakatime.com/badge/user/02d79381-005e-489b-b7f0-5fdf9dc2a088/project/d5dd888b-da07-4723-bc9d-f7c07c44307a) | ## ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ **๋ชจ๋„์ฝ”**(๋ชจ์—ฌ์„œ ๋„๋ž€๋„๋ž€ ์ฝ”๋”ฉ) ํ”„๋กœ์ ํŠธ๋Š” ๋ชจ๊ฐ์ฝ”๋ฅผ ํ•˜๊ณ  ์‹ถ์€ ์‚ฌ๋žŒ๋“ค์ด ๋ชจ์—ฌ ๋„๋ž€๋„๋ž€ ์ฝ”๋”ฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ํ”Œ๋žซํผ์ž…๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž ์นœํ™”์ ์ธ ๊ธฐ๋Šฅ์„ ๊ฐ–์ถ”๊ณ  ๋ชจ๊ฐ์ฝ”๋กœ ๋งŒ๋“ค์–ด์ง„ ์ธ์—ฐ์ด ์ด์–ด์งˆ ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ค๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค. +--- + +## ์‹คํ–‰๋ฐฉ๋ฒ• + +### Project Setting + +ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ธํŒ… + +```shell +# ************************************************* # +# This is an example env file for modoco frontend # +# ************************************************* # + +# backend server +REACT_APP_BASE_URL=your_backend_server + +# channel talk key +REACT_APP_CHANNEL_IO_KEY=your_channel_talk_key + +# oauth +# oauth client id +REACT_APP_GITHUB_CLIENT_ID=your_github_oauth_client_id +REACT_APP_KAKAO_CLIENT_ID=your_kakao_oauth_client_id +REACT_APP_GOOGLE_CLIENT_ID=your_google_oauth_client_id +# oauth redirect uri +REACT_APP_KAKAO_REDIRECT_URI=your_kakao_redirect_uri +REACT_APP_GOOGLE_REDIRECT_URI=your_google_redirect_uri + +# turn server +REACT_APP_TURN_URL=your_turn_server_url +REACT_APP_TURN_CREDENTIAL=your_turn_server_credential +REACT_APP_TURN_USERNAME=your_turn_server_username + +# lambda server +REACT_APP_LAMBDA_INVITE=your_lambda_server_url +``` + +### Installation + +#### 1. Install npm dependency + +```shell +# install packages +$ yarn install + +# clean install packages +$ yarn ci +``` + +#### 2. Run React + +```shell +# run app +yarn start + +# run app in https +# need SSL_CRT_FILE=cert.pem SSL_KEY_FILE=key.pem in root +yarn start:https + +# check style lint +yarn lint:css +``` + +### Build + +```shell +# build app +yarn build +``` + +### Testing + +```shell +# start test mode +yarn test + +# run app and open cypress +yarn cypress + +# open cypress without opening app +npx cypress open +``` + +--- + ## Stacks ๐Ÿš€ ### Environment @@ -50,6 +135,8 @@ ![GA](https://img.shields.io/badge/Google%20Analytics-E37400?style=for-the-badge&logo=google%20analytics&logoColor=white) ![Wakatime](https://img.shields.io/badge/WakaTime-000000?style=for-the-badge&logo=WakaTime&logoColor=white) ![NewRelic](https://img.shields.io/badge/New--Relic-008C99?style=for-the-badge&logo=NewRelic&logoColor=white) +--- + ## ๋™์ž‘ ํ™”๋ฉด ๐Ÿ’ป ### ํ™”๋ฉด ๊ตฌ์„ฑ @@ -66,6 +153,8 @@ | :-----------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------: | | ๋ฐ”๋‹ค | ์บ ํ•‘ | ๋ชจ๋‹ฅ๋ถˆ | ์šฐ์ฃผ | ์—ฌํ–‰ | +--- + ## ์ฃผ์š” ๊ธฐ๋Šฅ โœจ ### โญ๏ธ ์ง„ํ–‰์ค‘์ธ ๋ชจ๊ฐ์ฝ” ๋ฐฉ์— ์ž…์žฅ @@ -93,6 +182,8 @@ - ์–ผ๋งˆ๋‚˜ ํ–ˆ๋Š”์ง€ ๊ถ๊ธˆํ•˜์‹œ๋‹ค๋ฉด, ํ†ต๊ณ„ ํŽ˜์ด์ง€๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š” - ์˜ค๋Š˜, ์ด๋ฒˆ์ฃผ, ํ•œ๋‹ฌ ๋“ฑ ๋‹ค์–‘ํ•œ ํ†ต๊ณ„ ์ž๋ฃŒ๋ฅผ ๋ณด์—ฌ๋“œ๋ ค์š” +--- + ## ์•„ํ‚คํ…์ณ โš’ ### Full Architecture @@ -107,6 +198,8 @@ ![front-uml](https://user-images.githubusercontent.com/66371206/194737818-1ac02b91-7861-4983-8bc5-b00c2e55d7c8.jpeg) +--- + ## ๊ฐœ๋ฐœ๋กœ๊ทธ โœ๏ธ
@@ -128,11 +221,9 @@ [![071yoon's GitHub stats](https://velog-readme-stats.vercel.app/api?name=071yoon&slug=React๋กœ-์˜ค๋””์˜ค-๋น„์ฃผ์–ผ๋ผ์ด์ €-๋งŒ๋“ค๊ธฐ)](https://velog.io/@071yoon/React%EB%A1%9C-%EC%98%A4%EB%94%94%EC%98%A4-%EB%B9%84%EC%A3%BC%EC%96%BC%EB%9D%BC%EC%9D%B4%EC%A0%80-%EB%A7%8C%EB%93%A4%EA%B8%B0) -[![071yoon's GitHub stats](https://velog-readme-stats.vercel.app/api?name=071yoon&slug=Cypress๋กœ-e2e-ํ…Œ์ŠคํŠธ-์ง„ํ–‰ํ•˜๊ธฐ)]( -https://velog.io/@071yoon/Cypress%EB%A1%9C-e2e-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%A7%84%ED%96%89%ED%95%98%EA%B8%B0) +[![071yoon's GitHub stats](https://velog-readme-stats.vercel.app/api?name=071yoon&slug=Cypress๋กœ-e2e-ํ…Œ์ŠคํŠธ-์ง„ํ–‰ํ•˜๊ธฐ)](https://velog.io/@071yoon/Cypress%EB%A1%9C-e2e-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%A7%84%ED%96%89%ED%95%98%EA%B8%B0) -[![071yoon's GitHub stats](https://velog-readme-stats.vercel.app/api?name=071yoon&slug=APM-๋กœ๊ทธ๋กœ-๋ฌธ์ œ-ํ•ด๊ฒฐํ•˜๊ธฐ)]( -https://velog.io/@071yoon/APM-%EB%A1%9C%EA%B7%B8%EB%A1%9C-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0) +[![071yoon's GitHub stats](https://velog-readme-stats.vercel.app/api?name=071yoon&slug=APM-๋กœ๊ทธ๋กœ-๋ฌธ์ œ-ํ•ด๊ฒฐํ•˜๊ธฐ)](https://velog.io/@071yoon/APM-%EB%A1%9C%EA%B7%B8%EB%A1%9C-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0)
diff --git a/public/index.html b/public/index.html index ad6d4865..faf3dbde 100644 --- a/public/index.html +++ b/public/index.html @@ -1,5 +1,5 @@ - + diff --git a/src/adapters/mediaStateChange.ts b/src/adapters/mediaStateChange.ts index f8888495..a6ddcb04 100644 --- a/src/adapters/mediaStateChange.ts +++ b/src/adapters/mediaStateChange.ts @@ -24,7 +24,6 @@ const mediaStateChange = () => { const emitAudioStateChange = (room: string, enabled: boolean) => { newSocket?.emit(SOCKET_EVENT.AUDIO_STATE_CHANGE, { room, enabled }); - toggleAudioStream(enabled); }; useEffect(() => { @@ -32,6 +31,7 @@ const mediaStateChange = () => { const { uid, enabled } = data; const isMe = uid === userId; const audioStateUser = findUserByUid(uid); + if (!audioStateUser && !isMe) { appendUser({ nickname: '', @@ -41,20 +41,22 @@ const mediaStateChange = () => { enabledVideo: true, enabledAudio: enabled, isAlreadyEntered: true, - volume: enabled ? 0.5 : 0, + volume: 0.5, }); } else if (audioStateUser && !isMe) { setEnabledAudioByUid(uid, enabled); + } else if (isMe) { + toggleAudioStream(enabled); } }); newSocket?.on(SOCKET_EVENT.KICK_USER, (data) => { const { kickUser } = data; - if (kickUser.uid === userId) { + if (kickUser?.uid === userId) { alert('๋ฐฉ์žฅ์— ์˜ํ•ด ๊ฐ•ํ‡ด๋‹นํ•˜์˜€์Šต๋‹ˆ๋‹ค.'); newSocket.close(); } else { - const kickedUser = findUserByUid(kickUser.uid); + const kickedUser = findUserByUid(kickUser?.uid); console.log(kickedUser); if (kickedUser?.sid) { setPc({ sid: kickedUser?.sid, peerConnection: null }); diff --git a/src/adapters/roomSocket.ts b/src/adapters/roomSocket.ts index c84db9ab..b90a570d 100644 --- a/src/adapters/roomSocket.ts +++ b/src/adapters/roomSocket.ts @@ -12,6 +12,10 @@ const generateSocket = () => { : null; }; +const deleteSocket = () => { + roomSocket.socket = null; +}; + export default roomSocket; -export { generateSocket }; +export { generateSocket, deleteSocket }; diff --git a/src/components/archive/LobbyCanvas.tsx b/src/components/archive/LobbyCanvas.tsx index 7130d72b..357e4caa 100644 --- a/src/components/archive/LobbyCanvas.tsx +++ b/src/components/archive/LobbyCanvas.tsx @@ -47,7 +47,7 @@ export default function LobbyCanvas({ autoFocus type="button" > - + ); })} diff --git a/src/components/atoms/RoomDetail.tsx b/src/components/atoms/RoomDetail.tsx index 677c605c..d4266527 100644 --- a/src/components/atoms/RoomDetail.tsx +++ b/src/components/atoms/RoomDetail.tsx @@ -5,7 +5,7 @@ import ThemeImage from './ThemeImages'; export default function RoomDetail({ data }) { return ( - +
๐Ÿ”ฅ
{data.total}์ค‘
diff --git a/src/components/atoms/ThemeImages.tsx b/src/components/atoms/ThemeImages.tsx index 6b8bc522..5dab7a95 100644 --- a/src/components/atoms/ThemeImages.tsx +++ b/src/components/atoms/ThemeImages.tsx @@ -7,13 +7,17 @@ import Travel from '../../assets/theme/travel.png'; import Camping from '../../assets/theme/camp.png'; import { ReactComponent as Bar } from '../../assets/svg/Room/Bar.svg'; -export default function ThemeImage({ theme }) { +export default function ThemeImage({ theme, type }) { if (theme === 'cosmos') { return ( cosmos - ์šฐ์ฃผ - + {type === 'block' && ( + <> + ์šฐ์ฃผ + + + )} ); } @@ -21,8 +25,12 @@ export default function ThemeImage({ theme }) { return ( fire - ๋ชจ๋‹ฅ๋ถˆ - + {type === 'block' && ( + <> + ๋ชจ๋‹ฅ๋ถˆ + + + )} ); } @@ -30,8 +38,12 @@ export default function ThemeImage({ theme }) { return ( ocean - ๋ฐ”๋‹ค - + {type === 'block' && ( + <> + ๋ฐ”๋‹ค + + + )} ); } @@ -39,8 +51,12 @@ export default function ThemeImage({ theme }) { return ( travel - ์—ฌํ–‰ - + {type === 'block' && ( + <> + ์—ฌํ–‰ + + + )} ); } @@ -48,8 +64,12 @@ export default function ThemeImage({ theme }) { return ( camping - ์บ ํ•‘ - + {type === 'block' && ( + <> + ์บ ํ•‘ + + + )} ); } diff --git a/src/components/main/MainTitle.tsx b/src/components/main/MainTitle.tsx index 06e056e9..5d54211c 100644 --- a/src/components/main/MainTitle.tsx +++ b/src/components/main/MainTitle.tsx @@ -33,7 +33,7 @@ export default function TitleContainer() { // send my info lobbySocket.socket?.on('connect', () => { getMe().then((res) => { - lobbySocket.socket?.emit('joinLobby', { uid: res.data.uid }); + lobbySocket.socket?.emit('joinLobby', { uid: res?.data?.uid }); }); }); @@ -51,7 +51,7 @@ export default function TitleContainer() { appendUser({ nickname: res.data.nickname, uid, - avatar: res.data.avatar, + avatar: res.data?.avatar, sid, }); } else { @@ -64,13 +64,13 @@ export default function TitleContainer() { lobbySocket.socket?.on('existingUsers', ({ users, current }) => { console.log(current); users.map((user) => { - getUser(user.uid).then((res) => { + getUser(user?.uid).then((res) => { const existingUser = findUserByUid(user.uid); if (!existingUser) { appendUser({ nickname: res.data.nickname, uid: user.uid, - avatar: res.data.avatar, + avatar: res.data?.avatar, sid: user.sid, }); } else { @@ -82,7 +82,7 @@ export default function TitleContainer() { }); lobbySocket.socket?.on('LeftLobby', ({ sid }: { sid: string }) => { - if (lobbySocket.socket.id === sid) { + if (lobbySocket.socket?.id === sid) { return; } removeUser(sid); diff --git a/src/components/main/block/Block.tsx b/src/components/main/block/Block.tsx index 2666dbb0..5b313e53 100644 --- a/src/components/main/block/Block.tsx +++ b/src/components/main/block/Block.tsx @@ -13,7 +13,7 @@ import useEnterProfile from '../useEnterProfile'; export default function Block({ isMain, data }) { const navigate = useNavigate(); const { nickname } = UserStore(); - const { enterProfile } = useEnterProfile(data.moderator.uid); + const { enterProfile } = useEnterProfile(data?.moderator.uid); const enterRoom = (event: React.MouseEvent) => { event.preventDefault(); @@ -35,7 +35,7 @@ export default function Block({ isMain, data }) { return ( - + ๋ฐฉ์žฅ{data.moderator.nickname} diff --git a/src/components/main/block/filterMyBlock.ts b/src/components/main/block/filterMyBlock.ts index 5dea8376..ad91bdc3 100644 --- a/src/components/main/block/filterMyBlock.ts +++ b/src/components/main/block/filterMyBlock.ts @@ -4,7 +4,7 @@ import userStore from '../../../stores/userStore'; export const filterMyBlock = (data) => { const { uid } = userStore(); const newData = data?.filter( - (block: blockInterface) => block.moderator.uid === uid, + (block: blockInterface) => block.moderator?.uid === uid, ); newData?.sort((a, b) => { diff --git a/src/components/main/lobby/Participants.tsx b/src/components/main/lobby/Participants.tsx index 413103f3..fa4ace80 100644 --- a/src/components/main/lobby/Participants.tsx +++ b/src/components/main/lobby/Participants.tsx @@ -5,7 +5,7 @@ export default function Participants({ connectedUsers }) { return ( {connectedUsers.map((user) => { - return ; + return ; })} ); diff --git a/src/components/main/lobby/SingleParticipant.tsx b/src/components/main/lobby/SingleParticipant.tsx index b1b2462c..3962388d 100644 --- a/src/components/main/lobby/SingleParticipant.tsx +++ b/src/components/main/lobby/SingleParticipant.tsx @@ -3,12 +3,12 @@ import MyAvatar from 'src/assets/avatar/MyAvatar'; import useEnterProfile from '../useEnterProfile'; export default function SingleParticipant({ user }) { - const { enterProfile } = useEnterProfile(user.uid); + const { enterProfile } = useEnterProfile(user?.uid); return ( - + {user.nickname} diff --git a/src/components/profile/friends/FriendIcon.tsx b/src/components/profile/friends/FriendIcon.tsx index 3613e96d..dcc5507c 100644 --- a/src/components/profile/friends/FriendIcon.tsx +++ b/src/components/profile/friends/FriendIcon.tsx @@ -7,7 +7,7 @@ import MyAvatar from '../../../assets/avatar/MyAvatar'; import singleFriend from '../../../interface/singleFriend.interface'; export default function FriendIcon({ friend }: { friend: singleFriend }) { - const { enterProfile } = useEnterProfile(friend.uid); + const { enterProfile } = useEnterProfile(friend?.uid); const { closeProfileModal } = mainModalStore(); const onFriendProfile = (event: React.MouseEvent) => { @@ -19,7 +19,7 @@ export default function FriendIcon({ friend }: { friend: singleFriend }) { return ( - + {friend.nickname} diff --git a/src/components/ready/RoomDetail.tsx b/src/components/ready/RoomDetail.tsx index 5932c123..74898c67 100644 --- a/src/components/ready/RoomDetail.tsx +++ b/src/components/ready/RoomDetail.tsx @@ -1,38 +1,33 @@ -import React, { useState } from 'react'; +import React from 'react'; import styled from 'styled-components'; import { useNavigate } from 'react-router-dom'; import Card from './card/Card'; export default function RoomDetail({ roomNo: roomId, setIsPrompt }) { const navigate = useNavigate(); - const [disableButton, setDisableButton] = useState(true); + + // eslint-disable-next-line no-undef + const permissionName = 'microphone' as PermissionName; + const checkValid = !!navigator.permissions?.query; const enterRoom = (event: React.MouseEvent) => { event.preventDefault(); - if (disableButton) { - setIsPrompt(true); - } else if (localStorage.getItem('access_token')) { - navigate(`/room/${roomId}`); + if (checkValid) { + navigator.permissions.query({ name: permissionName }).then((result) => { + if (result.state === 'granted') { + setIsPrompt(false); + if (localStorage.getItem('access_token')) { + navigate(`/room/${roomId}`); + } + } else if (result.state === 'prompt') { + setIsPrompt(true); + } else if (result.state === 'denied') { + setIsPrompt(true); + } + }); } }; - // eslint-disable-next-line no-undef - const permissionName = 'microphone' as PermissionName; - const checkValid = !!navigator.permissions?.query; - if (checkValid) { - navigator.permissions.query({ name: permissionName }).then((result) => { - console.log(result); - if (result.state === 'granted') { - setIsPrompt(false); - setDisableButton(false); - } else if (result.state === 'prompt') { - setDisableButton(true); - } else if (result.state === 'denied') { - setDisableButton(true); - } - }); - } - return ( diff --git a/src/components/ready/card/Header.tsx b/src/components/ready/card/Header.tsx index 68a805eb..7301720c 100644 --- a/src/components/ready/card/Header.tsx +++ b/src/components/ready/card/Header.tsx @@ -5,7 +5,7 @@ export default function Header({ data }) { return ( - + ๋ฐฉ์žฅ diff --git a/src/components/room/ScreenModal.tsx b/src/components/room/ScreenModal.tsx index 1cba1558..aca058b0 100644 --- a/src/components/room/ScreenModal.tsx +++ b/src/components/room/ScreenModal.tsx @@ -51,7 +51,7 @@ export default function ScreenModal() { ) : ( <> - + {user.nickname} )} diff --git a/src/components/room/header/Theme.tsx b/src/components/room/header/Theme.tsx index decdc81c..a0e4734b 100644 --- a/src/components/room/header/Theme.tsx +++ b/src/components/room/header/Theme.tsx @@ -1,6 +1,6 @@ import { useState, useRef, useEffect } from 'react'; import styled from 'styled-components'; -import MovingTheme from '../screenShare/MovingTheme'; +import ThemeImage from '../../atoms/ThemeImages'; import { ReactComponent as VolumeOn } from '../../../assets/svg/VolumeOn.svg'; import { ReactComponent as VolumeOff } from '../../../assets/svg/VolumeOff.svg'; import UserMediaStreamStore from '../../../stores/room/userMediaStreamStore'; @@ -32,7 +32,7 @@ export default function Theme({ theme }) { return ( - + {userSpeaker && volume !== 0 ? : } diff --git a/src/components/room/screenShare/ScreenShare.tsx b/src/components/room/screenShare/ScreenShare.tsx index 41bff310..e1f77620 100644 --- a/src/components/room/screenShare/ScreenShare.tsx +++ b/src/components/room/screenShare/ScreenShare.tsx @@ -26,7 +26,7 @@ export default function ScreenShare({ theme }) { /> {connectedUsers[0] ? ( {connectedUsers[1] ? ( (null); const alarmRef = useRef(null); const isNewUser = - connectedUser.uid && - connectedUser.uid !== uid && + connectedUser?.uid && + connectedUser?.uid !== uid && !connectedUser.isAlreadyEntered; const { userAudioOutputDevice } = UserMediaStreamStore(); const openScreenModal = () => { - setScreenUid(connectedUser.uid); + setScreenUid(connectedUser?.uid); toggleScreenModal(); }; @@ -38,7 +38,7 @@ export default function SingleScreen({ connectedUser, stream }) { }, [stream, videoRef, userAudioOutputDevice]); useEffect(() => { - if (connectedUser.uid === uid) return; + if (connectedUser?.uid === uid) return; if (videoRef.current) { if (connectedUser.volume === 0) { videoRef.current.muted = true; @@ -58,7 +58,7 @@ export default function SingleScreen({ connectedUser, stream }) { const newMessages = messages.filter( (message) => - message.uid === connectedUser.uid && + message?.uid === connectedUser.uid && message.type === 'message' && new Date(message.createdAt).getTime() > currentTime.getTime() - 5000, ); @@ -67,7 +67,7 @@ export default function SingleScreen({ connectedUser, stream }) { <> {isNewUser && } - {uid === connectedUser.uid ? ( + {uid === connectedUser?.uid ? (