mirror of
https://github.com/logos-messaging/js-waku.git
synced 2026-01-09 01:03:11 +00:00
141 lines
3.6 KiB
TypeScript
141 lines
3.6 KiB
TypeScript
import { useEffect, useRef, useState } from 'react';
|
|
import { ChatMessage } from './ChatMessage';
|
|
import {
|
|
Message,
|
|
MessageText,
|
|
MessageGroup,
|
|
MessageList,
|
|
} from '@livechat/ui-kit';
|
|
|
|
interface Props {
|
|
archivedMessages: ChatMessage[];
|
|
newMessages: ChatMessage[];
|
|
}
|
|
|
|
export default function ChatList(props: Props) {
|
|
const [messages, setMessages] = useState<ChatMessage[]>([]);
|
|
let updatedMessages;
|
|
|
|
if (IsThereNewMessages(props.newMessages, messages)) {
|
|
updatedMessages = messages.slice().concat(props.newMessages);
|
|
if (IsThereNewMessages(props.archivedMessages, updatedMessages)) {
|
|
updatedMessages = copyMergeUniqueReplace(
|
|
props.archivedMessages,
|
|
updatedMessages
|
|
);
|
|
}
|
|
} else {
|
|
if (IsThereNewMessages(props.archivedMessages, messages)) {
|
|
updatedMessages = copyMergeUniqueReplace(
|
|
props.archivedMessages,
|
|
messages
|
|
);
|
|
}
|
|
}
|
|
|
|
if (updatedMessages) {
|
|
setMessages(updatedMessages);
|
|
}
|
|
|
|
const messagesGroupedBySender = groupMessagesBySender(messages).map(
|
|
(currentMessageGroup) => (
|
|
<MessageGroup onlyFirstWithMeta>
|
|
{currentMessageGroup.map((currentMessage) => (
|
|
<Message
|
|
key={
|
|
currentMessage.receivedTimestampMs.valueOf() +
|
|
currentMessage.nick +
|
|
currentMessage.message
|
|
}
|
|
authorName={currentMessage.nick}
|
|
date={formatDisplayDate(currentMessage)}
|
|
>
|
|
<MessageText>{currentMessage.message}</MessageText>
|
|
</Message>
|
|
))}
|
|
</MessageGroup>
|
|
)
|
|
);
|
|
|
|
return (
|
|
<MessageList active containScrollInSubtree>
|
|
{messagesGroupedBySender}
|
|
<AlwaysScrollToBottom newMessages={props.newMessages} />
|
|
</MessageList>
|
|
);
|
|
}
|
|
|
|
function groupMessagesBySender(messageArray: ChatMessage[]): ChatMessage[][] {
|
|
let currentSender = -1;
|
|
let lastNick = '';
|
|
let messagesBySender: ChatMessage[][] = [];
|
|
let currentSenderMessage = 0;
|
|
|
|
for (let currentMessage of messageArray) {
|
|
if (lastNick !== currentMessage.nick) {
|
|
currentSender++;
|
|
messagesBySender[currentSender] = [];
|
|
currentSenderMessage = 0;
|
|
lastNick = currentMessage.nick;
|
|
}
|
|
messagesBySender[currentSender][currentSenderMessage++] = currentMessage;
|
|
}
|
|
return messagesBySender;
|
|
}
|
|
|
|
function formatDisplayDate(message: ChatMessage): string {
|
|
return message.sentTimestamp.toLocaleString([], {
|
|
month: 'short',
|
|
day: 'numeric',
|
|
hour: 'numeric',
|
|
minute: '2-digit',
|
|
hour12: false,
|
|
});
|
|
}
|
|
|
|
const AlwaysScrollToBottom = (props: { newMessages: ChatMessage[] }) => {
|
|
const elementRef = useRef<HTMLDivElement>();
|
|
|
|
useEffect(() => {
|
|
// @ts-ignore
|
|
elementRef.current.scrollIntoView();
|
|
}, [props.newMessages]);
|
|
|
|
// @ts-ignore
|
|
return <div ref={elementRef} />;
|
|
};
|
|
|
|
function IsThereNewMessages(
|
|
newValues: ChatMessage[],
|
|
currentValues: ChatMessage[]
|
|
): boolean {
|
|
if (newValues.length === 0) return false;
|
|
if (currentValues.length === 0) return true;
|
|
|
|
return !newValues.find((newMsg) =>
|
|
currentValues.find(isEqual.bind({}, newMsg))
|
|
);
|
|
}
|
|
|
|
function copyMergeUniqueReplace(
|
|
newValues: ChatMessage[],
|
|
currentValues: ChatMessage[]
|
|
) {
|
|
const copy = currentValues.slice();
|
|
newValues.forEach((msg) => {
|
|
if (!copy.find(isEqual.bind({}, msg))) {
|
|
copy.push(msg);
|
|
}
|
|
});
|
|
copy.sort((a, b) => a.sentTimestamp.valueOf() - b.sentTimestamp.valueOf());
|
|
return copy;
|
|
}
|
|
|
|
function isEqual(lhs: ChatMessage, rhs: ChatMessage): boolean {
|
|
return (
|
|
lhs.nick === rhs.nick &&
|
|
lhs.message === rhs.message &&
|
|
lhs.sentTimestamp.toString() === rhs.sentTimestamp.toString()
|
|
);
|
|
}
|