MessegaForm.jsx 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import { Avatar, Box, Button} from '@mui/material';
  2. import { dateFormat } from '../utils/dateFormat';
  3. import { useSelector } from 'react-redux';
  4. import { useRef, useEffect, useState} from 'react';
  5. import { scrollToBottom } from '../utils/scrollToBottom';
  6. import { useDispatch } from 'react-redux';
  7. import { editMessage } from '../../../reducers/messageReducer';
  8. import { StyledAvatar } from './StyledAvatar';
  9. import { MessageEditorMenu } from '../MessageEditorMenu.jsx';
  10. import imgBtn from '../../../assets/img/gg.png';
  11. import useSound from 'use-sound';
  12. import notifSound from '../../../assets/get.mp3'
  13. import { useMemo } from 'react';
  14. export const MessageForm = () => {
  15. const dispatch = useDispatch();
  16. const socket = useSelector(state => state.getUserSocketReducer.socket)
  17. const SERVER_URL = process.env.REACT_APP_SERVER_URL;
  18. const startMessages = useSelector(state => state.getUserSocketReducer.startMessages)
  19. const user = useSelector(state => state.getUserSocketReducer.socketUserData)
  20. const usersOnline = useSelector(state => state.getUserSocketReducer.usersOnline)
  21. const userNamesOnlineSet = new Set(usersOnline.map( i => i.userName))
  22. const storeMessageId = useSelector(state => state.messageReducer.messageId)
  23. const newMessages = useSelector(state => state.getUserSocketReducer.newMessages)
  24. let endMessages = useRef(null);
  25. const [isEditing, setIsEditing] = useState(false)
  26. const [isEditiedMessage, setIsEditiedMessage] = useState(false) //need to type in the bottom of message after message was edited
  27. const regYoutube = /http(?:s?):\/\/(?:www\.)?youtu(?:be\.com\/watch\?v=|\.be\/)([\w\-\_]*)(&(amp;)?‌​[\w\?‌​=]*)?/; //for youtube video
  28. const [play] = useSound(notifSound);
  29. useEffect(() => {
  30. if (!isEditing) {
  31. scrollToBottom((endMessages))
  32. }
  33. }, [startMessages]);
  34. const messages = startMessages.concat(newMessages)
  35. useEffect(()=> {
  36. if(newMessages.length > 0 && newMessages[newMessages.length-1].userName !== user.userName){
  37. play()
  38. }
  39. }, [newMessages])
  40. return (
  41. <Box className='messageBox'>
  42. {
  43. messages.map((item, i) =>
  44. <div key={i + 1} className={
  45. (item.userName === user.userName)? 'message myMessage' :'message'}
  46. onClick = {(e) => {
  47. console.log(e.target)
  48. if(e.target.closest("div").className.includes('myMessage') && (item.userName === user.userName) && (item.text === e.target.textContent)){
  49. e.currentTarget.className += ' editMessage'
  50. dispatch(editMessage({socket, editMessage: e.target.textContent, messageId: item._id}))
  51. setIsEditing(true)
  52. }
  53. }}
  54. >
  55. {storeMessageId === item._id ? <MessageEditorMenu />: ""}
  56. <StyledAvatar
  57. anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
  58. variant = {userNamesOnlineSet.has(item.userName)? 'dot' : ''}
  59. >
  60. <Avatar
  61. key={i}
  62. src= {SERVER_URL + '/'+ item?.user?.avatar}
  63. sx={
  64. (item.userName === user.userName)
  65. ?
  66. {
  67. alignSelf: 'flex-end',
  68. }
  69. :
  70. {}
  71. }
  72. >
  73. {item?.userName.slice(0, 1)}
  74. </Avatar>
  75. </StyledAvatar>
  76. <div
  77. key={i}
  78. className={
  79. (item.userName === user.userName)? 'message myMessage' :'message'}>
  80. {
  81. item.text.match(regYoutube) ?
  82. <iframe
  83. width="280"
  84. height="160"
  85. src={`https://www.youtube.com/embed/`+ (item.text.match(regYoutube)[1])}
  86. title="YouTube video player"
  87. allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
  88. allowFullScreen>
  89. </iframe>
  90. :
  91. (item.file && item.fileType && item.fileType.split('/')[0] !== 'image') ?
  92. <div style={{'display': 'flex', 'alignItems': 'center'}} >
  93. <a href={SERVER_URL + item.file} download>
  94. <Button
  95. variant="contained"
  96. component="label"
  97. sx = {{
  98. minWidth: 'auto',
  99. minHeight: '25px',
  100. backgroundImage:'url(' + imgBtn + ')' ,
  101. backgroundPosition: 'center',
  102. backgroundRepeat: "no-repeat",
  103. backgroundSize: '15px 20px',
  104. backgroundColor: '#d3d3d3'
  105. }}
  106. >
  107. </Button>
  108. </a>
  109. <p style={{'marginLeft': '15px'}} >{item.text}</p>
  110. </div>
  111. :
  112. <p>{item.text}</p>
  113. }
  114. {
  115. (item.file && item.fileType && item.fileType.split('/')[0] == 'image' ) //need to fix for other type files
  116. ?
  117. <img width={'auto'} height={350} src={ SERVER_URL + item.file} alt={'error load image'}/>
  118. :
  119. ''
  120. }
  121. </div>
  122. {isEditiedMessage && <i>Edited</i>}
  123. <div className={
  124. (item.userName === user.userName)? 'myDate' :'date'}>
  125. {dateFormat(item).time}
  126. </div>
  127. </div>
  128. )}
  129. <div ref={endMessages}></div>
  130. </Box>
  131. )
  132. }