ChatPage.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. import { useEffect, useState, useMemo, useRef, Fragment} from 'react';
  2. import { MessageForm } from './messageForm/MessageForm';
  3. import {Button,Avatar, Box} from '@mui/material';
  4. import { UserInfo } from './userInfo/UserInfo';
  5. import { dateFormat } from './utils/dateFormat';
  6. import {io} from 'socket.io-client';
  7. import './chatPage.scss';
  8. import { scrollToBottom } from './utils/scrollToBottom';
  9. import { banUser } from './service/banUser';
  10. import { muteUser } from './service/muteUser';
  11. import {sendMessage} from './service/sendMessage';
  12. import { store } from '../../store';
  13. import { removeToken} from '../../reducers/userDataReducer'
  14. import { useDispatch } from 'react-redux';
  15. export const ChatPage = () => {
  16. const [socket, setSocket] = useState(null);
  17. const [messages, setMessages] = useState([])
  18. const [user, setUser] = useState({})
  19. const [usersOnline, setUsersOnline] = useState([])
  20. const [allUsers, setAllUsers] = useState([])
  21. const randomColor = require('randomcolor');
  22. const endMessages = useRef(null);
  23. const token = localStorage.getItem('token');
  24. const dispatch = useDispatch();
  25. useEffect(() => {
  26. if(token){
  27. try {
  28. setSocket(io.connect(
  29. process.env.REACT_APP_SERVER_URL || 'http://localhost:5000',
  30. {auth: {token}})
  31. )
  32. } catch (error) {
  33. console.log(error)
  34. }
  35. }
  36. }, [token])
  37. useEffect(() => {
  38. if(socket){
  39. socket.on('connected', (data) => {
  40. setUser(data);
  41. }).on('error', (e) => {
  42. console.log('On connected', e)
  43. });
  44. socket.on('allmessages', (data) => {
  45. setMessages(data)
  46. }).on('error', (e) => {
  47. console.log('allmessages', e)
  48. });
  49. socket.on('usersOnline', (data) => {
  50. setUsersOnline(data)
  51. }).on('error', (e) => {
  52. console.log(e)
  53. });
  54. socket.on('allDbUsers', (data) => {
  55. setAllUsers(data);
  56. }).on('error', (e) => {
  57. console.log(e)
  58. });
  59. socket.on('disconnect', (data) => {
  60. if(data === 'io server disconnect') {
  61. socket.disconnect();
  62. store.dispatch(removeToken());
  63. }
  64. }).on('error', (e) => {
  65. console.log('error token', e)
  66. });
  67. socket.on('message', (data) => {
  68. setMessages((messages) => [...messages, data] )
  69. }).on('error', (e) => {
  70. console.log(e)
  71. });
  72. }
  73. // return () => {
  74. // socket.off('connected');
  75. // socket.off('allmessages');
  76. // }
  77. }, [socket])
  78. useEffect(() => {
  79. scrollToBottom(endMessages)
  80. }, [messages]);
  81. let userColor = useMemo(() => randomColor(),[]);//color for myavatar
  82. return (
  83. <div className='rootContainer'>
  84. <Box
  85. sx={{
  86. display: 'flex',
  87. height: '100vh'
  88. }}>
  89. <Box
  90. sx={{
  91. display: 'flex',
  92. flexGrow:'2',
  93. maxWidth: '75%',
  94. flexDirection: 'column',
  95. }}>
  96. <Box className='messageBox'>
  97. {
  98. messages.map((item, i) =>
  99. <Fragment key={i} >
  100. <Avatar
  101. sx={
  102. (item.userName == user.userName)
  103. ?
  104. {
  105. alignSelf: 'flex-end',
  106. fontSize: 10,
  107. width: '60px',
  108. height: '60px',
  109. color:'black',
  110. backgroundColor: userColor
  111. }
  112. :
  113. {
  114. backgroundColor: (usersOnline.map(current => {
  115. if(item.userName == current.userName ) {
  116. return current.color
  117. }
  118. } )),
  119. fontSize: 10,
  120. width: '60px',
  121. height: '60px',
  122. color:'black'
  123. }
  124. }>
  125. {item.userName}
  126. </Avatar>
  127. <div
  128. key={item._id}
  129. onClick = {(e) => {
  130. if(e.target.className.includes('myMessage')){
  131. e.currentTarget.className += ' editMessage'
  132. }
  133. //add function to edit message
  134. }}
  135. className={
  136. (item.userName ==user.userName)
  137. ?
  138. 'message myMessage'
  139. :
  140. 'message'}
  141. >
  142. <p>{item.text}</p>
  143. <div
  144. style={{fontStyle:'italic',
  145. color: 'grey',
  146. fontSize: 14}}>
  147. {dateFormat(item).time}
  148. </div>
  149. <div
  150. style={{fontStyle:'italic',
  151. fontSize: 12,
  152. color: 'grey'}}>
  153. {dateFormat(item).year}
  154. </div>
  155. </div>
  156. </Fragment>
  157. )}
  158. <div ref={endMessages}></div>
  159. </Box>
  160. <MessageForm
  161. data = {user}
  162. sendMessage = {data => sendMessage(data, socket)}>
  163. </MessageForm>
  164. </Box>
  165. <Box
  166. className='usersBox'
  167. sx={{
  168. overflow: 'scroll',
  169. }}>
  170. <Button
  171. sx={{margin:'10px 5px'}}
  172. variant="outlined"
  173. onClick={(e)=> {
  174. socket.disconnect();
  175. localStorage.removeItem('token');
  176. dispatch(removeToken());
  177. }}>
  178. Logout
  179. </Button>
  180. <UserInfo
  181. data = {user.userName}
  182. color={userColor}/>
  183. {
  184. user.isAdmin
  185. ?
  186. allUsers.map((item) =>
  187. <div
  188. key={item._id}
  189. className='online'>
  190. <div style={
  191. {color: (usersOnline.map(current =>{
  192. if(item.userName == current.userName ) {
  193. return current.color
  194. }
  195. }))}}>{item.userName}</div>
  196. <div>
  197. <Button
  198. variant="contained"
  199. onClick={()=>{
  200. muteUser(item.userName, item.isMutted, socket)
  201. }}
  202. sx={{
  203. margin:'3px',
  204. height: '25px'
  205. }}>
  206. {item.isMutted
  207. ?
  208. 'unmute'
  209. : 'mute'}
  210. </Button>
  211. <Button
  212. variant="contained"
  213. onClick={()=>{
  214. banUser(item.userName, item.isBanned, socket)
  215. }}
  216. sx={{
  217. margin:'3px',
  218. height: '25px'
  219. }}>
  220. {item.isBanned
  221. ? 'unban'
  222. : 'ban'}
  223. </Button>
  224. </div>
  225. {
  226. usersOnline.map((user, i) =>{
  227. if(item.userName == user.userName){
  228. return <span key={i} style={{color: 'green'}}>online</span>
  229. }
  230. })
  231. }
  232. </div>)
  233. :
  234. usersOnline.map((item, i) =>
  235. <div
  236. key={i}
  237. className='online'>
  238. <div style={{color: item.color}}>
  239. {item.userName}
  240. </div>
  241. <span style={{color: 'green'}}>
  242. online
  243. </span>
  244. </div>)
  245. }
  246. </Box>
  247. </Box>
  248. </div>
  249. )
  250. }