unknown преди 2 години
родител
ревизия
386a3ac2cd

Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
.eslintcache


+ 5 - 5
build/asset-manifest.json

@@ -4,13 +4,13 @@
     "static/js/0.80d38630.chunk.js.map": "/static/js/0.80d38630.chunk.js.map",
     "AuthPage.js": "/static/js/AuthPage.8bf438db.chunk.js",
     "AuthPage.js.map": "/static/js/AuthPage.8bf438db.chunk.js.map",
-    "HomePage.js": "/static/js/HomePage.7c0e03b5.chunk.js",
-    "HomePage.js.map": "/static/js/HomePage.7c0e03b5.chunk.js.map",
+    "HomePage.js": "/static/js/HomePage.fc85d94f.chunk.js",
+    "HomePage.js.map": "/static/js/HomePage.fc85d94f.chunk.js.map",
     "main.css": "/static/css/main.648af75f.chunk.css",
     "main.js": "/static/js/main.f1c56119.chunk.js",
     "main.js.map": "/static/js/main.f1c56119.chunk.js.map",
-    "runtime-main.js": "/static/js/runtime-main.75029880.js",
-    "runtime-main.js.map": "/static/js/runtime-main.75029880.js.map",
+    "runtime-main.js": "/static/js/runtime-main.1ad30abe.js",
+    "runtime-main.js.map": "/static/js/runtime-main.1ad30abe.js.map",
     "static/js/5.f4279fe9.chunk.js": "/static/js/5.f4279fe9.chunk.js",
     "static/js/5.f4279fe9.chunk.js.map": "/static/js/5.f4279fe9.chunk.js.map",
     "static/css/6.c7cc29b3.chunk.css": "/static/css/6.c7cc29b3.chunk.css",
@@ -29,7 +29,7 @@
     "static/media/wallpaperNight.63a4f24a.jpg": "/static/media/wallpaperNight.63a4f24a.jpg"
   },
   "entrypoints": [
-    "static/js/runtime-main.75029880.js",
+    "static/js/runtime-main.1ad30abe.js",
     "static/css/6.c7cc29b3.chunk.css",
     "static/js/6.7a556023.chunk.js",
     "static/css/main.648af75f.chunk.css",

Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
build/index.html


Файловите разлики са ограничени, защото са твърде много
+ 0 - 1
build/static/js/HomePage.7c0e03b5.chunk.js.map


Файловите разлики са ограничени, защото са твърде много
+ 2 - 2
build/static/js/HomePage.7c0e03b5.chunk.js


Файловите разлики са ограничени, защото са твърде много
+ 1 - 0
build/static/js/HomePage.fc85d94f.chunk.js.map


Файловите разлики са ограничени, защото са твърде много
+ 2 - 2
build/static/js/runtime-main.75029880.js


Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
build/static/js/runtime-main.75029880.js.map


+ 11 - 0
src/api-data/index.ts

@@ -220,6 +220,16 @@ const muteChat = async <T>(id:string): Promise<T | undefined> => {
   }
 };
 
+const mediaControllersChat = async <T>(companionId:string,mutedMyVideo:boolean,mutedMyAudio:boolean): Promise<T | undefined> => {
+  try {
+    const { data: { data } } = await axios.patch('/chats/controllers', {companionId,mutedMyVideo,mutedMyAudio});
+    return data
+  } catch (e) {
+    forbidden(e)
+    return undefined
+  }
+};
+
 const sortChat = async <T>(id:string): Promise<T | undefined> => {
   try {
     const { data: { data } } = await axios.patch('/chats/sort', {id});
@@ -452,6 +462,7 @@ export {
   removeChatForBoth,
   getChatById,
   muteChat,
+  mediaControllersChat,
   sortChat,
   socketIdChat,
   seenChat,

+ 110 - 56
src/components/HomePage/CallBar/index.tsx

@@ -1,13 +1,13 @@
-import Stack from '@mui/material/Stack';
-import IconButton from '@mui/material/IconButton';
-import SearchIcon from '@mui/icons-material/Search';
-import PhoneIcon from '@mui/icons-material/Phone';
 import { makeStyles, Typography } from '@material-ui/core'
 import { useState,useEffect,useCallback,useRef } from 'react';
 import { useSelector,useDispatch } from 'react-redux';
+import io from 'socket.io-client';
+import Moveable from "react-moveable";
+import { OnDrag } from "react-moveable";
 import ListItemText from '@mui/material/ListItemText';
 import ListItemAvatar from '@mui/material/ListItemAvatar';
 import Avatar from '@mui/material/Avatar';
+import PhoneIcon from '@mui/icons-material/Phone';
 import MinimizeIcon from '@mui/icons-material/Minimize';
 import CropLandscapeIcon from '@mui/icons-material/CropLandscape';
 import CloseIcon from '@mui/icons-material/Close';
@@ -21,10 +21,13 @@ import CallEndIcon from '@mui/icons-material/CallEnd';
  
 import { getChat } from '../../../redux/chat/selector';
 import { getAuthorizationState } from '../../../redux/authorization/selector'; 
-import { prodAwsS3, firstLetter, slicedWord } from '../../../helpers'
-import { socketIdChat } from '../../../api-data';
+import { prodAwsS3,prodSocketURL, firstLetter, slicedWord } from '../../../helpers'
+import { socketIdChat, mediaControllersChat } from '../../../api-data';
+import { asyncGetChatById } from '../../../redux/chat/operations'
+import { actionRightIsOpen,actionScrollChat,actionOpenPinned } from '../../../redux/control/action'
 
 const Peer = require('simple-peer')
+const socket = io(prodSocketURL)
 
 const useStyles = makeStyles({
   container: {
@@ -42,10 +45,7 @@ const useStyles = makeStyles({
     backgroundColor: 'rgba(104, 105, 104, 0.6)',
   },
   shareScreenActive: {
-    width: '30%',
-    borderRadius: 7,
-    margin: 'auto',
-    border:'solid 2px #0084ff',
+    width: '100%',
   },
   shareScreenDisabled: {
     width: 0,
@@ -127,6 +127,15 @@ const useStyles = makeStyles({
     fontSize: 13,
     paddingTop:7
   },
+  myVideo: {
+    width: 250,
+    height: 'auto',
+    cursor: 'pointer',
+    position: 'absolute',
+    top: 0,
+    left: 0,
+    zIndex: 150,
+  },  
   '@keyframes pulsate': {
     '0%': {transform: 'scale(1, 1)', opacity: 0},
     '50%': { opacity: 1},
@@ -147,20 +156,22 @@ const useStyles = makeStyles({
 })
 
 interface ICallBar {
-  callStatus: string,
+  callStatus:any,
   setCallStatus: any,
-  socket: any,
-  myVideoRef :any,
 }
 
-const CallBar = ({callStatus,setCallStatus,socket,myVideoRef}:ICallBar) => {
+const CallBar = ({callStatus,setCallStatus}:ICallBar) => {
   const classes = useStyles()
+  const dispatch = useDispatch()
   const { _id } = useSelector(getAuthorizationState)
   const chat = useSelector(getChat)
-  const myAudioRef = useRef<any>(null);
-  const userAudioRef = useRef<any>(null);
-  const userVideoRef = useRef<any>(null);
+  const { mutedMyVideo, mutedMyAudio, socketId, companionId } = chat
   const connectionRef = useRef<any>(null);
+  const myVideoRef = useRef<any>(null);
+  const myAudioRef = useRef<any>(null);
+  const companionVideoRef = useRef<any>(null);
+  const companionAudioRef = useRef<any>(null);
+  const [formChatId, setFormChatId] = useState<string>('')
   const [mySocket, setMySocket] = useState<string>('')
   const [companionSocket, setCompanionSocket] = useState<string>('')
   const [companionSignal, setCompanionSignal] = useState<string>('')
@@ -168,18 +179,31 @@ const CallBar = ({callStatus,setCallStatus,socket,myVideoRef}:ICallBar) => {
   const [lastName, setLastName] = useState<string>('')
   const [avatarUrl, setAvatarUrl] = useState<string>('')
   const [color, setColor] = useState<string>('')
-  const [number,setNumber] = useState<string>('')
+  const [number, setNumber] = useState<string>('')
+  const handleMuteVideo = () => {
+    if (callStatus === 'conversation') {
+      mediaControllersChat(chat.companionId,!mutedMyVideo,mutedMyAudio)
+    }
+  }
+  const handleMuteAudio = () => {
+    mediaControllersChat(chat.companionId,mutedMyVideo,!mutedMyAudio)
+  }  
   const handleLeaveCall = () => {
+    setCallStatus('hanging up...')
     connectionRef.current.destroy();
     setCallStatus('')
   };
-  // requesting, waiting ,ringing, hanging up,line busy
-
   const handleStartCall = useCallback(async () => {
-    const stream = await navigator.mediaDevices.getUserMedia({
+    setCallStatus('waiting...')
+    const mediaDevices: any = navigator.mediaDevices
+    const stream = await mediaDevices.getDisplayMedia({
       video: true,
       audio: true
     })
+    myVideoRef.current.srcObject = stream;
+    myAudioRef.current.srcObject = stream;
+    companionVideoRef.current.srcObject = stream;
+    companionAudioRef.current.srcObject = stream;
     const peer = new Peer({
       initiator: true,
       trickle: false, 
@@ -187,64 +211,80 @@ const CallBar = ({callStatus,setCallStatus,socket,myVideoRef}:ICallBar) => {
     });
     peer.on("signal", (data:any) => {
       socket.emit("callTo", {
-        to: chat.socketId,
+        to: socketId,
         signalData: data,
         from: mySocket,
         userId: _id,
-        companionId:chat.companionId
+        companionId
       })
-      setCallStatus('ringing')
+      setCallStatus('ringing...')
     });
-    peer.on("stream", (stream: any) => {
-      console.log(stream,'user stream')
+    peer.on("stream", (companionStream: any) => {
+      companionVideoRef.current.srcObject = companionStream;
+      companionAudioRef.current.srcObject = companionStream;
     });
     socket.on("acceptedCall", ({ signal }: any) => {
+      setCallStatus('connection')
       peer.signal(signal)
-      setCallStatus('accepted')
-      console.log(signal,'signal accepted from companion')
+      setCallStatus('conversation')
     });
     connectionRef.current = peer; 
-  },[chat.socketId,chat.companionId,_id,socket,setCallStatus,mySocket])
+  },[socketId,companionId,_id,mySocket,myVideoRef,setCallStatus])
 
   const handleAnswerCall = useCallback(async () => {
+    setCallStatus('connection')
+    dispatch(actionRightIsOpen(''))
+    dispatch(actionOpenPinned(false))
+    dispatch(asyncGetChatById(formChatId))
+    setTimeout(() => dispatch(actionScrollChat(true)), 500)
     const stream = await navigator.mediaDevices.getUserMedia({
       video: true,
       audio: true
     })
+    myVideoRef.current.srcObject = stream;
+    myAudioRef.current.srcObject = stream;
     const peer = new Peer({
       initiator: false,
       trickle: false,
       stream,
     });
     peer.on("signal", (data: any) => {
-      socket.emit("answerCall", { signal: data, to: companionSocket });
+      socket.emit("answerCall", {
+        signal: data,
+        to: companionSocket,
+      });
+      setCallStatus('conversation')
     });
-    peer.on("stream", (stream: any) => {
-      userVideoRef.current.srcObject = stream;
+    peer.on("stream", (companionStream: any) => {
+      companionVideoRef.current.srcObject = companionStream;
+      companionAudioRef.current.srcObject = companionStream;
     });
     peer.signal(companionSignal);
     connectionRef.current = peer;
-  },[socket,companionSocket,companionSignal])
+  },[companionSocket,companionSignal,setCallStatus,formChatId,dispatch])
 
   useEffect(() => {
     socket.on("me", (id: string) => {
       setMySocket(id)
       socketIdChat(id)
     })
-    socket.on('incomeCall', (data: any) => {
-      setCallStatus('is calling you')
-      setName(data.name)
-      setLastName(data.lastName)
-      setAvatarUrl(data.avatarUrl)
-      setColor(data.color)
-      setNumber(data.number)
-      setCompanionSocket(data.from)
-      setCompanionSignal(data.signal)
+    socket.on('incomeCall', ({ name, lastName, avatarUrl, color, number, from, signal,_companionId }: any) => {
+      if (connectionRef.current === null) {
+        setCallStatus('is calling you')
+        setName(name)
+        setLastName(lastName)
+        setAvatarUrl(avatarUrl)
+        setColor(color)
+        setNumber(number)
+        setCompanionSocket(from)
+        setCompanionSignal(signal)
+        setFormChatId(_companionId)
+      }
     })
-  },[socket,setCallStatus,setName,setLastName,setCompanionSocket,setCompanionSignal])
+  }, [setCallStatus])
 
   useEffect(() => {
-    if(callStatus === 'requesting') handleStartCall()
+    if(callStatus === 'requesting...') handleStartCall()
   }, [callStatus, handleStartCall])
 
   useEffect(() => {
@@ -255,10 +295,22 @@ const CallBar = ({callStatus,setCallStatus,socket,myVideoRef}:ICallBar) => {
       setColor(chat.color)
       setNumber(chat.number)
     }
-  }, [callStatus,chat])  
+  }, [callStatus, chat])
 
   return (
-    <div className={classes.container} style={{top: callStatus?0:'-100%'}}>
+    <div className={classes.container} style={{ top: callStatus ? 0 : '-100%' }}>
+      <video className={classes.myVideo} ref={myVideoRef} playsInline autoPlay/>
+      <Moveable
+        target={myVideoRef.current}
+        draggable={true}
+        throttleDrag={0}
+        hideDefaultLines={true}
+        renderDirections={[]}
+        rotationPosition="none"
+        origin={false}
+        onDrag={({ target, transform }: OnDrag) =>
+          target!.style.transform = transform }
+      />
       <div className={classes.modalCall}>
         <div className={classes.rightIcons} style={{marginBottom: true?0:40,}}>
           <div className={classes.rightIconWrapper}>
@@ -282,9 +334,11 @@ const CallBar = ({callStatus,setCallStatus,socket,myVideoRef}:ICallBar) => {
           ${firstLetter(lastName)}${slicedWord(lastName, 15, 1)}`}
             primaryTypographyProps={{ color: '#dfdfdf', fontSize: 20, fontWeight: 500 }}/>
           <ListItemText primary={number} primaryTypographyProps={{ color: '#ffffff', fontSize: 15, fontWeight: 500,textAlign:"center" }}/>
-          <ListItemText secondary={callStatus+'...'} secondaryTypographyProps={{ color: "#dfdfdf",textAlign: "center" }} />
+          <ListItemText secondary={callStatus} secondaryTypographyProps={{ color: "#dfdfdf",textAlign: "center" }} />
         </div>}
-        <video className={true ? classes.shareScreenActive : classes.shareScreenDisabled} ref={userVideoRef} playsInline autoPlay />
+        <audio ref={companionAudioRef} playsInline controls autoPlay/>
+        <video className={true ? classes.shareScreenActive : classes.shareScreenDisabled} ref={companionVideoRef} playsInline autoPlay />
+        <audio ref={myAudioRef} playsInline controls autoPlay/>
         <div className={classes.bottomWrapper}>
           {!true&&<div className={classes.bottomItem}>
             <Avatar className={classes.bottomIcon}
@@ -293,12 +347,12 @@ const CallBar = ({callStatus,setCallStatus,socket,myVideoRef}:ICallBar) => {
             </Avatar>
             <Typography variant="h6" className={classes.titleIconBottom}>Screencast</Typography>
           </div>}
-          <div className={classes.bottomItem}>
+          <div className={classes.bottomItem} onClick={handleMuteVideo}>
             <Avatar className={classes.bottomIcon} 
-              sx={{backgroundColor: true?'rgb(88, 88, 88)':'#ffffff',color: true?'#ffffff':'rgb(36, 36, 36)', width: 44, height: 44,zIndex:0}}>
-              {true?<VideocamOffIcon fontSize="medium" />:<VideocamIcon fontSize="medium" />}
+              sx={{backgroundColor: mutedMyVideo?'#ffffff':'rgb(88, 88, 88)',color: mutedMyVideo?'rgb(36, 36, 36)':'#ffffff', width: 44, height: 44,zIndex:0}}>
+              {mutedMyVideo?<VideocamIcon fontSize="medium" />:<VideocamOffIcon fontSize="medium" />}
             </Avatar>
-            <Typography variant="h6" className={classes.titleIconBottom}>{true?'Stop Video':'Start Video'}</Typography>
+            <Typography variant="h6" className={classes.titleIconBottom}>{mutedMyVideo?'Start Video':'Stop Video'}</Typography>
           </div>
           <div className={classes.bottomItem}>
             <Avatar className={classes.bottomIconEndAccept} onClick={handleLeaveCall}
@@ -321,11 +375,11 @@ const CallBar = ({callStatus,setCallStatus,socket,myVideoRef}:ICallBar) => {
             </Typography>
           </div>}          
           <div className={classes.bottomItem}>
-            <Avatar className={classes.bottomIcon} 
-              sx={{backgroundColor: true?'rgb(88, 88, 88)':'#ffffff',color: true?'#ffffff':'rgb(36, 36, 36)', width: 44, height: 44,zIndex:0}}>
-              {true?<MicIcon fontSize="medium" />:<MicOffIcon fontSize="medium" />}
+            <Avatar className={classes.bottomIcon} onClick={handleMuteAudio}
+              sx={{backgroundColor: mutedMyAudio?'#ffffff':'rgb(88, 88, 88)',color: mutedMyAudio?'rgb(36, 36, 36)':'#ffffff', width: 44, height: 44,zIndex:0}}>
+              {mutedMyAudio?<MicOffIcon fontSize="medium" />:<MicIcon fontSize="medium" />}
             </Avatar>
-            <Typography variant="h6" className={classes.titleIconBottom}>{true?'Mute':'Unmute'}</Typography>
+            <Typography variant="h6" className={classes.titleIconBottom}>{mutedMyAudio?'Unmute':'Mute'}</Typography>
           </div>
         </div>
       </div>

+ 4 - 33
src/components/HomePage/index.tsx

@@ -2,9 +2,6 @@ import Grid from '@mui/material/Grid'
 import { makeStyles } from '@material-ui/core'
 import { useSelector } from 'react-redux'
 import { useState,useRef } from 'react'
-import io from 'socket.io-client';
-import Moveable from "react-moveable";
-import { OnDrag } from "react-moveable";
 
 import LeftBar from './LeftBar'
 import CentralBar from './CentralBar'
@@ -15,9 +12,6 @@ import { getChatMemo } from '../../redux/chat/selector'
 import { getNightMode } from '../../redux/authorization/selector'
 import wallpaper from '../../img/wallpaper.jpg'
 import wallpaperNight from '../../img/wallpaperNight.jpg'
-import { prodSocketURL } from '../../helpers';
-
-const socket = io(prodSocketURL)
 
 const useStyles = makeStyles({
   container: {
@@ -26,45 +20,22 @@ const useStyles = makeStyles({
   },
   centralAndRight: {
     display:'flex'
-  },
-  myVideo: {
-    width: 250,
-    height: 'auto',
-    cursor: 'pointer',
-    position: 'absolute',
-    top: 0,
-    left: 0,
-    zIndex: 150,
-    backgroundColor:'#28e217',
   },  
 })
 
 const HomePage = () => {
   const classes = useStyles()
   const rightIsOpen = useSelector(getRightIsOpen)
-  const myVideoRef = useRef<any | null>(null);
-  const chatDivRef = useRef<any | null>(null)
   const nightMode = useSelector(getNightMode)
   const { companionId } = useSelector(getChatMemo)
+  const chatDivRef = useRef<any>(null)
   const [callStatus,setCallStatus] = useState<string>('')
   const backgroundImage =  `url(${nightMode ? wallpaperNight : wallpaper})`
-  const handleStartCall = () => setCallStatus('requesting')
-
+  const handleStartCall = () => setCallStatus('requesting...')
+  
 return (
     <Grid className={classes.container} container spacing={0} >
-      <video className={classes.myVideo} ref={myVideoRef} playsInline autoPlay muted/>
-      <Moveable
-        target={myVideoRef.current}
-        draggable={true}
-        throttleDrag={0}
-        hideDefaultLines={true}
-        renderDirections={[]}
-        rotationPosition="none"
-        origin={false}
-        onDrag={({ target, transform }: OnDrag) =>
-          target!.style.transform = transform }
-      />
-      <CallBar callStatus={callStatus} setCallStatus={setCallStatus} socket={socket} myVideoRef={myVideoRef}/>
+      <CallBar callStatus={callStatus} setCallStatus={setCallStatus}/>
       <LeftBar chatDivRef={chatDivRef} />
       {companionId ?
       <Grid item lg={9} className={classes.centralAndRight}>

+ 6 - 2
src/helpers/index.ts

@@ -47,6 +47,9 @@ const timeStampFilter = (updatedAt: string) => new Date(updatedAt).toLocaleStrin
     day: 'numeric',
 })
 
+const getTimeBySeconds = (seconds: number) =>
+    Math.floor(seconds / 60) + ':' + ('0' + Math.floor(seconds % 60)).slice(-2)
+
 
 const playNotification = (url:string) => {
   const audio = new Audio(url);
@@ -157,8 +160,8 @@ const emojisArr = ['💘','😀','😍','😲','😡']
 
 let prodBaseURL = 'https://w-telegram.herokuapp.com'
 let prodSocketURL = 'https://w-telegram-socket.herokuapp.com'
-// prodSocketURL = 'http://localhost:3001'
-// prodBaseURL = 'http://localhost:3000'
+prodSocketURL = 'http://localhost:3001'
+prodBaseURL = 'http://localhost:3000'
 
 const prodAwsS3 = 'https://my-telegram-bucket.s3.eu-west-1.amazonaws.com'
 
@@ -174,6 +177,7 @@ export {
   timeStampMessage,
   timeStampFilter,
   playNotification,
+  getTimeBySeconds,
   notification,
   copied,
   playNotificationWithoutPermission,

+ 5 - 1
src/redux/chat/reducer/index.ts

@@ -30,7 +30,11 @@ const initialState: TChat = {
      number: '',
      country: '',
      pinned: false,
-     socketId:"",
+     socketId: "",
+     mutedMyVideo: true,
+     mutedMyAudio: false,
+     companionMutedVideo: true,
+     companionMutedAudio: false,
      _id: '',
      companionId: '',
      owner: '',

+ 4 - 0
src/typescript/redux/chat/types.ts

@@ -20,6 +20,10 @@ export type TChat = {
   country: string,
   pinned: boolean,
   socketId: string,
+  mutedMyAudio: boolean,
+  mutedMyVideo: boolean,
+  companionMutedVideo: boolean,
+  companionMutedAudio: boolean,
   _id: string,
   companionId: string,
   owner: any,

+ 4 - 0
src/typescript/redux/chats/types.ts

@@ -19,6 +19,10 @@ export type TChat = {
   number: string,
   pinned: boolean,
   socketId: string,
+  mutedMyAudio: boolean,
+  mutedMyVideo: boolean,
+  companionMutedVideo: boolean,
+  companionMutedAudio: boolean,
   _id: string,
   companionId: string,
   owner: any,