ChatPage.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  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 '../../actions/actions';
  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. flexDirection: 'column',
  94. }}>
  95. <Box className='messageBox'>
  96. {
  97. messages.map((item, i) =>
  98. <Fragment key={i} >
  99. <Avatar
  100. sx={
  101. (item.userName == user.userName)
  102. ?
  103. {
  104. alignSelf: 'flex-end',
  105. fontSize: 10,
  106. width: '60px',
  107. height: '60px',
  108. color:'black',
  109. backgroundColor: userColor
  110. }
  111. :
  112. {
  113. backgroundColor: (usersOnline.map(current =>{
  114. if(item.userName == current.userName ) {
  115. return current.color
  116. }
  117. } )),
  118. fontSize: 10,
  119. width: '60px',
  120. height: '60px',
  121. color:'black'
  122. }
  123. }>
  124. {item.userName}
  125. </Avatar>
  126. <div
  127. key={item._id}
  128. onClick = {(e) => {
  129. if(e.target.className.includes('myMessage')){
  130. e.currentTarget.className += ' editMessage'
  131. }
  132. }}
  133. className={
  134. (item.userName ==user.userName)
  135. ?
  136. 'message myMessage'
  137. :
  138. 'message'}
  139. >
  140. <p>{item.text}</p>
  141. <div
  142. style={{fontStyle:'italic',
  143. color: 'grey',
  144. fontSize: 14}}>
  145. {dateFormat(item).time}
  146. </div>
  147. <div
  148. style={{fontStyle:'italic',
  149. fontSize: 12,
  150. color: 'grey'}}>
  151. {dateFormat(item).year}
  152. </div>
  153. </div>
  154. </Fragment>
  155. )}
  156. <div ref={endMessages}></div>
  157. </Box>
  158. <MessageForm
  159. data = {user}
  160. sendMessage = {data => sendMessage(data, socket)}>
  161. </MessageForm>
  162. </Box>
  163. <Box
  164. className='usersBox'
  165. sx={{
  166. overflow: 'scroll',
  167. }}>
  168. <Button
  169. sx={{margin:'10px 5px'}}
  170. variant="outlined"
  171. onClick={(e)=> {
  172. socket.disconnect()
  173. dispatch(removeToken())
  174. }}>
  175. Logout
  176. </Button>
  177. <UserInfo
  178. data = {user.userName}
  179. color={userColor}/>
  180. {
  181. user.isAdmin
  182. ?
  183. allUsers.map((item) =>
  184. <div
  185. key={item._id}
  186. className='online'>
  187. <div style={
  188. {color: (usersOnline.map(current =>{
  189. if(item.userName == current.userName ) {
  190. return current.color
  191. }
  192. }))}}>{item.userName}</div>
  193. <div>
  194. <Button
  195. variant="contained"
  196. onClick={()=>{
  197. muteUser(item.userName, item.isMutted, socket)
  198. }}
  199. sx={{
  200. margin:'3px',
  201. height: '25px'
  202. }}>
  203. {item.isMutted
  204. ?
  205. 'unmute'
  206. : 'mute'}
  207. </Button>
  208. <Button
  209. variant="contained"
  210. onClick={()=>{
  211. banUser(item.userName, item.isBanned, socket)
  212. }}
  213. sx={{
  214. margin:'3px',
  215. height: '25px'
  216. }}>
  217. {item.isBanned
  218. ? 'unban'
  219. : 'ban'}
  220. </Button>
  221. </div>
  222. {
  223. usersOnline.map((user, i) =>{
  224. if(item.userName == user.userName){
  225. return <span key={i} style={{color: 'green'}}>online</span>
  226. }
  227. })
  228. }
  229. </div>)
  230. :
  231. usersOnline.map((item, i) =>
  232. <div
  233. key={i}
  234. className='online'>
  235. <div style={{color: item.color}}>
  236. {item.userName}
  237. </div>
  238. <span style={{color: 'green'}}>
  239. online
  240. </span>
  241. </div>)
  242. }
  243. </Box>
  244. </Box>
  245. </div>
  246. )
  247. }