From 05538a051c899753c0fb7b6962dbc0046c7a07a5 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Wed, 26 Jun 2024 14:44:54 +0200 Subject: [PATCH 01/27] use new conversation query params --- packages/lib/shared/src/IBackendConnector.ts | 7 +- .../src/new/cloudStorage/getCloudStorage.ts | 16 ++-- .../src/context/BackendContext.tsx | 8 +- .../hooks/conversation/useConversation.tsx | 91 +++++++++---------- 4 files changed, 62 insertions(+), 60 deletions(-) diff --git a/packages/lib/shared/src/IBackendConnector.ts b/packages/lib/shared/src/IBackendConnector.ts index e163ce2ff..9f0d37650 100644 --- a/packages/lib/shared/src/IBackendConnector.ts +++ b/packages/lib/shared/src/IBackendConnector.ts @@ -4,7 +4,12 @@ export interface IBackendConnector { ensName: string, size: number, offset: number, - ): Promise; + ): Promise< + { + contact: string; + previewMessage: string; + }[] + >; toggleHideConversation( ensName: string, encryptedContactName: string, diff --git a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts index f4f4f7e8a..ef4fe5ded 100644 --- a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts +++ b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts @@ -18,22 +18,18 @@ export const getCloudStorage = ( }; const getConversations = async (size: number, offset: number) => { - const encryptedConversations = await backendConnector.getConversations( + const conversations = await backendConnector.getConversations( ensName, size, offset, ); return await Promise.all( - encryptedConversations.map( - async (encryptedContactName: string) => ({ - contactEnsName: await encryption.decryptSync( - encryptedContactName, - ), - isHidden: false, - messageCounter: 0, - }), - ), + conversations.map(async ({ contact }: { contact: string }) => ({ + contactEnsName: await encryption.decryptSync(contact), + isHidden: false, + messageCounter: 0, + })), ); }; const getMessages = async (contactEnsName: string, page: number) => { diff --git a/packages/messenger-widget/src/context/BackendContext.tsx b/packages/messenger-widget/src/context/BackendContext.tsx index e829220e5..4e628fb4f 100644 --- a/packages/messenger-widget/src/context/BackendContext.tsx +++ b/packages/messenger-widget/src/context/BackendContext.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { useDeliveryService } from '../hooks/server-side/useDeliveryService'; import { useBackend } from '../hooks/server-side/useBackend'; export type BackendContextType = { @@ -9,7 +8,12 @@ export type BackendContextType = { ensName: string, size: number, offset: number, - ) => Promise; + ) => Promise< + { + contact: string; + previewMessage: string; + }[] + >; toggleHideConversation: ( ensName: string, encryptedContactName: string, diff --git a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx index f9f1d4ca6..0ef5ca3ad 100644 --- a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx +++ b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx @@ -16,7 +16,7 @@ import { ContactPreview, getEmptyContact } from '../../interfaces/utils'; import { useMainnetProvider } from '../mainnetprovider/useMainnetProvider'; import { hydrateContract } from './hydrateContact'; -const DEFAULT_CONVERSATION_PAGE_SIZE = 1; +const DEFAULT_CONVERSATION_PAGE_SIZE = 2; export const useConversation = (config: DM3Configuration) => { const mainnetProvider = useMainnetProvider(); @@ -196,37 +196,6 @@ export const useConversation = (config: DM3Configuration) => { return conversationPreview; }; - const _addConversation = (_ensName: string, isHidden: boolean) => { - const ensName = normalizeEnsName(_ensName); - //Check if the contact is the user itself - const isOwnContact = normalizeEnsName(account!.ensName) === ensName; - //We don't want to add ourselfs - if (isOwnContact) { - return; - } - const alreadyAddedContact = contacts.find( - (existingContact) => - existingContact.contactDetails.account.ensName === ensName, - ); - //If the contact is already in the list return it - if (alreadyAddedContact) { - //Unhide the contact if it was hidden - if (alreadyAddedContact.isHidden) { - unhideContact(alreadyAddedContact); - } - return alreadyAddedContact; - } - - const newContact: ContactPreview = getEmptyContact(ensName, isHidden); - //Set the new contact to the list - _setContactsSafe([newContact]); - //Hydrate the contact in the background - hydrateExistingContactAsync(newContact); - - //Return the new onhydrated contact - return newContact; - }; - /** * When a conversation is added via the AddContacts dialog it should appeat in the conversation list immediately. * Hence we're doing a hydrate here asynchroniously in the background @@ -257,7 +226,22 @@ export const useConversation = (config: DM3Configuration) => { }); }; - const toggleHideContact = (_ensName: string, isHidden: boolean) => { + const hideContact = (_ensName: string) => { + const ensName = normalizeEnsName(_ensName); + _toggleHideContact(ensName, true); + setSelectedContactName(undefined); + }; + + const unhideContact = (contact: ContactPreview) => { + _toggleHideContact(contact.contactDetails.account.ensName, false); + const unhiddenContact = { + ...contact, + isHidden: false, + }; + setSelectedContactName(unhiddenContact.contactDetails.account.ensName); + hydrateExistingContactAsync(unhiddenContact); + }; + const _toggleHideContact = (_ensName: string, isHidden: boolean) => { const ensName = normalizeEnsName(_ensName); setContacts((prev) => { return prev.map((existingContact) => { @@ -276,23 +260,36 @@ export const useConversation = (config: DM3Configuration) => { //update the storage toggleHideContactAsync(ensName, isHidden); }; - - const hideContact = (_ensName: string) => { + const _addConversation = (_ensName: string, isHidden: boolean) => { const ensName = normalizeEnsName(_ensName); - toggleHideContact(ensName, true); - setSelectedContactName(undefined); - }; + //Check if the contact is the user itself + const isOwnContact = normalizeEnsName(account!.ensName) === ensName; + //We don't want to add ourselfs + if (isOwnContact) { + return; + } + const alreadyAddedContact = contacts.find( + (existingContact) => + existingContact.contactDetails.account.ensName === ensName, + ); + //If the contact is already in the list return it + if (alreadyAddedContact) { + //Unhide the contact if it was hidden + if (alreadyAddedContact.isHidden) { + unhideContact(alreadyAddedContact); + } + return alreadyAddedContact; + } - const unhideContact = (contact: ContactPreview) => { - toggleHideContact(contact.contactDetails.account.ensName, false); - const unhiddenContact = { - ...contact, - isHidden: false, - }; - setSelectedContactName(unhiddenContact.contactDetails.account.ensName); - hydrateExistingContactAsync(unhiddenContact); - }; + const newContact: ContactPreview = getEmptyContact(ensName, isHidden); + //Set the new contact to the list + _setContactsSafe([newContact]); + //Hydrate the contact in the background + hydrateExistingContactAsync(newContact); + //Return the new onhydrated contact + return newContact; + }; return { contacts, conversationCount, From a7145f1802ad6c7e80e47fa2cf83aa63d0502766 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Wed, 26 Jun 2024 17:10:46 +0200 Subject: [PATCH 02/27] add paginated API for messages --- packages/lib/shared/src/IBackendConnector.ts | 3 ++- .../storage/src/new/cloudStorage/getCloudStorage.ts | 9 +++++++-- packages/lib/storage/src/new/types.ts | 3 ++- .../messenger-widget/src/context/BackendContext.tsx | 3 ++- .../messenger-widget/src/context/StorageContext.tsx | 3 ++- .../testHelper/getMockedConversationContext.ts | 1 + .../messages/sources/handleMessagesFromStorage.ts | 6 ++---- .../src/hooks/server-side/BackendConnector.ts | 12 +++++++++--- .../src/hooks/server-side/useBackend.ts | 6 ++++-- .../src/hooks/storage/useStorage.tsx | 11 ++++++++--- 10 files changed, 39 insertions(+), 18 deletions(-) diff --git a/packages/lib/shared/src/IBackendConnector.ts b/packages/lib/shared/src/IBackendConnector.ts index 9f0d37650..c5ce7eedd 100644 --- a/packages/lib/shared/src/IBackendConnector.ts +++ b/packages/lib/shared/src/IBackendConnector.ts @@ -18,7 +18,8 @@ export interface IBackendConnector { getMessagesFromStorage( ensName: string, encryptedContactName: string, - pageNumber: number, + pageSize: number, + offset: number, ): Promise; addMessage( ensName: string, diff --git a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts index ef4fe5ded..275f050ca 100644 --- a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts +++ b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts @@ -32,7 +32,11 @@ export const getCloudStorage = ( })), ); }; - const getMessages = async (contactEnsName: string, page: number) => { + const getMessages = async ( + contactEnsName: string, + pageSize: number, + offset: number, + ) => { const encryptedContactName = await encryption.encryptSync( contactEnsName, ); @@ -40,7 +44,8 @@ export const getCloudStorage = ( const messageRecords = await backendConnector.getMessagesFromStorage( ensName, encryptedContactName, - page, + pageSize, + offset, ); const decryptedMessageRecords = await Promise.all( messageRecords.map(async (messageRecord: MessageRecord) => { diff --git a/packages/lib/storage/src/new/types.ts b/packages/lib/storage/src/new/types.ts index 0ed77ca0a..1897ea83b 100644 --- a/packages/lib/storage/src/new/types.ts +++ b/packages/lib/storage/src/new/types.ts @@ -4,7 +4,8 @@ export interface StorageAPI { getConversations: (size: number, offset: number) => Promise; getMessages: ( contactEnsName: string, - page: number, + pageSize: number, + offset: number, ) => Promise; addMessageBatch: ( contactEnsName: string, diff --git a/packages/messenger-widget/src/context/BackendContext.tsx b/packages/messenger-widget/src/context/BackendContext.tsx index 4e628fb4f..0af02558a 100644 --- a/packages/messenger-widget/src/context/BackendContext.tsx +++ b/packages/messenger-widget/src/context/BackendContext.tsx @@ -22,7 +22,8 @@ export type BackendContextType = { getMessagesFromStorage: ( ensName: string, encryptedContactName: string, - pageNumber: number, + pageSize: number, + offset: number, ) => Promise; addMessage: ( ensName: string, diff --git a/packages/messenger-widget/src/context/StorageContext.tsx b/packages/messenger-widget/src/context/StorageContext.tsx index 3dd4c6574..a2bf8d254 100644 --- a/packages/messenger-widget/src/context/StorageContext.tsx +++ b/packages/messenger-widget/src/context/StorageContext.tsx @@ -42,7 +42,8 @@ export const StorageContext = React.createContext({ getConversations: async (size: number, offset: number) => Promise.resolve([]), addConversationAsync: (contact: string) => {}, - getMessages: async (contact: string, page: number) => Promise.resolve([]), + getMessages: async (contact: string, pageSize: number, offset: number) => + Promise.resolve([]), getNumberOfMessages: async (contact: string) => Promise.resolve(0), toggleHideContactAsync: async (contact: string, value: boolean) => {}, initialized: false, diff --git a/packages/messenger-widget/src/context/testHelper/getMockedConversationContext.ts b/packages/messenger-widget/src/context/testHelper/getMockedConversationContext.ts index 2cce22060..3718297d6 100644 --- a/packages/messenger-widget/src/context/testHelper/getMockedConversationContext.ts +++ b/packages/messenger-widget/src/context/testHelper/getMockedConversationContext.ts @@ -16,6 +16,7 @@ export const getMockedConversationContext = ( addConversation: (ensName: string) => { return {} as ContactPreview; }, + loadMoreConversations: () => {}, hideContact: (ensName: string) => {}, }; diff --git a/packages/messenger-widget/src/hooks/messages/sources/handleMessagesFromStorage.ts b/packages/messenger-widget/src/hooks/messages/sources/handleMessagesFromStorage.ts index e8ffe881e..6e6370a64 100644 --- a/packages/messenger-widget/src/hooks/messages/sources/handleMessagesFromStorage.ts +++ b/packages/messenger-widget/src/hooks/messages/sources/handleMessagesFromStorage.ts @@ -12,10 +12,8 @@ export const handleMessagesFromStorage = async ( }); const MAX_MESSAGES_PER_CHUNK = 100; const numberOfmessages = await getNumberOfMessages(contactName); - const storedMessages = await getMessagesFromStorage( - contactName, - Math.floor(numberOfmessages / MAX_MESSAGES_PER_CHUNK), - ); + const storedMessages = await getMessagesFromStorage(contactName, 100, 0); + return storedMessages.map( (message) => ({ diff --git a/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts b/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts index 90f07c895..4aa0729d0 100644 --- a/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts +++ b/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts @@ -49,13 +49,19 @@ export class BackendConnector public async getMessagesFromStorage( ensName: string, encryptedContactName: string, - pageNumber: number, + pageSize: number, + offset: number, ) { const url = `/storage/new/${normalizeEnsName( ensName, - )}/getMessages/${encryptedContactName}/${pageNumber}`; + )}/getMessages/${encryptedContactName}`; - const { data } = await this.getAuthenticatedAxiosClient().get(url); + const { data } = await this.getAuthenticatedAxiosClient().get(url, { + params: { + pageSize, + offset, + }, + }); return ( data.map((message: any) => { diff --git a/packages/messenger-widget/src/hooks/server-side/useBackend.ts b/packages/messenger-widget/src/hooks/server-side/useBackend.ts index c61dba118..9c5be3725 100644 --- a/packages/messenger-widget/src/hooks/server-side/useBackend.ts +++ b/packages/messenger-widget/src/hooks/server-side/useBackend.ts @@ -76,12 +76,14 @@ export const useBackend = (): IBackendConnector & { getMessagesFromStorage: async ( ensName: string, encryptedContactName: string, - pageNumber: number, + pageSize: number, + offset: number, ) => { return beConnector?.getMessagesFromStorage( ensName, encryptedContactName, - pageNumber, + pageSize, + offset, ); }, addMessage: async ( diff --git a/packages/messenger-widget/src/hooks/storage/useStorage.tsx b/packages/messenger-widget/src/hooks/storage/useStorage.tsx index f627ca266..98870a760 100644 --- a/packages/messenger-widget/src/hooks/storage/useStorage.tsx +++ b/packages/messenger-widget/src/hooks/storage/useStorage.tsx @@ -134,11 +134,15 @@ export const useStorage = ( } storageApi.addConversation(contact); }; - const getMessages = async (contact: string, page: number) => { + const getMessages = async ( + contact: string, + pageSize: number, + offset: number, + ) => { if (!storageApi) { return Promise.resolve([]); } - return storageApi.getMessages(contact, page); + return storageApi.getMessages(contact, pageSize, offset); }; const getNumberOfMessages = async (contact: string) => { @@ -187,7 +191,8 @@ export type GetConversations = ( export type AddConversation = (contact: string) => void; export type GetMessages = ( contact: string, - page: number, + pageSize: number, + offset: number, ) => Promise; export type GetNumberOfMessages = (contact: string) => Promise; export type ToggleHideContactAsync = (contact: string, value: boolean) => void; From 9211aab9bb123c3a7840afce7d12ff9c510ca9da Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Wed, 26 Jun 2024 17:31:43 +0200 Subject: [PATCH 03/27] POC paginated conversations --- packages/messenger-widget/package.json | 1 + .../src/components/Contacts/Contacts.tsx | 299 ++++++++++-------- .../src/context/ConversationContext.tsx | 5 +- .../hooks/conversation/useConversation.tsx | 24 +- yarn.lock | 19 ++ 5 files changed, 216 insertions(+), 132 deletions(-) diff --git a/packages/messenger-widget/package.json b/packages/messenger-widget/package.json index 1404195a7..ea58ecf56 100644 --- a/packages/messenger-widget/package.json +++ b/packages/messenger-widget/package.json @@ -34,6 +34,7 @@ "jsonwebtoken": "^9.0.2", "localforage": "^1.10.0", "nacl": "^0.1.3", + "react-infinite-scroll-component": "^6.1.0", "react-scripts": "5.0.0", "rimraf": "^5.0.5", "socket.io-client": "^4.7.5", diff --git a/packages/messenger-widget/src/components/Contacts/Contacts.tsx b/packages/messenger-widget/src/components/Contacts/Contacts.tsx index af5250429..a52c0bae1 100644 --- a/packages/messenger-widget/src/components/Contacts/Contacts.tsx +++ b/packages/messenger-widget/src/components/Contacts/Contacts.tsx @@ -15,14 +15,19 @@ import { ContactPreview } from '../../interfaces/utils'; import { DM3ConfigurationContext } from '../../context/DM3ConfigurationContext'; import { UiViewContext } from '../../context/UiViewContext'; import { ModalContext } from '../../context/ModalContext'; +import InfiniteScroll from 'react-infinite-scroll-component'; export function Contacts() { const { dm3Configuration } = useContext(DM3ConfigurationContext); const { getMessages, getUnreadMessageCount } = useContext(MessageContext); const { selectedRightView, setSelectedRightView } = useContext(UiViewContext); - const { contacts, setSelectedContactName, selectedContact } = - useContext(ConversationContext); + const { + contacts, + setSelectedContactName, + selectedContact, + loadMoreConversations, + } = useContext(ConversationContext); const { setLastMessageAction } = useContext(ModalContext); const [isMenuAlignedAtBottom, setIsMenuAlignedAtBottom] = useState< @@ -99,153 +104,187 @@ export function Contacts() { ' ', contacts.length > 6 ? 'scroller-active' : 'scroller-hidden', )} + style={{ + overflow: 'auto', + display: 'flex', + flexDirection: 'column-reverse', + }} > - {contacts.length > 0 && - filterDuplicateContacts(contacts).map((data) => { - const id = data.contactDetails.account.ensName; - const unreadMessageCount = getUnreadMessageCount(id); + + Loading ... + + } + scrollableTarget="chat-scroller" + > + {contacts.length > 0 && + filterDuplicateContacts(contacts).map((data) => { + const id = data.contactDetails.account.ensName; + const unreadMessageCount = getUnreadMessageCount(id); - return ( - !data.isHidden && ( -
{ - // On change of contact, message action is set to none - // so that it automatically scrolls to latest message. - setLastMessageAction( - MessageActionType.NONE, - ); - setSelectedContactName( - data.contactDetails.account.ensName, - ); - if ( - selectedRightView !== - RightViewSelected.Chat - ) { - setSelectedRightView( - RightViewSelected.Chat, + return ( + !data.isHidden && ( +
{ + // On change of contact, message action is set to none + // so that it automatically scrolls to latest message. + setLastMessageAction( + MessageActionType.NONE, ); - } - setIsMenuAlignedAtBottom( - showMenuInBottom( + setSelectedContactName( data.contactDetails.account.ensName, - ), - ); - }} - > -
-
- profile-pic -
+
+
+ profile-pic +
-
-
+
-

- {getAccountDisplayName( - data.name, - 25, - )} -

-
+
+

+ {getAccountDisplayName( + data.name, + 25, + )} +

+
- {id !== - selectedContact?.contactDetails - .account.ensName && - unreadMessageCount > 0 && ( -
-
- {unreadMessageCount} + {id !== + selectedContact + ?.contactDetails.account + .ensName && + unreadMessageCount > 0 && ( +
+
+ { + unreadMessageCount + } +
-
- )} + )} - {selectedContact?.contactDetails - .account.ensName === id ? ( - selectedContact.message !== - null ? ( -
-
- action - { - +
+ action - } + { + + } +
+
+ ) : ( +
+ loader
-
+ ) ) : ( -
- loader -
- ) - ) : ( - <> - )} -
+ <> + )} +
-
-

- {getPreviewMessage(id)} -

+
+

+ {getPreviewMessage(id)} +

+
-
- ) - ); - })} + ) + ); + })} + {/* Hidden content for highlighting css */} {hiddenData.map((data) => ( diff --git a/packages/messenger-widget/src/context/ConversationContext.tsx b/packages/messenger-widget/src/context/ConversationContext.tsx index 6f0b1cefa..db2ecfda2 100644 --- a/packages/messenger-widget/src/context/ConversationContext.tsx +++ b/packages/messenger-widget/src/context/ConversationContext.tsx @@ -11,6 +11,7 @@ export type ConversationContextType = { setSelectedContactName: (contactEnsName: string | undefined) => void; initialized: boolean; addConversation: (ensName: string) => ContactPreview | undefined; + loadMoreConversations: () => void; hideContact: (ensName: string) => void; }; @@ -24,6 +25,7 @@ export const ConversationContext = React.createContext( addConversation: (ensName: string) => { return {} as ContactPreview; }, + loadMoreConversations: () => {}, hideContact: (ensName: string) => {}, }, ); @@ -43,13 +45,14 @@ export const ConversationContextProvider = ({ setSelectedContactName, selectedContact, hideContact, - unhideContact, + loadMoreConversations, } = useConversation(config); return ( { const mainnetProvider = useMainnetProvider(); @@ -196,6 +196,27 @@ export const useConversation = (config: DM3Configuration) => { return conversationPreview; }; + const loadMoreConversations = async () => { + const hasDefaultContact = config.defaultContact !== undefined; + //If a default contact is set we have to subtract one from the conversation count since its not part of the conversation list + const conversationCount = hasDefaultContact + ? contacts.length - 1 + : contacts.length; + //We calculate the offset based on the conversation count divided by the default page size + //offset * pagesize equals the amount of conversations that will be skipped + const offset = conversationCount / DEFAULT_CONVERSATION_PAGE_SIZE; + const conversations = await getConversationsFromStorage( + DEFAULT_CONVERSATION_PAGE_SIZE, + Math.floor(offset), + ); + conversations.forEach((conversation) => { + _addConversation( + conversation.contactEnsName, + conversation.isHidden, + ); + }); + }; + /** * When a conversation is added via the AddContacts dialog it should appeat in the conversation list immediately. * Hence we're doing a hydrate here asynchroniously in the background @@ -294,6 +315,7 @@ export const useConversation = (config: DM3Configuration) => { contacts, conversationCount, addConversation, + loadMoreConversations, initialized: conversationsInitialized, setSelectedContactName, selectedContact, diff --git a/yarn.lock b/yarn.lock index 8eedfd310..a5cedae86 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2440,6 +2440,7 @@ __metadata: react: ^18.2.0 react-app-rewired: ^2.2.1 react-dom: ^18.2.0 + react-infinite-scroll-component: ^6.1.0 react-scripts: 5.0.0 rimraf: ^5.0.5 socket.io-client: ^4.7.5 @@ -27037,6 +27038,17 @@ __metadata: languageName: node linkType: hard +"react-infinite-scroll-component@npm:^6.1.0": + version: 6.1.0 + resolution: "react-infinite-scroll-component@npm:6.1.0" + dependencies: + throttle-debounce: ^2.1.0 + peerDependencies: + react: ">=16.0.0" + checksum: 3708398934366df907dbad215247ebc1033221957ce7e32289ea31750cce70aa16513e2d03743e06c8b868ac7c542d12d5dbb6c830fd408433a4762f3cb5ecfb + languageName: node + linkType: hard + "react-is@npm:^16.13.1": version: 16.13.1 resolution: "react-is@npm:16.13.1" @@ -30322,6 +30334,13 @@ __metadata: languageName: node linkType: hard +"throttle-debounce@npm:^2.1.0": + version: 2.3.0 + resolution: "throttle-debounce@npm:2.3.0" + checksum: 6d90aa2ddb294f8dad13d854a1cfcd88fdb757469669a096a7da10f515ee466857ac1e750649cb9da931165c6f36feb448318e7cb92570f0a3679d20e860a925 + languageName: node + linkType: hard + "through2@npm:^2.0.1": version: 2.0.5 resolution: "through2@npm:2.0.5" From ed224c2cedf199c4472a3dbae14ccfc830afe980 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Thu, 27 Jun 2024 10:45:25 +0200 Subject: [PATCH 04/27] add use conversation test --- .../conversation/useConversation.test.tsx | 79 ++++++++++++++++++- .../hooks/conversation/useConversation.tsx | 5 +- 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx b/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx index 4a910d109..2a212890d 100644 --- a/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx +++ b/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx @@ -326,6 +326,77 @@ describe('useConversation hook test cases', () => { }); }); + describe('load more conversations', () => { + it('Should load more conversations', async () => { + const authContext: AuthContextType = getMockedAuthContext({ + account: { + ensName: 'alice.eth', + profile: { + deliveryServices: ['ds.eth'], + publicEncryptionKey: '', + publicSigningKey: '', + }, + }, + }); + + const storageContext: StorageContextType = getMockedStorageContext({ + getConversations: function ( + pageSize: number, + offset: number, + ): Promise { + return Promise.resolve( + Array.from({ length: pageSize }, (_, i) => { + return { + //Use offset here to create a distinct contactEnsName + contactEnsName: 'contact ' + i + offset, + isHidden: false, + messageCounter: 0, + }; + }), + ); + }, + addConversationAsync: jest.fn(), + initialized: true, + }); + const deliveryServiceContext: DeliveryServiceContextType = + getMockedDeliveryServiceContext({ + fetchIncommingMessages: function (ensName: string) { + return Promise.resolve([]); + }, + getDeliveryServiceProperties: function (): Promise { + return Promise.resolve([{ sizeLimit: 0 }]); + }, + isInitialized: true, + }); + + const wrapper = ({ children }: { children: any }) => ( + <> + + + + {children} + + + + + ); + + const { result } = renderHook(() => useConversation(config), { + wrapper, + }); + + await waitFor(() => result.current.initialized); + await waitFor(() => result.current.contacts.length > 1); + expect(result.current.contacts.length).toBe(10); + + await act(async () => result.current.loadMoreConversations()); + await waitFor(() => result.current.contacts.length > 10); + expect(result.current.contacts.length).toBe(20); + }); + }); + describe('add conversation', () => { it('Should add multiple contacts', async () => { const authContext: AuthContextType = getMockedAuthContext({ @@ -837,6 +908,7 @@ describe('useConversation hook test cases', () => { return Promise.resolve(sender.address); }, getResolver: (ensName: string) => { + console.log('mock resolver for ', ensName); if (ensName === sender.account.ensName) { return { getText: () => sender.stringified, @@ -884,7 +956,12 @@ describe('useConversation hook test cases', () => { wrapper, }); await waitFor(() => expect(result.current.initialized).toBe(true)); - + await waitFor(() => + expect( + result.current.contacts[0].contactDetails + .deliveryServiceProfiles.length, + ).toBe(2), + ); expect( result.current.contacts[0].contactDetails .deliveryServiceProfiles[0], diff --git a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx index 923162d5a..22d9a2def 100644 --- a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx +++ b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx @@ -16,7 +16,7 @@ import { ContactPreview, getEmptyContact } from '../../interfaces/utils'; import { useMainnetProvider } from '../mainnetprovider/useMainnetProvider'; import { hydrateContract } from './hydrateContact'; -const DEFAULT_CONVERSATION_PAGE_SIZE = 1; +const DEFAULT_CONVERSATION_PAGE_SIZE = 10; export const useConversation = (config: DM3Configuration) => { const mainnetProvider = useMainnetProvider(); @@ -197,7 +197,7 @@ export const useConversation = (config: DM3Configuration) => { }; const loadMoreConversations = async () => { - const hasDefaultContact = config.defaultContact !== undefined; + const hasDefaultContact = config.defaultContact; //If a default contact is set we have to subtract one from the conversation count since its not part of the conversation list const conversationCount = hasDefaultContact ? contacts.length - 1 @@ -205,6 +205,7 @@ export const useConversation = (config: DM3Configuration) => { //We calculate the offset based on the conversation count divided by the default page size //offset * pagesize equals the amount of conversations that will be skipped const offset = conversationCount / DEFAULT_CONVERSATION_PAGE_SIZE; + console.log('load more conversations', conversationCount, offset); const conversations = await getConversationsFromStorage( DEFAULT_CONVERSATION_PAGE_SIZE, Math.floor(offset), From 53524576b7c0e4fcc8a18dd4fb3771d3940142cd Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Thu, 27 Jun 2024 11:01:05 +0200 Subject: [PATCH 05/27] remove unsued fields unreadMsgCount and messageCount --- .../storage/src/new/cloudStorage/getCloudStorage.ts | 1 - packages/lib/storage/src/new/types.ts | 1 - .../src/components/ContactMenu/ContactMenu.test.tsx | 2 -- .../src/hooks/conversation/hydrateContact.ts | 4 ---- .../src/hooks/conversation/useConversation.test.tsx | 11 ----------- .../src/hooks/conversation/useConversation.tsx | 3 --- .../src/hooks/messages/useMessage.test.tsx | 12 ------------ packages/messenger-widget/src/interfaces/utils.ts | 4 ---- 8 files changed, 38 deletions(-) diff --git a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts index 275f050ca..79c566493 100644 --- a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts +++ b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts @@ -10,7 +10,6 @@ export const getCloudStorage = ( const encryptedContactName = await encryption.encryptSync( contactEnsName, ); - console.log('store new contact ', encryptedContactName); return await backendConnector.addConversation( ensName, encryptedContactName, diff --git a/packages/lib/storage/src/new/types.ts b/packages/lib/storage/src/new/types.ts index 1897ea83b..94ce4d8c3 100644 --- a/packages/lib/storage/src/new/types.ts +++ b/packages/lib/storage/src/new/types.ts @@ -36,7 +36,6 @@ export interface StorageEnvelopContainer { export interface Conversation { contactEnsName: string; isHidden: boolean; - messageCounter: number; } export type Encryption = { diff --git a/packages/messenger-widget/src/components/ContactMenu/ContactMenu.test.tsx b/packages/messenger-widget/src/components/ContactMenu/ContactMenu.test.tsx index 13ac37119..925e073f2 100644 --- a/packages/messenger-widget/src/components/ContactMenu/ContactMenu.test.tsx +++ b/packages/messenger-widget/src/components/ContactMenu/ContactMenu.test.tsx @@ -14,8 +14,6 @@ describe('ContactMenu test cases', () => { ensName: '', }, } as any, - unreadMsgCount: 0, - messageCount: 1, isHidden: false, messageSizeLimit: 100000, }, diff --git a/packages/messenger-widget/src/hooks/conversation/hydrateContact.ts b/packages/messenger-widget/src/hooks/conversation/hydrateContact.ts index d4fb5069f..2df1e907a 100644 --- a/packages/messenger-widget/src/hooks/conversation/hydrateContact.ts +++ b/packages/messenger-widget/src/hooks/conversation/hydrateContact.ts @@ -59,10 +59,6 @@ const fetchPreview = async ( contact.account.ensName, addrEnsSubdomain, ), - //ToDo maybe can be removed aswell - messageCount: conversatoinManifest.messageCounter, - //ToDo field is not used and can be removed - unreadMsgCount: 21, contactDetails: contact, isHidden: conversatoinManifest.isHidden, messageSizeLimit: messageSizeLimit, diff --git a/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx b/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx index 2a212890d..8967de73d 100644 --- a/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx +++ b/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx @@ -350,7 +350,6 @@ describe('useConversation hook test cases', () => { //Use offset here to create a distinct contactEnsName contactEnsName: 'contact ' + i + offset, isHidden: false, - messageCounter: 0, }; }), ); @@ -477,7 +476,6 @@ describe('useConversation hook test cases', () => { { contactEnsName: 'max.eth', isHidden: false, - messageCounter: 1, }, ]); }, @@ -549,7 +547,6 @@ describe('useConversation hook test cases', () => { { contactEnsName: 'max.eth', isHidden: false, - messageCounter: 1, }, ]); }, @@ -633,12 +630,10 @@ describe('useConversation hook test cases', () => { { contactEnsName: 'max.eth', isHidden: false, - messageCounter: 1, }, { contactEnsName: 'mydefaultcontract.eth', isHidden: false, - messageCounter: 1, }, ]); }, @@ -722,17 +717,14 @@ describe('useConversation hook test cases', () => { { contactEnsName: 'ron.eth', isHidden: true, - messageCounter: 1, }, { contactEnsName: 'max.eth', isHidden: false, - messageCounter: 1, }, { contactEnsName: 'mydefaultcontract.eth', isHidden: false, - messageCounter: 1, }, ]); }, @@ -818,7 +810,6 @@ describe('useConversation hook test cases', () => { { contactEnsName: 'max.eth', isHidden: false, - messageCounter: 1, }, ]); }, @@ -887,7 +878,6 @@ describe('useConversation hook test cases', () => { { contactEnsName: sender.account.ensName, isHidden: false, - messageCounter: 1, }, ]); }, @@ -996,7 +986,6 @@ describe('useConversation hook test cases', () => { { contactEnsName: sender.account.ensName, isHidden: false, - messageCounter: 1, }, ]); }, diff --git a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx index 22d9a2def..73e9e63a6 100644 --- a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx +++ b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx @@ -136,7 +136,6 @@ export const useConversation = (config: DM3Configuration) => { //I there are no conversations yet we add the default contact const defaultConversation: Conversation = { contactEnsName: normalizeEnsName(aliasName!), - messageCounter: 0, isHidden: false, }; @@ -172,7 +171,6 @@ export const useConversation = (config: DM3Configuration) => { return { contactEnsName, - messageCounter: 0, isHidden: false, }; }) @@ -225,7 +223,6 @@ export const useConversation = (config: DM3Configuration) => { const hydrateExistingContactAsync = async (contact: ContactPreview) => { const conversation: Conversation = { contactEnsName: contact.contactDetails.account.ensName, - messageCounter: contact?.messageCount || 0, isHidden: contact.isHidden, }; const hydratedContact = await hydrateContract( diff --git a/packages/messenger-widget/src/hooks/messages/useMessage.test.tsx b/packages/messenger-widget/src/hooks/messages/useMessage.test.tsx index 6300a91fa..724037375 100644 --- a/packages/messenger-widget/src/hooks/messages/useMessage.test.tsx +++ b/packages/messenger-widget/src/hooks/messages/useMessage.test.tsx @@ -54,14 +54,6 @@ describe('useMessage hook test cases', () => { expect(loading).toBe(false); }); - it('Should check contact is loading or not ', async () => { - const { result } = renderHook(() => useMessage()); - const unreadMsgCount = await act(async () => - result.current.getUnreadMessageCount(CONTACT_NAME), - ); - expect(unreadMsgCount).toBe(0); - }); - describe('add Message', () => { let sender: MockedUserProfile; let receiver: MockedUserProfile; @@ -293,8 +285,6 @@ describe('useMessage hook test cases', () => { name: '', message: '', image: 'human.svg', - messageCount: 1, - unreadMsgCount: 21, contactDetails: { account: { ensName: receiver.account.ensName, @@ -396,8 +386,6 @@ describe('useMessage hook test cases', () => { name: '', message: '', image: 'human.svg', - messageCount: 1, - unreadMsgCount: 21, contactDetails: { account: { ensName: receiver.account.ensName, diff --git a/packages/messenger-widget/src/interfaces/utils.ts b/packages/messenger-widget/src/interfaces/utils.ts index 2efd79704..b89f820f1 100644 --- a/packages/messenger-widget/src/interfaces/utils.ts +++ b/packages/messenger-widget/src/interfaces/utils.ts @@ -24,8 +24,6 @@ export interface ContactPreview { name: string; message: string | null; image: string; - unreadMsgCount: number; - messageCount: number; contactDetails: Contact; isHidden: boolean; messageSizeLimit: number; @@ -55,8 +53,6 @@ export const getEmptyContact = (ensName: string, isHidden: boolean = false) => { name: getAccountDisplayName(ensName, 25), message: null, image: humanIcon, - unreadMsgCount: 0, - messageCount: 0, contactDetails: { account: { ensName, From 58df3ea68e3675128ec95b77cbee491c126d6488 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Thu, 27 Jun 2024 11:41:33 +0200 Subject: [PATCH 06/27] include preview message to useConversation --- .../src/new/cloudStorage/getCloudStorage.ts | 23 +++- packages/lib/storage/src/new/types.ts | 4 + .../testHelper/getMockedStorageContext.ts | 1 + .../src/hooks/conversation/hydrateContact.ts | 27 ++--- .../conversation/useConversation.test.tsx | 112 +++++++++++++++--- .../hooks/conversation/useConversation.tsx | 2 + 6 files changed, 135 insertions(+), 34 deletions(-) diff --git a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts index 79c566493..e4911a1a1 100644 --- a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts +++ b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts @@ -1,6 +1,8 @@ import { IBackendConnector } from '@dm3-org/dm3-lib-shared'; import { MessageRecord } from '../chunkStorage/ChunkStorageTypes'; import { Encryption, StorageAPI, StorageEnvelopContainer } from '../types'; +//getCloudStorages is the interface to the cloud storage. +//It encrypts and decrypts the data before sending/reciving it to/from the cloud storage of the DM3 backend export const getCloudStorage = ( backendConnector: IBackendConnector, ensName: string, @@ -24,11 +26,22 @@ export const getCloudStorage = ( ); return await Promise.all( - conversations.map(async ({ contact }: { contact: string }) => ({ - contactEnsName: await encryption.decryptSync(contact), - isHidden: false, - messageCounter: 0, - })), + conversations.map( + async ({ + contact, + previewMessage, + }: { + contact: string; + previewMessage: string | null; + }) => ({ + contactEnsName: await encryption.decryptSync(contact), + isHidden: false, + messageCounter: 0, + previewMessage: previewMessage + ? await encryption.decryptSync(previewMessage) + : null, + }), + ), ); }; const getMessages = async ( diff --git a/packages/lib/storage/src/new/types.ts b/packages/lib/storage/src/new/types.ts index 94ce4d8c3..8fcd284c9 100644 --- a/packages/lib/storage/src/new/types.ts +++ b/packages/lib/storage/src/new/types.ts @@ -34,7 +34,11 @@ export interface StorageEnvelopContainer { } export interface Conversation { + //the contactEnsName is the ensName of the contact contactEnsName: string; + //the previewMessage is the last message of the conversation + previewMessage: string | null; + //isHidden is a flag to hide the conversation from the conversation list isHidden: boolean; } diff --git a/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts b/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts index bf50d0d3e..e807f08aa 100644 --- a/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts +++ b/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts @@ -38,6 +38,7 @@ export const getMockedStorageContext = ( contactEnsName: 'max.eth', isHidden: false, messageCounter: 1, + previewMessage: null, }, ]); }, diff --git a/packages/messenger-widget/src/hooks/conversation/hydrateContact.ts b/packages/messenger-widget/src/hooks/conversation/hydrateContact.ts index 2df1e907a..9a7a4168e 100644 --- a/packages/messenger-widget/src/hooks/conversation/hydrateContact.ts +++ b/packages/messenger-widget/src/hooks/conversation/hydrateContact.ts @@ -15,25 +15,22 @@ import { fetchMessageSizeLimit } from '../messages/sizeLimit/fetchSizeLimit'; export const hydrateContract = async ( provider: ethers.providers.JsonRpcProvider, - conversatoinManifest: Conversation, + conversation: Conversation, resolveAliasToTLD: (alias: string) => Promise, addrEnsSubdomain: string, ) => { //If the profile property of the account is defined the user has already used DM3 previously - const account = await fetchAccount( - provider, - conversatoinManifest.contactEnsName, - ); + const account = await _fetchAccount(provider, conversation.contactEnsName); //Has to become fetchMultipleDsProfiles - const contact = await fetchDsProfiles(provider, account); + const contact = await _fetchDsProfiles(provider, account); //get the maximum size limit by looking for the smallest size limit of every ds const maximumSizeLimit = await fetchMessageSizeLimit( contact.deliveryServiceProfiles, ); - const contactPreview = await fetchPreview( + const contactPreview = await _fetchContactPreview( provider, - conversatoinManifest, + conversation, contact, resolveAliasToTLD, maximumSizeLimit, @@ -42,9 +39,9 @@ export const hydrateContract = async ( return contactPreview; }; -const fetchPreview = async ( +const _fetchContactPreview = async ( provider: ethers.providers.JsonRpcProvider, - conversatoinManifest: Conversation, + conversation: Conversation, contact: Contact, resolveAliasToTLD: (alias: string) => Promise, messageSizeLimit: number, @@ -53,19 +50,19 @@ const fetchPreview = async ( return { //display name, if alias is not defined the addr ens name will be used name: await resolveAliasToTLD(contact.account.ensName), - message: '', + message: conversation.previewMessage, image: await getAvatarProfilePic( provider, contact.account.ensName, addrEnsSubdomain, ), contactDetails: contact, - isHidden: conversatoinManifest.isHidden, + isHidden: conversation.isHidden, messageSizeLimit: messageSizeLimit, }; }; -const fetchAccount = async ( +const _fetchAccount = async ( provider: ethers.providers.JsonRpcProvider, contact: string, ): Promise => { @@ -93,13 +90,13 @@ const fetchAccount = async ( } }; -const fetchDsProfiles = async ( +const _fetchDsProfiles = async ( provider: ethers.providers.JsonRpcProvider, account: Account, ): Promise => { const deliveryServiceEnsNames = account.profile?.deliveryServices ?? []; if (deliveryServiceEnsNames.length === 0) { - //If there is now DS profile the message will be storaged at the client side until they recipient has createed an account + //If there is nop DS profile the message will be storaged at the client side until they recipient has createed an account console.debug( '[fetchDeliverServicePorfile] Cant resolve deliveryServiceEnsName', ); diff --git a/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx b/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx index 8967de73d..84652106f 100644 --- a/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx +++ b/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx @@ -350,6 +350,7 @@ describe('useConversation hook test cases', () => { //Use offset here to create a distinct contactEnsName contactEnsName: 'contact ' + i + offset, isHidden: false, + previewMessage: null, }; }), ); @@ -396,8 +397,8 @@ describe('useConversation hook test cases', () => { }); }); - describe('add conversation', () => { - it('Should add multiple contacts', async () => { + describe('initialize', () => { + it('reads conversations from storage', async () => { const authContext: AuthContextType = getMockedAuthContext({ account: { ensName: 'alice.eth', @@ -412,8 +413,15 @@ describe('useConversation hook test cases', () => { const storageContext: StorageContextType = getMockedStorageContext({ getConversations: function ( page: number, + offset: number, ): Promise { - return Promise.resolve([]); + return Promise.resolve([ + { + contactEnsName: 'max.eth', + previewMessage: null, + isHidden: false, + }, + ]); }, addConversationAsync: jest.fn(), initialized: true, @@ -446,16 +454,16 @@ describe('useConversation hook test cases', () => { const { result } = renderHook(() => useConversation(config), { wrapper, }); - await act(async () => result.current.addConversation('bob.eth')); - await act(async () => result.current.addConversation('liza.eth')); - await act(async () => result.current.addConversation('heroku.eth')); - await act(async () => result.current.addConversation('samar.eth')); - await waitFor(() => expect(result.current.contacts.length).toBe(4)); - }); - }); + await waitFor(() => expect(result.current.initialized).toBe(true)); - describe('initialize', () => { - it('reads conversations from storage', async () => { + const conversations = result.current.contacts; + + expect(conversations.length).toBe(1); + expect(conversations[0].contactDetails.account.ensName).toBe( + 'max.eth', + ); + }); + it('has last message attached as previewMessage', async () => { const authContext: AuthContextType = getMockedAuthContext({ account: { ensName: 'alice.eth', @@ -476,6 +484,12 @@ describe('useConversation hook test cases', () => { { contactEnsName: 'max.eth', isHidden: false, + previewMessage: null, + }, + { + contactEnsName: 'bob.eth', + previewMessage: 'Hello from Bob', + isHidden: false, }, ]); }, @@ -514,12 +528,18 @@ describe('useConversation hook test cases', () => { const conversations = result.current.contacts; - expect(conversations.length).toBe(1); + expect(conversations.length).toBe(2); expect(conversations[0].contactDetails.account.ensName).toBe( 'max.eth', ); + expect(conversations[1].contactDetails.account.ensName).toBe( + 'bob.eth', + ); + expect(conversations[1].contactDetails.account.ensName).toBe( + 'bob.eth', + ); }); - it('add default contact if specified in conversation list', async () => { + it('add default contact if specified in config ', async () => { const configurationContext = getMockedDm3Configuration({ dm3Configuration: { ...DEFAULT_DM3_CONFIGURATION, @@ -547,6 +567,7 @@ describe('useConversation hook test cases', () => { { contactEnsName: 'max.eth', isHidden: false, + previewMessage: null, }, ]); }, @@ -630,10 +651,12 @@ describe('useConversation hook test cases', () => { { contactEnsName: 'max.eth', isHidden: false, + previewMessage: null, }, { contactEnsName: 'mydefaultcontract.eth', isHidden: false, + previewMessage: null, }, ]); }, @@ -717,14 +740,17 @@ describe('useConversation hook test cases', () => { { contactEnsName: 'ron.eth', isHidden: true, + previewMessage: null, }, { contactEnsName: 'max.eth', isHidden: false, + previewMessage: null, }, { contactEnsName: 'mydefaultcontract.eth', isHidden: false, + previewMessage: null, }, ]); }, @@ -810,6 +836,7 @@ describe('useConversation hook test cases', () => { { contactEnsName: 'max.eth', isHidden: false, + previewMessage: null, }, ]); }, @@ -859,6 +886,61 @@ describe('useConversation hook test cases', () => { 'bob.eth', ); }); + it('Should add multiple contacts', async () => { + const authContext: AuthContextType = getMockedAuthContext({ + account: { + ensName: 'alice.eth', + profile: { + deliveryServices: ['ds.eth'], + publicEncryptionKey: '', + publicSigningKey: '', + }, + }, + }); + + const storageContext: StorageContextType = getMockedStorageContext({ + getConversations: function ( + page: number, + ): Promise { + return Promise.resolve([]); + }, + addConversationAsync: jest.fn(), + initialized: true, + }); + const deliveryServiceContext: DeliveryServiceContextType = + getMockedDeliveryServiceContext({ + fetchIncommingMessages: function (ensName: string) { + return Promise.resolve([]); + }, + getDeliveryServiceProperties: function (): Promise { + return Promise.resolve([{ sizeLimit: 0 }]); + }, + isInitialized: true, + }); + + const wrapper = ({ children }: { children: any }) => ( + <> + + + + {children} + + + + + ); + + const { result } = renderHook(() => useConversation(config), { + wrapper, + }); + await act(async () => result.current.addConversation('bob.eth')); + await act(async () => result.current.addConversation('liza.eth')); + await act(async () => result.current.addConversation('heroku.eth')); + await act(async () => result.current.addConversation('samar.eth')); + await waitFor(() => expect(result.current.contacts.length).toBe(4)); + }); }); describe('hydrate contact', () => { @@ -878,6 +960,7 @@ describe('useConversation hook test cases', () => { { contactEnsName: sender.account.ensName, isHidden: false, + previewMessage: null, }, ]); }, @@ -986,6 +1069,7 @@ describe('useConversation hook test cases', () => { { contactEnsName: sender.account.ensName, isHidden: false, + previewMessage: null, }, ]); }, diff --git a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx index 73e9e63a6..a5d2e8912 100644 --- a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx +++ b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx @@ -136,6 +136,7 @@ export const useConversation = (config: DM3Configuration) => { //I there are no conversations yet we add the default contact const defaultConversation: Conversation = { contactEnsName: normalizeEnsName(aliasName!), + previewMessage: null, isHidden: false, }; @@ -223,6 +224,7 @@ export const useConversation = (config: DM3Configuration) => { const hydrateExistingContactAsync = async (contact: ContactPreview) => { const conversation: Conversation = { contactEnsName: contact.contactDetails.account.ensName, + previewMessage: contact.message, isHidden: contact.isHidden, }; const hydratedContact = await hydrateContract( From 3ca311f6f915f9fdc5f66b35b9eea4c29e0b5903 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Thu, 27 Jun 2024 11:46:58 +0200 Subject: [PATCH 07/27] adjust migration test --- packages/lib/storage/src/migrate-storage.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/lib/storage/src/migrate-storage.test.ts b/packages/lib/storage/src/migrate-storage.test.ts index 6799e85d8..cc8dddb7e 100644 --- a/packages/lib/storage/src/migrate-storage.test.ts +++ b/packages/lib/storage/src/migrate-storage.test.ts @@ -70,11 +70,11 @@ describe('MigrateStorage', () => { const conversations = new Map(); return { - getConversationList: async (page: number) => + getConversations: async (page: number) => Array.from(conversations.keys()).map((contactEnsName) => ({ contactEnsName, isHidden: false, - messageCounter: 0, + previewMessage: null, })), getMessages: async (contactEnsName: string, page: number) => [], addMessageBatch: async ( @@ -125,7 +125,7 @@ describe('MigrateStorage', () => { await migrageStorage(db, newStorage, tldResolver); - const newConversations = await newStorage.getConversationList(0); + const newConversations = await newStorage.getConversations(100, 0); 0.45; expect(newConversations.length).toBe(2); expect(newConversations[0].contactEnsName).toBe( @@ -153,7 +153,7 @@ describe('MigrateStorage', () => { await migrageStorage(db, newStorage, tldResolver); - const newConversations = await newStorage.getConversationList(0); + const newConversations = await newStorage.getConversations(100, 0); 0.45; expect(newConversations.length).toBe(2); expect(newConversations[0].contactEnsName).toBe( From 921ef7e34d6ff270a260d3ca02102f7a64febe10 Mon Sep 17 00:00:00 2001 From: Bhupesh-MS Date: Thu, 27 Jun 2024 15:54:58 +0530 Subject: [PATCH 08/27] fixed contacts loading on scroll --- .../ConfigureProfileBox.css | 2 +- .../src/components/Contacts/Contacts.css | 4 ++ .../src/components/Contacts/Contacts.tsx | 64 ++++++++++--------- .../src/context/ConversationContext.tsx | 8 +-- .../getMockedConversationContext.ts | 2 +- .../hooks/conversation/useConversation.tsx | 3 +- .../src/views/LeftView/LeftView.tsx | 2 +- 7 files changed, 47 insertions(+), 38 deletions(-) diff --git a/packages/messenger-widget/src/components/ConfigureProfileBox/ConfigureProfileBox.css b/packages/messenger-widget/src/components/ConfigureProfileBox/ConfigureProfileBox.css index 1999c403c..5cba2991e 100644 --- a/packages/messenger-widget/src/components/ConfigureProfileBox/ConfigureProfileBox.css +++ b/packages/messenger-widget/src/components/ConfigureProfileBox/ConfigureProfileBox.css @@ -2,7 +2,7 @@ padding: 10px 1px 10px 0px; bottom: 1%; margin: 0rem 1rem 1rem 1rem; - margin-top: 0.5rem !important; + /* margin-top: 0.5rem !important; */ } .configure-msg-box { diff --git a/packages/messenger-widget/src/components/Contacts/Contacts.css b/packages/messenger-widget/src/components/Contacts/Contacts.css index a753c8c8d..5762d80a1 100644 --- a/packages/messenger-widget/src/components/Contacts/Contacts.css +++ b/packages/messenger-widget/src/components/Contacts/Contacts.css @@ -156,3 +156,7 @@ font-size: 12px !important; } } + +.infinite-scroll-component__outerdiv{ + height: 100vh; +} \ No newline at end of file diff --git a/packages/messenger-widget/src/components/Contacts/Contacts.tsx b/packages/messenger-widget/src/components/Contacts/Contacts.tsx index a52c0bae1..0c60cf3f8 100644 --- a/packages/messenger-widget/src/components/Contacts/Contacts.tsx +++ b/packages/messenger-widget/src/components/Contacts/Contacts.tsx @@ -16,6 +16,7 @@ import { DM3ConfigurationContext } from '../../context/DM3ConfigurationContext'; import { UiViewContext } from '../../context/UiViewContext'; import { ModalContext } from '../../context/ModalContext'; import InfiniteScroll from 'react-infinite-scroll-component'; +import ConfigureProfileBox from '../ConfigureProfileBox/ConfigureProfileBox'; export function Contacts() { const { dm3Configuration } = useContext(DM3ConfigurationContext); @@ -30,9 +31,16 @@ export function Contacts() { } = useContext(ConversationContext); const { setLastMessageAction } = useContext(ModalContext); - const [isMenuAlignedAtBottom, setIsMenuAlignedAtBottom] = useState< - boolean | null - >(null); + const [isMenuAlignedAtBottom, setIsMenuAlignedAtBottom] = useState(null); + + const [hasMoreContact, setHasMoreContact] = useState(true); + + const getMoreContacts = async () => { + const newContactsCount = await loadMoreConversations(); + if (!newContactsCount) { + setHasMoreContact(false); + } + } useEffect(() => { if ( @@ -100,28 +108,22 @@ export function Contacts() { return (
6 ? 'scroller-active' : 'scroller-hidden', - )} - style={{ - overflow: 'auto', - display: 'flex', - flexDirection: 'column-reverse', - }} + className={'contacts-scroller width-fill scroller-active'} > @@ -229,7 +231,7 @@ export function Contacts() { {selectedContact?.contactDetails .account.ensName === id ? ( selectedContact.message !== - null ? ( + null ? (
@@ -287,7 +289,7 @@ export function Contacts() { {/* Hidden content for highlighting css */} - {hiddenData.map((data) => ( + {/* {hiddenData.map((data) => (
- ))} + ))} */} + +
); -} +} \ No newline at end of file diff --git a/packages/messenger-widget/src/context/ConversationContext.tsx b/packages/messenger-widget/src/context/ConversationContext.tsx index db2ecfda2..2bc735666 100644 --- a/packages/messenger-widget/src/context/ConversationContext.tsx +++ b/packages/messenger-widget/src/context/ConversationContext.tsx @@ -11,22 +11,22 @@ export type ConversationContextType = { setSelectedContactName: (contactEnsName: string | undefined) => void; initialized: boolean; addConversation: (ensName: string) => ContactPreview | undefined; - loadMoreConversations: () => void; + loadMoreConversations: () => Promise; hideContact: (ensName: string) => void; }; export const ConversationContext = React.createContext( { contacts: [], - setSelectedContactName: (contactEnsName: string | undefined) => {}, + setSelectedContactName: (contactEnsName: string | undefined) => { }, conversationCount: 0, initialized: false, selectedContact: undefined, addConversation: (ensName: string) => { return {} as ContactPreview; }, - loadMoreConversations: () => {}, - hideContact: (ensName: string) => {}, + loadMoreConversations: () => { return new Promise((resolve, reject) => resolve(0)) }, + hideContact: (ensName: string) => { }, }, ); diff --git a/packages/messenger-widget/src/context/testHelper/getMockedConversationContext.ts b/packages/messenger-widget/src/context/testHelper/getMockedConversationContext.ts index 3718297d6..3affaa2b2 100644 --- a/packages/messenger-widget/src/context/testHelper/getMockedConversationContext.ts +++ b/packages/messenger-widget/src/context/testHelper/getMockedConversationContext.ts @@ -16,7 +16,7 @@ export const getMockedConversationContext = ( addConversation: (ensName: string) => { return {} as ContactPreview; }, - loadMoreConversations: () => {}, + loadMoreConversations: () => { return new Promise((resolve, reject) => resolve(0)) }, hideContact: (ensName: string) => {}, }; diff --git a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx index 923162d5a..f27e0174f 100644 --- a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx +++ b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx @@ -196,7 +196,7 @@ export const useConversation = (config: DM3Configuration) => { return conversationPreview; }; - const loadMoreConversations = async () => { + const loadMoreConversations = async (): Promise => { const hasDefaultContact = config.defaultContact !== undefined; //If a default contact is set we have to subtract one from the conversation count since its not part of the conversation list const conversationCount = hasDefaultContact @@ -215,6 +215,7 @@ export const useConversation = (config: DM3Configuration) => { conversation.isHidden, ); }); + return conversations.length; }; /** diff --git a/packages/messenger-widget/src/views/LeftView/LeftView.tsx b/packages/messenger-widget/src/views/LeftView/LeftView.tsx index b44d308c7..00b75edfa 100644 --- a/packages/messenger-widget/src/views/LeftView/LeftView.tsx +++ b/packages/messenger-widget/src/views/LeftView/LeftView.tsx @@ -103,7 +103,7 @@ export default function LeftView() {
- + {/* */}
Date: Thu, 27 Jun 2024 15:21:26 +0200 Subject: [PATCH 09/27] add pagination for messages --- .../testHelper/getMockedStorageContext.ts | 3 +- .../handleMessagesFromDeliveryService.ts | 49 ++-- .../sources/handleMessagesFromStorage.ts | 16 +- .../sources/handleMessagesFromWebSocket.ts | 6 +- .../src/hooks/messages/useMessage.test.tsx | 215 ++++++++++++++++++ .../src/hooks/messages/useMessage.tsx | 80 +++++-- 6 files changed, 320 insertions(+), 49 deletions(-) diff --git a/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts b/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts index e807f08aa..6c4643af9 100644 --- a/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts +++ b/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts @@ -50,7 +50,8 @@ export const getMockedStorageContext = ( }, getMessages: function ( contact: string, - page: number, + pageSize: number, + offset: number, ): Promise { throw new Error('Function not implemented.'); }, diff --git a/packages/messenger-widget/src/hooks/messages/sources/handleMessagesFromDeliveryService.ts b/packages/messenger-widget/src/hooks/messages/sources/handleMessagesFromDeliveryService.ts index f3dc3083d..0720843fa 100644 --- a/packages/messenger-widget/src/hooks/messages/sources/handleMessagesFromDeliveryService.ts +++ b/packages/messenger-widget/src/hooks/messages/sources/handleMessagesFromDeliveryService.ts @@ -4,7 +4,7 @@ import { Envelop, MessageState, } from '@dm3-org/dm3-lib-messaging'; -import { MessageModel } from '../useMessage'; +import { MessageModel, MessageSource } from '../useMessage'; import { Account, ProfileKeys } from '@dm3-org/dm3-lib-profile'; import { AddConversation, StoreMessageBatch } from '../../storage/useStorage'; import { Acknoledgment } from '@dm3-org/dm3-lib-delivery'; @@ -30,30 +30,33 @@ export const handleMessagesFromDeliveryService = async ( ); const incommingMessages: MessageModel[] = await Promise.all( - encryptedIncommingMessages.map(async (envelop: EncryptionEnvelop) => { - const decryptedEnvelop: Envelop = { - message: JSON.parse( - await decryptAsymmetric( - profileKeys?.encryptionKeyPair!, - JSON.parse(envelop.message), + encryptedIncommingMessages.map( + async (envelop: EncryptionEnvelop): Promise => { + const decryptedEnvelop: Envelop = { + message: JSON.parse( + await decryptAsymmetric( + profileKeys?.encryptionKeyPair!, + JSON.parse(envelop.message), + ), ), - ), - postmark: JSON.parse( - await decryptAsymmetric( - profileKeys?.encryptionKeyPair!, - JSON.parse(envelop.postmark!), + postmark: JSON.parse( + await decryptAsymmetric( + profileKeys?.encryptionKeyPair!, + JSON.parse(envelop.postmark!), + ), ), - ), - metadata: envelop.metadata, - }; - return { - envelop: decryptedEnvelop, - //Messages from the delivery service are already send by the sender - messageState: MessageState.Send, - messageChunkKey: '', - reactions: [], - }; - }), + metadata: envelop.metadata, + }; + return { + envelop: decryptedEnvelop, + //Messages from the delivery service are already send by the sender + messageState: MessageState.Send, + reactions: [], + //The source of the message is the delivery service + source: MessageSource.DeliveryService, + }; + }, + ), ); const messagesSortedASC = incommingMessages.sort((a, b) => { diff --git a/packages/messenger-widget/src/hooks/messages/sources/handleMessagesFromStorage.ts b/packages/messenger-widget/src/hooks/messages/sources/handleMessagesFromStorage.ts index 6e6370a64..2e127c65c 100644 --- a/packages/messenger-widget/src/hooks/messages/sources/handleMessagesFromStorage.ts +++ b/packages/messenger-widget/src/hooks/messages/sources/handleMessagesFromStorage.ts @@ -1,24 +1,30 @@ import { GetMessages } from '../../storage/useStorage'; -import { MessageModel } from '../useMessage'; +import { MessageModel, MessageSource } from '../useMessage'; export const handleMessagesFromStorage = async ( setContactsLoading: Function, - getNumberOfMessages: (contactName: string) => Promise, getMessagesFromStorage: GetMessages, contactName: string, + pageSize: number, + offSet: number, ) => { setContactsLoading((prev: string[]) => { return [...prev, contactName]; }); - const MAX_MESSAGES_PER_CHUNK = 100; - const numberOfmessages = await getNumberOfMessages(contactName); - const storedMessages = await getMessagesFromStorage(contactName, 100, 0); + + const storedMessages = await getMessagesFromStorage( + contactName, + pageSize, + offSet, + ); return storedMessages.map( (message) => ({ ...message, reactions: [], + //The message has been fetched from teh storage + source: MessageSource.Storage, } as MessageModel), ); }; diff --git a/packages/messenger-widget/src/hooks/messages/sources/handleMessagesFromWebSocket.ts b/packages/messenger-widget/src/hooks/messages/sources/handleMessagesFromWebSocket.ts index 40ac5a7bc..9fcdc9ae7 100644 --- a/packages/messenger-widget/src/hooks/messages/sources/handleMessagesFromWebSocket.ts +++ b/packages/messenger-widget/src/hooks/messages/sources/handleMessagesFromWebSocket.ts @@ -7,7 +7,7 @@ import { import { ProfileKeys, normalizeEnsName } from '@dm3-org/dm3-lib-profile'; import { ContactPreview } from '../../../interfaces/utils'; import { AddConversation, StoreMessageAsync } from '../../storage/useStorage'; -import { MessageStorage } from '../useMessage'; +import { MessageModel, MessageSource, MessageStorage } from '../useMessage'; export const handleMessagesFromWebSocket = async ( addConversation: AddConversation, @@ -46,11 +46,11 @@ export const handleMessagesFromWebSocket = async ( ? MessageState.Read : MessageState.Send; - const messageModel = { + const messageModel: MessageModel = { envelop: decryptedEnvelop, messageState, - messageChunkKey: '', reactions: [], + source: MessageSource.WebSocket, }; setMessages((prev: MessageStorage) => { //Check if message already exists diff --git a/packages/messenger-widget/src/hooks/messages/useMessage.test.tsx b/packages/messenger-widget/src/hooks/messages/useMessage.test.tsx index 724037375..8bc55b64b 100644 --- a/packages/messenger-widget/src/hooks/messages/useMessage.test.tsx +++ b/packages/messenger-widget/src/hooks/messages/useMessage.test.tsx @@ -645,4 +645,219 @@ describe('useMessage hook test cases', () => { expect(result.current.messages['alice.eth'].length).toBe(3); }); }); + describe('message pagination', () => { + let sender: MockedUserProfile; + let receiver: MockedUserProfile; + let ds: any; + + beforeEach(async () => { + sender = await mockUserProfile( + ethers.Wallet.createRandom(), + 'alice.eth', + ['https://example.com'], + ); + receiver = await mockUserProfile( + ethers.Wallet.createRandom(), + 'bob.eth', + ['https://example.com'], + ); + ds = await getMockDeliveryServiceProfile( + ethers.Wallet.createRandom(), + 'https://example.com', + ); + }); + it('should load more messages from Storage', async () => { + const messageFactory = MockMessageFactory(sender, receiver, ds); + //const messages + const storageContext = getMockedStorageContext({ + editMessageBatchAsync: jest.fn(), + storeMessageBatch: jest.fn(), + storeMessage: jest.fn(), + getMessages: async ( + contactName: string, + pageSize: number, + offset: number, + ) => + Promise.all( + Array.from({ length: pageSize }, (_, i) => + messageFactory.createStorageEnvelopContainer( + 'hello dm3 ' + i + offset, + ), + ), + ), + }); + const conversationContext = getMockedConversationContext({ + selectedContact: getEmptyContact('max.eth'), + contacts: [getEmptyContact('alice.eth')], + }); + const deliveryServiceContext = getMockedDeliveryServiceContext({ + onNewMessage: (cb: Function) => { + console.log('on new message'); + }, + fetchNewMessages: jest.fn().mockResolvedValue([]), + syncAcknowledgment: jest.fn(), + removeOnNewMessageListener: jest.fn(), + }); + const authContext = getMockedAuthContext({ + profileKeys: receiver.profileKeys, + account: { + ensName: 'bob.eth', + profile: { + deliveryServices: ['ds.eth'], + publicEncryptionKey: '', + publicSigningKey: '', + }, + }, + }); + const tldContext = getMockedTldContext({}); + + const wrapper = ({ children }: { children: any }) => ( + <> + + + + + + {children} + + + + + + + ); + + const { result } = renderHook(() => useMessage(), { + wrapper, + }); + //Wait until bobs messages have been initialized + await waitFor( + () => + result.current.contactIsLoading('alice.eth') === false && + result.current.messages['alice.eth'].length > 0, + ); + + expect(result.current.contactIsLoading('alice.eth')).toBe(false); + expect(result.current.messages['alice.eth'].length).toBe(100); + + await act(async () => result.current.loadMoreMessages('alice.eth')); + + //Wait until new messages have been loaded + await waitFor( + () => + result.current.contactIsLoading('alice.eth') === false && + result.current.messages['alice.eth'].length > 100, + ); + + expect(result.current.contactIsLoading('alice.eth')).toBe(false); + expect(result.current.messages['alice.eth'].length).toBe(200); + }); + it('messages from sources different as storage should not be considered in pagination calculation', async () => { + const messageFactory = MockMessageFactory(sender, receiver, ds); + //const messages + const storageContext = getMockedStorageContext({ + editMessageBatchAsync: jest.fn(), + storeMessageBatch: jest.fn(), + storeMessage: jest.fn(), + getMessages: async ( + contactName: string, + pageSize: number, + offset: number, + ) => + Promise.all( + Array.from({ length: pageSize }, (_, i) => + messageFactory.createStorageEnvelopContainer( + 'hello dm3 ' + i + offset, + ), + ), + ), + }); + const conversationContext = getMockedConversationContext({ + selectedContact: getEmptyContact('max.eth'), + contacts: [getEmptyContact('alice.eth')], + }); + const deliveryServiceContext = getMockedDeliveryServiceContext({ + onNewMessage: (cb: Function) => { + console.log('on new message'); + }, + fetchNewMessages: async (_: string) => + Promise.all( + Array.from({ length: 13 }, (_, i) => + messageFactory.createEncryptedEnvelop( + 'hello dm3 from ds' + i, + ), + ), + ), + syncAcknowledgment: jest.fn(), + removeOnNewMessageListener: jest.fn(), + }); + const authContext = getMockedAuthContext({ + profileKeys: receiver.profileKeys, + account: { + ensName: 'bob.eth', + profile: { + deliveryServices: ['ds.eth'], + publicEncryptionKey: '', + publicSigningKey: '', + }, + }, + }); + const tldContext = getMockedTldContext({}); + + const wrapper = ({ children }: { children: any }) => ( + <> + + + + + + {children} + + + + + + + ); + + const { result } = renderHook(() => useMessage(), { + wrapper, + }); + //Wait until bobs messages have been initialized + await waitFor( + () => + result.current.contactIsLoading('alice.eth') === false && + result.current.messages['alice.eth'].length > 0, + ); + + expect(result.current.contactIsLoading('alice.eth')).toBe(false); + //Initial message number would be storage(100) = Ds (13) == 113 + expect(result.current.messages['alice.eth'].length).toBe(113); + + await act(async () => result.current.loadMoreMessages('alice.eth')); + + //Wait until new messages have been loaded + await waitFor( + () => + result.current.contactIsLoading('alice.eth') === false && + result.current.messages['alice.eth'].length > 133, + ); + + expect(result.current.contactIsLoading('alice.eth')).toBe(false); + expect(result.current.messages['alice.eth'].length).toBe(213); + //991 = 99 message 100(since pageSize starts from 0) = 1 offset + expect( + result.current.messages['alice.eth'][212].envelop.message + .message, + ).toBe('hello dm3 991'); + }); + }); }); diff --git a/packages/messenger-widget/src/hooks/messages/useMessage.tsx b/packages/messenger-widget/src/hooks/messages/useMessage.tsx index 5d08fdabe..ea0a75afc 100644 --- a/packages/messenger-widget/src/hooks/messages/useMessage.tsx +++ b/packages/messenger-widget/src/hooks/messages/useMessage.tsx @@ -1,16 +1,14 @@ -import { encryptAsymmetric, sign } from '@dm3-org/dm3-lib-crypto'; +import { encryptAsymmetric } from '@dm3-org/dm3-lib-crypto'; import { - EncryptionEnvelop, DispatchableEnvelop, + EncryptionEnvelop, Envelop, Message, MessageState, buildEnvelop, } from '@dm3-org/dm3-lib-messaging'; -import { - DeliveryServiceProfile, - normalizeEnsName, -} from '@dm3-org/dm3-lib-profile'; +import { normalizeEnsName } from '@dm3-org/dm3-lib-profile'; +import { sha256, stringify } from '@dm3-org/dm3-lib-shared'; import { StorageEnvelopContainer as StorageEnvelopContainerNew } from '@dm3-org/dm3-lib-storage'; import axios from 'axios'; import { useCallback, useContext, useEffect, useState } from 'react'; @@ -24,12 +22,25 @@ import { checkIfEnvelopAreInSizeLimit } from './sizeLimit/checkIfEnvelopIsInSize import { handleMessagesFromDeliveryService } from './sources/handleMessagesFromDeliveryService'; import { handleMessagesFromStorage } from './sources/handleMessagesFromStorage'; import { handleMessagesFromWebSocket } from './sources/handleMessagesFromWebSocket'; -import { sha256, stringify } from '@dm3-org/dm3-lib-shared'; -import { ContactPreview } from '../../interfaces/utils'; + +const DEFAULT_MESSAGE_PAGESIZE = 100; + +//Message source to identify where a message comes from. This is important to handle pagination of storage messages properly +export enum MessageSource { + //Messages added by the client via addMessage + Client, + //Messages fetched from the storage + Storage, + //Messages fetched from the deliveryService + DeliveryService, + //Messages received from the Websocket + WebSocket, +} export type MessageModel = StorageEnvelopContainerNew & { reactions: Envelop[]; replyToMessageEnvelop?: Envelop; + source: MessageSource; }; export type MessageStorage = { @@ -51,7 +62,6 @@ export const useMessage = () => { const { resolveTLDtoAlias } = useContext(TLDContext); const { - getNumberOfMessages, getMessages: getMessagesFromStorage, storeMessage, storeMessageBatch, @@ -191,8 +201,6 @@ export const useMessage = () => { message: Message, ): Promise<{ isSuccess: boolean; error?: string }> => { const contact = normalizeEnsName(_contactName); - console.log(contacts); - //If a message is empty it should not be added if (!message.message || message.message.trim() === '') { @@ -229,7 +237,7 @@ export const useMessage = () => { }, }, messageState: MessageState.Created, - + source: MessageSource.Client, reactions: [], }; setMessages((prev) => { @@ -286,6 +294,8 @@ export const useMessage = () => { envelop: envelops[0].envelop, messageState: MessageState.Created, reactions: [], + //Message has just been created by the client + source: MessageSource.Client, }; //Add the message to the state @@ -339,9 +349,11 @@ export const useMessage = () => { const initialMessages = await Promise.all([ handleMessagesFromStorage( setContactsLoading, - getNumberOfMessages, getMessagesFromStorage, contactName, + DEFAULT_MESSAGE_PAGESIZE, + //For the first page we use 0 as offset + 0, ), handleMessagesFromDeliveryService( account!, @@ -353,13 +365,43 @@ export const useMessage = () => { syncAcknowledgment, ), ]); - const flatten = initialMessages.reduce( (acc, val) => acc.concat(val), [], ); - const messages = flatten + await _addMessages(contactName, flatten); + }; + + const loadMoreMessages = async (_contactName: string) => { + const contactName = normalizeEnsName(_contactName); + + const messagesFromContact = messages[contactName] ?? []; + //For the messageCount we only consider emssages from the MessageSource storage + const messageCount = messagesFromContact.filter( + (message) => message.source === MessageSource.Storage, + ).length; + + //We calculate the offset based on the messageCount + const offset = Math.floor(messageCount / DEFAULT_MESSAGE_PAGESIZE); + + const messagesFromStorage = await handleMessagesFromStorage( + setContactsLoading, + getMessagesFromStorage, + contactName, + DEFAULT_MESSAGE_PAGESIZE, + offset, + ); + await _addMessages(contactName, messagesFromStorage); + }; + + const _addMessages = async ( + _contactName: string, + newMessages: MessageModel[], + ) => { + const contactName = normalizeEnsName(_contactName); + + newMessages //filter duplicates .filter((message, index, self) => { if (!message.envelop.metadata?.encryptedMessageHash) { @@ -375,12 +417,15 @@ export const useMessage = () => { ); }); - const withResolvedAliasNames = await resolveAliasNames(messages); + const withResolvedAliasNames = await resolveAliasNames(newMessages); setMessages((prev) => { return { ...prev, - [contactName]: withResolvedAliasNames, + [contactName]: [ + ...(prev[contactName] ?? []), + ...withResolvedAliasNames, + ], }; }); @@ -423,6 +468,7 @@ export const useMessage = () => { getUnreadMessageCount, getMessages, addMessage, + loadMoreMessages, contactIsLoading, }; }; From d4d55278f5afc537f53864ce5c69f0795e450da2 Mon Sep 17 00:00:00 2001 From: Bhupesh-MS Date: Thu, 27 Jun 2024 19:14:28 +0530 Subject: [PATCH 10/27] fixed contacts pagination issue --- .../ConfigureProfileBox.css | 1 - .../ConfigureProfileBox.tsx | 2 +- .../src/components/Contacts/Contacts.css | 17 ++++----- .../src/components/Contacts/Contacts.tsx | 37 +++++++++---------- .../src/context/ConversationContext.tsx | 8 ++-- .../getMockedConversationContext.ts | 4 +- .../hooks/conversation/useConversation.tsx | 19 +++++++--- .../src/views/LeftView/LeftView.tsx | 19 ++++------ 8 files changed, 55 insertions(+), 52 deletions(-) diff --git a/packages/messenger-widget/src/components/ConfigureProfileBox/ConfigureProfileBox.css b/packages/messenger-widget/src/components/ConfigureProfileBox/ConfigureProfileBox.css index 5cba2991e..340b45fe2 100644 --- a/packages/messenger-widget/src/components/ConfigureProfileBox/ConfigureProfileBox.css +++ b/packages/messenger-widget/src/components/ConfigureProfileBox/ConfigureProfileBox.css @@ -2,7 +2,6 @@ padding: 10px 1px 10px 0px; bottom: 1%; margin: 0rem 1rem 1rem 1rem; - /* margin-top: 0.5rem !important; */ } .configure-msg-box { diff --git a/packages/messenger-widget/src/components/ConfigureProfileBox/ConfigureProfileBox.tsx b/packages/messenger-widget/src/components/ConfigureProfileBox/ConfigureProfileBox.tsx index d413bda76..af9883fb2 100644 --- a/packages/messenger-widget/src/components/ConfigureProfileBox/ConfigureProfileBox.tsx +++ b/packages/messenger-widget/src/components/ConfigureProfileBox/ConfigureProfileBox.tsx @@ -28,7 +28,7 @@ export default function ConfigureProfileBox() { return showConfigBox ? (
(null); + const [isMenuAlignedAtBottom, setIsMenuAlignedAtBottom] = useState< + boolean | null + >(null); const [hasMoreContact, setHasMoreContact] = useState(true); @@ -40,7 +41,7 @@ export function Contacts() { if (!newContactsCount) { setHasMoreContact(false); } - } + }; useEffect(() => { if ( @@ -116,7 +117,7 @@ export function Contacts() { style={{ display: 'flex', flexDirection: 'column', - overflow: "hidden" + overflow: 'hidden', }} inverse={false} hasMore={hasMoreContact} @@ -148,7 +149,7 @@ export function Contacts() { ' ', selectedContact ? selectedContact.contactDetails - .account.ensName !== id + .account.ensName !== id ? 'highlight-right-border' : 'contact-details-container-active' : '', @@ -200,9 +201,9 @@ export function Contacts() { title={ data.contactDetails ? data - .contactDetails - .account - .ensName + .contactDetails + .account + .ensName : '' } > @@ -231,7 +232,7 @@ export function Contacts() { {selectedContact?.contactDetails .account.ensName === id ? ( selectedContact.message !== - null ? ( + null ? (
@@ -301,8 +302,6 @@ export function Contacts() {
))} */} - -
); -} \ No newline at end of file +} diff --git a/packages/messenger-widget/src/context/ConversationContext.tsx b/packages/messenger-widget/src/context/ConversationContext.tsx index 2bc735666..40fc79ce4 100644 --- a/packages/messenger-widget/src/context/ConversationContext.tsx +++ b/packages/messenger-widget/src/context/ConversationContext.tsx @@ -18,15 +18,17 @@ export type ConversationContextType = { export const ConversationContext = React.createContext( { contacts: [], - setSelectedContactName: (contactEnsName: string | undefined) => { }, + setSelectedContactName: (contactEnsName: string | undefined) => {}, conversationCount: 0, initialized: false, selectedContact: undefined, addConversation: (ensName: string) => { return {} as ContactPreview; }, - loadMoreConversations: () => { return new Promise((resolve, reject) => resolve(0)) }, - hideContact: (ensName: string) => { }, + loadMoreConversations: () => { + return new Promise((resolve, reject) => resolve(0)); + }, + hideContact: (ensName: string) => {}, }, ); diff --git a/packages/messenger-widget/src/context/testHelper/getMockedConversationContext.ts b/packages/messenger-widget/src/context/testHelper/getMockedConversationContext.ts index 3affaa2b2..e9793edfd 100644 --- a/packages/messenger-widget/src/context/testHelper/getMockedConversationContext.ts +++ b/packages/messenger-widget/src/context/testHelper/getMockedConversationContext.ts @@ -16,7 +16,9 @@ export const getMockedConversationContext = ( addConversation: (ensName: string) => { return {} as ContactPreview; }, - loadMoreConversations: () => { return new Promise((resolve, reject) => resolve(0)) }, + loadMoreConversations: () => { + return new Promise((resolve, reject) => resolve(0)); + }, hideContact: (ensName: string) => {}, }; diff --git a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx index f27e0174f..c88725f88 100644 --- a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx +++ b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx @@ -209,13 +209,22 @@ export const useConversation = (config: DM3Configuration) => { DEFAULT_CONVERSATION_PAGE_SIZE, Math.floor(offset), ); + + let newContactAddedCount = 0; + conversations.forEach((conversation) => { - _addConversation( - conversation.contactEnsName, - conversation.isHidden, - ); + // check if the contact is really added in the list or not + // if its added it will return contact object else nothing + if ( + _addConversation( + conversation.contactEnsName, + conversation.isHidden, + ) + ) { + newContactAddedCount++; + } }); - return conversations.length; + return newContactAddedCount; }; /** diff --git a/packages/messenger-widget/src/views/LeftView/LeftView.tsx b/packages/messenger-widget/src/views/LeftView/LeftView.tsx index 00b75edfa..708e32e68 100644 --- a/packages/messenger-widget/src/views/LeftView/LeftView.tsx +++ b/packages/messenger-widget/src/views/LeftView/LeftView.tsx @@ -72,7 +72,7 @@ export default function LeftView() { return (
- {/* */} +
-
- -
+ {selectedLeftView === LeftViewSelected.Menu && ( +
+ +
+ )}
); } From dc3f47674adb01433264a20f79326801184316c9 Mon Sep 17 00:00:00 2001 From: Bhupesh-MS Date: Thu, 27 Jun 2024 19:48:54 +0530 Subject: [PATCH 11/27] removed condition which is of no use --- .../hooks/conversation/useConversation.tsx | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx index 47bb5552a..c0b6dfb6b 100644 --- a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx +++ b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx @@ -210,21 +210,14 @@ export const useConversation = (config: DM3Configuration) => { Math.floor(offset), ); - let newContactAddedCount = 0; - conversations.forEach((conversation) => { - // check if the contact is really added in the list or not - // if its added it will return contact object else nothing - if ( - _addConversation( - conversation.contactEnsName, - conversation.isHidden, - ) - ) { - newContactAddedCount++; - } + _addConversation( + conversation.contactEnsName, + conversation.isHidden, + ); }); - return newContactAddedCount; + + return conversations.length; }; /** From b868cb9f42bc095c499642e7bdf09c27b4e43423 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Thu, 27 Jun 2024 16:39:53 +0200 Subject: [PATCH 12/27] add createdAt to addMessage method --- packages/lib/shared/src/IBackendConnector.ts | 1 + .../src/new/cloudStorage/getCloudStorage.ts | 4 + .../src/components/Chat/Chat.tsx | 113 ++++++++++++------ .../src/components/Contacts/Contacts.tsx | 4 +- .../src/context/BackendContext.tsx | 1 + .../src/context/MessageContext.tsx | 4 + .../src/hooks/server-side/BackendConnector.ts | 2 + .../src/hooks/server-side/useBackend.ts | 2 + 8 files changed, 91 insertions(+), 40 deletions(-) diff --git a/packages/lib/shared/src/IBackendConnector.ts b/packages/lib/shared/src/IBackendConnector.ts index c5ce7eedd..b37dd01e4 100644 --- a/packages/lib/shared/src/IBackendConnector.ts +++ b/packages/lib/shared/src/IBackendConnector.ts @@ -25,6 +25,7 @@ export interface IBackendConnector { ensName: string, encryptedContactName: string, messageId: string, + createdAt: number, encryptedEnvelopContainer: string, ): Promise; addMessageBatch( diff --git a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts index e4911a1a1..08e6ee6b8 100644 --- a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts +++ b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts @@ -83,11 +83,15 @@ export const getCloudStorage = ( JSON.stringify(envelop), ); + //The client defines the createdAt timestamp for the message so it can be used to sort the messages + const createdAt = Date.now(); + await backendConnector.addMessage( ensName, encryptedContactName, envelop.envelop.metadata?.encryptedMessageHash! ?? envelop.envelop.id, + createdAt, encryptedEnvelopContainer, ); diff --git a/packages/messenger-widget/src/components/Chat/Chat.tsx b/packages/messenger-widget/src/components/Chat/Chat.tsx index c84e131c6..f558fc708 100644 --- a/packages/messenger-widget/src/components/Chat/Chat.tsx +++ b/packages/messenger-widget/src/components/Chat/Chat.tsx @@ -12,6 +12,7 @@ import { Message } from '../Message/Message'; import { MessageInputBox } from '../MessageInputBox/MessageInputBox'; import { scrollToBottomOfChat } from './scrollToBottomOfChat'; import { ModalContext } from '../../context/ModalContext'; +import InfiniteScroll from 'react-infinite-scroll-component'; export function Chat() { const { account } = useContext(AuthContext); @@ -20,7 +21,8 @@ export function Chat() { const { screenWidth, dm3Configuration } = useContext( DM3ConfigurationContext, ); - const { getMessages, contactIsLoading } = useContext(MessageContext); + const { getMessages, contactIsLoading, loadMoreMessages } = + useContext(MessageContext); const { lastMessageAction } = useContext(ModalContext); const [isProfileConfigured, setIsProfileConfigured] = @@ -142,44 +144,79 @@ export function Chat() { ? 'chat-height-small' : 'chat-height-high', )} + style={{ + overflow: 'auto', + display: 'flex', + flexDirection: 'column-reverse', + }} > - {messages.length > 0 && - messages.map( - ( - storageEnvelopContainer: MessageModel, - index, - ) => ( -
- -
- ), - )} + + loadMoreMessages( + selectedContact?.contactDetails.account + .ensName!, + ) + } + style={{ + display: 'flex', + flexDirection: 'column-reverse', + }} //To put endMessage and loader to the top. + inverse={true} + hasMore={true} + loader={ +

+ Loading old messages... +

+ } + scrollableTarget="chat-box" + > + {messages.length > 0 && + messages.map( + ( + storageEnvelopContainer: MessageModel, + index, + ) => ( +
+ +
+ ), + )} +
{/* Message, emoji and file attachments */} diff --git a/packages/messenger-widget/src/components/Contacts/Contacts.tsx b/packages/messenger-widget/src/components/Contacts/Contacts.tsx index a52c0bae1..3b562d8f9 100644 --- a/packages/messenger-widget/src/components/Contacts/Contacts.tsx +++ b/packages/messenger-widget/src/components/Contacts/Contacts.tsx @@ -225,10 +225,10 @@ export function Contacts() {
)} - + {/* //TODO add loading state for message */} {selectedContact?.contactDetails .account.ensName === id ? ( - selectedContact.message !== + selectedContact.message === null ? (
diff --git a/packages/messenger-widget/src/context/BackendContext.tsx b/packages/messenger-widget/src/context/BackendContext.tsx index 0af02558a..53b2ece63 100644 --- a/packages/messenger-widget/src/context/BackendContext.tsx +++ b/packages/messenger-widget/src/context/BackendContext.tsx @@ -29,6 +29,7 @@ export type BackendContextType = { ensName: string, encryptedContactName: string, messageId: string, + createdAt: number, encryptedEnvelopContainer: string, ) => Promise; addMessageBatch: ( diff --git a/packages/messenger-widget/src/context/MessageContext.tsx b/packages/messenger-widget/src/context/MessageContext.tsx index 1208430cd..f015a3444 100644 --- a/packages/messenger-widget/src/context/MessageContext.tsx +++ b/packages/messenger-widget/src/context/MessageContext.tsx @@ -11,6 +11,7 @@ export type MessageContextType = { getMessages: GetMessages; getUnreadMessageCount: (contact: string) => number; addMessage: AddMessage; + loadMoreMessages: (contact: string) => void; contactIsLoading: (contact: string) => boolean; messages: MessageStorage; }; @@ -22,6 +23,7 @@ export const MessageContext = React.createContext({ new Promise(() => { isSuccess: true; }), + loadMoreMessages: (contact: string) => {}, contactIsLoading: (contact: string) => false, messages: {}, }); @@ -30,6 +32,7 @@ export const MessageContextProvider = ({ children }: { children?: any }) => { const { addMessage, getMessages, + loadMoreMessages, getUnreadMessageCount, contactIsLoading, messages, @@ -40,6 +43,7 @@ export const MessageContextProvider = ({ children }: { children?: any }) => { value={{ addMessage, getMessages, + loadMoreMessages, getUnreadMessageCount, contactIsLoading, messages, diff --git a/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts b/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts index 4aa0729d0..0924b8012 100644 --- a/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts +++ b/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts @@ -74,12 +74,14 @@ export class BackendConnector ensName: string, encryptedContactName: string, messageId: string, + createdAt: number, encryptedEnvelopContainer: string, ) { const url = `/storage/new/${normalizeEnsName(ensName)}/addMessage`; await this.getAuthenticatedAxiosClient().post(url, { encryptedContactName, messageId, + createdAt, encryptedEnvelopContainer, }); } diff --git a/packages/messenger-widget/src/hooks/server-side/useBackend.ts b/packages/messenger-widget/src/hooks/server-side/useBackend.ts index 9c5be3725..4e81afc90 100644 --- a/packages/messenger-widget/src/hooks/server-side/useBackend.ts +++ b/packages/messenger-widget/src/hooks/server-side/useBackend.ts @@ -90,12 +90,14 @@ export const useBackend = (): IBackendConnector & { ensName: string, encryptedContactName: string, messageId: string, + createdAt: number, encryptedEnvelopContainer: string, ) => { return beConnector?.addMessage( ensName, encryptedContactName, messageId, + createdAt, encryptedEnvelopContainer, ); }, From c132b542b58a4fdb5eb6b5ffe9f0eb66e179578d Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Thu, 27 Jun 2024 17:48:05 +0200 Subject: [PATCH 13/27] normalize contact before storing them --- .../lib/storage/src/new/cloudStorage/getCloudStorage.ts | 1 - .../src/hooks/conversation/useConversation.tsx | 7 +++++-- .../messenger-widget/src/hooks/messages/useMessage.tsx | 6 ++++-- .../messenger-widget/src/hooks/storage/useStorage.tsx | 9 ++------- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts index 08e6ee6b8..0a7aa8089 100644 --- a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts +++ b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts @@ -68,7 +68,6 @@ export const getCloudStorage = ( }), ); - //TODO make type right return decryptedMessageRecords as StorageEnvelopContainer[]; }; diff --git a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx index c0b6dfb6b..4b93628e3 100644 --- a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx +++ b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx @@ -88,6 +88,8 @@ export const useConversation = (config: DM3Configuration) => { getConversationsFromDeliveryService(), ]); + console.log('conversations', conversations); + //Flatten the conversations and remove duplicates conversations .flat() @@ -187,10 +189,11 @@ export const useConversation = (config: DM3Configuration) => { }; const addConversation = (_ensName: string) => { + const contact = normalizeEnsName(_ensName); //Adds the conversation to the conversation state - const conversationPreview = _addConversation(_ensName, false); + const conversationPreview = _addConversation(contact, false); //Add the contact to the storage in the background - storeConversationAsync(_ensName); + storeConversationAsync(contact); return conversationPreview; }; diff --git a/packages/messenger-widget/src/hooks/messages/useMessage.tsx b/packages/messenger-widget/src/hooks/messages/useMessage.tsx index ea0a75afc..f01ebf625 100644 --- a/packages/messenger-widget/src/hooks/messages/useMessage.tsx +++ b/packages/messenger-widget/src/hooks/messages/useMessage.tsx @@ -112,11 +112,13 @@ export const useMessage = () => { //Mark messages as read when the selected contact changes useEffect(() => { - const contact = selectedContact?.contactDetails.account.ensName; - if (!contact) { + const _contact = selectedContact?.contactDetails.account.ensName; + if (!_contact) { return; } + const contact = normalizeEnsName(_contact); + const unreadMessages = (messages[contact] ?? []).filter( (message) => message.messageState !== MessageState.Read && diff --git a/packages/messenger-widget/src/hooks/storage/useStorage.tsx b/packages/messenger-widget/src/hooks/storage/useStorage.tsx index 98870a760..927ddf714 100644 --- a/packages/messenger-widget/src/hooks/storage/useStorage.tsx +++ b/packages/messenger-widget/src/hooks/storage/useStorage.tsx @@ -94,13 +94,8 @@ export const useStorage = ( if (!storageApi) { throw Error('Storage not initialized'); } - /** - * Because the storage cannot handle concurrency properly - * we need to catch the error and retry if the message is not yet synced - */ - storageApi.editMessageBatch(contact, batch).catch((e) => { - console.log('message not sync yet'); - }); + + storageApi.editMessageBatch(contact, batch); }; const storeMessageAsync = ( From 10c15b41488c939018f45aa37ff31dd86e52b6ab Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Thu, 27 Jun 2024 18:50:25 +0200 Subject: [PATCH 14/27] show preview message in conversation list --- .../src/new/cloudStorage/getCloudStorage.ts | 4 +- .../src/components/Contacts/Contacts.tsx | 18 +++++-- .../hooks/conversation/useConversation.tsx | 49 ++++++++++-------- .../src/hooks/messages/useMessage.test.tsx | 26 +++++----- .../src/hooks/messages/useMessage.tsx | 51 +++++++++---------- .../messenger-widget/src/interfaces/utils.ts | 8 ++- 6 files changed, 88 insertions(+), 68 deletions(-) diff --git a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts index 0a7aa8089..e399c64f7 100644 --- a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts +++ b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts @@ -38,7 +38,9 @@ export const getCloudStorage = ( isHidden: false, messageCounter: 0, previewMessage: previewMessage - ? await encryption.decryptSync(previewMessage) + ? JSON.parse( + await encryption.decryptAsync(previewMessage), + ) : null, }), ), diff --git a/packages/messenger-widget/src/components/Contacts/Contacts.tsx b/packages/messenger-widget/src/components/Contacts/Contacts.tsx index fcf66bd71..e920673b6 100644 --- a/packages/messenger-widget/src/components/Contacts/Contacts.tsx +++ b/packages/messenger-widget/src/components/Contacts/Contacts.tsx @@ -10,7 +10,10 @@ import { } from '../../utils/enum-type-utils'; import { ContactMenu } from '../ContactMenu/ContactMenu'; import { showMenuInBottom } from './bl'; -import { getAccountDisplayName } from '@dm3-org/dm3-lib-profile'; +import { + getAccountDisplayName, + normalizeEnsName, +} from '@dm3-org/dm3-lib-profile'; import { ContactPreview } from '../../interfaces/utils'; import { DM3ConfigurationContext } from '../../context/DM3ConfigurationContext'; import { UiViewContext } from '../../context/UiViewContext'; @@ -98,12 +101,19 @@ export function Contacts() { }); } - const getPreviewMessage = (contact: string) => { - const messages = getMessages(contact); + const getPreviewMessage = (contactEnsName: string) => { + const _contact = normalizeEnsName(contactEnsName); + const messages = getMessages(_contact); + if (messages?.length > 0) { return messages[messages.length - 1].envelop.message.message ?? ''; } - return ''; + const contact = contacts.find( + (c) => c.contactDetails.account.ensName === _contact, + ); + const previewMessage = contact?.message; + console.log('previewMessage', previewMessage); + return previewMessage ?? ''; }; return ( diff --git a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx index 4b93628e3..8bb56a953 100644 --- a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx +++ b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx @@ -2,6 +2,7 @@ import { DeliveryInformation, EncryptionEnvelop, + Envelop, } from '@dm3-org/dm3-lib-messaging'; import { normalizeEnsName } from '@dm3-org/dm3-lib-profile'; import { Conversation } from '@dm3-org/dm3-lib-storage/dist/new/types'; @@ -15,6 +16,7 @@ import { DM3Configuration } from '../../interfaces/config'; import { ContactPreview, getEmptyContact } from '../../interfaces/utils'; import { useMainnetProvider } from '../mainnetprovider/useMainnetProvider'; import { hydrateContract } from './hydrateContact'; +import { StorageEnvelopContainer } from '@dm3-org/dm3-lib-storage/dist/Storage'; const DEFAULT_CONVERSATION_PAGE_SIZE = 10; @@ -88,8 +90,6 @@ export const useConversation = (config: DM3Configuration) => { getConversationsFromDeliveryService(), ]); - console.log('conversations', conversations); - //Flatten the conversations and remove duplicates conversations .flat() @@ -103,12 +103,7 @@ export const useConversation = (config: DM3Configuration) => { ), ) //Add the conversations to the list - .forEach((conversation) => { - _addConversation( - conversation.contactEnsName, - conversation.isHidden, - ); - }); + .forEach((conversation) => _addConversation(conversation)); initDefaultContact(); setConversationsInitialized(true); @@ -189,12 +184,16 @@ export const useConversation = (config: DM3Configuration) => { }; const addConversation = (_ensName: string) => { - const contact = normalizeEnsName(_ensName); + const contactEnsName = normalizeEnsName(_ensName); + const newConversation: Conversation = { + contactEnsName, + isHidden: false, + previewMessage: null, + }; //Adds the conversation to the conversation state - const conversationPreview = _addConversation(contact, false); + const conversationPreview = _addConversation(newConversation); //Add the contact to the storage in the background - storeConversationAsync(contact); - + storeConversationAsync(contactEnsName); return conversationPreview; }; @@ -213,13 +212,8 @@ export const useConversation = (config: DM3Configuration) => { Math.floor(offset), ); - conversations.forEach((conversation) => { - _addConversation( - conversation.contactEnsName, - conversation.isHidden, - ); - }); - + //add every conversation + conversations.forEach((conversation) => _addConversation(conversation)); return conversations.length; }; @@ -287,8 +281,8 @@ export const useConversation = (config: DM3Configuration) => { //update the storage toggleHideContactAsync(ensName, isHidden); }; - const _addConversation = (_ensName: string, isHidden: boolean) => { - const ensName = normalizeEnsName(_ensName); + const _addConversation = (conversation: Conversation) => { + const ensName = normalizeEnsName(conversation.contactEnsName); //Check if the contact is the user itself const isOwnContact = normalizeEnsName(account!.ensName) === ensName; //We don't want to add ourselfs @@ -308,7 +302,18 @@ export const useConversation = (config: DM3Configuration) => { return alreadyAddedContact; } - const newContact: ContactPreview = getEmptyContact(ensName, isHidden); + //If the conversation already contains messages the preview message is the last message. The backend attaches that message to the conversation so we can use it here and safe a request to fetch the messages + const previewMessage = conversation.previewMessage + ? ( + conversation.previewMessage as unknown as StorageEnvelopContainer + ).envelop.message.message ?? '' + : null; + + const newContact: ContactPreview = getEmptyContact( + ensName, + previewMessage, + conversation.isHidden, + ); //Set the new contact to the list _setContactsSafe([newContact]); //Hydrate the contact in the background diff --git a/packages/messenger-widget/src/hooks/messages/useMessage.test.tsx b/packages/messenger-widget/src/hooks/messages/useMessage.test.tsx index 8bc55b64b..02ecf06a0 100644 --- a/packages/messenger-widget/src/hooks/messages/useMessage.test.tsx +++ b/packages/messenger-widget/src/hooks/messages/useMessage.test.tsx @@ -98,7 +98,7 @@ describe('useMessage hook test cases', () => { storeMessage: jest.fn(), }); const conversationContext = getMockedConversationContext({ - selectedContact: getEmptyContact('max.eth'), + selectedContact: getEmptyContact('max.eth', null), }); const deliveryServiceContext = getMockedDeliveryServiceContext({ //Add websocket mock @@ -155,7 +155,7 @@ describe('useMessage hook test cases', () => { storeMessage: jest.fn(), }); const conversationContext = getMockedConversationContext({ - selectedContact: getEmptyContact('max.eth'), + selectedContact: getEmptyContact('max.eth', null), }); const deliveryServiceContext = getMockedDeliveryServiceContext({ //Add websocket mock @@ -212,7 +212,7 @@ describe('useMessage hook test cases', () => { storeMessage: jest.fn(), }); const conversationContext = getMockedConversationContext({ - selectedContact: getEmptyContact('max.eth'), + selectedContact: getEmptyContact('max.eth', null), }); const deliveryServiceContext = getMockedDeliveryServiceContext({ //Add websocket mock @@ -279,7 +279,7 @@ describe('useMessage hook test cases', () => { }); const conversationContext = getMockedConversationContext({ - selectedContact: getEmptyContact('max.eth'), + selectedContact: getEmptyContact('max.eth', null), contacts: [ { name: '', @@ -380,7 +380,7 @@ describe('useMessage hook test cases', () => { }); const conversationContext = getMockedConversationContext({ - selectedContact: getEmptyContact('max.eth'), + selectedContact: getEmptyContact('max.eth', null), contacts: [ { name: '', @@ -508,8 +508,8 @@ describe('useMessage hook test cases', () => { getNumberOfMessages: jest.fn().mockResolvedValue(3), }); const conversationContext = getMockedConversationContext({ - selectedContact: getEmptyContact('max.eth'), - contacts: [getEmptyContact('alice.eth')], + selectedContact: getEmptyContact('max.eth', null), + contacts: [getEmptyContact('alice.eth', null)], }); const deliveryServiceContext = getMockedDeliveryServiceContext({ onNewMessage: (cb: Function) => { @@ -585,8 +585,8 @@ describe('useMessage hook test cases', () => { getNumberOfMessages: jest.fn().mockResolvedValue(0), }); const conversationContext = getMockedConversationContext({ - selectedContact: getEmptyContact('max.eth'), - contacts: [getEmptyContact('alice.eth')], + selectedContact: getEmptyContact('max.eth', null), + contacts: [getEmptyContact('alice.eth', null)], }); const deliveryServiceContext = getMockedDeliveryServiceContext({ onNewMessage: (cb: Function) => { @@ -687,8 +687,8 @@ describe('useMessage hook test cases', () => { ), }); const conversationContext = getMockedConversationContext({ - selectedContact: getEmptyContact('max.eth'), - contacts: [getEmptyContact('alice.eth')], + selectedContact: getEmptyContact('max.eth', null), + contacts: [getEmptyContact('alice.eth', null)], }); const deliveryServiceContext = getMockedDeliveryServiceContext({ onNewMessage: (cb: Function) => { @@ -777,8 +777,8 @@ describe('useMessage hook test cases', () => { ), }); const conversationContext = getMockedConversationContext({ - selectedContact: getEmptyContact('max.eth'), - contacts: [getEmptyContact('alice.eth')], + selectedContact: getEmptyContact('max.eth', null), + contacts: [getEmptyContact('alice.eth', null)], }); const deliveryServiceContext = getMockedDeliveryServiceContext({ onNewMessage: (cb: Function) => { diff --git a/packages/messenger-widget/src/hooks/messages/useMessage.tsx b/packages/messenger-widget/src/hooks/messages/useMessage.tsx index f01ebf625..5511a50a4 100644 --- a/packages/messenger-widget/src/hooks/messages/useMessage.tsx +++ b/packages/messenger-widget/src/hooks/messages/useMessage.tsx @@ -347,32 +347,31 @@ export const useMessage = () => { }; const loadInitialMessages = async (_contactName: string) => { - const contactName = normalizeEnsName(_contactName); - const initialMessages = await Promise.all([ - handleMessagesFromStorage( - setContactsLoading, - getMessagesFromStorage, - contactName, - DEFAULT_MESSAGE_PAGESIZE, - //For the first page we use 0 as offset - 0, - ), - handleMessagesFromDeliveryService( - account!, - profileKeys!, - addConversation, - storeMessageBatch, - contactName, - fetchNewMessages, - syncAcknowledgment, - ), - ]); - const flatten = initialMessages.reduce( - (acc, val) => acc.concat(val), - [], - ); - - await _addMessages(contactName, flatten); + // const contactName = normalizeEnsName(_contactName); + // const initialMessages = await Promise.all([ + // handleMessagesFromStorage( + // setContactsLoading, + // getMessagesFromStorage, + // contactName, + // DEFAULT_MESSAGE_PAGESIZE, + // //For the first page we use 0 as offset + // 0, + // ), + // handleMessagesFromDeliveryService( + // account!, + // profileKeys!, + // addConversation, + // storeMessageBatch, + // contactName, + // fetchNewMessages, + // syncAcknowledgment, + // ), + // ]); + // const flatten = initialMessages.reduce( + // (acc, val) => acc.concat(val), + // [], + // ); + // await _addMessages(contactName, flatten); }; const loadMoreMessages = async (_contactName: string) => { diff --git a/packages/messenger-widget/src/interfaces/utils.ts b/packages/messenger-widget/src/interfaces/utils.ts index b89f820f1..5eae356f2 100644 --- a/packages/messenger-widget/src/interfaces/utils.ts +++ b/packages/messenger-widget/src/interfaces/utils.ts @@ -48,10 +48,14 @@ export interface IAttachmentPreview { isImage: boolean; } -export const getEmptyContact = (ensName: string, isHidden: boolean = false) => { +export const getEmptyContact = ( + ensName: string, + message: string | null, + isHidden: boolean = false, +) => { const newContact: ContactPreview = { name: getAccountDisplayName(ensName, 25), - message: null, + message, image: humanIcon, contactDetails: { account: { From 3c47ecbdd294f36fb9b392f5c49566ed53f3dbca Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Thu, 27 Jun 2024 18:51:48 +0200 Subject: [PATCH 15/27] return load initial messages --- .../src/hooks/messages/useMessage.tsx | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/packages/messenger-widget/src/hooks/messages/useMessage.tsx b/packages/messenger-widget/src/hooks/messages/useMessage.tsx index 5511a50a4..f673f9774 100644 --- a/packages/messenger-widget/src/hooks/messages/useMessage.tsx +++ b/packages/messenger-widget/src/hooks/messages/useMessage.tsx @@ -347,31 +347,31 @@ export const useMessage = () => { }; const loadInitialMessages = async (_contactName: string) => { - // const contactName = normalizeEnsName(_contactName); - // const initialMessages = await Promise.all([ - // handleMessagesFromStorage( - // setContactsLoading, - // getMessagesFromStorage, - // contactName, - // DEFAULT_MESSAGE_PAGESIZE, - // //For the first page we use 0 as offset - // 0, - // ), - // handleMessagesFromDeliveryService( - // account!, - // profileKeys!, - // addConversation, - // storeMessageBatch, - // contactName, - // fetchNewMessages, - // syncAcknowledgment, - // ), - // ]); - // const flatten = initialMessages.reduce( - // (acc, val) => acc.concat(val), - // [], - // ); - // await _addMessages(contactName, flatten); + const contactName = normalizeEnsName(_contactName); + const initialMessages = await Promise.all([ + handleMessagesFromStorage( + setContactsLoading, + getMessagesFromStorage, + contactName, + DEFAULT_MESSAGE_PAGESIZE, + //For the first page we use 0 as offset + 0, + ), + handleMessagesFromDeliveryService( + account!, + profileKeys!, + addConversation, + storeMessageBatch, + contactName, + fetchNewMessages, + syncAcknowledgment, + ), + ]); + const flatten = initialMessages.reduce( + (acc, val) => acc.concat(val), + [], + ); + await _addMessages(contactName, flatten); }; const loadMoreMessages = async (_contactName: string) => { From a47c23bb524714e8fc0df3df998bacf29c02b0f2 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Thu, 27 Jun 2024 19:07:19 +0200 Subject: [PATCH 16/27] use envelop type instead of string --- packages/lib/storage/src/new/types.ts | 2 +- .../testHelper/getMockedStorageContext.ts | 2 +- .../src/hooks/conversation/hydrateContact.ts | 2 +- .../conversation/useConversation.test.tsx | 33 +++++++++++-------- .../hooks/conversation/useConversation.tsx | 12 +++---- .../src/hooks/messages/useMessage.test.tsx | 26 +++++++-------- .../messenger-widget/src/interfaces/utils.ts | 4 +-- 7 files changed, 42 insertions(+), 39 deletions(-) diff --git a/packages/lib/storage/src/new/types.ts b/packages/lib/storage/src/new/types.ts index 8fcd284c9..328f8f491 100644 --- a/packages/lib/storage/src/new/types.ts +++ b/packages/lib/storage/src/new/types.ts @@ -37,7 +37,7 @@ export interface Conversation { //the contactEnsName is the ensName of the contact contactEnsName: string; //the previewMessage is the last message of the conversation - previewMessage: string | null; + previewMessage?: Envelop; //isHidden is a flag to hide the conversation from the conversation list isHidden: boolean; } diff --git a/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts b/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts index 6c4643af9..3210e4784 100644 --- a/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts +++ b/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts @@ -38,7 +38,7 @@ export const getMockedStorageContext = ( contactEnsName: 'max.eth', isHidden: false, messageCounter: 1, - previewMessage: null, + previewMessage: undefined, }, ]); }, diff --git a/packages/messenger-widget/src/hooks/conversation/hydrateContact.ts b/packages/messenger-widget/src/hooks/conversation/hydrateContact.ts index 9a7a4168e..b6cd4a3a1 100644 --- a/packages/messenger-widget/src/hooks/conversation/hydrateContact.ts +++ b/packages/messenger-widget/src/hooks/conversation/hydrateContact.ts @@ -50,7 +50,7 @@ const _fetchContactPreview = async ( return { //display name, if alias is not defined the addr ens name will be used name: await resolveAliasToTLD(contact.account.ensName), - message: conversation.previewMessage, + message: conversation.previewMessage?.message.message, image: await getAvatarProfilePic( provider, contact.account.ensName, diff --git a/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx b/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx index 84652106f..4dc393377 100644 --- a/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx +++ b/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx @@ -35,6 +35,7 @@ import { } from '@dm3-org/dm3-lib-test-helper'; import MockAdapter from 'axios-mock-adapter'; import axios from 'axios'; +import { Envelop } from '@dm3-org/dm3-lib-messaging'; describe('useConversation hook test cases', () => { let sender: MockedUserProfile; @@ -350,7 +351,7 @@ describe('useConversation hook test cases', () => { //Use offset here to create a distinct contactEnsName contactEnsName: 'contact ' + i + offset, isHidden: false, - previewMessage: null, + previewMessage: undefined, }; }), ); @@ -418,7 +419,7 @@ describe('useConversation hook test cases', () => { return Promise.resolve([ { contactEnsName: 'max.eth', - previewMessage: null, + previewMessage: undefined, isHidden: false, }, ]); @@ -484,11 +485,17 @@ describe('useConversation hook test cases', () => { { contactEnsName: 'max.eth', isHidden: false, - previewMessage: null, + previewMessage: undefined, }, { contactEnsName: 'bob.eth', - previewMessage: 'Hello from Bob', + previewMessage: { + envelop: { + message: { + message: 'Hello from Bob', + }, + }, + } as unknown as Envelop, isHidden: false, }, ]); @@ -567,7 +574,7 @@ describe('useConversation hook test cases', () => { { contactEnsName: 'max.eth', isHidden: false, - previewMessage: null, + previewMessage: undefined, }, ]); }, @@ -651,12 +658,12 @@ describe('useConversation hook test cases', () => { { contactEnsName: 'max.eth', isHidden: false, - previewMessage: null, + previewMessage: undefined, }, { contactEnsName: 'mydefaultcontract.eth', isHidden: false, - previewMessage: null, + previewMessage: undefined, }, ]); }, @@ -740,17 +747,17 @@ describe('useConversation hook test cases', () => { { contactEnsName: 'ron.eth', isHidden: true, - previewMessage: null, + previewMessage: undefined, }, { contactEnsName: 'max.eth', isHidden: false, - previewMessage: null, + previewMessage: undefined, }, { contactEnsName: 'mydefaultcontract.eth', isHidden: false, - previewMessage: null, + previewMessage: undefined, }, ]); }, @@ -836,7 +843,7 @@ describe('useConversation hook test cases', () => { { contactEnsName: 'max.eth', isHidden: false, - previewMessage: null, + previewMessage: undefined, }, ]); }, @@ -960,7 +967,7 @@ describe('useConversation hook test cases', () => { { contactEnsName: sender.account.ensName, isHidden: false, - previewMessage: null, + previewMessage: undefined, }, ]); }, @@ -1069,7 +1076,7 @@ describe('useConversation hook test cases', () => { { contactEnsName: sender.account.ensName, isHidden: false, - previewMessage: null, + previewMessage: undefined, }, ]); }, diff --git a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx index 8bb56a953..1f0e8152d 100644 --- a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx +++ b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx @@ -133,7 +133,7 @@ export const useConversation = (config: DM3Configuration) => { //I there are no conversations yet we add the default contact const defaultConversation: Conversation = { contactEnsName: normalizeEnsName(aliasName!), - previewMessage: null, + previewMessage: undefined, isHidden: false, }; @@ -188,7 +188,7 @@ export const useConversation = (config: DM3Configuration) => { const newConversation: Conversation = { contactEnsName, isHidden: false, - previewMessage: null, + previewMessage: undefined, }; //Adds the conversation to the conversation state const conversationPreview = _addConversation(newConversation); @@ -224,7 +224,7 @@ export const useConversation = (config: DM3Configuration) => { const hydrateExistingContactAsync = async (contact: ContactPreview) => { const conversation: Conversation = { contactEnsName: contact.contactDetails.account.ensName, - previewMessage: contact.message, + previewMessage: undefined, isHidden: contact.isHidden, }; const hydratedContact = await hydrateContract( @@ -303,11 +303,7 @@ export const useConversation = (config: DM3Configuration) => { } //If the conversation already contains messages the preview message is the last message. The backend attaches that message to the conversation so we can use it here and safe a request to fetch the messages - const previewMessage = conversation.previewMessage - ? ( - conversation.previewMessage as unknown as StorageEnvelopContainer - ).envelop.message.message ?? '' - : null; + const previewMessage = conversation.previewMessage?.message?.message; const newContact: ContactPreview = getEmptyContact( ensName, diff --git a/packages/messenger-widget/src/hooks/messages/useMessage.test.tsx b/packages/messenger-widget/src/hooks/messages/useMessage.test.tsx index 02ecf06a0..701825b64 100644 --- a/packages/messenger-widget/src/hooks/messages/useMessage.test.tsx +++ b/packages/messenger-widget/src/hooks/messages/useMessage.test.tsx @@ -98,7 +98,7 @@ describe('useMessage hook test cases', () => { storeMessage: jest.fn(), }); const conversationContext = getMockedConversationContext({ - selectedContact: getEmptyContact('max.eth', null), + selectedContact: getEmptyContact('max.eth', undefined), }); const deliveryServiceContext = getMockedDeliveryServiceContext({ //Add websocket mock @@ -155,7 +155,7 @@ describe('useMessage hook test cases', () => { storeMessage: jest.fn(), }); const conversationContext = getMockedConversationContext({ - selectedContact: getEmptyContact('max.eth', null), + selectedContact: getEmptyContact('max.eth', undefined), }); const deliveryServiceContext = getMockedDeliveryServiceContext({ //Add websocket mock @@ -212,7 +212,7 @@ describe('useMessage hook test cases', () => { storeMessage: jest.fn(), }); const conversationContext = getMockedConversationContext({ - selectedContact: getEmptyContact('max.eth', null), + selectedContact: getEmptyContact('max.eth', undefined), }); const deliveryServiceContext = getMockedDeliveryServiceContext({ //Add websocket mock @@ -279,7 +279,7 @@ describe('useMessage hook test cases', () => { }); const conversationContext = getMockedConversationContext({ - selectedContact: getEmptyContact('max.eth', null), + selectedContact: getEmptyContact('max.eth', undefined), contacts: [ { name: '', @@ -380,7 +380,7 @@ describe('useMessage hook test cases', () => { }); const conversationContext = getMockedConversationContext({ - selectedContact: getEmptyContact('max.eth', null), + selectedContact: getEmptyContact('max.eth', undefined), contacts: [ { name: '', @@ -508,8 +508,8 @@ describe('useMessage hook test cases', () => { getNumberOfMessages: jest.fn().mockResolvedValue(3), }); const conversationContext = getMockedConversationContext({ - selectedContact: getEmptyContact('max.eth', null), - contacts: [getEmptyContact('alice.eth', null)], + selectedContact: getEmptyContact('max.eth', undefined), + contacts: [getEmptyContact('alice.eth', undefined)], }); const deliveryServiceContext = getMockedDeliveryServiceContext({ onNewMessage: (cb: Function) => { @@ -585,8 +585,8 @@ describe('useMessage hook test cases', () => { getNumberOfMessages: jest.fn().mockResolvedValue(0), }); const conversationContext = getMockedConversationContext({ - selectedContact: getEmptyContact('max.eth', null), - contacts: [getEmptyContact('alice.eth', null)], + selectedContact: getEmptyContact('max.eth', undefined), + contacts: [getEmptyContact('alice.eth', undefined)], }); const deliveryServiceContext = getMockedDeliveryServiceContext({ onNewMessage: (cb: Function) => { @@ -687,8 +687,8 @@ describe('useMessage hook test cases', () => { ), }); const conversationContext = getMockedConversationContext({ - selectedContact: getEmptyContact('max.eth', null), - contacts: [getEmptyContact('alice.eth', null)], + selectedContact: getEmptyContact('max.eth', undefined), + contacts: [getEmptyContact('alice.eth', undefined)], }); const deliveryServiceContext = getMockedDeliveryServiceContext({ onNewMessage: (cb: Function) => { @@ -777,8 +777,8 @@ describe('useMessage hook test cases', () => { ), }); const conversationContext = getMockedConversationContext({ - selectedContact: getEmptyContact('max.eth', null), - contacts: [getEmptyContact('alice.eth', null)], + selectedContact: getEmptyContact('max.eth', undefined), + contacts: [getEmptyContact('alice.eth', undefined)], }); const deliveryServiceContext = getMockedDeliveryServiceContext({ onNewMessage: (cb: Function) => { diff --git a/packages/messenger-widget/src/interfaces/utils.ts b/packages/messenger-widget/src/interfaces/utils.ts index 5eae356f2..d7f2c03d5 100644 --- a/packages/messenger-widget/src/interfaces/utils.ts +++ b/packages/messenger-widget/src/interfaces/utils.ts @@ -22,7 +22,7 @@ export interface IButton { export interface ContactPreview { name: string; - message: string | null; + message: string | undefined; image: string; contactDetails: Contact; isHidden: boolean; @@ -50,7 +50,7 @@ export interface IAttachmentPreview { export const getEmptyContact = ( ensName: string, - message: string | null, + message: string | undefined, isHidden: boolean = false, ) => { const newContact: ContactPreview = { From e5559b4f5f7bdf79d33fa976a0eddfe9e3596426 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Fri, 28 Jun 2024 10:11:16 +0200 Subject: [PATCH 17/27] fix contact laoding state --- .../src/components/Contacts/Contacts.tsx | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/packages/messenger-widget/src/components/Contacts/Contacts.tsx b/packages/messenger-widget/src/components/Contacts/Contacts.tsx index e920673b6..405ae4028 100644 --- a/packages/messenger-widget/src/components/Contacts/Contacts.tsx +++ b/packages/messenger-widget/src/components/Contacts/Contacts.tsx @@ -1,5 +1,5 @@ import './Contacts.css'; -import { useContext, useEffect, useState } from 'react'; +import { useCallback, useContext, useEffect, useState } from 'react'; import loader from '../../assets/images/loader.svg'; import threeDotsIcon from '../../assets/images/three-dots.svg'; import { ConversationContext } from '../../context/ConversationContext'; @@ -22,7 +22,8 @@ import InfiniteScroll from 'react-infinite-scroll-component'; export function Contacts() { const { dm3Configuration } = useContext(DM3ConfigurationContext); - const { getMessages, getUnreadMessageCount } = useContext(MessageContext); + const { getMessages, getUnreadMessageCount, contactIsLoading } = + useContext(MessageContext); const { selectedRightView, setSelectedRightView, setSelectedLeftView } = useContext(UiViewContext); const { @@ -85,9 +86,6 @@ export function Contacts() { return uniqueContacts; }; - /* Hidden content for highlighting css */ - const hiddenData: number[] = Array.from({ length: 44 }, (_, i) => i + 1); - const scroller = document.getElementById('chat-scroller'); //If a selected contact is selected and the menu is open, we want to align the menu at the bottom @@ -112,10 +110,26 @@ export function Contacts() { (c) => c.contactDetails.account.ensName === _contact, ); const previewMessage = contact?.message; - console.log('previewMessage', previewMessage); return previewMessage ?? ''; }; + const isContactSelected = (id: string) => { + return selectedContact?.contactDetails.account.ensName === id; + }; + + const isContactLoading = (id: string) => { + const contactName = selectedContact?.contactDetails?.account?.ensName; + //If there is no selectedContact return false + if (!contactName) { + return false; + } + //selectedContact in the state matches the list entry + const contactIsSelected = + selectedContact?.contactDetails.account.ensName === id; + + return contactIsSelected && contactIsLoading(contactName); + }; + return (
)} {/* //TODO add loading state for message */} - {selectedContact?.contactDetails - .account.ensName === id ? ( - selectedContact.message === - null ? ( + {isContactSelected(id) ? ( + !isContactLoading(id) ? (
Date: Fri, 28 Jun 2024 10:46:38 +0200 Subject: [PATCH 18/27] fix message sorting --- packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts | 3 +++ packages/messenger-widget/src/components/Chat/Chat.tsx | 1 + .../messenger-widget/src/components/Contacts/Contacts.tsx | 2 +- .../src/hooks/messages/renderer/renderMessage.ts | 5 +++-- packages/messenger-widget/src/hooks/messages/useMessage.tsx | 2 +- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts index e399c64f7..c7e69750e 100644 --- a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts +++ b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts @@ -140,6 +140,8 @@ export const getCloudStorage = ( const encryptedContactName = await encryption.encryptSync( contactEnsName, ); + //The client defines the createdAt timestamp for the message so it can be used to sort the messages + const createdAt = Date.now(); const encryptedMessages: MessageRecord[] = await Promise.all( batch.map( async (storageEnvelopContainer: StorageEnvelopContainer) => { @@ -152,6 +154,7 @@ export const getCloudStorage = ( messageId: storageEnvelopContainer.envelop.metadata ?.encryptedMessageHash!, + createdAt, }; }, ), diff --git a/packages/messenger-widget/src/components/Chat/Chat.tsx b/packages/messenger-widget/src/components/Chat/Chat.tsx index f558fc708..5d5762ec8 100644 --- a/packages/messenger-widget/src/components/Chat/Chat.tsx +++ b/packages/messenger-widget/src/components/Chat/Chat.tsx @@ -58,6 +58,7 @@ export function Chat() { if (messages.length && lastMessageAction === MessageActionType.NONE) { scrollToBottomOfChat(); } + console.log(messages); }, [messages]); /** diff --git a/packages/messenger-widget/src/components/Contacts/Contacts.tsx b/packages/messenger-widget/src/components/Contacts/Contacts.tsx index 405ae4028..beda57960 100644 --- a/packages/messenger-widget/src/components/Contacts/Contacts.tsx +++ b/packages/messenger-widget/src/components/Contacts/Contacts.tsx @@ -104,7 +104,7 @@ export function Contacts() { const messages = getMessages(_contact); if (messages?.length > 0) { - return messages[messages.length - 1].envelop.message.message ?? ''; + return messages[0].envelop.message.message ?? ''; } const contact = contacts.find( (c) => c.contactDetails.account.ensName === _contact, diff --git a/packages/messenger-widget/src/hooks/messages/renderer/renderMessage.ts b/packages/messenger-widget/src/hooks/messages/renderer/renderMessage.ts index 11b7d29d9..0775864c1 100644 --- a/packages/messenger-widget/src/hooks/messages/renderer/renderMessage.ts +++ b/packages/messenger-widget/src/hooks/messages/renderer/renderMessage.ts @@ -18,10 +18,11 @@ export const renderMessage = (messages: MessageModel[]) => { //Its desirable to have all messages in a conversation sorted by their timestamp. However edited messages are an //exception to this rule, since they should be displayed in the order they were edited. // Therefore we sort the messages by their timestamp and then we eventually replace messages that have been edited + //Messages are sorted DESC, so the pagination adds old messages at the end of the array withReply.sort( (a, b) => - a.envelop.message.metadata.timestamp - - b.envelop.message.metadata.timestamp, + b.envelop.message.metadata.timestamp - + a.envelop.message.metadata.timestamp, ); const withoutEdited = renderEdit(withReply); diff --git a/packages/messenger-widget/src/hooks/messages/useMessage.tsx b/packages/messenger-widget/src/hooks/messages/useMessage.tsx index f673f9774..a4179f5c0 100644 --- a/packages/messenger-widget/src/hooks/messages/useMessage.tsx +++ b/packages/messenger-widget/src/hooks/messages/useMessage.tsx @@ -23,7 +23,7 @@ import { handleMessagesFromDeliveryService } from './sources/handleMessagesFromD import { handleMessagesFromStorage } from './sources/handleMessagesFromStorage'; import { handleMessagesFromWebSocket } from './sources/handleMessagesFromWebSocket'; -const DEFAULT_MESSAGE_PAGESIZE = 100; +const DEFAULT_MESSAGE_PAGESIZE = 20; //Message source to identify where a message comes from. This is important to handle pagination of storage messages properly export enum MessageSource { From 323bf9ea0d35d71d091ef4ce47a3187d6d2ed316 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Fri, 28 Jun 2024 10:55:55 +0200 Subject: [PATCH 19/27] reset default pagesize --- .../messenger-widget/src/hooks/conversation/useConversation.tsx | 2 -- packages/messenger-widget/src/hooks/messages/useMessage.tsx | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx index 1f0e8152d..75d149149 100644 --- a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx +++ b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx @@ -2,7 +2,6 @@ import { DeliveryInformation, EncryptionEnvelop, - Envelop, } from '@dm3-org/dm3-lib-messaging'; import { normalizeEnsName } from '@dm3-org/dm3-lib-profile'; import { Conversation } from '@dm3-org/dm3-lib-storage/dist/new/types'; @@ -16,7 +15,6 @@ import { DM3Configuration } from '../../interfaces/config'; import { ContactPreview, getEmptyContact } from '../../interfaces/utils'; import { useMainnetProvider } from '../mainnetprovider/useMainnetProvider'; import { hydrateContract } from './hydrateContact'; -import { StorageEnvelopContainer } from '@dm3-org/dm3-lib-storage/dist/Storage'; const DEFAULT_CONVERSATION_PAGE_SIZE = 10; diff --git a/packages/messenger-widget/src/hooks/messages/useMessage.tsx b/packages/messenger-widget/src/hooks/messages/useMessage.tsx index a4179f5c0..f673f9774 100644 --- a/packages/messenger-widget/src/hooks/messages/useMessage.tsx +++ b/packages/messenger-widget/src/hooks/messages/useMessage.tsx @@ -23,7 +23,7 @@ import { handleMessagesFromDeliveryService } from './sources/handleMessagesFromD import { handleMessagesFromStorage } from './sources/handleMessagesFromStorage'; import { handleMessagesFromWebSocket } from './sources/handleMessagesFromWebSocket'; -const DEFAULT_MESSAGE_PAGESIZE = 20; +const DEFAULT_MESSAGE_PAGESIZE = 100; //Message source to identify where a message comes from. This is important to handle pagination of storage messages properly export enum MessageSource { From e5c5be6be31c4087e8da3479426ed1489e4aea1b Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Fri, 28 Jun 2024 11:00:21 +0200 Subject: [PATCH 20/27] fix stroage-migration test --- packages/lib/storage/src/migrate-storage.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lib/storage/src/migrate-storage.test.ts b/packages/lib/storage/src/migrate-storage.test.ts index cc8dddb7e..a7762b081 100644 --- a/packages/lib/storage/src/migrate-storage.test.ts +++ b/packages/lib/storage/src/migrate-storage.test.ts @@ -74,7 +74,7 @@ describe('MigrateStorage', () => { Array.from(conversations.keys()).map((contactEnsName) => ({ contactEnsName, isHidden: false, - previewMessage: null, + previewMessage: undefined, })), getMessages: async (contactEnsName: string, page: number) => [], addMessageBatch: async ( From a188c5dbea84f84b3198ca495f1d99f257fb4a2a Mon Sep 17 00:00:00 2001 From: Bhupesh-MS Date: Fri, 28 Jun 2024 15:37:09 +0530 Subject: [PATCH 21/27] fixed contacts pagination CSS issue --- .../src/components/Contacts/Contacts.tsx | 77 +++++++++++-------- 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/packages/messenger-widget/src/components/Contacts/Contacts.tsx b/packages/messenger-widget/src/components/Contacts/Contacts.tsx index e920673b6..d07d3d984 100644 --- a/packages/messenger-widget/src/components/Contacts/Contacts.tsx +++ b/packages/messenger-widget/src/components/Contacts/Contacts.tsx @@ -37,6 +37,9 @@ export function Contacts() { boolean | null >(null); + /* Hidden content for highlighting css */ + const [hiddenData, setHiddenData] = useState([]); + const [hasMoreContact, setHasMoreContact] = useState(true); const getMoreContacts = async () => { @@ -85,9 +88,6 @@ export function Contacts() { return uniqueContacts; }; - /* Hidden content for highlighting css */ - const hiddenData: number[] = Array.from({ length: 44 }, (_, i) => i + 1); - const scroller = document.getElementById('chat-scroller'); //If a selected contact is selected and the menu is open, we want to align the menu at the bottom @@ -116,13 +116,41 @@ export function Contacts() { return previewMessage ?? ''; }; + // updates hidden contacts data for highlighted border + const setHiddenContentForHighlightedBorder = () => { + const element: HTMLElement = document.getElementById( + 'chat-scroller', + ) as HTMLElement; + if (element) { + // fetch height of chat window + const height = element.clientHeight; + // divide it by each contact height to show in UI + const minimumContactCount = height / 64; + // get count of hidden contacts to add + const hiddenContacts = minimumContactCount - contacts.length + 10; + if (hiddenData.length !== hiddenContacts) { + setHiddenData( + Array.from({ length: hiddenContacts }, (_, i) => i + 1), + ); + } + } + }; + + // handles change in screen size + window.addEventListener('resize', setHiddenContentForHighlightedBorder); + + // sets hidden content styles for higlighted border + useEffect(() => { + setHiddenContentForHighlightedBorder(); + }, [contacts]); + return (
- Loading ... - - } + loader={<>} scrollableTarget="chat-scroller" > {contacts.length > 0 && @@ -297,21 +314,21 @@ export function Contacts() { ) ); })} - - {/* Hidden content for highlighting css */} - {/* {hiddenData.map((data) => ( -
-
-
- ))} */} + {/* Hidden content for highlighting css */} + {hiddenData.map((data) => ( +
+
+
+ ))} +
); } From d2380ac6a703feb483b2d74b8ae1a1547a12f287 Mon Sep 17 00:00:00 2001 From: Bhupesh-MS Date: Mon, 1 Jul 2024 16:02:29 +0530 Subject: [PATCH 22/27] fixed chat screen pagination --- .../src/components/Chat/Chat.css | 3 ++ .../src/components/Chat/Chat.tsx | 40 ++++++++++++++----- .../src/components/Contacts/Contacts.tsx | 21 +++++----- .../src/context/MessageContext.tsx | 7 +++- .../src/hooks/messages/useMessage.tsx | 7 +++- 5 files changed, 54 insertions(+), 24 deletions(-) diff --git a/packages/messenger-widget/src/components/Chat/Chat.css b/packages/messenger-widget/src/components/Chat/Chat.css index 9a9747c8c..ea469323e 100644 --- a/packages/messenger-widget/src/components/Chat/Chat.css +++ b/packages/messenger-widget/src/components/Chat/Chat.css @@ -53,6 +53,9 @@ flex-direction: column; } +.infinite-scroll-component__outerdiv{ + height: auto; +} /* =================== Mobile Responsive CSS =================== */ diff --git a/packages/messenger-widget/src/components/Chat/Chat.tsx b/packages/messenger-widget/src/components/Chat/Chat.tsx index 5d5762ec8..dce595a87 100644 --- a/packages/messenger-widget/src/components/Chat/Chat.tsx +++ b/packages/messenger-widget/src/components/Chat/Chat.tsx @@ -29,6 +29,23 @@ export function Chat() { useState(false); const [showShimEffect, setShowShimEffect] = useState(false); + // state which tracks old msgs loading is active or not + const [loadingOldMsgs, setLoadingOldMsgs] = useState(false); + + // state to track more old msgs exists or not + const [hasMoreOldMsgs, setHasMoreOldMsgs] = useState(true); + + const fetchOldMessages = async () => { + setLoadingOldMsgs(true); + const newMsgCount = await loadMoreMessages( + selectedContact?.contactDetails.account.ensName!, + ); + // if no old msgs are found, sets state to no more old msgs exists + if (!newMsgCount) { + setHasMoreOldMsgs(false); + } + }; + useEffect(() => { if (!selectedContact) { return; @@ -50,15 +67,23 @@ export function Chat() { const isLoading = contactIsLoading( selectedContact?.contactDetails.account.ensName!, ); - setShowShimEffect(isLoading); + // shim effect must be visible only if the messages are loaded first time + if (!messages.length) { + setShowShimEffect(isLoading); + } }, [contactIsLoading]); // scrolls to bottom of chat when messages are loaded useEffect(() => { - if (messages.length && lastMessageAction === MessageActionType.NONE) { + // scrolls to bottom only when old msgs are not fetched + if ( + messages.length && + lastMessageAction === MessageActionType.NONE && + !loadingOldMsgs + ) { scrollToBottomOfChat(); } - console.log(messages); + setLoadingOldMsgs(false); }, [messages]); /** @@ -153,18 +178,13 @@ export function Chat() { > - loadMoreMessages( - selectedContact?.contactDetails.account - .ensName!, - ) - } + next={fetchOldMessages} style={{ display: 'flex', flexDirection: 'column-reverse', }} //To put endMessage and loader to the top. inverse={true} - hasMore={true} + hasMore={hasMoreOldMsgs} loader={

+ loader +

+ ) : (
- ) : ( -
- loader -
) ) : ( <> diff --git a/packages/messenger-widget/src/context/MessageContext.tsx b/packages/messenger-widget/src/context/MessageContext.tsx index f015a3444..cfbc0cd6a 100644 --- a/packages/messenger-widget/src/context/MessageContext.tsx +++ b/packages/messenger-widget/src/context/MessageContext.tsx @@ -11,7 +11,7 @@ export type MessageContextType = { getMessages: GetMessages; getUnreadMessageCount: (contact: string) => number; addMessage: AddMessage; - loadMoreMessages: (contact: string) => void; + loadMoreMessages: (contact: string) => Promise; contactIsLoading: (contact: string) => boolean; messages: MessageStorage; }; @@ -23,7 +23,10 @@ export const MessageContext = React.createContext({ new Promise(() => { isSuccess: true; }), - loadMoreMessages: (contact: string) => {}, + loadMoreMessages: (contact: string) => + new Promise(() => { + return 0; + }), contactIsLoading: (contact: string) => false, messages: {}, }); diff --git a/packages/messenger-widget/src/hooks/messages/useMessage.tsx b/packages/messenger-widget/src/hooks/messages/useMessage.tsx index f673f9774..857e8953b 100644 --- a/packages/messenger-widget/src/hooks/messages/useMessage.tsx +++ b/packages/messenger-widget/src/hooks/messages/useMessage.tsx @@ -374,7 +374,7 @@ export const useMessage = () => { await _addMessages(contactName, flatten); }; - const loadMoreMessages = async (_contactName: string) => { + const loadMoreMessages = async (_contactName: string): Promise => { const contactName = normalizeEnsName(_contactName); const messagesFromContact = messages[contactName] ?? []; @@ -393,7 +393,7 @@ export const useMessage = () => { DEFAULT_MESSAGE_PAGESIZE, offset, ); - await _addMessages(contactName, messagesFromStorage); + return await _addMessages(contactName, messagesFromStorage); }; const _addMessages = async ( @@ -433,6 +433,9 @@ export const useMessage = () => { setContactsLoading((prev) => { return prev.filter((contact) => contact !== contactName); }); + + // the count of new messages added + return withResolvedAliasNames.length; }; /** From e481752f223063c087806049cc6685d18a5db9c9 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Mon, 1 Jul 2024 13:09:12 +0200 Subject: [PATCH 23/27] check if its the last page --- .../src/hooks/messages/useMessage.tsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/messenger-widget/src/hooks/messages/useMessage.tsx b/packages/messenger-widget/src/hooks/messages/useMessage.tsx index f673f9774..8c63ac484 100644 --- a/packages/messenger-widget/src/hooks/messages/useMessage.tsx +++ b/packages/messenger-widget/src/hooks/messages/useMessage.tsx @@ -23,7 +23,7 @@ import { handleMessagesFromDeliveryService } from './sources/handleMessagesFromD import { handleMessagesFromStorage } from './sources/handleMessagesFromStorage'; import { handleMessagesFromWebSocket } from './sources/handleMessagesFromWebSocket'; -const DEFAULT_MESSAGE_PAGESIZE = 100; +const DEFAULT_MESSAGE_PAGESIZE = 10; //Message source to identify where a message comes from. This is important to handle pagination of storage messages properly export enum MessageSource { @@ -378,13 +378,21 @@ export const useMessage = () => { const contactName = normalizeEnsName(_contactName); const messagesFromContact = messages[contactName] ?? []; - //For the messageCount we only consider emssages from the MessageSource storage + //For the messageCount we only consider messages from the MessageSource storage const messageCount = messagesFromContact.filter( (message) => message.source === MessageSource.Storage, ).length; + //The conversations has less messages than the DEFAULT_MESSAGE_PAGESIZE. Hence we dont need to load more messages + const isLastPage = messageCount % DEFAULT_MESSAGE_PAGESIZE !== 0; + if (isLastPage) { + console.log('full'); + return; + } + //We calculate the offset based on the messageCount const offset = Math.floor(messageCount / DEFAULT_MESSAGE_PAGESIZE); + console.log('load more ', messageCount, offset); const messagesFromStorage = await handleMessagesFromStorage( setContactsLoading, From e7cbba863287b3b795194bfb0d11749234a0eee6 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Mon, 1 Jul 2024 13:51:50 +0200 Subject: [PATCH 24/27] sort messages desc --- .../backend/src/persistence/storage/postgres/getMessages.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/backend/src/persistence/storage/postgres/getMessages.ts b/packages/backend/src/persistence/storage/postgres/getMessages.ts index 3eb34cc8f..a5690ce84 100644 --- a/packages/backend/src/persistence/storage/postgres/getMessages.ts +++ b/packages/backend/src/persistence/storage/postgres/getMessages.ts @@ -39,6 +39,9 @@ export const getMessages = ownerId: account.id, encryptedContactName, }, + orderBy: { + createdAt: 'desc', + }, }); if (messageRecord.length === 0) { return []; From 09df51bb9a6083030093330b3970072aa94e8a09 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Mon, 1 Jul 2024 13:52:07 +0200 Subject: [PATCH 25/27] add createdAt to messageBatch --- packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts index c7e69750e..cc6ca9333 100644 --- a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts +++ b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts @@ -113,8 +113,11 @@ export const getCloudStorage = ( await encryption.encryptAsync( JSON.stringify(storageEnvelopContainer), ); + //The client defines the createdAt timestamp for the message so it can be used to sort the messages + const createdAt = Date.now(); return { encryptedEnvelopContainer, + createdAt, messageId: storageEnvelopContainer.envelop.metadata ?.encryptedMessageHash! ?? From 0054c53b7af493c8e823787236def170c7a37a4f Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Mon, 1 Jul 2024 13:54:26 +0200 Subject: [PATCH 26/27] stopm pagination on the last page --- .../messenger-widget/src/hooks/messages/useMessage.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/messenger-widget/src/hooks/messages/useMessage.tsx b/packages/messenger-widget/src/hooks/messages/useMessage.tsx index dcd13644e..6e93e32b1 100644 --- a/packages/messenger-widget/src/hooks/messages/useMessage.tsx +++ b/packages/messenger-widget/src/hooks/messages/useMessage.tsx @@ -383,11 +383,12 @@ export const useMessage = () => { (message) => message.source === MessageSource.Storage, ).length; - //The conversations has less messages than the DEFAULT_MESSAGE_PAGESIZE. Hence we dont need to load more messages + //We dont need to fetch more messages if the previously fetched page is smaller than the default pagesize const isLastPage = messageCount % DEFAULT_MESSAGE_PAGESIZE !== 0; if (isLastPage) { - console.log('full'); - return; + console.log('all messages loaded for ', messagesFromContact); + //No more messages have been added + return 0; } //We calculate the offset based on the messageCount From c76258ad6107894123b63532bef2f804548da2b0 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Mon, 1 Jul 2024 14:01:41 +0200 Subject: [PATCH 27/27] set default message size to 100 --- packages/messenger-widget/src/hooks/messages/useMessage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/messenger-widget/src/hooks/messages/useMessage.tsx b/packages/messenger-widget/src/hooks/messages/useMessage.tsx index 6e93e32b1..e5a241c8b 100644 --- a/packages/messenger-widget/src/hooks/messages/useMessage.tsx +++ b/packages/messenger-widget/src/hooks/messages/useMessage.tsx @@ -23,7 +23,7 @@ import { handleMessagesFromDeliveryService } from './sources/handleMessagesFromD import { handleMessagesFromStorage } from './sources/handleMessagesFromStorage'; import { handleMessagesFromWebSocket } from './sources/handleMessagesFromWebSocket'; -const DEFAULT_MESSAGE_PAGESIZE = 10; +const DEFAULT_MESSAGE_PAGESIZE = 100; //Message source to identify where a message comes from. This is important to handle pagination of storage messages properly export enum MessageSource {