MessageList.jsx 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import React from "react";
  2. import styled from "styled-components";
  3. import { useUsers } from "../users";
  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. return (
  68. <div key={groupUid}>
  69. {group.map(({ uid: msgUid, user, timestamp, content }, index) => (
  70. <Message
  71. first={index === 0}
  72. user={user}
  73. timestamp={timestamp}
  74. content={content}
  75. key={msgUid}
  76. />
  77. ))}
  78. </div>
  79. );
  80. })}
  81. </StyledMessageList>
  82. );
  83. };
  84. export default MessageList;