ChatPage.jsx 11 KB

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