Guest User

Untitled

a guest
Feb 24th, 2024
118
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import { messageStore } from "$/utils/Stores.ts";
  2. import {
  3.     Badge,
  4.     Box,
  5.     Flex,
  6.     Image,
  7.     Popover,
  8.     PopoverTrigger,
  9.     Text,
  10.     List,
  11.     ListItem
  12. } from "@chakra-ui/react";
  13. import { useRecoilState } from "recoil";
  14. import PopOver from "../members/popover.tsx";
  15. import { clientStore } from "@/utils/stores.ts";
  16. import { useEffect, useState } from "react";
  17.  
  18. const getMessageColor = (state: "sending" | "sent" | "failed") => {
  19.     if (state === "sending") return "gray";
  20.     if (state === "sent") return "white";
  21.     if (state === "failed") return "red";
  22. };
  23.  
  24. interface User {
  25.     globalNickname: string;
  26.     avatar: string;
  27.     presence: string;
  28.     username: string;
  29.     discriminator: string;
  30. }
  31.  
  32. interface Message {
  33.     user: User;
  34.     content: string;
  35.     time: Date;
  36.     id: string;
  37.     state: "sent" | "sending" | "failed";
  38.     edited: boolean;
  39. }
  40.  
  41. interface Chunk {
  42.     user: User;
  43.     time: Date;
  44.     messages: Message[];
  45. }
  46.  
  47. const messageChunker = (msgs: {
  48.     user: {
  49.         globalNickname: string;
  50.         avatar: string;
  51.         presence: string;
  52.         username: string;
  53.         discriminator: string;
  54.     };
  55.     content: string;
  56.     time: Date;
  57.     id: string;
  58.     state: "sent" | "sending" | "failed";
  59.     edited: boolean;
  60. }[]): Chunk[] => {
  61.     /*
  62.      Messages go from a top to bottom, i.e top being oldest message and bottom being the newest
  63.      we need to chunk messages. How this works is for example:
  64.    
  65.     * 8:00 AM User1: Hello
  66.     * 8:02 AM User1: Hello 2
  67.     * 8:04 AM User1: Hello 3
  68.    
  69.     These messages should be chunked into one message, the reason for this is simple, its the same user in a row, and the previous message was sent within 15 minutes of the next message
  70.  
  71.     heres an example of messages that should not be chunked:
  72.  
  73.     * 8:00 AM User1: Hello
  74.     * 8:02 AM User2: Hello 2
  75.     * 8:04 AM User1: Hello 3
  76.  
  77.     This is because the user changed, so we should not chunk these messages together
  78.  
  79.     this is another example of messages that should not be chunked:
  80.  
  81.     * 8:00 AM User1: Hello
  82.     * 9:00 AM User1: Hello 2
  83.      
  84.     This is because the previous message was sent over 15 minutes ago, so we should not chunk these messages together
  85.  
  86.     */
  87.  
  88.     const chunkedMessages: Chunk[] = [];
  89.     let currentChunk: Chunk | null = null;
  90.  
  91.     for (const msg of msgs) {
  92.         if (!currentChunk ||
  93.             currentChunk.user.username !== msg.user.username ||
  94.             Math.abs(msg.time.getTime()! - currentChunk.time.getTime()) > 15 * 60 * 1000
  95.         ) {
  96.             currentChunk = {
  97.                 user: msg.user,
  98.                 time: msg.time,
  99.                 messages: [{
  100.                     ...msg
  101.                 }]
  102.             };
  103.             chunkedMessages.push(currentChunk);
  104.         } else {
  105.             currentChunk.messages.push({
  106.                 ...msg
  107.             });
  108.         }
  109.     }
  110.  
  111.     return chunkedMessages;
  112. };
  113.  
  114. const Message = ({
  115.     message
  116. }: {
  117.     message: {
  118.         user: {
  119.             globalNickname: string;
  120.             avatar: string;
  121.             presence: string;
  122.             username: string;
  123.             discriminator: string;
  124.         };
  125.         time: string;
  126.         content: string;
  127.         id: string;
  128.         state: "sent" | "sending" | "failed";
  129.         edited: boolean;
  130.         chunked: boolean;
  131.         hasMore: boolean;
  132.     };
  133. }) => {
  134.     const [client] = useRecoilState(clientStore);
  135.     const [hovered, setHovered] = useState(false);
  136.  
  137.     return (
  138.         <Box
  139.             key={message.id}
  140.             _hover={{
  141.                 bg: "rgba(0, 0, 0, 0.1)",
  142.             }}
  143.             mt={message.chunked ? 0 : 2}
  144.             onMouseEnter={() => setHovered(true)}
  145.             onMouseLeave={() => setHovered(false)}
  146.         >
  147.             <Popover placement={"right"} >
  148.                 <Flex ml={5}
  149.                     mt={message.chunked ? 0 : 1.5}
  150.                 >
  151.                     {!message.chunked && (
  152.                         <PopoverTrigger>
  153.                             <Image
  154.                                 draggable={"false"}
  155.                                 borderRadius={"full"}
  156.                                 src={"/icon-1.png"}
  157.                                 alt={message?.user?.username || "loading"}
  158.                                 fit="cover"
  159.                                 boxSize={"32px"}
  160.                                 cursor={"pointer"}
  161.                                 mt={1.5}
  162.                                 userSelect={"none"}
  163.                                 fetchPriority="high"
  164.                             />
  165.                         </PopoverTrigger>
  166.                     )}
  167.                     <Box ml="3" position={"relative"}>
  168.                         {!message.chunked && (
  169.                             <Text
  170.                                 cursor={"default"}
  171.                             >
  172.                                 <PopoverTrigger>
  173.                                     <Text
  174.                                         cursor={"pointer"}
  175.                                         display="inline"
  176.                                         as={"span"}
  177.                                     >{message.user.username}</Text>
  178.                                 </PopoverTrigger>
  179.                                 <Badge
  180.                                     bg={"unset"}
  181.                                     color={"inherit"}
  182.                                     textTransform={"unset"}
  183.                                     fontWeight={"unset"}
  184.                                     ml="1"
  185.                                     fontSize={"xx-small"}
  186.                                 >
  187.                                     {message.time}
  188.                                 </Badge>
  189.                             </Text>
  190.                         )}
  191.                         {message.chunked && hovered && (
  192.                             <Box position="absolute" left="-5" top="0">
  193.                                 <Badge
  194.                                     bg={"unset"}
  195.                                     color={"inherit"}
  196.                                     textTransform={"unset"}
  197.                                     fontWeight={"unset"}
  198.                                     ml="1"
  199.                                     fontSize={"xx-small"}
  200.                                     display={"inline"}
  201.                                     userSelect={"none"}
  202.                                 >
  203.                                     4:43 AM
  204.                                 </Badge>
  205.                             </Box>
  206.                         )}
  207.                         <Text
  208.                             fontSize="sm"
  209.                             color={getMessageColor(message.state)}
  210.                             transition={"color 0.2s"}
  211.                             ml={message.chunked ? 8 : 0}
  212.                             display={"inline"}
  213.                         >{message.content} <Text
  214.                             fontSize="x-small"
  215.                             color={"gray.500"}
  216.                             transition={"color 0.2s"}
  217.                             display={"inline"}
  218.                             as={"span"}
  219.                             cursor={"default"}
  220.                             userSelect={"none"}
  221.                         >{message.edited ? "(edited)" : ""}</Text></Text>
  222.                     </Box>
  223.                 </Flex>
  224.                 {!message.chunked && (
  225.                     <PopOver user={client.members[0].user} member={client.members[0]} />
  226.                 )}
  227.             </Popover>
  228.         </Box>
  229.     );
  230. };
  231.  
  232. const GuildMessages = () => {
  233.     const [rawMessages] = useRecoilState(messageStore);
  234.  
  235.     const [messages, setMessages] = useState<Chunk[]>([]);
  236.  
  237.     useEffect(() => {
  238.         setMessages(messageChunker(rawMessages));
  239.     }, [rawMessages]);
  240.  
  241.     return (
  242.         <>
  243.             <Box mb={2} maxHeight="calc(100vh - 100px)" overflowY="auto" ml={-2} mr={-2}>
  244.                 <List spacing={3}>
  245.                     {messages.map((message, index) => {
  246.                         return (
  247.                             <ListItem key={index}>
  248.                                 {message.messages.map((msg, index) => {
  249.                                     return (
  250.                                         <Message
  251.                                             message={{
  252.                                                 ...msg,
  253.                                                 user: message.user,
  254.                                                 time: `Today at ${msg.time.toLocaleTimeString("en-US", {
  255.                                                     hour: "numeric",
  256.                                                     minute: "numeric",
  257.                                                 })}`,
  258.                                                 chunked: index !== 0,
  259.                                                 hasMore: index === 0 && message.messages.length > 1
  260.                                             }}
  261.                                             key={msg.id}
  262.                                         />
  263.                                     );
  264.                                 })}
  265.                             </ListItem>
  266.                         );
  267.                     })}
  268.                 </List>
  269.                 <div id="bottom-chat" />
  270.             </Box>
  271.         </>
  272.     );
  273. };
  274.  
  275. export default GuildMessages;
  276.  
Advertisement
Add Comment
Please, Sign In to add comment