@amityco/ts-sdk 0.0.1-beta.37 → 0.0.1-beta.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +3 -5
- package/dist/@types/core/events.d.ts +1 -0
- package/dist/@types/core/events.d.ts.map +1 -1
- package/dist/@types/core/model.d.ts +2 -0
- package/dist/@types/core/model.d.ts.map +1 -1
- package/dist/@types/domains/category.d.ts +7 -0
- package/dist/@types/domains/category.d.ts.map +1 -1
- package/dist/@types/domains/channel.d.ts +2 -2
- package/dist/@types/domains/channel.d.ts.map +1 -1
- package/dist/@types/domains/community.d.ts +12 -0
- package/dist/@types/domains/community.d.ts.map +1 -1
- package/dist/@types/domains/feed.d.ts +1 -2
- package/dist/@types/domains/feed.d.ts.map +1 -1
- package/dist/@types/domains/message.d.ts +1 -1
- package/dist/@types/domains/message.d.ts.map +1 -1
- package/dist/@types/domains/post.d.ts +1 -1
- package/dist/@types/domains/post.d.ts.map +1 -1
- package/dist/@types/domains/user.d.ts +8 -0
- package/dist/@types/domains/user.d.ts.map +1 -1
- package/dist/@types/global.d.ts +5 -0
- package/dist/@types/global.d.ts.map +1 -1
- package/dist/category/api/queryCategories.d.ts +1 -5
- package/dist/category/api/queryCategories.d.ts.map +1 -1
- package/dist/category/observers/index.d.ts +2 -0
- package/dist/category/observers/index.d.ts.map +1 -0
- package/dist/category/observers/liveCategories.d.ts +18 -0
- package/dist/category/observers/liveCategories.d.ts.map +1 -0
- package/dist/category/observers/tests/liveCategories.test.d.ts +2 -0
- package/dist/category/observers/tests/liveCategories.test.d.ts.map +1 -0
- package/dist/channel/api/tests/getChannels.test.d.ts +2 -0
- package/dist/channel/api/tests/getChannels.test.d.ts.map +1 -0
- package/dist/channel/api/tests/leaveChannel.test.d.ts +2 -0
- package/dist/channel/api/tests/leaveChannel.test.d.ts.map +1 -0
- package/dist/channel/observers/liveChannel.d.ts.map +1 -1
- package/dist/channel/observers/liveChannels.d.ts.map +1 -1
- package/dist/client/api/accessTokenExpiryWatcher.d.ts +4 -1
- package/dist/client/api/accessTokenExpiryWatcher.d.ts.map +1 -1
- package/dist/client/api/connectClient.d.ts.map +1 -1
- package/dist/client/api/getToken.d.ts +3 -1
- package/dist/client/api/getToken.d.ts.map +1 -1
- package/dist/client/utils/setClientToken.d.ts +3 -3
- package/dist/comment/api/deleteComment.d.ts.map +1 -1
- package/dist/comment/api/getComment.d.ts.map +1 -1
- package/dist/comment/observers/index.d.ts +1 -0
- package/dist/comment/observers/index.d.ts.map +1 -1
- package/dist/comment/observers/liveComment.d.ts +21 -0
- package/dist/comment/observers/liveComment.d.ts.map +1 -0
- package/dist/comment/observers/tests/liveComment.test.d.ts +2 -0
- package/dist/comment/observers/tests/liveComment.test.d.ts.map +1 -0
- package/dist/community/api/queryCommunities.d.ts +1 -10
- package/dist/community/api/queryCommunities.d.ts.map +1 -1
- package/dist/community/events/index.d.ts +1 -0
- package/dist/community/events/index.d.ts.map +1 -1
- package/dist/community/events/onCommunityUserChanged.d.ts +17 -0
- package/dist/community/events/onCommunityUserChanged.d.ts.map +1 -0
- package/dist/community/events/utils.d.ts +1 -0
- package/dist/community/events/utils.d.ts.map +1 -1
- package/dist/community/observers/index.d.ts +1 -0
- package/dist/community/observers/index.d.ts.map +1 -1
- package/dist/community/observers/liveCommunities.d.ts +20 -0
- package/dist/community/observers/liveCommunities.d.ts.map +1 -0
- package/dist/community/observers/tests/liveCommunities.test.d.ts +2 -0
- package/dist/community/observers/tests/liveCommunities.test.d.ts.map +1 -0
- package/dist/core/events.d.ts +3 -3
- package/dist/core/events.d.ts.map +1 -1
- package/dist/core/model/idResolvers.d.ts.map +1 -1
- package/dist/core/model/identifyModel.d.ts.map +1 -1
- package/dist/core/model/index.d.ts.map +1 -1
- package/dist/core/query/filtering.d.ts +10 -0
- package/dist/core/query/filtering.d.ts.map +1 -1
- package/dist/core/query/paging.d.ts +2 -2
- package/dist/core/query/paging.d.ts.map +1 -1
- package/dist/core/query/sorting.d.ts +6 -0
- package/dist/core/query/sorting.d.ts.map +1 -1
- package/dist/core/query/tests/paging.test.d.ts +2 -0
- package/dist/core/query/tests/paging.test.d.ts.map +1 -0
- package/dist/core/transports/http.d.ts +0 -5
- package/dist/core/transports/http.d.ts.map +1 -1
- package/dist/file/api/test/createImage.test.d.ts +2 -0
- package/dist/file/api/test/createImage.test.d.ts.map +1 -0
- package/dist/file/api/test/createVideo.test.d.ts +2 -0
- package/dist/file/api/test/createVideo.test.d.ts.map +1 -0
- package/dist/index.cjs.js +607 -252
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +599 -251
- package/dist/index.umd.js +4 -4
- package/dist/message/api/queryMessages.d.ts +2 -2
- package/dist/message/api/queryMessages.d.ts.map +1 -1
- package/dist/message/observers/liveMessage.d.ts.map +1 -1
- package/dist/post/observers/index.d.ts +1 -0
- package/dist/post/observers/index.d.ts.map +1 -1
- package/dist/post/observers/livePost.d.ts +21 -0
- package/dist/post/observers/livePost.d.ts.map +1 -0
- package/dist/post/observers/livePosts.d.ts +2 -2
- package/dist/post/observers/livePosts.d.ts.map +1 -1
- package/dist/post/observers/tests/livePost.test.d.ts +2 -0
- package/dist/post/observers/tests/livePost.test.d.ts.map +1 -0
- package/dist/report/api/createReport.d.ts.map +1 -1
- package/dist/report/api/deleteReport.d.ts.map +1 -1
- package/dist/report/api/tests/createReport.test.d.ts +2 -0
- package/dist/report/api/tests/createReport.test.d.ts.map +1 -0
- package/dist/report/api/tests/deleteReport.test.d.ts +2 -0
- package/dist/report/api/tests/deleteReport.test.d.ts.map +1 -0
- package/dist/subChannel/api/tests/deleteSubChannel.test.d.ts +2 -0
- package/dist/subChannel/api/tests/deleteSubChannel.test.d.ts.map +1 -0
- package/dist/subChannel/api/tests/getSubChannel.test.d.ts +2 -0
- package/dist/subChannel/api/tests/getSubChannel.test.d.ts.map +1 -0
- package/dist/subChannel/api/tests/getSubChannels.test.d.ts +2 -0
- package/dist/subChannel/api/tests/getSubChannels.test.d.ts.map +1 -0
- package/dist/subChannel/api/tests/updateSubChannel.test.d.ts +2 -0
- package/dist/subChannel/api/tests/updateSubChannel.test.d.ts.map +1 -0
- package/dist/subChannel/observers/liveSubChannel.d.ts.map +1 -1
- package/dist/user/api/queryUsers.d.ts +1 -6
- package/dist/user/api/queryUsers.d.ts.map +1 -1
- package/dist/user/api/tests/updateUser.test.d.ts +2 -0
- package/dist/user/api/tests/updateUser.test.d.ts.map +1 -0
- package/dist/user/observers/index.d.ts +1 -0
- package/dist/user/observers/index.d.ts.map +1 -1
- package/dist/user/observers/liveUser.d.ts.map +1 -1
- package/dist/user/observers/liveUsers.d.ts +18 -0
- package/dist/user/observers/liveUsers.d.ts.map +1 -0
- package/dist/user/observers/tests/liveUsers.test.d.ts +2 -0
- package/dist/user/observers/tests/liveUsers.test.d.ts.map +1 -0
- package/dist/utils/liveObject.d.ts +2 -0
- package/dist/utils/liveObject.d.ts.map +1 -0
- package/dist/utils/tests/dummy/category.d.ts +64 -0
- package/dist/utils/tests/dummy/category.d.ts.map +1 -0
- package/dist/utils/tests/dummy/channel.d.ts +50 -0
- package/dist/utils/tests/dummy/channel.d.ts.map +1 -1
- package/dist/utils/tests/dummy/community.d.ts +132 -0
- package/dist/utils/tests/dummy/community.d.ts.map +1 -1
- package/dist/utils/tests/dummy/feed.d.ts +21 -0
- package/dist/utils/tests/dummy/feed.d.ts.map +1 -0
- package/dist/utils/tests/dummy/file.d.ts +3 -0
- package/dist/utils/tests/dummy/file.d.ts.map +1 -1
- package/dist/utils/tests/dummy/index.d.ts +2 -0
- package/dist/utils/tests/dummy/index.d.ts.map +1 -1
- package/dist/utils/tests/dummy/post.d.ts +11 -0
- package/dist/utils/tests/dummy/post.d.ts.map +1 -1
- package/dist/utils/tests/dummy/subChannel.d.ts +0 -20
- package/dist/utils/tests/dummy/subChannel.d.ts.map +1 -1
- package/dist/utils/tests/dummy/user.d.ts +81 -0
- package/dist/utils/tests/dummy/user.d.ts.map +1 -1
- package/dist/utils/tests/liveObject.test.d.ts +2 -0
- package/dist/utils/tests/liveObject.test.d.ts.map +1 -0
- package/package.json +4 -4
- package/src/@types/core/events.ts +1 -0
- package/src/@types/core/model.ts +4 -0
- package/src/@types/domains/category.ts +13 -0
- package/src/@types/domains/channel.ts +2 -2
- package/src/@types/domains/community.ts +25 -0
- package/src/@types/domains/feed.ts +1 -3
- package/src/@types/domains/message.ts +4 -1
- package/src/@types/domains/post.ts +1 -1
- package/src/@types/domains/user.ts +14 -0
- package/src/@types/global.ts +5 -0
- package/src/cache/api/tests/ingestInCache.test.ts +2 -0
- package/src/category/api/queryCategories.ts +3 -5
- package/src/category/observers/index.ts +1 -0
- package/src/category/observers/liveCategories.ts +141 -0
- package/src/category/observers/tests/liveCategories.test.ts +147 -0
- package/src/channel/api/tests/createChannel.test.ts +30 -6
- package/src/channel/api/tests/getChannel.test.ts +3 -1
- package/src/channel/api/tests/getChannels.test.ts +97 -0
- package/src/channel/api/tests/joinChannel.test.ts +62 -3
- package/src/channel/api/tests/leaveChannel.test.ts +90 -0
- package/src/channel/api/tests/queryChannels.test.ts +38 -1
- package/src/channel/observers/liveChannel.ts +8 -80
- package/src/channel/observers/liveChannels.ts +29 -24
- package/src/client/api/accessTokenExpiryWatcher.ts +7 -5
- package/src/client/api/connectClient.ts +0 -2
- package/src/client/api/tests/accessTokenExpiryWatcher.test.ts +8 -5
- package/src/comment/api/deleteComment.ts +5 -5
- package/src/comment/api/getComment.ts +8 -3
- package/src/comment/observers/index.ts +1 -0
- package/src/comment/observers/liveComment.ts +43 -0
- package/src/comment/observers/tests/liveComment.test.ts +95 -0
- package/src/community/api/queryCommunities.ts +3 -10
- package/src/community/api/test/addCommunityMember.test.ts +14 -2
- package/src/community/api/test/joinCommunity.test.ts +14 -2
- package/src/community/api/test/leaveCommunity.test.ts +11 -1
- package/src/community/api/test/removeCommunityMembers.test.ts +11 -1
- package/src/community/events/index.ts +1 -0
- package/src/community/events/onCommunityUserChanged.ts +20 -0
- package/src/community/events/test/onCommunityJoined.test.ts +1 -1
- package/src/community/events/test/onCommunityUserAdded.test.ts +1 -1
- package/src/community/events/test/onCommunityUserBanned.test.ts +1 -1
- package/src/community/events/test/onCommunityUserUnbaned.test.ts +1 -1
- package/src/community/events/test/utils.test.ts +52 -3
- package/src/community/events/utils.ts +49 -0
- package/src/community/observers/index.ts +1 -0
- package/src/community/observers/liveCommunities.ts +188 -0
- package/src/community/observers/tests/liveCommunities.test.ts +284 -0
- package/src/core/model/idResolvers.ts +2 -0
- package/src/core/model/identifyModel.ts +1 -0
- package/src/core/model/index.ts +2 -0
- package/src/core/query/filtering.ts +33 -3
- package/src/core/query/paging.ts +5 -4
- package/src/core/query/sorting.ts +8 -0
- package/src/core/query/tests/paging.test.ts +66 -0
- package/src/core/transports/http.ts +17 -13
- package/src/core/transports/test/http.test.ts +49 -60
- package/src/file/api/createFile.ts +1 -1
- package/src/file/api/createImage.ts +1 -1
- package/src/file/api/createVideo.ts +1 -1
- package/src/file/api/test/createImage.test.ts +69 -0
- package/src/file/api/test/createVideo.test.ts +81 -0
- package/src/index.ts +1 -0
- package/src/message/api/queryMessages.ts +7 -7
- package/src/message/api/tests/queryMessages.test.ts +6 -6
- package/src/message/observers/liveMessage.ts +11 -83
- package/src/message/tests/observers/liveMessage.test.ts +1 -143
- package/src/message/tests/observers/liveMessages.test.ts +4 -4
- package/src/post/observers/index.ts +1 -0
- package/src/post/observers/livePost.ts +47 -0
- package/src/post/observers/livePosts.ts +14 -22
- package/src/post/observers/tests/livePost.test.ts +97 -0
- package/src/post/observers/tests/livePosts.test.ts +65 -8
- package/src/report/api/createReport.ts +1 -6
- package/src/report/api/deleteReport.ts +2 -6
- package/src/report/api/tests/createReport.test.ts +93 -0
- package/src/report/api/tests/deleteReport.test.ts +93 -0
- package/src/stream/api/tests/createStream.test.ts +3 -11
- package/src/stream/api/tests/deleteStream.test.ts +5 -3
- package/src/subChannel/api/tests/createSubChannel.test.ts +21 -14
- package/src/subChannel/api/tests/deleteSubChannel.test.ts +112 -0
- package/src/subChannel/api/tests/getSubChannel.test.ts +97 -0
- package/src/subChannel/api/tests/getSubChannels.test.ts +97 -0
- package/src/subChannel/api/tests/updateSubChannel.test.ts +86 -0
- package/src/subChannel/observers/liveSubChannel.ts +6 -56
- package/src/subChannel/observers/tests/liveSubChannel.test.ts +0 -82
- package/src/user/api/queryUsers.ts +1 -6
- package/src/user/api/tests/updateUser.test.ts +60 -0
- package/src/user/observers/index.ts +1 -0
- package/src/user/observers/liveUser.ts +9 -61
- package/src/user/observers/liveUsers.ts +162 -0
- package/src/user/observers/tests/liveUsers.test.ts +202 -0
- package/src/user/tests/observers/liveUser.test.ts +1 -154
- package/src/utils/liveObject.ts +86 -0
- package/src/utils/tests/dummy/category.ts +57 -0
- package/src/utils/tests/dummy/channel.ts +52 -1
- package/src/utils/tests/dummy/community.ts +94 -0
- package/src/utils/tests/dummy/feed.ts +13 -0
- package/src/utils/tests/dummy/file.ts +32 -0
- package/src/utils/tests/dummy/index.ts +3 -0
- package/src/utils/tests/dummy/post.ts +62 -47
- package/src/utils/tests/dummy/stream.ts +73 -73
- package/src/utils/tests/dummy/subChannel.ts +0 -22
- package/src/utils/tests/dummy/user.ts +57 -0
- package/src/utils/tests/liveObject.test.ts +172 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/* eslint-disable no-use-before-define */
|
|
2
|
+
import { getResolver } from '~/core/model';
|
|
3
|
+
import { pullFromCache, pushToCache } from '~/cache/api';
|
|
4
|
+
import { getActiveClient } from '~/client/api';
|
|
5
|
+
import {
|
|
6
|
+
createQuery,
|
|
7
|
+
runQuery,
|
|
8
|
+
queryOptions,
|
|
9
|
+
filterByPropEquality,
|
|
10
|
+
sortByLastCreated,
|
|
11
|
+
sortByDisplayName,
|
|
12
|
+
sortByFirstCreated,
|
|
13
|
+
} from '~/core/query';
|
|
14
|
+
import {
|
|
15
|
+
COLLECTION_DEFAULT_CACHING_POLICY,
|
|
16
|
+
COLLECTION_DEFAULT_PAGINATION_LIMIT,
|
|
17
|
+
ENABLE_CACHE_MESSAGE,
|
|
18
|
+
} from '~/utils/constants';
|
|
19
|
+
import {
|
|
20
|
+
onCommunityCreated,
|
|
21
|
+
onCommunityDeleted,
|
|
22
|
+
onCommunityUpdated,
|
|
23
|
+
onCommunityJoined,
|
|
24
|
+
onCommunityLeft,
|
|
25
|
+
onCommunityUserChanged,
|
|
26
|
+
} from '../events';
|
|
27
|
+
import { queryCommunities } from '../api';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* ```js
|
|
31
|
+
* import { liveCommunities } from '@amityco/ts-sdk'
|
|
32
|
+
*
|
|
33
|
+
* let communities = []
|
|
34
|
+
* const unsub = liveCommunities({
|
|
35
|
+
* displayName: Amity.Community['displayName'],
|
|
36
|
+
* }, response => merge(communities, response.data))
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* Observe all mutations on a list of {@link Amity.Community}s
|
|
40
|
+
*
|
|
41
|
+
* @param params for querying communities
|
|
42
|
+
* @param callback the function to call when new data are available
|
|
43
|
+
* @returns An {@link Amity.Unsubscriber} function to run when willing to stop observing the communities
|
|
44
|
+
*
|
|
45
|
+
* @category Community Live Collection
|
|
46
|
+
*/
|
|
47
|
+
export const liveCommunities = (
|
|
48
|
+
params: Amity.CommunityLiveCollection,
|
|
49
|
+
callback: Amity.LiveCollectionCallback<Amity.Community>,
|
|
50
|
+
config?: Amity.LiveCollectionConfig,
|
|
51
|
+
) => {
|
|
52
|
+
const { log, cache } = getActiveClient();
|
|
53
|
+
|
|
54
|
+
if (!cache) {
|
|
55
|
+
console.log(ENABLE_CACHE_MESSAGE);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const timestamp = Date.now();
|
|
59
|
+
log(`liveCommunities(tmpid: ${timestamp}) > listen`);
|
|
60
|
+
|
|
61
|
+
const { limit: queryLimit, ...queryParams } = params;
|
|
62
|
+
|
|
63
|
+
const limit = queryLimit ?? COLLECTION_DEFAULT_PAGINATION_LIMIT;
|
|
64
|
+
const { policy = COLLECTION_DEFAULT_CACHING_POLICY } = config ?? {};
|
|
65
|
+
|
|
66
|
+
const disposers: Amity.Unsubscriber[] = [];
|
|
67
|
+
const cacheKey = ['community', 'collection', {}];
|
|
68
|
+
|
|
69
|
+
const responder = (data: Amity.CommunityLiveCollectionCache) => {
|
|
70
|
+
let communities: Amity.Community[] =
|
|
71
|
+
data.data
|
|
72
|
+
.map(communityId => pullFromCache<Amity.Community>(['community', 'get', communityId])!)
|
|
73
|
+
.filter(Boolean)
|
|
74
|
+
.map(({ data }) => data) ?? [];
|
|
75
|
+
|
|
76
|
+
communities = filterByPropEquality(communities, 'isDeleted', params.isDeleted);
|
|
77
|
+
communities = filterByPropEquality(communities, 'displayName', params.displayName);
|
|
78
|
+
|
|
79
|
+
if (params.categoryId) {
|
|
80
|
+
communities = communities.filter(c => c.categoryIds?.includes(params.categoryId!));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (params.tags) {
|
|
84
|
+
communities = communities.filter(c => c.tags?.some(t => params.tags?.includes(t)));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (params.membership === 'member') {
|
|
88
|
+
communities = filterByPropEquality(communities, 'isJoined', true);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (params.membership === 'notMember') {
|
|
92
|
+
communities = filterByPropEquality(communities, 'isJoined', false);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const sortBy = params.sortBy || 'lastCreated';
|
|
96
|
+
|
|
97
|
+
if (sortBy === 'lastCreated' || sortBy === 'firstCreated') {
|
|
98
|
+
communities = communities.sort(
|
|
99
|
+
sortBy === 'lastCreated' ? sortByLastCreated : sortByFirstCreated,
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/*
|
|
104
|
+
* The server returns communities with empty | null displayName's first before
|
|
105
|
+
* returning sorted list of communities with displayNames
|
|
106
|
+
*
|
|
107
|
+
* This section needs to be updated as displayNames can be null as well
|
|
108
|
+
*/
|
|
109
|
+
if (sortBy === 'displayName') {
|
|
110
|
+
communities = communities
|
|
111
|
+
// this needs to be aligned with the backend data type
|
|
112
|
+
.map(c => (c.displayName ? c : { ...c, displayName: '' }))
|
|
113
|
+
// @ts-ignore
|
|
114
|
+
.sort(sortByDisplayName);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
callback({
|
|
118
|
+
onNextPage: onFetch,
|
|
119
|
+
data: communities,
|
|
120
|
+
hasNextPage: !!data.params?.page,
|
|
121
|
+
loading: data.loading,
|
|
122
|
+
error: data.error,
|
|
123
|
+
});
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const realtimeRouter = (_: Amity.CommunityActionType) => (community: Amity.Community) => {
|
|
127
|
+
const collection = pullFromCache<Amity.CommunityLiveCollectionCache>(cacheKey)?.data;
|
|
128
|
+
if (!collection) return;
|
|
129
|
+
|
|
130
|
+
/*
|
|
131
|
+
* Simply update collection and let responder decide what to do with data
|
|
132
|
+
*/
|
|
133
|
+
collection.data = [...new Set([community.communityId, ...collection.data])];
|
|
134
|
+
|
|
135
|
+
pushToCache(cacheKey, collection);
|
|
136
|
+
responder(collection);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const onFetch = () => {
|
|
140
|
+
const collection = pullFromCache<Amity.CommunityLiveCollectionCache>(cacheKey)?.data;
|
|
141
|
+
|
|
142
|
+
const communities = collection?.data ?? [];
|
|
143
|
+
|
|
144
|
+
if (communities.length > 0 && !collection?.params.page) return;
|
|
145
|
+
|
|
146
|
+
const query = createQuery(queryCommunities, {
|
|
147
|
+
...queryParams,
|
|
148
|
+
page: collection?.params.page ?? { limit },
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
runQuery(
|
|
152
|
+
query,
|
|
153
|
+
({ data: result, error, loading, nextPage: page }) => {
|
|
154
|
+
const data = {
|
|
155
|
+
loading,
|
|
156
|
+
error,
|
|
157
|
+
params: { page },
|
|
158
|
+
data: communities,
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
if (result) {
|
|
162
|
+
data.data = [...new Set([...communities, ...result.map(getResolver('community'))])];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
pushToCache(cacheKey, data);
|
|
166
|
+
|
|
167
|
+
responder(data);
|
|
168
|
+
},
|
|
169
|
+
queryOptions(policy),
|
|
170
|
+
);
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
disposers.push(
|
|
174
|
+
onCommunityCreated(realtimeRouter('onCreate')),
|
|
175
|
+
onCommunityDeleted(realtimeRouter('onDelete')),
|
|
176
|
+
onCommunityUpdated(realtimeRouter('onUpdate')),
|
|
177
|
+
onCommunityJoined(realtimeRouter('onJoin')),
|
|
178
|
+
onCommunityLeft(realtimeRouter('onLeft')),
|
|
179
|
+
onCommunityUserChanged(realtimeRouter('onMemberCountChanged')),
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
onFetch();
|
|
183
|
+
|
|
184
|
+
return () => {
|
|
185
|
+
log(`liveCommunities(tmpid: ${timestamp}) > dispose`);
|
|
186
|
+
disposers.forEach(fn => fn());
|
|
187
|
+
};
|
|
188
|
+
};
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { disableCache, enableCache } from '~/cache/api';
|
|
2
|
+
import {
|
|
3
|
+
communityQueryResponse,
|
|
4
|
+
communityQueryResponsePage2,
|
|
5
|
+
client,
|
|
6
|
+
connectClient,
|
|
7
|
+
disconnectClient,
|
|
8
|
+
pause,
|
|
9
|
+
communityUser11,
|
|
10
|
+
} from '~/utils/tests';
|
|
11
|
+
|
|
12
|
+
import { liveCommunities } from '../liveCommunities';
|
|
13
|
+
|
|
14
|
+
import { unpackCommunityPayload } from '../../utils';
|
|
15
|
+
|
|
16
|
+
const getSnapshot = (params?: Record<string, any>) => {
|
|
17
|
+
return {
|
|
18
|
+
data: [] as Amity.Community[],
|
|
19
|
+
loading: true,
|
|
20
|
+
error: undefined as any,
|
|
21
|
+
...params,
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const { paging, ...payload } = communityQueryResponse.data;
|
|
26
|
+
const { paging: paging2, ...payload2 } = communityQueryResponsePage2.data;
|
|
27
|
+
|
|
28
|
+
const community1 = unpackCommunityPayload(payload).communities[0];
|
|
29
|
+
const community2 = unpackCommunityPayload(payload).communities[1];
|
|
30
|
+
|
|
31
|
+
describe('liveCommunities', () => {
|
|
32
|
+
beforeAll(connectClient);
|
|
33
|
+
afterAll(disconnectClient);
|
|
34
|
+
|
|
35
|
+
beforeEach(enableCache);
|
|
36
|
+
|
|
37
|
+
afterEach(disableCache);
|
|
38
|
+
|
|
39
|
+
test('it should return community collection', async () => {
|
|
40
|
+
const callback = jest.fn();
|
|
41
|
+
client.http.get = jest.fn().mockResolvedValue(communityQueryResponse);
|
|
42
|
+
|
|
43
|
+
liveCommunities({}, callback);
|
|
44
|
+
await pause();
|
|
45
|
+
|
|
46
|
+
expect(callback).toHaveBeenCalledTimes(2);
|
|
47
|
+
expect(callback).toHaveBeenNthCalledWith(1, expect.objectContaining(getSnapshot()));
|
|
48
|
+
expect(callback).toHaveBeenNthCalledWith(
|
|
49
|
+
2,
|
|
50
|
+
expect.objectContaining(
|
|
51
|
+
getSnapshot({
|
|
52
|
+
data: unpackCommunityPayload(payload).communities,
|
|
53
|
+
loading: false,
|
|
54
|
+
}),
|
|
55
|
+
),
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('it should return data from cache', async () => {
|
|
60
|
+
const callback = jest.fn();
|
|
61
|
+
client.http.get = jest.fn().mockResolvedValue(communityQueryResponse);
|
|
62
|
+
|
|
63
|
+
liveCommunities({}, () => undefined);
|
|
64
|
+
await pause();
|
|
65
|
+
liveCommunities({}, callback);
|
|
66
|
+
await pause();
|
|
67
|
+
|
|
68
|
+
expect(callback).toHaveBeenCalledTimes(2);
|
|
69
|
+
expect(callback).toHaveBeenNthCalledWith(
|
|
70
|
+
1,
|
|
71
|
+
expect.objectContaining(
|
|
72
|
+
getSnapshot({
|
|
73
|
+
data: unpackCommunityPayload(payload).communities,
|
|
74
|
+
}),
|
|
75
|
+
),
|
|
76
|
+
);
|
|
77
|
+
expect(callback).toHaveBeenNthCalledWith(
|
|
78
|
+
2,
|
|
79
|
+
expect.objectContaining(
|
|
80
|
+
getSnapshot({
|
|
81
|
+
data: unpackCommunityPayload(payload).communities,
|
|
82
|
+
loading: false,
|
|
83
|
+
}),
|
|
84
|
+
),
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const filters: [string, Amity.CommunityLiveCollection, Amity.Community[]][] = [
|
|
89
|
+
['deleted', { isDeleted: true }, [community1]],
|
|
90
|
+
['categoryId', { categoryId: 'test-category-id' }, [community1]],
|
|
91
|
+
['displayName', { displayName: 'community 1' }, [community1]],
|
|
92
|
+
['tagged', { tags: ['test-community-tag'] }, [community1]],
|
|
93
|
+
['member', { membership: 'member' }, [community1]],
|
|
94
|
+
['not member', { membership: 'notMember' }, [community2]],
|
|
95
|
+
['all membership', { membership: 'all' }, [community1, community2]],
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
test.each(filters)('it should filter by %s communities', async (filter, params, expected) => {
|
|
99
|
+
const callback = jest.fn();
|
|
100
|
+
client.http.get = jest.fn().mockResolvedValue(communityQueryResponse);
|
|
101
|
+
|
|
102
|
+
liveCommunities(params, callback);
|
|
103
|
+
|
|
104
|
+
expect(callback).toHaveBeenCalledTimes(1);
|
|
105
|
+
// check if cache data returned (should be empty)
|
|
106
|
+
expect(callback).toHaveBeenCalledWith(expect.objectContaining(getSnapshot()));
|
|
107
|
+
|
|
108
|
+
await pause();
|
|
109
|
+
|
|
110
|
+
expect(callback).toHaveBeenCalledTimes(2);
|
|
111
|
+
expect(callback).toHaveBeenCalledWith(
|
|
112
|
+
expect.objectContaining(
|
|
113
|
+
getSnapshot({
|
|
114
|
+
loading: false,
|
|
115
|
+
data: expected,
|
|
116
|
+
}),
|
|
117
|
+
),
|
|
118
|
+
);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test('it should return method to fetch next page', async () => {
|
|
122
|
+
const callback = jest.fn();
|
|
123
|
+
client.http.get = jest
|
|
124
|
+
.fn()
|
|
125
|
+
.mockResolvedValue(communityQueryResponse)
|
|
126
|
+
.mockResolvedValueOnce(communityQueryResponsePage2);
|
|
127
|
+
|
|
128
|
+
liveCommunities({}, callback);
|
|
129
|
+
await pause();
|
|
130
|
+
|
|
131
|
+
expect(callback).toHaveBeenCalled();
|
|
132
|
+
expect(callback.mock.lastCall).toHaveLength(1);
|
|
133
|
+
|
|
134
|
+
const { onNextPage, hasNextPage } = callback.mock.lastCall[0];
|
|
135
|
+
|
|
136
|
+
expect(hasNextPage).toBe(true);
|
|
137
|
+
expect(onNextPage).toBeTruthy();
|
|
138
|
+
|
|
139
|
+
onNextPage();
|
|
140
|
+
await pause();
|
|
141
|
+
|
|
142
|
+
// 4 -> because 1 local & server call each per call (2)
|
|
143
|
+
expect(callback).toHaveBeenCalledTimes(4);
|
|
144
|
+
expect(callback).toHaveBeenNthCalledWith(
|
|
145
|
+
4,
|
|
146
|
+
expect.objectContaining(
|
|
147
|
+
getSnapshot({
|
|
148
|
+
loading: false,
|
|
149
|
+
data: unpackCommunityPayload(payload).communities,
|
|
150
|
+
}),
|
|
151
|
+
),
|
|
152
|
+
);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
describe('events', () => {
|
|
156
|
+
const newCommunityPayload = {
|
|
157
|
+
...communityQueryResponse.data.communities[0],
|
|
158
|
+
communityId: 'new-community',
|
|
159
|
+
isDeleted: false,
|
|
160
|
+
};
|
|
161
|
+
const newCommunity = unpackCommunityPayload({ communities: [newCommunityPayload] })
|
|
162
|
+
.communities[0];
|
|
163
|
+
|
|
164
|
+
const communityPayload = {
|
|
165
|
+
communities: [communityQueryResponse.data.communities[0]],
|
|
166
|
+
communityUsers: [communityUser11],
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const cases: [string, keyof Amity.Events, Amity.CommunityPayload, Amity.Community[]][] = [
|
|
170
|
+
[
|
|
171
|
+
'it should add new community to collection onCreate',
|
|
172
|
+
'community.created',
|
|
173
|
+
{ communities: [newCommunityPayload] },
|
|
174
|
+
[newCommunity, community2],
|
|
175
|
+
],
|
|
176
|
+
[
|
|
177
|
+
'it should update community in collection onUpdate',
|
|
178
|
+
'community.updated',
|
|
179
|
+
{ communities: [{ ...newCommunityPayload, communityId: community1.communityId }] },
|
|
180
|
+
[{ ...newCommunity, communityId: community1.communityId }, community2],
|
|
181
|
+
],
|
|
182
|
+
[
|
|
183
|
+
'it should remove community from collection onDelete',
|
|
184
|
+
'community.deleted',
|
|
185
|
+
communityPayload,
|
|
186
|
+
[community2],
|
|
187
|
+
],
|
|
188
|
+
];
|
|
189
|
+
|
|
190
|
+
test.each(cases)('%s', async (test, event, communityPayload, expected) => {
|
|
191
|
+
const callback = jest.fn();
|
|
192
|
+
client.http.get = jest.fn().mockResolvedValue(communityQueryResponse);
|
|
193
|
+
|
|
194
|
+
liveCommunities({ isDeleted: false }, callback);
|
|
195
|
+
await pause();
|
|
196
|
+
|
|
197
|
+
client.emitter.emit(event, communityPayload);
|
|
198
|
+
await pause();
|
|
199
|
+
|
|
200
|
+
expect(callback).toHaveBeenNthCalledWith(
|
|
201
|
+
3,
|
|
202
|
+
expect.objectContaining(
|
|
203
|
+
getSnapshot({
|
|
204
|
+
data: expected,
|
|
205
|
+
loading: false,
|
|
206
|
+
}),
|
|
207
|
+
),
|
|
208
|
+
);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
const joinCommunityPayload = {
|
|
212
|
+
...communityQueryResponse.data.communities[0],
|
|
213
|
+
communityId: 'joining-community',
|
|
214
|
+
isDeleted: false,
|
|
215
|
+
};
|
|
216
|
+
const joinedCommunity = unpackCommunityPayload({ communities: [joinCommunityPayload] })
|
|
217
|
+
.communities[0];
|
|
218
|
+
|
|
219
|
+
const joiningUser: Amity.MembershipRaw<'community'> = {
|
|
220
|
+
...communityUser11,
|
|
221
|
+
userId: 'test',
|
|
222
|
+
communityId: 'joining-community',
|
|
223
|
+
communityMembership: 'member',
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
const memberEvents: [
|
|
227
|
+
string,
|
|
228
|
+
Amity.CommunityLiveCollection,
|
|
229
|
+
keyof Amity.Events,
|
|
230
|
+
Amity.CommunityPayload,
|
|
231
|
+
Amity.Community[],
|
|
232
|
+
][] = [
|
|
233
|
+
[
|
|
234
|
+
'it should add new community to collection onJoin',
|
|
235
|
+
{ membership: 'member' },
|
|
236
|
+
'community.joined',
|
|
237
|
+
{ communities: [joinCommunityPayload], communityUsers: [joiningUser] },
|
|
238
|
+
[joinedCommunity, community1],
|
|
239
|
+
],
|
|
240
|
+
[
|
|
241
|
+
'it should not add new member to community collection onJoin if membership:not member',
|
|
242
|
+
{ membership: 'notMember' },
|
|
243
|
+
'community.joined',
|
|
244
|
+
{ communities: [joinCommunityPayload], communityUsers: [joiningUser] },
|
|
245
|
+
[],
|
|
246
|
+
],
|
|
247
|
+
[
|
|
248
|
+
'it should update community in collection onLeft',
|
|
249
|
+
{ membership: 'member' },
|
|
250
|
+
'community.left',
|
|
251
|
+
{ ...communityPayload, communities: [{ ...community1, isJoined: false }] },
|
|
252
|
+
[],
|
|
253
|
+
],
|
|
254
|
+
[
|
|
255
|
+
'it should add new community in collection onLeft and if membership:not member',
|
|
256
|
+
{ membership: 'notMember' },
|
|
257
|
+
'community.left',
|
|
258
|
+
{ ...communityPayload, communities: [{ ...community1, isJoined: false }] },
|
|
259
|
+
[{ ...community1, isJoined: false }],
|
|
260
|
+
],
|
|
261
|
+
];
|
|
262
|
+
|
|
263
|
+
test.each(memberEvents)('%s', async (test, params, event, communityPayload, expected) => {
|
|
264
|
+
const callback = jest.fn();
|
|
265
|
+
client.http.get = jest.fn().mockResolvedValue(communityQueryResponsePage2);
|
|
266
|
+
|
|
267
|
+
liveCommunities(params, callback);
|
|
268
|
+
await pause();
|
|
269
|
+
|
|
270
|
+
client.emitter.emit(event, communityPayload);
|
|
271
|
+
await pause();
|
|
272
|
+
|
|
273
|
+
expect(callback).toHaveBeenNthCalledWith(
|
|
274
|
+
3,
|
|
275
|
+
expect.objectContaining(
|
|
276
|
+
getSnapshot({
|
|
277
|
+
data: expected,
|
|
278
|
+
loading: false,
|
|
279
|
+
}),
|
|
280
|
+
),
|
|
281
|
+
);
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
});
|
package/src/core/model/index.ts
CHANGED
|
@@ -58,10 +58,40 @@ export const filterByChannelMembership = (
|
|
|
58
58
|
channelUserCacheKey,
|
|
59
59
|
])?.data;
|
|
60
60
|
|
|
61
|
-
if (membership === 'member'
|
|
62
|
-
return
|
|
61
|
+
if (membership === 'member') {
|
|
62
|
+
return channelUser && channelUser.membership !== 'none';
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
// only membership value remainging is 'notMember'
|
|
66
|
+
return !channelUser || channelUser.membership === 'none';
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Filter a channel collection by membership of the userId
|
|
72
|
+
*
|
|
73
|
+
* @param collection the channel collection to filter
|
|
74
|
+
* @param feedType to be filtered by
|
|
75
|
+
* @returns a filtered collection with items only matching the criteria
|
|
76
|
+
*
|
|
77
|
+
* @hidden
|
|
78
|
+
*/
|
|
79
|
+
export const filterByFeedType = <T extends Amity.Post>(
|
|
80
|
+
collection: T[],
|
|
81
|
+
feedType: Amity.Feed['feedType'],
|
|
82
|
+
): T[] => {
|
|
83
|
+
/*
|
|
84
|
+
* It is possible that the targetId & feedId are the same for most of the posts
|
|
85
|
+
* But since cache is in-memory, i've avoided memoizing, to avoid premature
|
|
86
|
+
* optimization. Can be revisited if performance issues arise
|
|
87
|
+
*/
|
|
88
|
+
return collection.filter(({ targetId, feedId }) => {
|
|
89
|
+
const feed = pullFromCache<Amity.Feed>([
|
|
90
|
+
'feed',
|
|
91
|
+
'get',
|
|
92
|
+
getResolver('feed')({ targetId, feedId }),
|
|
93
|
+
])?.data!;
|
|
94
|
+
|
|
95
|
+
return feed && feed.feedType === feedType;
|
|
66
96
|
});
|
|
67
97
|
};
|
package/src/core/query/paging.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { encode, decode } from 'js-base64';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Type guard to find if the a given decoded backend token uses "skip
|
|
4
|
+
* Type guard to find if the a given decoded backend token uses "skip" pagination style
|
|
5
5
|
*
|
|
6
6
|
* @param json any json object as extracted from the backend
|
|
7
7
|
* @returns success boolean if the token has either "skip" or "limit" props
|
|
8
8
|
*
|
|
9
9
|
* @hidden
|
|
10
10
|
*/
|
|
11
|
-
export const
|
|
12
|
-
['skip'
|
|
11
|
+
export const isSkip = (json: Record<string, unknown>): json is Amity.SkipLimitPagination =>
|
|
12
|
+
['skip'].some(prop => prop in json);
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Type guard to find if the a given decoded backend token uses "after/before" pagination style
|
|
@@ -120,7 +120,7 @@ export const toPage = (token?: Amity.Token): Amity.Page | undefined => {
|
|
|
120
120
|
// don't try catch, let it throw
|
|
121
121
|
const json = JSON.parse(decode(token));
|
|
122
122
|
|
|
123
|
-
if (
|
|
123
|
+
if (isSkip(json)) {
|
|
124
124
|
return {
|
|
125
125
|
after: json.skip,
|
|
126
126
|
limit: json.limit!,
|
|
@@ -133,6 +133,7 @@ export const toPage = (token?: Amity.Token): Amity.Page | undefined => {
|
|
|
133
133
|
limit: json.last,
|
|
134
134
|
} as Amity.PrevPage<number>;
|
|
135
135
|
}
|
|
136
|
+
|
|
136
137
|
if ('after' in json) {
|
|
137
138
|
return {
|
|
138
139
|
after: json.after,
|
|
@@ -15,6 +15,14 @@ export const sortByDisplayName: SortingFunc<{ displayName: string }> = (
|
|
|
15
15
|
return a < b ? -1 : 1;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Alphabetic sorting of objects having a name
|
|
20
|
+
*/
|
|
21
|
+
export const sortByName: SortingFunc<{ name: string }> = ({ name: a }, { name: b }) => {
|
|
22
|
+
if (a === b) return 0;
|
|
23
|
+
return a < b ? -1 : 1;
|
|
24
|
+
};
|
|
25
|
+
|
|
18
26
|
/**
|
|
19
27
|
* Sorting a collection by their apparition order (oldest first)
|
|
20
28
|
*/
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { toPage, isSkip, isAfterBefore } from '../paging';
|
|
2
|
+
|
|
3
|
+
describe('paging', () => {
|
|
4
|
+
const skipToken = 'eyJza2lwIjoiMTAiLCJsaW1pdCI6IjEwIn0=';
|
|
5
|
+
const afterToken = 'eyJhZnRlciI6InRlc3QtdG9rZW4iLCJsaW1pdCI6Mn0=';
|
|
6
|
+
const beforeToken =
|
|
7
|
+
'eyJiZWZvcmUiOiI2M2Y0NzFjZmI2MTQzOTExZjFkMWUwNmYiLCJsaW1pdCI6Miwic2VnbWVudCI6Nn0=';
|
|
8
|
+
|
|
9
|
+
describe('toPage', () => {
|
|
10
|
+
test('it should return expected response for skip paging token', () => {
|
|
11
|
+
const expected = { after: '10', limit: '10' };
|
|
12
|
+
|
|
13
|
+
expect(toPage(skipToken)).toStrictEqual(expected);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('it should return appropriate response for "before" paging token', () => {
|
|
17
|
+
const expected = {
|
|
18
|
+
before: '63f471cfb6143911f1d1e06f',
|
|
19
|
+
limit: undefined,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
expect(toPage(beforeToken)).toStrictEqual(expected);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('it should return appropriate response for "after" paging token', () => {
|
|
26
|
+
const expected = {
|
|
27
|
+
after: 'test-token',
|
|
28
|
+
limit: undefined,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
expect(toPage(afterToken)).toStrictEqual(expected);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('isSkip', () => {
|
|
36
|
+
test('it should return true if skip prop in object', () => {
|
|
37
|
+
expect(isSkip({ skip: 10 })).toBe(true);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('it should return true if skip prop not in object', () => {
|
|
41
|
+
expect(isSkip({ limit: 10 })).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('isAfterBefore', () => {
|
|
46
|
+
test('it should return true if after prop in object', () => {
|
|
47
|
+
expect(isAfterBefore({ after: '' })).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('it should return true if before prop in object', () => {
|
|
51
|
+
expect(isAfterBefore({ before: '' })).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('it should return true if first prop in object', () => {
|
|
55
|
+
expect(isAfterBefore({ first: '' })).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('it should return true if last prop in object', () => {
|
|
59
|
+
expect(isAfterBefore({ last: '' })).toBe(true);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('it should return false if skip prop in object', () => {
|
|
63
|
+
expect(isAfterBefore({ skip: '' })).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
});
|