chatWindow.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import { useEffect, useRef, useState } from "react"
  2. import { Message, ShortMessage } from "./message"
  3. import { MyDropzone } from "./dropzone"
  4. import { Backdrop, Button, CircularProgress, List, TextField } from "@mui/material"
  5. import SendIcon from '@mui/icons-material/Send';
  6. import AttachFileIcon from '@mui/icons-material/AttachFile';
  7. import { Box } from "@mui/system";
  8. import { ArrowCircleDown } from "@mui/icons-material";
  9. const updateScroll = (el) => {
  10. el.scrollTop = el.scrollHeight
  11. }
  12. const Chat = ({ chat_id, chat_title, user_id, messages, isLoad, onUpload, onSend, onMSGEdit, onScrollTopComplete }) => {
  13. let [msg, setMSG] = useState("")
  14. let [isUpload, setIsUpload] = useState(false)
  15. let [files, setFiles] = useState([])
  16. let [isForward, setIsForward] = useState([false, ""])
  17. let [isReply, setIsReply] = useState([false, ""])
  18. let [skip, setSkip] = useState(20)
  19. let [isScroll, setIsScroll] = useState(true)
  20. let scrollRef = useRef(null)
  21. let input = useRef(null)
  22. useEffect(() => {
  23. if (isScroll) {
  24. updateScroll(scrollRef.current)
  25. }
  26. }, [messages, isScroll])
  27. useEffect(() => {
  28. input.current && input.current.focus()
  29. }, [isReply, isForward])
  30. let filesHandler = (file) => {
  31. setFiles(file)
  32. }
  33. let buttonScrollHandler = () => {
  34. setIsScroll(true)
  35. updateScroll(scrollRef.current)
  36. }
  37. let scrollHandler = (el) => {
  38. setIsScroll(Math.round(el.scrollTop + el.clientHeight) === el.scrollHeight)
  39. if (el && el.scrollTop === 0) {
  40. el.scrollTop = el.scrollHeight / 30
  41. !isScroll && onScrollTopComplete(chat_id, skip)
  42. setSkip(skip + 20)
  43. }
  44. }
  45. let sendHandler = (e) => {
  46. if (e.key === "Escape") {
  47. setIsReply([false, ""])
  48. setMSG("")
  49. }
  50. if ((e.key === "Enter" && !e.shiftKey) || e.type === "click") {
  51. if (!isReply[0] && !isForward[0]) { //отправить обычное сообщение
  52. onSend(chat_id, msg, files)
  53. }
  54. if (isReply[0]) {
  55. onSend(chat_id, msg, files, isReply[1]) //ответить на сообщение (isReply[1] - id msg на какое отвечаем)
  56. setIsReply([false, ""])
  57. }
  58. if (isForward[0]) {
  59. onSend(chat_id, msg, files, false, isForward[1]) //переслать (isForward[1] - id чата куда переслать)
  60. setIsForward([false, ""])
  61. }
  62. setMSG("")
  63. updateScroll(scrollRef.current)
  64. setFiles([])
  65. setIsUpload(false)
  66. e.preventDefault()
  67. }
  68. }
  69. return (
  70. <Box>
  71. {isLoad === "PENDING" && <Backdrop
  72. sx={{ color: '#fff', zIndex: (theme) => theme.zIndex.drawer + 1 }}
  73. open={true}
  74. >
  75. <CircularProgress color="inherit" />
  76. </Backdrop>}
  77. <List ref={scrollRef} onScroll={() => scrollHandler(scrollRef.current)} sx={{ maxWidth: '100%', height: '85vh', overflowY: 'auto', display: 'flex', flexDirection: 'column' }}>
  78. {messages.length > 0 &&
  79. messages.map(message => {
  80. return <Message key={message._id}
  81. id={message._id}
  82. nick={message.owner.nick || message.owner.login}
  83. msg={message.text}
  84. date={message.createdAt}
  85. media={message.media}
  86. own={message.owner._id === user_id}
  87. replyTo={message.replyTo}
  88. onMSGEdit={onMSGEdit}
  89. onMSGReply={setIsReply}
  90. onMSGForward={setIsForward} />
  91. })}
  92. </List>
  93. {isReply[0] &&
  94. messages.filter(message => message._id === isReply[1]).map(m =>
  95. <ShortMessage key={m._id} nick={m.owner.nick || m.owner.login}
  96. text={m.text}
  97. date={m.createdAt} />)}
  98. {!isScroll && <Button size='large'
  99. onClick={() => buttonScrollHandler()}
  100. sx={{
  101. position: 'fixed',
  102. bottom: '10vh',
  103. left: '25vw',
  104. }}><ArrowCircleDown /></Button>}
  105. <div className="message-input">
  106. <TextField
  107. label="Введите сообщение..."
  108. placeholder="Введите сообщение..."
  109. variant="outlined"
  110. fullWidth
  111. multiline
  112. ref={input}
  113. value={msg}
  114. onFocus={() => updateScroll(scrollRef.current)}
  115. onInput={(e) => setMSG(e.target.value)}
  116. onKeyDown={(e) => sendHandler(e)}
  117. />
  118. {isUpload && <MyDropzone onUpload={onUpload} onSet={filesHandler} />}
  119. <Button onClick={() => setIsUpload(!isUpload)} variant="outlined"><AttachFileIcon /></Button>
  120. <Button onClick={(e) => sendHandler(e)} variant="contained" endIcon={<SendIcon />}>Отправить</Button>
  121. </div>
  122. </ Box>
  123. )
  124. }
  125. export default Chat