feat: chat with infinite scroll
This commit is contained in:
		@@ -1,53 +1,82 @@
 | 
			
		||||
import { ScrollArea, Stack } from "@mantine/core";
 | 
			
		||||
import Message from "./components/Message/Message.tsx";
 | 
			
		||||
import MessageInput from "./components/MessageInput/MessageInput.tsx";
 | 
			
		||||
import { useChatContext } from "../../pages/ClientsPage/contexts/ChatContext.tsx";
 | 
			
		||||
import { MessageSchema } from "../../client";
 | 
			
		||||
import { ReactNode } from "react";
 | 
			
		||||
import { ReactNode, useCallback } from "react";
 | 
			
		||||
import ChatDate from "./components/ChatDate/ChatDate.tsx";
 | 
			
		||||
import MessageInput from "./components/MessageInput/MessageInput.tsx";
 | 
			
		||||
import { Virtuoso } from "react-virtuoso";
 | 
			
		||||
import { Stack } from "@mantine/core";
 | 
			
		||||
 | 
			
		||||
const Chat = () => {
 | 
			
		||||
    const {
 | 
			
		||||
        messages,
 | 
			
		||||
        scrollRef,
 | 
			
		||||
        onScrollPositionChange,
 | 
			
		||||
        lastMessage,
 | 
			
		||||
        firstItemIndex,
 | 
			
		||||
        fetchMoreMessages,
 | 
			
		||||
    } = useChatContext();
 | 
			
		||||
 | 
			
		||||
    const getChatElements = (): ReactNode[] => {
 | 
			
		||||
        const elements: ReactNode[] = [];
 | 
			
		||||
        let prevMessage: MessageSchema | null = null;
 | 
			
		||||
 | 
			
		||||
        for (let i = messages.length - 1; i >= 0; i--) {
 | 
			
		||||
            const currMessage = messages[i];
 | 
			
		||||
    const onFollowOutputHandler = useCallback(
 | 
			
		||||
        (atBottom: boolean) => {
 | 
			
		||||
            if (atBottom || lastMessage?.crmSender) {
 | 
			
		||||
                return "auto";
 | 
			
		||||
            } else {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        [lastMessage],
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const itemContent = useCallback(
 | 
			
		||||
        (index: number, sessionData: MessageSchema) => {
 | 
			
		||||
            let dateComponent: ReactNode | null = null;
 | 
			
		||||
            const msgArrayIdx = index - firstItemIndex;
 | 
			
		||||
            const currMessage = messages[msgArrayIdx];
 | 
			
		||||
            let prevMessage = null;
 | 
			
		||||
            if (msgArrayIdx > 0) {
 | 
			
		||||
                prevMessage = messages[msgArrayIdx - 1];
 | 
			
		||||
            }
 | 
			
		||||
            if (!prevMessage || prevMessage.createdAt.substring(5, 10) != currMessage.createdAt.substring(5, 10)) {
 | 
			
		||||
                elements.push((
 | 
			
		||||
                dateComponent = (
 | 
			
		||||
                    <ChatDate
 | 
			
		||||
                        key={currMessage.id + "date"}
 | 
			
		||||
                        date={new Date(currMessage.createdAt)}
 | 
			
		||||
                    />
 | 
			
		||||
                ));
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
            elements.push(
 | 
			
		||||
                <Message key={currMessage.id + "msg"} message={currMessage} />
 | 
			
		||||
            return (
 | 
			
		||||
                <Stack mb={"xs"} mr={"xs"}>
 | 
			
		||||
                    {dateComponent}
 | 
			
		||||
                    <Message
 | 
			
		||||
                        key={`${sessionData.id}${index}`}
 | 
			
		||||
                        message={sessionData}
 | 
			
		||||
                    />
 | 
			
		||||
                </Stack>
 | 
			
		||||
            );
 | 
			
		||||
            prevMessage = currMessage;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return elements;
 | 
			
		||||
    };
 | 
			
		||||
        },
 | 
			
		||||
        [messages],
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (messages.length === 0) {
 | 
			
		||||
        return (
 | 
			
		||||
            <Stack h={"96vh"} justify={"flex-end"}>
 | 
			
		||||
                <MessageInput />
 | 
			
		||||
            </Stack>
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return (
 | 
			
		||||
        <Stack h={"96vh"}>
 | 
			
		||||
            <ScrollArea
 | 
			
		||||
                h={"100%"}
 | 
			
		||||
                viewportRef={scrollRef}
 | 
			
		||||
                onScrollPositionChange={onScrollPositionChange}
 | 
			
		||||
            >
 | 
			
		||||
                <Stack pr={"md"} gap={"sm"}>
 | 
			
		||||
                    {getChatElements()}
 | 
			
		||||
                </Stack>
 | 
			
		||||
            </ScrollArea>
 | 
			
		||||
            <Virtuoso
 | 
			
		||||
                data={messages}
 | 
			
		||||
                followOutput={onFollowOutputHandler}
 | 
			
		||||
                firstItemIndex={firstItemIndex}
 | 
			
		||||
                initialTopMostItemIndex={messages.length - 1}
 | 
			
		||||
                itemContent={itemContent}
 | 
			
		||||
                startReached={fetchMoreMessages}
 | 
			
		||||
                height={"100%"}
 | 
			
		||||
                increaseViewportBy={100}
 | 
			
		||||
                alignToBottom
 | 
			
		||||
            />
 | 
			
		||||
            <MessageInput />
 | 
			
		||||
        </Stack>
 | 
			
		||||
    );
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user