MessageList.jsx 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import React from "react";
  2. import styled from "styled-components";
  3. import { useUsers } from "react-sync-board";
  4. import Message from "./Message";
  5. const computeMessageGroup = (messages, userMap, maxTimeDiff = 30000) => {
  6. if (!messages || messages.length === 0) return [];
  7. const messageGroups = [];
  8. let previousUser = messages[0].user.uid;
  9. let previousUserName = messages[0].user.name;
  10. let previousTime = messages[0].timestamp;
  11. let currentGroup = [];
  12. messages.forEach((message, index) => {
  13. if (
  14. message.user.uid !== previousUser ||
  15. message.user.name !== previousUserName ||
  16. message.timestamp.diff(previousTime) > maxTimeDiff
  17. ) {
  18. previousUser = message.user.uid;
  19. previousUserName = message.user.name;
  20. messageGroups.push({
  21. id: currentGroup[0].uid,
  22. group: currentGroup,
  23. });
  24. currentGroup = [];
  25. }
  26. previousTime = message.timestamp;
  27. // Get user from current session
  28. const messageWithUser = { ...message };
  29. if (message.user.uid in userMap) {
  30. messageWithUser.user = userMap[message.user.uid];
  31. }
  32. currentGroup.push(messageWithUser);
  33. if (index === messages.length - 1) {
  34. messageGroups.push({
  35. id: currentGroup[0].uid,
  36. group: currentGroup,
  37. });
  38. }
  39. });
  40. return messageGroups;
  41. };
  42. const StyledMessageList = styled.div`
  43. height: 100%;
  44. overflow: auto;
  45. `;
  46. const MessageList = ({ messages }) => {
  47. const messageList = React.useRef(null);
  48. const { users } = useUsers();
  49. const userMap = React.useMemo(
  50. () =>
  51. users.reduce((acc, user) => {
  52. acc[user.uid] = user;
  53. return acc;
  54. }, {}),
  55. [users]
  56. );
  57. const messageGroups = React.useMemo(
  58. () => computeMessageGroup(messages, userMap),
  59. [messages, userMap]
  60. );
  61. React.useEffect(() => {
  62. messageList.current.scrollTop = messageList.current.scrollHeight;
  63. });
  64. return (
  65. <StyledMessageList ref={messageList}>
  66. {messageGroups.map(({ id: groupUid, group }) => (
  67. <div key={groupUid}>
  68. {group.map(({ uid: msgUid, user, timestamp, content }, index) => (
  69. <Message
  70. first={index === 0}
  71. user={user}
  72. timestamp={timestamp}
  73. content={content}
  74. key={msgUid}
  75. />
  76. ))}
  77. </div>
  78. ))}
  79. </StyledMessageList>
  80. );
  81. };
  82. export default MessageList;