ChatPage.jsx 11 KB

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