ChatPage.jsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. import { useEffect, useState} from 'react';
  2. import {Button, Box} from '@mui/material';
  3. import TextareaAutosize from '@mui/material/TextareaAutosize';
  4. import { MessageForm } from './messageForm/MessegaForm';
  5. import { UserInfo } from './userInfo/UserInfo';
  6. import { store } from '../../store';
  7. import { removeToken, isPrivatChat, privateMessage} from '../../reducers/userDataReducer'
  8. import { useDispatch, useSelector } from 'react-redux';
  9. import {getSocket} from'../../reducers/socketReducer';
  10. import { sendMessage, storeMessage, fileMessage } from '../../reducers/messageReducer';
  11. import { editMessage } from '../../reducers/messageReducer';
  12. import { SwitchButton } from './SwitchButton';
  13. import { MessageEditorMenu } from './MessageEditorMenu.jsx';
  14. import imgBtn from '../../assets/img/gg.png';
  15. import imgBtnPhoto from '../../assets/img/photo.png'
  16. import './chatPage.scss';
  17. import WebcamCapture from './service/webCam/WebcamCapture';
  18. import useSound from 'use-sound';
  19. import getNotif from '../../assets/sendSound.mp3'
  20. import { PrivateChat } from './privateChat/PrivateChat';
  21. export const ChatPage = () => {
  22. const SOCKET_EVENTS = ['allmessages', 'usersOnline', 'allDbUsers']
  23. const dispatch = useDispatch();
  24. const token = useSelector(state => localStorage.getItem('token') || state.userDataReducer.token);
  25. const user = useSelector(state => state.getUserSocketReducer.socketUserData)
  26. const socket = useSelector(state => state.getUserSocketReducer.socket)
  27. const editOldMessage = useSelector(state => state.messageReducer.editMessage)
  28. let showUserInfoBox = useSelector(state => state.messageReducer.showUserInfoBox)// || localStorage.getItem('showBox');
  29. const toUser = useSelector(state => state.userDataReducer.toUser)
  30. const chatId = useSelector(state => state.userDataReducer.toUser.socketId)
  31. const isPrivatChat = useSelector(state => state.userDataReducer.isPrivatChat)
  32. const [message, setMessage] = useState({message: ''});
  33. const [isUserTyping, setUserTyping] = useState([]);
  34. const [isCamActiv, setisCamActiv] = useState(false);
  35. const [showSpinner, setshowSpinner] = useState(false);
  36. const [loadingPercentage, setLoadPercentage] = useState(0)
  37. const isTabletorMobile = (window.screen.width < 730);
  38. const [play] = useSound(getNotif, {volume: 0.005});
  39. const axiosConfig = {
  40. headers: {
  41. "Content-type": "multipart/form-data"
  42. },
  43. onUploadProgress: (progress) => {
  44. const {loaded, total} = progress;
  45. const loadStatus = Math.floor(loaded * 100 / total);
  46. setLoadPercentage(loadStatus)
  47. if(loadStatus == 100) {
  48. setshowSpinner(false)
  49. }
  50. }}
  51. const webcamEventHandler = async () => {
  52. let stream = null;
  53. try {
  54. stream = await navigator.mediaDevices.getUserMedia({ video: { width: 300 }});
  55. if (stream){
  56. setisCamActiv(!isCamActiv)
  57. }
  58. } catch(err) {
  59. console.log(err)
  60. }
  61. setisCamActiv(!isCamActiv) // test camera
  62. }
  63. const sendPrivateMessage = () => {
  64. socket.emit("private message", {
  65. fromUser: user,
  66. message: message.message,
  67. to: chatId,
  68. toUser
  69. })
  70. }
  71. useEffect(() => {
  72. if(socket) {
  73. socket.on('writing', (data) => {
  74. setUserTyping(data)
  75. setTimeout(() => setUserTyping([]), 500 )
  76. })
  77. socket.on("private message", ({ content, from }) => {
  78. console.log(content, from)
  79. });
  80. }
  81. }, [])
  82. useEffect(() => {
  83. if(token){
  84. SOCKET_EVENTS.map(event => dispatch(getSocket(event)))
  85. }
  86. }, [token, editOldMessage, showUserInfoBox])
  87. return (
  88. <div className='rootContainer'>
  89. <Box className = {isTabletorMobile?'mobileRootBox':'rootBox'}>
  90. <Box className={isTabletorMobile?'usersBoxMobile':'usersBox'}
  91. sx = {showUserInfoBox ? {
  92. transform: "translateX(100%)",
  93. display: "none"
  94. }: { }}>
  95. <UserInfo/>
  96. { isTabletorMobile ? <SwitchButton/> : null}
  97. <Button
  98. style={isTabletorMobile ?
  99. {
  100. maxHeight:'20px',
  101. maxWidth: '15px',
  102. fontSize: '10px',
  103. marginLeft: '25px',
  104. marginRight: '10px'}
  105. :{margin:'10px 5px'}}
  106. variant="contained"
  107. onClick={()=> {
  108. localStorage.removeItem('token');
  109. dispatch(removeToken());
  110. socket.disconnect();
  111. }}>
  112. Logout
  113. </Button>
  114. </Box>
  115. <Box className ={isTabletorMobile ? 'rootMessageFormMobile':'rootMessageForm'} >
  116. {isCamActiv ?
  117. <div>
  118. <Button
  119. variant="contained"
  120. component="label"
  121. onClick = {() => webcamEventHandler()}
  122. >
  123. close camera
  124. </Button>
  125. <WebcamCapture />
  126. </div>
  127. :
  128. ""}
  129. {isPrivatChat?<PrivateChat/> : <MessageForm/>}
  130. {isUserTyping.isTyping && (isUserTyping.userName !== user.userName)? <span> User {isUserTyping.userName} typing..</span> : ""}
  131. <Box
  132. component="form"
  133. onSubmit = {e => {
  134. e.preventDefault()
  135. if (message.message.length){
  136. isPrivatChat? sendPrivateMessage() : dispatch(sendMessage({user, socket}))
  137. dispatch(getSocket('allmessages'))
  138. dispatch(editMessage({editMessage: ''}))
  139. setMessage({message: ''})
  140. play()
  141. }
  142. }}
  143. sx={(isTabletorMobile)?{
  144. display: 'flex',
  145. margin: '10px 2px'}
  146. :{
  147. display: 'flex',
  148. margin: '20px 5px'}
  149. }>
  150. <Button
  151. disabled={showSpinner}
  152. variant="contained"
  153. component="label"
  154. sx = {showSpinner?
  155. {
  156. minWidth: 'auto'}
  157. :
  158. {
  159. minWidth: 'auto',
  160. backgroundImage:'url(' + imgBtn + ')' ,
  161. backgroundPosition: 'center',
  162. backgroundRepeat: "no-repeat",
  163. backgroundSize: '20px 20px'
  164. }}
  165. style = {{color: 'green'}}
  166. >
  167. <input
  168. onChange={e =>{
  169. setshowSpinner(true)
  170. dispatch(fileMessage({files: e.target.files, axiosConfig}))
  171. }}
  172. type="file"
  173. multiple
  174. hidden
  175. />
  176. {showSpinner? loadingPercentage : ""}
  177. </Button>
  178. <Button
  179. variant="contained"
  180. component="label"
  181. sx = {{
  182. minWidth: 'auto',
  183. backgroundImage:'url(' + imgBtnPhoto + ')' ,
  184. backgroundPosition: 'center',
  185. backgroundRepeat: "no-repeat",
  186. backgroundSize: '20px 20px'
  187. }}
  188. onClick = {() => webcamEventHandler()}
  189. >
  190. </Button>
  191. <TextareaAutosize
  192. id="outlined-basic"
  193. label="Type a message..."
  194. variant="outlined"
  195. value={message.message}
  196. placeholder='type you message...'
  197. minRows={2}
  198. maxRows={4}
  199. className='textArea'
  200. onKeyPress={(e) => {
  201. if (e.key === "Enter") {
  202. e.preventDefault();
  203. dispatch(sendMessage({user, socket}))
  204. dispatch(getSocket('allmessages'))
  205. dispatch(editMessage({editMessage: ''}))
  206. setMessage({message: ''})
  207. }
  208. }}
  209. onChange={e => {
  210. dispatch(storeMessage({message: e.target.value}))
  211. socket.emit('userWriting');
  212. setMessage({message: e.target.value})}
  213. }
  214. // onFocus={ e => {
  215. // if (isTabletorMobile) {
  216. // e.target.className = 'focus'
  217. // }
  218. // }}
  219. // onBlur={e=> {
  220. // e.target.className = 'blur'
  221. // }}
  222. />
  223. <Button
  224. variant="contained"
  225. type='submit'
  226. disabled={user?.isMutted || !message.message.length}
  227. style={{width: '20%'}}
  228. >
  229. Send
  230. </Button>
  231. </Box>
  232. </Box>
  233. </Box>
  234. </div>
  235. )
  236. }