mirror of
https://github.com/colanode/colanode.git
synced 2025-12-16 11:47:47 +01:00
94 lines
2.9 KiB
TypeScript
94 lines
2.9 KiB
TypeScript
import { Fragment, useEffect, useRef, useState } from 'react';
|
|
import { InView } from 'react-intersection-observer';
|
|
|
|
import { MessageListQueryInput } from '@colanode/client/queries';
|
|
import { compareString } from '@colanode/core';
|
|
import { Message } from '@colanode/ui/components/messages/message';
|
|
import { useConversation } from '@colanode/ui/contexts/conversation';
|
|
import { useWorkspace } from '@colanode/ui/contexts/workspace';
|
|
import { useLiveQueries } from '@colanode/ui/hooks/use-live-queries';
|
|
|
|
const MESSAGES_PER_PAGE = 50;
|
|
|
|
export const MessageList = () => {
|
|
const workspace = useWorkspace();
|
|
const conversation = useConversation();
|
|
|
|
const lastMessageId = useRef<string | null>(null);
|
|
const [lastPage, setLastPage] = useState<number>(1);
|
|
|
|
const inputs: MessageListQueryInput[] = Array.from({
|
|
length: lastPage,
|
|
}).map((_, i) => ({
|
|
type: 'message.list',
|
|
conversationId: conversation.id,
|
|
accountId: workspace.accountId,
|
|
workspaceId: workspace.id,
|
|
page: i + 1,
|
|
count: MESSAGES_PER_PAGE,
|
|
}));
|
|
|
|
const result = useLiveQueries(inputs);
|
|
const messages = result
|
|
.flatMap((data) => data.data ?? [])
|
|
.sort((a, b) => compareString(a.id, b.id));
|
|
|
|
const isPending = result.some((data) => data.isPending);
|
|
|
|
const hasMore =
|
|
!isPending && messages.length === lastPage * MESSAGES_PER_PAGE;
|
|
|
|
useEffect(() => {
|
|
if (messages.length > 0) {
|
|
const lastMessage = messages[messages.length - 1];
|
|
if (!lastMessage) {
|
|
return;
|
|
}
|
|
|
|
if (lastMessage.id !== lastMessageId.current) {
|
|
lastMessageId.current = lastMessage.id;
|
|
conversation.onLastMessageIdChange(lastMessage.id);
|
|
}
|
|
}
|
|
}, [messages]);
|
|
|
|
return (
|
|
<Fragment>
|
|
<InView
|
|
rootMargin="200px"
|
|
onChange={(inView) => {
|
|
if (inView && hasMore && !isPending) {
|
|
setLastPage(lastPage + 1);
|
|
}
|
|
}}
|
|
></InView>
|
|
{messages.map((message, index) => {
|
|
const previousMessage = index > 0 ? messages[index - 1] : null;
|
|
|
|
const currentMessageDate = new Date(message.createdAt);
|
|
const previousMessageDate = previousMessage
|
|
? new Date(previousMessage.createdAt)
|
|
: null;
|
|
const showDate =
|
|
!previousMessageDate ||
|
|
currentMessageDate.getDate() !== previousMessageDate.getDate();
|
|
|
|
return (
|
|
<Fragment key={message.id}>
|
|
{showDate && (
|
|
<div className="relative flex items-center py-1">
|
|
<div className="flex-grow border-t border-gray-100" />
|
|
<span className="mx-4 flex-shrink text-xs text-muted-foreground">
|
|
{currentMessageDate.toDateString()}
|
|
</span>
|
|
<div className="flex-grow border-t border-gray-100" />
|
|
</div>
|
|
)}
|
|
<Message message={message} previousMessage={previousMessage} />
|
|
</Fragment>
|
|
);
|
|
})}
|
|
</Fragment>
|
|
);
|
|
};
|