Skip to content

Commit 8900c2b

Browse files
committed
add hide contract to storage
1 parent cf947c5 commit 8900c2b

File tree

6 files changed

+142
-24
lines changed

6 files changed

+142
-24
lines changed

packages/lib/storage/src/new/index.ts

+50-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
/* eslint-disable max-len */
2-
/* eslint-disable no-console */
32
import { Envelop } from '@dm3-org/dm3-lib-messaging';
43
import { createKeyValueStore } from './KeyValueStore';
54
import { getConversationManifestKey } from './keys';
@@ -12,6 +11,7 @@ import {
1211
} from './read';
1312
import {
1413
Chunk,
14+
Conversation,
1515
Db,
1616
Encryption,
1717
INITIAL_CONVERSATION_MANIFEST,
@@ -72,13 +72,38 @@ function addConversationSideEffectContainment(
7272
newConversationChunk.accountManifest,
7373
);
7474

75-
await db.keyValueStoreLocal.write(
75+
await db.keyValueStoreRemote.write(
7676
conversationManifestKey,
7777
INITIAL_CONVERSATION_MANIFEST(conversationManifestKey),
7878
);
7979
}
8080
};
8181
}
82+
function toggleHideConversationSideEffectContainment(
83+
db: Db,
84+
): (contactEnsName: string, isHidden: boolean) => Promise<void> {
85+
return async (contactEnsName: string, isHidden: boolean) => {
86+
const conversationManifest = await getConversationManifest(
87+
contactEnsName,
88+
db,
89+
);
90+
91+
if (!conversationManifest) {
92+
return;
93+
}
94+
await db.keyValueStoreLocal.write(conversationManifest.key, {
95+
...conversationManifest,
96+
isHidden,
97+
});
98+
99+
if (db.keyValueStoreRemote) {
100+
await db.keyValueStoreRemote.write(conversationManifest.key, {
101+
...conversationManifest,
102+
isHidden,
103+
});
104+
}
105+
};
106+
}
82107

83108
/**
84109
* This function creates a closure that, when invoked, adds a new message to a conversation
@@ -202,13 +227,35 @@ export function createStorage(
202227
if (!chunk) {
203228
return [];
204229
}
205-
return chunk.conversationList;
230+
//For each contact name in the conversation list, we have to get the conversation manifest
231+
const manifests = await Promise.all(
232+
chunk.conversationList.map((c) =>
233+
getConversationManifest(c, db),
234+
),
235+
);
236+
237+
const conversations = manifests
238+
.map((m, idx) => {
239+
if (!m) {
240+
//Should not happen since for each conversation in the list there is a manifest. But just in case we filter it out to be sure and satisfy the compiler
241+
return undefined;
242+
}
243+
return {
244+
...m,
245+
contactEnsName: chunk.conversationList[idx],
246+
};
247+
})
248+
.filter((c): c is Conversation => c !== undefined);
249+
250+
return conversations;
206251
},
207252

208253
getNumberOfConverations: () => getNumberOfConverations(db),
209254

210255
addConversation: addConversationSideEffectContainment(db),
211256

212257
addMessage: addMessageSideEffectContainment(db),
258+
259+
toggleHideConversation: toggleHideConversationSideEffectContainment(db),
213260
};
214261
}

packages/lib/storage/src/new/storage.test.ts

+70-13
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,13 @@ describe('createStorage Integration Tests', () => {
5656
readStrategy: ReadStrategy.RemoteFirst,
5757
keyValueStoreRemote: remoteKeyValueStore,
5858
});
59-
const list = await storageApi.getConversationList(0);
59+
const conversations = await storageApi.getConversationList(0);
60+
61+
expect(conversations.length).toBe(1);
6062

61-
expect(list.length).toBe(1);
62-
expect(list[0]).toBe('bob.eth');
63+
expect(conversations[0].contactEnsName).toBe('bob.eth');
64+
expect(conversations[0].isHidden).toBe(false);
65+
expect(conversations[0].messageCounter).toBe(0);
6366
});
6467
it('addConversation - conversationList should not contain duplicates', async () => {
6568
await storageApi.addConversation('bob.eth');
@@ -70,12 +73,17 @@ describe('createStorage Integration Tests', () => {
7073
readStrategy: ReadStrategy.RemoteFirst,
7174
keyValueStoreRemote: remoteKeyValueStore,
7275
});
73-
const list = await storageApi.getConversationList(0);
76+
const conversations = await storageApi.getConversationList(0);
77+
78+
expect(conversations.length).toBe(2);
79+
80+
expect(conversations[0].contactEnsName).toBe('bob.eth');
81+
expect(conversations[0].isHidden).toBe(false);
82+
expect(conversations[0].messageCounter).toBe(0);
7483

75-
expect(list.length).toBe(2);
76-
expect(list[0]).toBe('bob.eth');
77-
expect(list[1]).toBe('max.eth');
78-
expect(list[2]).toBe(undefined);
84+
expect(conversations[1].contactEnsName).toBe('max.eth');
85+
expect(conversations[1].isHidden).toBe(false);
86+
expect(conversations[1].messageCounter).toBe(0);
7987
});
8088
it('add new message - stores new message', async () => {
8189
await storageApi.addConversation('bob.eth');
@@ -210,12 +218,37 @@ describe('createStorage Integration Tests', () => {
210218

211219
const conversations = await storageApi.getConversationList(0);
212220
expect(conversations.length).toBe(1);
213-
expect(conversations[0]).toBe('bob.eth');
221+
expect(conversations[0].contactEnsName).toBe('bob.eth');
222+
expect(conversations[0].isHidden).toBe(false);
223+
expect(conversations[0].messageCounter).toBe(1);
214224

215225
const getMessages = await storageApi.getMessages('bob.eth', 0);
216226
expect(getMessages.length).toBe(1);
217227
expect(getMessages[0]).toEqual(envelop);
218228
});
229+
it('hide conversation -- conversation can be hidden', async () => {
230+
await storageApi.addConversation('bob.eth');
231+
await storageApi.addConversation('max.eth');
232+
await storageApi.toggleHideConversation('max.eth', true);
233+
//We acreate an newStorageApi to verify that the data is stored in remote storage and not just locally
234+
storageApi = await createStorage('alice.eth', mockSign, {
235+
readStrategy: ReadStrategy.RemoteFirst,
236+
keyValueStoreRemote: remoteKeyValueStore,
237+
});
238+
const conversations = await storageApi.getConversationList(0);
239+
240+
expect(conversations.length).toBe(2);
241+
expect(conversations[0].isHidden).toBe(false);
242+
expect(conversations[1].isHidden).toBe(true);
243+
244+
//Can unhide conversation aswell
245+
await storageApi.toggleHideConversation('max.eth', false);
246+
const conversations2 = await storageApi.getConversationList(0);
247+
248+
expect(conversations2.length).toBe(2);
249+
expect(conversations2[0].isHidden).toBe(false);
250+
expect(conversations2[1].isHidden).toBe(false);
251+
});
219252
});
220253

221254
describe('Local first', () => {
@@ -239,10 +272,13 @@ describe('createStorage Integration Tests', () => {
239272
});
240273
it('addConversation - conversationList should include the previously added conversation', async () => {
241274
await storageApi.addConversation('bob.eth');
242-
const list = await storageApi.getConversationList(0);
275+
const conversations = await storageApi.getConversationList(0);
243276

244-
expect(list.length).toBe(1);
245-
expect(list[0]).toBe('bob.eth');
277+
expect(conversations.length).toBe(1);
278+
expect(conversations.length).toBe(1);
279+
expect(conversations[0].contactEnsName).toBe('bob.eth');
280+
expect(conversations[0].isHidden).toBe(false);
281+
expect(conversations[0].messageCounter).toBe(0);
246282
});
247283
it('add new message - stores new message', async () => {
248284
await storageApi.addConversation('bob.eth');
@@ -322,11 +358,32 @@ describe('createStorage Integration Tests', () => {
322358

323359
const conversations = await storageApi.getConversationList(0);
324360
expect(conversations.length).toBe(1);
325-
expect(conversations[0]).toBe('bob.eth');
361+
expect(conversations[0].contactEnsName).toBe('bob.eth');
362+
expect(conversations[0].isHidden).toBe(false);
363+
expect(conversations[0].messageCounter).toBe(1);
326364

327365
const getMessages = await storageApi.getMessages('bob.eth', 0);
328366
expect(getMessages.length).toBe(1);
329367
expect(getMessages[0]).toEqual(envelop);
330368
});
369+
it('hide conversation -- conversation can be hidden', async () => {
370+
await storageApi.addConversation('bob.eth');
371+
await storageApi.addConversation('max.eth');
372+
await storageApi.toggleHideConversation('max.eth', true);
373+
374+
const conversations = await storageApi.getConversationList(0);
375+
376+
expect(conversations.length).toBe(2);
377+
expect(conversations[0].isHidden).toBe(false);
378+
expect(conversations[1].isHidden).toBe(true);
379+
380+
//Can unhide conversation aswell
381+
await storageApi.toggleHideConversation('max.eth', false);
382+
const conversations2 = await storageApi.getConversationList(0);
383+
384+
expect(conversations2.length).toBe(2);
385+
expect(conversations2[0].isHidden).toBe(false);
386+
expect(conversations2[1].isHidden).toBe(false);
387+
});
331388
});
332389
});

packages/lib/storage/src/new/testHelper.ts

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ export const db: Db = {
8383
case await getConversationManifestKey(db, 'alice.eth'):
8484
const conversationManifest: ConversationManifest = {
8585
key,
86+
isHidden: false,
8687
messageCounter: 101,
8788
};
8889
return conversationManifest as T;

packages/lib/storage/src/new/types.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,27 @@ export const INITIAL_ACCOUNT_MANIFEST = (key: string): AccountManifest => ({
77
export const INITIAL_CONVERSATION_MANIFEST = (
88
key: string,
99
): ConversationManifest => ({
10+
isHidden: false,
1011
messageCounter: 0,
1112
key,
1213
});
1314

15+
export interface Conversation extends ConversationManifest {
16+
contactEnsName: string;
17+
}
18+
1419
export interface StorageAPI {
20+
getConversationList: (page: number) => Promise<Conversation[]>;
21+
1522
getMessages: (contactEnsName: string, page: number) => Promise<Envelop[]>;
16-
getConversationList: (page: number) => Promise<string[]>;
1723
getNumberOfMessages: (contactEnsName: string) => Promise<number>;
1824
getNumberOfConverations: () => Promise<number>;
1925
addConversation: (contactEnsName: string) => Promise<void>;
2026
addMessage: (contactEnsName: string, envelop: Envelop) => Promise<void>;
27+
toggleHideConversation: (
28+
contactEnsName: string,
29+
isHidden: boolean,
30+
) => Promise<void>;
2131
}
2232

2333
export enum ReadStrategy {
@@ -63,6 +73,7 @@ export interface ConversationList extends Chunk {
6373

6474
export interface ConversationManifest extends Chunk {
6575
messageCounter: number;
76+
isHidden: false;
6677
}
6778

6879
export interface MessageChunk extends Chunk {

packages/messenger-widget/src/hooks/conversation/useConversation.tsx

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
/* eslint-disable max-len */
22
/* eslint-disable no-console */
3+
import { getAccountDisplayName } from '@dm3-org/dm3-lib-profile';
34
import { useContext, useEffect, useMemo, useState } from 'react';
5+
import humanIcon from '../../assets/images/human.svg';
6+
import { AuthContext } from '../../context/AuthContext';
47
import { StorageContext } from '../../context/StorageContext';
58
import { ContactPreview } from '../../interfaces/utils';
69
import { useMainnetProvider } from '../mainnetprovider/useMainnetProvider';
710
import { hydrateContract } from './hydrateContact';
8-
import { getAccountDisplayName } from '@dm3-org/dm3-lib-profile';
9-
import humanIcon from '../../assets/images/human.svg';
10-
import { useAuth } from '../auth/useAuth';
11-
import { AuthContext } from '../../context/AuthContext';
1211

1312
export const useConversation = () => {
1413
const mainnetProvider = useMainnetProvider();
@@ -46,7 +45,7 @@ export const useConversation = () => {
4645
currentConversationsPage.map((contact) =>
4746
hydrateContract(
4847
mainnetProvider,
49-
contact,
48+
contact.contactEnsName,
5049
getMessages,
5150
getNumberOfMessages,
5251
),

packages/messenger-widget/src/hooks/storage/useStorage.tsx

+5-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ import {
1717
} from '@dm3-org/dm3-lib-crypto';
1818
import { Account, ProfileKeys } from '@dm3-org/dm3-lib-profile';
1919
import { stringify } from '@dm3-org/dm3-lib-shared';
20-
import { StorageAPI } from '@dm3-org/dm3-lib-storage/dist/new/types';
20+
import {
21+
Conversation,
22+
StorageAPI,
23+
} from '@dm3-org/dm3-lib-storage/dist/new/types';
2124
import { useEffect, useMemo, useRef, useState } from 'react';
2225
import { useMainnetProvider } from '../mainnetprovider/useMainnetProvider';
2326
import { Envelop } from '@dm3-org/dm3-lib-messaging';
@@ -127,7 +130,7 @@ export const useStorage = (
127130
};
128131

129132
export type StoreMessageAsync = (message: any) => void;
130-
export type GetConversations = (page: number) => Promise<string[]>;
133+
export type GetConversations = (page: number) => Promise<Conversation[]>;
131134
export type AddConversation = (contact: string) => void;
132135
export type GetMessages = (contact: string, page: number) => Promise<Envelop[]>;
133136
export type GetNumberOfMessages = (contact: string) => Promise<number>;

0 commit comments

Comments
 (0)