index.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. import { makeStyles } from "@material-ui/core/styles";
  2. import { useState, useEffect, useCallback } from "react";
  3. import { useSelector,useDispatch } from "react-redux";
  4. import ArrowBack from "./ArrowBack";
  5. import SendMessage from "./SendMessage";
  6. import MessageLeftText from './Messages/MessageLeftText'
  7. import MessageLeftImage from './Messages/MessageLeftImage'
  8. import MessageLeftAudio from './Messages/MessageLeftAudio'
  9. import MessageLeftVideo from './Messages/MessageLeftVideo'
  10. import MessageLeftFile from "./Messages/MessageLeftFile";
  11. import MessageRightText from './Messages/MessageRightText'
  12. import MessageRightImage from './Messages/MessageRightImage'
  13. import MessageRightAudio from './Messages/MessageRightAudio'
  14. import MessageRightVideo from './Messages/MessageRightVideo'
  15. import MessageRightFile from "./Messages/MessageRightFile";
  16. import MessageTime from "./Messages/MessageTime";
  17. import AlertInfo from "../../../reusableComponents/AlertInfo";
  18. import { getMessagesMemo } from '../../../../redux/messages/selector'
  19. import { getNumber } from '../../../../redux/authorization/selector'
  20. import { getChat } from '../../../../redux/chat/selector'
  21. import { getScrollChat } from '../../../../redux/control/selector'
  22. import { actionScrollChat } from '../../../../redux/control/action'
  23. import { asyncGetMessagesById } from '../../../../redux/messages/operations'
  24. import { asyncGetChatById } from "../../../../redux/chat/operations";
  25. import { seenChat } from "../../../../api-data";
  26. import { timeStampFilter,prodAwsS3,refreshAppTime } from "../../../../helpers";
  27. const debounce = require('lodash.debounce');
  28. const useStyles = makeStyles({
  29. container: {
  30. height: '93vh',
  31. width: "100%",
  32. display: "flex",
  33. alignItems: "center",
  34. alignContent:"center",
  35. flexDirection: "column",
  36. position: "relative",
  37. },
  38. messagesScroll: {
  39. paddingTop: 30,
  40. overflowY: "scroll",
  41. maxHeight: '83vh',
  42. width: "100%",
  43. display: "flex",
  44. justifyContent: 'center',
  45. '&::-webkit-scrollbar': {
  46. width: '0.4em'
  47. },
  48. '&::-webkit-scrollbar-track': {
  49. boxShadow: 'inset 0 0 6px rgba(0,0,0,0.00)',
  50. webkitBoxShadow: 'inset 0 0 6px rgba(0,0,0,0.00)',
  51. backgroundColor: '#eceeec',
  52. },
  53. '&::-webkit-scrollbar-thumb': {
  54. backgroundColor: '#ccc8c8',
  55. },
  56. "&::-webkit-scrollbar-thumb:focus": {
  57. backgroundColor: "#959595",
  58. },
  59. "&::-webkit-scrollbar-thumb:active": {
  60. backgroundColor: "#959595",
  61. },
  62. },
  63. messagesEmpty: {
  64. overflowY: "hidden",
  65. width: "100%",
  66. display: "flex",
  67. justifyContent: 'center',
  68. paddingTop: 30,
  69. },
  70. messagesBody: {
  71. width: "60%",
  72. },
  73. });
  74. interface IChatBar {
  75. divRef: any | null,
  76. selectedArr: string[] | [],
  77. setSelectedArr: React.Dispatch<React.SetStateAction<string[] | []>>,
  78. isSomeSelected: boolean,
  79. setIsSomeSelected: React.Dispatch<React.SetStateAction<boolean>>,
  80. }
  81. const ChatBar = ({divRef,selectedArr,setSelectedArr,isSomeSelected,setIsSomeSelected}:IChatBar) => {
  82. const classes = useStyles();
  83. const dispatch = useDispatch()
  84. const messages = useSelector(getMessagesMemo)
  85. const userNumber = useSelector(getNumber)
  86. const { companionId,total,seen,mute } = useSelector(getChat)
  87. const scrollChat = useSelector(getScrollChat)
  88. const [isArrow, setIsArrow] = useState<boolean>(false)
  89. const [isNew, setIsNew] = useState<{new:number,mute:boolean}>({new:0,mute:false})
  90. let time: any
  91. const isSelected = (_id: string) => selectedArr.some((el: string) => el === _id)
  92. const handleSelected = (_id: string) => {
  93. !isSomeSelected&&setIsSomeSelected(true)
  94. if (selectedArr.some((el: string) => el === _id))
  95. setSelectedArr(selectedArr.filter((el:string) => el !== _id))
  96. else setSelectedArr([...selectedArr,_id])
  97. }
  98. const handleScrollTo = useCallback(() => {
  99. divRef.current&&divRef.current.scrollTo({
  100. top: divRef.current.scrollHeight,
  101. behavior: 'smooth'
  102. })
  103. },[divRef])
  104. const handleScroll = useCallback(({ target:{scrollHeight,scrollTop,clientHeight}}: any) => {
  105. const different = scrollHeight - Math.floor(scrollTop)
  106. const reached = different - clientHeight
  107. if (total !== seen&&reached < 10) seenChat(companionId)
  108. setIsArrow(different === clientHeight ? false : true)
  109. }, [total,seen, companionId])
  110. const debouncedHandleScroll = debounce(handleScroll, 300)
  111. useEffect(() => {
  112. if (scrollChat) {
  113. dispatch(asyncGetMessagesById(companionId, handleScrollTo))
  114. dispatch(actionScrollChat(false))
  115. }
  116. }, [dispatch,handleScrollTo, scrollChat, companionId])
  117. useEffect(() => {
  118. const handleReset = () => {
  119. dispatch(asyncGetChatById(companionId))
  120. dispatch(asyncGetMessagesById(companionId, null))
  121. }
  122. handleReset()
  123. const idInterval = setInterval(handleReset, refreshAppTime);
  124. return () => clearInterval(idInterval);
  125. }, [dispatch, companionId]);
  126. useEffect(() => {
  127. setIsNew({ new:total-seen,mute})
  128. }, [total,seen,mute]);
  129. useEffect(() => {
  130. const handleReset = () => {
  131. if (divRef.current) {
  132. const { scrollHeight, clientHeight } = divRef.current
  133. if (total !== seen && scrollHeight === clientHeight) seenChat(companionId)
  134. }
  135. }
  136. const idInterval = setInterval(handleReset, refreshAppTime);
  137. return () => clearInterval(idInterval);
  138. }, [total, seen, divRef,companionId]);
  139. return (
  140. <div className={classes.container} >
  141. <ArrowBack isArrow={isArrow} isNew={isNew} handleScrollTo={handleScrollTo}/>
  142. <div id={companionId} ref={divRef} onScroll={debouncedHandleScroll}
  143. className={messages.length > 0 ? classes.messagesScroll : classes.messagesEmpty}>
  144. <div className={classes.messagesBody}>
  145. {messages.length > 0 ? messages.map(({ message, name, lastName, color,pinned,
  146. createdAt,number, type,fullType,caption,emoji,emojiCompanion,_id }) => {
  147. let isTime
  148. if (!time) {
  149. isTime = true
  150. time = createdAt
  151. } else if (timeStampFilter(time) !== timeStampFilter(createdAt)) {
  152. time = createdAt
  153. isTime = true
  154. }
  155. const url = `${prodAwsS3}/${message}`
  156. if (number !== userNumber) {
  157. if (type === 'text') return (<div key={createdAt} id={_id} style={{borderRadius: 7}}>
  158. {isTime&&<MessageTime message={timeStampFilter(createdAt)}/>}
  159. <MessageLeftText
  160. message={message}
  161. createdAt={createdAt}
  162. name={name}
  163. lastName={lastName}
  164. caption={caption}
  165. emoji={emoji}
  166. emojiCompanion={emojiCompanion}
  167. pinned={pinned}
  168. isSomeSelected={isSomeSelected}
  169. isSelected={isSelected}
  170. handleSelected={handleSelected}
  171. _id={_id}
  172. /></div>)
  173. if (type === 'image') return (<div key={createdAt} id={_id} style={{borderRadius: 7}}>
  174. {isTime&&<MessageTime message={timeStampFilter(createdAt)}/>}
  175. <MessageLeftImage
  176. url={url}
  177. createdAt={createdAt}
  178. color={color}
  179. fullType={fullType}
  180. caption={caption}
  181. emoji={emoji}
  182. emojiCompanion={emojiCompanion}
  183. pinned={pinned}
  184. isSomeSelected={isSomeSelected}
  185. isSelected={isSelected}
  186. handleSelected={handleSelected}
  187. _id={_id}
  188. /></div>)
  189. if (type === 'audio') return (<div key={createdAt} id={_id} style={{borderRadius: 7}}>
  190. {isTime&&<MessageTime message={timeStampFilter(createdAt)}/>}
  191. <MessageLeftAudio
  192. url={url}
  193. createdAt={createdAt}
  194. fullType={fullType}
  195. caption={caption}
  196. emoji={emoji}
  197. emojiCompanion={emojiCompanion}
  198. pinned={pinned}
  199. isSomeSelected={isSomeSelected}
  200. isSelected={isSelected}
  201. handleSelected={handleSelected}
  202. _id={_id}
  203. /></div>)
  204. if (type === 'video') return (<div key={createdAt} id={_id} style={{borderRadius: 7}}>
  205. {isTime&&<MessageTime message={timeStampFilter(createdAt)}/>}
  206. <MessageLeftVideo
  207. url={url}
  208. createdAt={createdAt}
  209. fullType={fullType}
  210. caption={caption}
  211. emoji={emoji}
  212. emojiCompanion={emojiCompanion}
  213. pinned={pinned}
  214. isSomeSelected={isSomeSelected}
  215. isSelected={isSelected}
  216. handleSelected={handleSelected}
  217. _id={_id}
  218. /></div>)
  219. if (type) return (<div key={createdAt} id={_id} style={{borderRadius: 7}}>
  220. {isTime&&<MessageTime message={timeStampFilter(createdAt)}/>}
  221. <MessageLeftFile
  222. url={url}
  223. createdAt={createdAt}
  224. type={type}
  225. caption={caption}
  226. emoji={emoji}
  227. emojiCompanion={emojiCompanion}
  228. pinned={pinned}
  229. isSomeSelected={isSomeSelected}
  230. isSelected={isSelected}
  231. handleSelected={handleSelected}
  232. _id={_id}
  233. /></div>)
  234. } else {
  235. if (type === 'text') return (<div key={createdAt} id={_id} style={{borderRadius: 7}}>
  236. {isTime&&<MessageTime message={timeStampFilter(createdAt)}/>}
  237. <MessageRightText
  238. message={message}
  239. createdAt={createdAt}
  240. name={name}
  241. lastName={lastName}
  242. caption={caption}
  243. emoji={emoji}
  244. emojiCompanion={emojiCompanion}
  245. pinned={pinned}
  246. isSomeSelected={isSomeSelected}
  247. isSelected={isSelected}
  248. handleSelected={handleSelected}
  249. _id={_id}
  250. /></div>)
  251. if (type === 'image') return (<div key={createdAt} id={_id} style={{borderRadius: 7}}>
  252. {isTime&&<MessageTime message={timeStampFilter(createdAt)}/>}
  253. <MessageRightImage
  254. url={url}
  255. createdAt={createdAt}
  256. color={color}
  257. fullType={fullType}
  258. caption={caption}
  259. emoji={emoji}
  260. emojiCompanion={emojiCompanion}
  261. pinned={pinned}
  262. isSomeSelected={isSomeSelected}
  263. isSelected={isSelected}
  264. handleSelected={handleSelected}
  265. _id={_id}
  266. /></div>)
  267. if (type === 'audio') return (<div key={createdAt} id={_id} style={{borderRadius: 7}}>
  268. {isTime&&<MessageTime message={timeStampFilter(createdAt)}/>}
  269. <MessageRightAudio
  270. url={url}
  271. createdAt={createdAt}
  272. fullType={fullType}
  273. caption={caption}
  274. emoji={emoji}
  275. emojiCompanion={emojiCompanion}
  276. pinned={pinned}
  277. isSomeSelected={isSomeSelected}
  278. isSelected={isSelected}
  279. handleSelected={handleSelected}
  280. _id={_id}
  281. /></div>)
  282. if (type === 'video') return (<div key={createdAt} id={_id} style={{borderRadius: 7}}>
  283. {isTime&&<MessageTime message={timeStampFilter(createdAt)}/>}
  284. <MessageRightVideo
  285. url={url}
  286. createdAt={createdAt}
  287. fullType={fullType}
  288. caption={caption}
  289. emoji={emoji}
  290. emojiCompanion={emojiCompanion}
  291. pinned={pinned}
  292. isSomeSelected={isSomeSelected}
  293. isSelected={isSelected}
  294. handleSelected={handleSelected}
  295. _id={_id}
  296. /></div>)
  297. if (type) return (<div key={createdAt} id={_id} style={{borderRadius: 7}}>
  298. {isTime&&<MessageTime message={timeStampFilter(createdAt)}/>}
  299. <MessageRightFile
  300. url={url}
  301. createdAt={createdAt}
  302. type={type}
  303. caption={caption}
  304. emoji={emoji}
  305. emojiCompanion={emojiCompanion}
  306. pinned={pinned}
  307. isSomeSelected={isSomeSelected}
  308. isSelected={isSelected}
  309. handleSelected={handleSelected}
  310. _id={_id}
  311. /></div>)
  312. }
  313. }) : <AlertInfo name='You do not have messages yet!' />}
  314. </div>
  315. </div>
  316. <SendMessage isArrow={isArrow} />
  317. </div>
  318. );
  319. }
  320. export default ChatBar