Add loading history in group chats (#139)

This commit is contained in:
Szymon Szlachtowicz 2021-11-29 10:30:10 +01:00 committed by GitHub
parent 0742fa3635
commit 9592f7eab3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 76 additions and 24 deletions

View File

@ -76,7 +76,7 @@ function DragDiv() {
<ReactChat <ReactChat
theme={theme ? lightTheme : darkTheme} theme={theme ? lightTheme : darkTheme}
communityKey={ communityKey={
"0x0229d71fb62c14ec0370d2507ef7e13f1d53ddf1170db3babb5710fd113d0d94f9" "0x0235564b1b402e8f6ad540f4da0f6384fb828b8f7bb5a34942aa03719041b8b793"
} }
fetchMetadata={fetchMetadata} fetchMetadata={fetchMetadata}
/> />

View File

@ -94,7 +94,7 @@ function ChatUiMessage({
export function ChatMessages() { export function ChatMessages() {
const { messages, activeChannel, contacts } = useMessengerContext(); const { messages, activeChannel, contacts } = useMessengerContext();
const ref = useRef<HTMLHeadingElement>(null); const ref = useRef<HTMLHeadingElement>(null);
const loadingMessages = useChatScrollHandle(messages, ref, activeChannel.id); const loadingMessages = useChatScrollHandle(messages, ref, activeChannel);
const shownMessages = useMemo( const shownMessages = useMemo(
() => () =>

View File

@ -1,11 +1,12 @@
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
import { Messenger } from "status-communities/dist/cjs"; import { GroupChats, Messenger } from "status-communities/dist/cjs";
const _MS_PER_DAY = 1000 * 60 * 60 * 24; const _MS_PER_DAY = 1000 * 60 * 60 * 24;
export function useLoadPrevDay( export function useLoadPrevDay(
chatId: string, chatId: string,
messenger: Messenger | undefined messenger: Messenger | undefined,
groupChats?: GroupChats
) { ) {
const loadingPreviousMessages = useRef<{ const loadingPreviousMessages = useRef<{
[chatId: string]: boolean; [chatId: string]: boolean;
@ -20,7 +21,7 @@ export function useLoadPrevDay(
}, [chatId]); }, [chatId]);
const loadPrevDay = useCallback( const loadPrevDay = useCallback(
async (id: string) => { async (id: string, groupChat?: boolean) => {
if (messenger) { if (messenger) {
const endTime = lastLoadTime.current[id] ?? new Date(); const endTime = lastLoadTime.current[id] ?? new Date();
const startTime = new Date(endTime.getTime() - _MS_PER_DAY); const startTime = new Date(endTime.getTime() - _MS_PER_DAY);
@ -31,16 +32,25 @@ export function useLoadPrevDay(
if (!loadingPreviousMessages.current[id]) { if (!loadingPreviousMessages.current[id]) {
loadingPreviousMessages.current[id] = true; loadingPreviousMessages.current[id] = true;
setLoadingMessages(true); setLoadingMessages(true);
const amountOfMessages = await messenger.retrievePreviousMessages( let amountOfMessages = 0;
id, if (groupChat && groupChats) {
startTime, amountOfMessages = await groupChats.retrievePreviousMessages(
endTime id,
); startTime,
endTime
);
} else {
amountOfMessages = await messenger.retrievePreviousMessages(
id,
startTime,
endTime
);
}
lastLoadTime.current[id] = startTime; lastLoadTime.current[id] = startTime;
loadingPreviousMessages.current[id] = false; loadingPreviousMessages.current[id] = false;
setLoadingMessages(false); setLoadingMessages(false);
if (amountOfMessages === 0) { if (amountOfMessages === 0) {
loadPrevDay(id); loadPrevDay(id, groupChat);
} }
} }
} }

View File

@ -30,7 +30,7 @@ export type MessengerType = {
clearNotifications: (id: string) => void; clearNotifications: (id: string) => void;
mentions: { [chatId: string]: number }; mentions: { [chatId: string]: number };
clearMentions: (id: string) => void; clearMentions: (id: string) => void;
loadPrevDay: (id: string) => Promise<void>; loadPrevDay: (id: string, groupChat?: boolean) => Promise<void>;
loadingMessages: boolean; loadingMessages: boolean;
communityData: CommunityData | undefined; communityData: CommunityData | undefined;
contacts: Contacts; contacts: Contacts;
@ -109,7 +109,6 @@ export function useMessenger(
clearMentions, clearMentions,
} = useMessages(chatId, identity, contactsClass); } = useMessages(chatId, identity, contactsClass);
const [community, setCommunity] = useState<Community | undefined>(undefined); const [community, setCommunity] = useState<Community | undefined>(undefined);
const { loadPrevDay, loadingMessages } = useLoadPrevDay(chatId, messenger);
useEffect(() => { useEffect(() => {
if (identity) { if (identity) {
@ -127,14 +126,6 @@ export function useMessenger(
} }
}, [messenger, communityKey, addMessage, contactsClass]); }, [messenger, communityKey, addMessage, contactsClass]);
useEffect(() => {
if (messenger && community?.chats) {
Array.from(community?.chats.values()).forEach(({ id }) =>
loadPrevDay(id)
);
}
}, [messenger, community]);
const [channels, setChannels] = useState<ChannelsData>({}); const [channels, setChannels] = useState<ChannelsData>({});
const setChannel = useCallback((channel: ChannelData) => { const setChannel = useCallback((channel: ChannelData) => {
@ -201,6 +192,19 @@ export function useMessenger(
channels channels
); );
const { loadPrevDay, loadingMessages } = useLoadPrevDay(
chatId,
messenger,
groupChat
);
useEffect(() => {
if (messenger && community?.chats) {
Array.from(community?.chats.values()).forEach(({ id }) =>
loadPrevDay(id)
);
}
}, [messenger, community]);
const sendMessage = useCallback( const sendMessage = useCallback(
async (messageText?: string, image?: Uint8Array) => { async (messageText?: string, image?: Uint8Array) => {
if (activeChannel.type === "group") { if (activeChannel.type === "group") {

View File

@ -1,12 +1,13 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useMessengerContext } from "../contexts/messengerProvider"; import { useMessengerContext } from "../contexts/messengerProvider";
import { ChannelData } from "../models/ChannelData";
import { ChatMessage } from "../models/ChatMessage"; import { ChatMessage } from "../models/ChatMessage";
export function useChatScrollHandle( export function useChatScrollHandle(
messages: ChatMessage[], messages: ChatMessage[],
ref: React.RefObject<HTMLHeadingElement>, ref: React.RefObject<HTMLHeadingElement>,
activeChannelId: string activeChannel: ChannelData
) { ) {
const { loadPrevDay, loadingMessages } = useMessengerContext(); const { loadPrevDay, loadingMessages } = useMessengerContext();
const [scrollOnBot, setScrollOnBot] = useState(true); const [scrollOnBot, setScrollOnBot] = useState(true);
@ -23,7 +24,7 @@ export function useChatScrollHandle(
(ref?.current?.clientHeight ?? 0) >= (ref?.current?.scrollHeight ?? 0) (ref?.current?.clientHeight ?? 0) >= (ref?.current?.scrollHeight ?? 0)
) { ) {
setScrollOnBot(true); setScrollOnBot(true);
loadPrevDay(activeChannelId); loadPrevDay(activeChannel.id, activeChannel.type === "group");
} }
} }
}, [messages.length, loadingMessages]); }, [messages.length, loadingMessages]);
@ -32,7 +33,7 @@ export function useChatScrollHandle(
const setScroll = () => { const setScroll = () => {
if (ref?.current) { if (ref?.current) {
if (ref.current.scrollTop <= 0) { if (ref.current.scrollTop <= 0) {
loadPrevDay(activeChannelId); loadPrevDay(activeChannel.id, activeChannel.type === "group");
} }
if ( if (
ref.current.scrollTop + ref.current.clientHeight == ref.current.scrollTop + ref.current.clientHeight ==

View File

@ -246,4 +246,41 @@ export class GroupChats {
); );
wakuMessages.forEach((msg) => this.waku.relay.send(msg)); wakuMessages.forEach((msg) => this.waku.relay.send(msg));
} }
/**
* Retrieve previous messages from a Waku Store node for the given chat Id.
*
*/
public async retrievePreviousMessages(
chatId: string,
startTime: Date,
endTime: Date
): Promise<number> {
const chat = this.chats[chatId];
if (!chat)
throw `Failed to retrieve messages, chat is not joined: ${chatId}`;
const _callback = (wakuMessages: WakuMessage[], member: string): void => {
wakuMessages.forEach((wakuMessage: WakuMessage) =>
this.handleWakuChatMessage(wakuMessage, chat, member)
);
};
const amountOfMessages: number[] = [];
await Promise.all(
chat.members.map(async (member) => {
const topic = await getNegotiatedTopic(this.identity, member);
const msgLength = (
await this.waku.store.queryHistory([topic], {
timeFilter: { startTime, endTime },
callback: (msg) => _callback(msg, member),
})
).length;
amountOfMessages.push(msgLength);
})
);
return amountOfMessages.reduce((a, b) => a + b);
}
} }