@amityco/ts-sdk-react-native 6.22.1-600ab29.0 → 6.22.1-b0a1854.0

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.
Files changed (89) hide show
  1. package/package.json +3 -1
  2. package/rollup.config.js +6 -0
  3. package/src/@types/core/events.ts +8 -0
  4. package/src/@types/domains/channel.ts +1 -0
  5. package/src/@types/domains/community.ts +50 -1
  6. package/src/@types/domains/post.ts +3 -3
  7. package/src/channelRepository/api/getChannel.ts +1 -1
  8. package/src/channelRepository/api/getChannelByIds.ts +4 -3
  9. package/src/channelRepository/api/markAsRead.ts +6 -2
  10. package/src/channelRepository/channelMembership/observers/getMembers/ChannelMemberLiveCollectionController.ts +2 -2
  11. package/src/channelRepository/channelMembership/observers/getMembers/ChannelMemberQueryStreamController.ts +5 -2
  12. package/src/channelRepository/events/onChannelMemberRoleAdded.ts +1 -1
  13. package/src/channelRepository/events/onChannelMemberRoleRemoved.ts +1 -1
  14. package/src/channelRepository/observers/getChannel.ts +8 -4
  15. package/src/channelRepository/observers/getChannels/ChannelLiveCollectionController.ts +10 -8
  16. package/src/channelRepository/observers/observeChannel.ts +15 -3
  17. package/src/channelRepository/observers/observeChannels.ts +8 -4
  18. package/src/client/api/index.ts +3 -0
  19. package/src/client/api/logout.ts +1 -1
  20. package/src/client/api/registerPushNotification.ts +37 -0
  21. package/src/client/api/secureLogout.ts +1 -1
  22. package/src/client/api/unregisterPushNotification.ts +26 -0
  23. package/src/client/utils/ReadReceiptSync/readReceiptSyncEngine.ts +6 -3
  24. package/src/client/utils/markerSyncEngine.ts +4 -1
  25. package/src/commentRepository/api/createComment.ts +2 -2
  26. package/src/commentRepository/api/deleteComment.ts +2 -4
  27. package/src/commentRepository/events/utils.ts +9 -6
  28. package/src/commentRepository/internalApi/createComment.ts +3 -2
  29. package/src/commentRepository/internalApi/deleteComment.ts +2 -2
  30. package/src/communityRepository/api/createCommunity.ts +5 -2
  31. package/src/communityRepository/api/getCommunities.ts +5 -1
  32. package/src/communityRepository/api/getCommunity.ts +5 -1
  33. package/src/communityRepository/api/queryCommunities.ts +2 -2
  34. package/src/communityRepository/api/updateCommunity.ts +5 -1
  35. package/src/communityRepository/communityMembership/events/utils.ts +2 -2
  36. package/src/communityRepository/communityMembership/observers/getMembers/CommunityMembersLiveCollectionController.ts +151 -0
  37. package/src/communityRepository/communityMembership/observers/getMembers/CommunityMembersPaginationController.ts +26 -0
  38. package/src/communityRepository/communityMembership/observers/getMembers/CommunityMembersQueryStreamController.ts +114 -0
  39. package/src/communityRepository/communityMembership/observers/getMembers/enums.ts +10 -0
  40. package/src/communityRepository/communityMembership/observers/getMembers.ts +15 -128
  41. package/src/communityRepository/communityMembership/observers/index.ts +1 -0
  42. package/src/communityRepository/communityMembership/observers/searchMembers/SearchCommunityMembersLiveCollectionController.ts +130 -0
  43. package/src/communityRepository/communityMembership/observers/searchMembers/SearchCommunityMembersPaginationController.ts +29 -0
  44. package/src/communityRepository/communityMembership/observers/searchMembers/SearchCommunityMembersQueryStreamController.ts +105 -0
  45. package/src/communityRepository/communityMembership/observers/searchMembers/enums.ts +9 -0
  46. package/src/communityRepository/communityMembership/observers/searchMembers.ts +60 -0
  47. package/src/communityRepository/observers/getCommunities/CommunitiesLiveCollectionController.ts +155 -0
  48. package/src/communityRepository/observers/getCommunities/CommunitiesPaginationController.ts +31 -0
  49. package/src/communityRepository/observers/getCommunities/CommunitiesQueryStreamController.ts +89 -0
  50. package/src/communityRepository/observers/getCommunities/enums.ts +5 -0
  51. package/src/communityRepository/observers/getCommunities.ts +7 -150
  52. package/src/communityRepository/observers/index.ts +1 -0
  53. package/src/communityRepository/observers/searchCommunities/SearchCommunitiesLiveCollectionController.ts +127 -0
  54. package/src/communityRepository/observers/searchCommunities/SearchCommunitiesPaginationController.ts +31 -0
  55. package/src/communityRepository/observers/searchCommunities/SearchCommunitiesQueryStreamController.ts +82 -0
  56. package/src/communityRepository/observers/searchCommunities/enums.ts +5 -0
  57. package/src/communityRepository/observers/searchCommunities.ts +56 -0
  58. package/src/communityRepository/utils/payload.ts +35 -1
  59. package/src/communityRepository/utils/saveCommunityUsers.ts +16 -0
  60. package/src/core/liveCollection/LiveCollectionController.ts +10 -6
  61. package/src/fileRepository/api/createFile.ts +5 -2
  62. package/src/fileRepository/api/createImage.ts +6 -2
  63. package/src/fileRepository/api/createVideo.ts +5 -2
  64. package/src/fileRepository/api/uploadFile.ts +5 -2
  65. package/src/fileRepository/api/uploadImage.ts +5 -2
  66. package/src/fileRepository/api/uploadVideo.ts +5 -2
  67. package/src/marker/events/onChannelUnreadUpdatedLocal.ts +29 -0
  68. package/src/marker/events/onSubChannelMarkerFetched.ts +1 -1
  69. package/src/marker/events/onSubChannelUnreadUpdatedLocal.ts +29 -0
  70. package/src/marker/events/onUserFeedMarkerUpdated.ts +3 -4
  71. package/src/marker/utils/reCalculateChannelUnreadInfo.ts +7 -3
  72. package/src/messagePreview/utils/getChannelMessagePreviewWithUser.ts +5 -1
  73. package/src/messageRepository/events/onMessageCreated.ts +4 -0
  74. package/src/messageRepository/observers/getMessages/MessageLiveCollectionController.ts +3 -3
  75. package/src/messageRepository/utils/markReadMessage.ts +8 -0
  76. package/src/postRepository/api/createPost.ts +1 -2
  77. package/src/postRepository/api/editPost.ts +1 -1
  78. package/src/postRepository/api/updatePost.ts +1 -1
  79. package/src/postRepository/observers/getPost.ts +26 -0
  80. package/src/postRepository/observers/getPosts.ts +31 -0
  81. package/src/storyRepository/observers/getGlobalStoryTargets/GlobalStoryLiveCollectionController.ts +2 -2
  82. package/src/storyRepository/observers/getStoriesByTargetIds/StoryLiveCollectionController.ts +1 -1
  83. package/src/subChannelRepository/observers/getSubChannel.ts +10 -6
  84. package/src/subChannelRepository/observers/getSubChannels/SubChannelLiveCollectionController.ts +13 -10
  85. package/src/utils/linkedObject/channelLinkedObject.ts +8 -0
  86. package/src/utils/linkedObject/index.ts +2 -0
  87. package/src/utils/linkedObject/messageLinkedObject.ts +2 -7
  88. package/src/utils/liveObject.ts +3 -0
  89. package/src/utils/object.ts +15 -0
@@ -0,0 +1,130 @@
1
+ /* eslint-disable no-use-before-define */
2
+ import hash from 'object-hash';
3
+ import { pullFromCache, pushToCache } from '~/cache/api';
4
+ import { SearchCommunityMembersPaginationController } from './SearchCommunityMembersPaginationController';
5
+ import { SearchCommunityMembersQueryStreamController } from './SearchCommunityMembersQueryStreamController';
6
+ import { LiveCollectionController } from '~/core/liveCollection/LiveCollectionController';
7
+ import {
8
+ onCommunityJoined,
9
+ onCommunityLeft,
10
+ onCommunityUserBanned,
11
+ onCommunityUserChanged,
12
+ onCommunityUserRoleRemoved,
13
+ onCommunityUserUnbanned,
14
+ } from '~/communityRepository/communityMembership/events';
15
+ import { filterByPropIntersection, filterBySearchTerm } from '~/core/query';
16
+ import { prepareCommunityPayload } from '~/communityRepository/utils';
17
+ import { isNonNullable } from '~/utils';
18
+ import { EnumCommunityMemberActions } from './enums';
19
+
20
+ export class SearchCommunityMembersLiveCollectionController extends LiveCollectionController<
21
+ 'communityUser',
22
+ Amity.SearchCommunityMemberLiveCollection,
23
+ Amity.Membership<'community'>,
24
+ SearchCommunityMembersPaginationController
25
+ > {
26
+ private queryStreamController: SearchCommunityMembersQueryStreamController;
27
+
28
+ private query: Amity.SearchCommunityMemberLiveCollection;
29
+
30
+ constructor(
31
+ query: Amity.SearchCommunityMemberLiveCollection,
32
+ callback: Amity.LiveCollectionCallback<Amity.Membership<'community'>>,
33
+ ) {
34
+ const queryStreamId = hash(query);
35
+ const cacheKey = ['communityUsers', 'collection', queryStreamId];
36
+ const paginationController = new SearchCommunityMembersPaginationController(query);
37
+
38
+ super(paginationController, queryStreamId, cacheKey, callback);
39
+
40
+ this.query = query;
41
+ this.queryStreamController = new SearchCommunityMembersQueryStreamController(
42
+ this.query,
43
+ this.cacheKey,
44
+ this.notifyChange.bind(this),
45
+ prepareCommunityPayload,
46
+ );
47
+
48
+ this.callback = callback.bind(this);
49
+ this.loadPage({ initial: true });
50
+ }
51
+
52
+ protected setup() {
53
+ const collection = pullFromCache<Amity.SearchCommunityMemberLiveCollectionCache>(
54
+ this.cacheKey,
55
+ )?.data;
56
+ if (!collection) {
57
+ pushToCache(this.cacheKey, {
58
+ data: [],
59
+ params: {},
60
+ });
61
+ }
62
+ }
63
+
64
+ protected async persistModel(queryPayload: Amity.CommunityMembershipPayload & Amity.Pagination) {
65
+ await this.queryStreamController.saveToMainDB(queryPayload);
66
+ }
67
+
68
+ protected persistQueryStream({
69
+ response,
70
+ direction,
71
+ refresh,
72
+ }: Amity.LiveCollectionPersistQueryStreamParams<'communityUser'>) {
73
+ this.queryStreamController.appendToQueryStream(response, direction, refresh);
74
+ }
75
+
76
+ startSubscription() {
77
+ return this.queryStreamController.subscribeRTE([
78
+ { fn: onCommunityJoined, action: EnumCommunityMemberActions.OnCommunityJoined },
79
+ { fn: onCommunityLeft, action: EnumCommunityMemberActions.OnCommunityLeft },
80
+ { fn: onCommunityUserBanned, action: EnumCommunityMemberActions.OnCommunityUserBanned },
81
+ { fn: onCommunityUserChanged, action: EnumCommunityMemberActions.OnCommunityUserChanged },
82
+ {
83
+ fn: onCommunityUserRoleRemoved,
84
+ action: EnumCommunityMemberActions.OnCommunityUserRoleRemoved,
85
+ },
86
+ { fn: onCommunityUserUnbanned, action: EnumCommunityMemberActions.OnCommunityUserUnbanned },
87
+ ]);
88
+ }
89
+
90
+ notifyChange({ origin, loading, error }: Amity.LiveCollectionNotifyParams) {
91
+ const collection = pullFromCache<Amity.SearchCommunityMemberLiveCollectionCache>(
92
+ this.cacheKey,
93
+ )?.data;
94
+ if (!collection) return;
95
+
96
+ const data = this.applyFilter(
97
+ collection.data
98
+ .map(id => pullFromCache<Amity.Membership<'community'>>(['communityUsers', 'get', id])!)
99
+ .filter(isNonNullable)
100
+ .map(({ data }) => data) ?? [],
101
+ );
102
+
103
+ if (!this.shouldNotify(data) && origin === 'event') return;
104
+
105
+ this.callback({
106
+ onNextPage: () => this.loadPage({ direction: Amity.LiveCollectionPageDirection.NEXT }),
107
+ data,
108
+ hasNextPage: !!this.paginationController.getNextToken(),
109
+ loading,
110
+ error,
111
+ });
112
+ }
113
+
114
+ applyFilter(data: Amity.Membership<'community'>[]) {
115
+ let communityMembers = filterByPropIntersection(data, 'roles', this.query.roles);
116
+
117
+ if (this.query.memberships) {
118
+ communityMembers = communityMembers.filter(({ communityMembership }) => {
119
+ const memberships: Amity.GroupMembership[] = this.query.memberships || [];
120
+ return memberships.includes(communityMembership);
121
+ });
122
+ }
123
+
124
+ if (this.query.search) {
125
+ communityMembers = filterBySearchTerm(communityMembers, this.query.search);
126
+ }
127
+
128
+ return communityMembers;
129
+ }
130
+ }
@@ -0,0 +1,29 @@
1
+ import { PaginationController } from '~/core/liveCollection/PaginationController';
2
+ import { COLLECTION_DEFAULT_PAGINATION_LIMIT } from '~/utils/constants';
3
+
4
+ /**
5
+ * TODO: handle cache receive cache option, and cache policy
6
+ * TODO: check if querybyIds is supported
7
+ */
8
+ export class SearchCommunityMembersPaginationController extends PaginationController<
9
+ 'communityUser',
10
+ Amity.CommunityMemberLiveCollection
11
+ > {
12
+ async getRequest(
13
+ queryParams: Amity.SearchCommunityMemberLiveCollection,
14
+ token: string | undefined,
15
+ ) {
16
+ const { limit = COLLECTION_DEFAULT_PAGINATION_LIMIT, ...params } = queryParams;
17
+ const options = token ? { token } : { limit };
18
+
19
+ const { data: queryResponse } = await this.http.get<
20
+ Amity.CommunityMembershipPayload & Amity.Pagination
21
+ >(`/api/v3/communities/${params.communityId}/users`, {
22
+ params: {
23
+ ...params,
24
+ options,
25
+ },
26
+ });
27
+ return queryResponse;
28
+ }
29
+ }
@@ -0,0 +1,105 @@
1
+ import { QueryStreamController } from '~/core/liveCollection/QueryStreamController';
2
+ import { pullFromCache, pushToCache } from '~/cache/api';
3
+ import { ingestInCache } from '~/cache/api/ingestInCache';
4
+ import { getResolver } from '~/core/model';
5
+ import { getActiveClient } from '~/client';
6
+ import { EnumCommunityMemberActions } from './enums';
7
+
8
+ export class SearchCommunityMembersQueryStreamController extends QueryStreamController<
9
+ Amity.CommunityMembershipPayload,
10
+ Amity.SearchCommunityMemberLiveCollection
11
+ > {
12
+ private notifyChange: (params: Amity.LiveCollectionNotifyParams) => void;
13
+
14
+ private preparePayload: (
15
+ response: Amity.CommunityMembershipPayload,
16
+ ) => Amity.ProcessedCommunityMembershipPayload;
17
+
18
+ constructor(
19
+ query: Amity.SearchCommunityMemberLiveCollection,
20
+ cacheKey: string[],
21
+ notifyChange: (params: Amity.LiveCollectionNotifyParams) => void,
22
+ preparePayload: (
23
+ response: Amity.CommunityMembershipPayload,
24
+ ) => Amity.ProcessedCommunityMembershipPayload,
25
+ ) {
26
+ super(query, cacheKey);
27
+ this.notifyChange = notifyChange;
28
+ this.preparePayload = preparePayload;
29
+ }
30
+
31
+ async saveToMainDB(response: Amity.CommunityMembershipPayload) {
32
+ const processedPayload = await this.preparePayload(response);
33
+
34
+ const client = getActiveClient();
35
+ const cachedAt = client.cache && Date.now();
36
+
37
+ if (client.cache) {
38
+ ingestInCache(processedPayload, { cachedAt });
39
+ }
40
+ }
41
+
42
+ appendToQueryStream(
43
+ response: Amity.CommunityMembershipPayload & Partial<Amity.Pagination>,
44
+ direction: Amity.LiveCollectionPageDirection,
45
+ refresh = false,
46
+ ) {
47
+ if (refresh) {
48
+ pushToCache(this.cacheKey, {
49
+ data: response.communityUsers.map(({ communityId, userId }) =>
50
+ getResolver('communityUsers')({ communityId, userId }),
51
+ ),
52
+ });
53
+ } else {
54
+ const collection = pullFromCache<Amity.CommunityLiveCollectionCache>(this.cacheKey)?.data;
55
+
56
+ const communityUsers = collection?.data ?? [];
57
+
58
+ pushToCache(this.cacheKey, {
59
+ ...collection,
60
+ data: [
61
+ ...new Set([
62
+ ...communityUsers,
63
+ ...response.communityUsers.map(({ communityId, userId }) =>
64
+ getResolver('communityUsers')({ communityId, userId }),
65
+ ),
66
+ ]),
67
+ ],
68
+ });
69
+ }
70
+ }
71
+
72
+ reactor(action: EnumCommunityMemberActions) {
73
+ return (community: Amity.Community, communityMembers: Amity.Membership<'community'>[]) => {
74
+ const collection = pullFromCache<Amity.SearchCommunityMemberLiveCollectionCache>(
75
+ this.cacheKey,
76
+ )?.data;
77
+ if (!collection) return;
78
+
79
+ communityMembers.forEach(communityMember => {
80
+ const communityMemberCacheId = getResolver('communityUsers')({
81
+ communityId: this.query.communityId,
82
+ userId: communityMember.userId,
83
+ });
84
+
85
+ if (communityMember.communityMembership === 'none') {
86
+ collection.data = collection.data.filter(m => m !== communityMemberCacheId);
87
+ }
88
+ });
89
+
90
+ pushToCache(this.cacheKey, collection);
91
+ this.notifyChange({ origin: Amity.LiveDataOrigin.EVENT, loading: false });
92
+ };
93
+ }
94
+
95
+ subscribeRTE(
96
+ createSubscriber: {
97
+ fn: (
98
+ reactor: (channel: Amity.Community, communityUser: Amity.Membership<'community'>[]) => void,
99
+ ) => Amity.Unsubscriber;
100
+ action: EnumCommunityMemberActions;
101
+ }[],
102
+ ) {
103
+ return createSubscriber.map(subscriber => subscriber.fn(this.reactor(subscriber.action)));
104
+ }
105
+ }
@@ -0,0 +1,9 @@
1
+ export enum EnumCommunityMemberActions {
2
+ OnCommunityJoined = 'onCommunityJoined',
3
+ OnCommunityLeft = 'onCommunityLeft',
4
+ OnCommunityUserBanned = 'onCommunityUserBanned',
5
+ OnCommunityUserChanged = 'onCommunityUserChanged',
6
+ OnCommunityUserRoleAdded = 'onCommunityUserRoleAdded',
7
+ OnCommunityUserRoleRemoved = 'onCommunityUserRoleRemoved',
8
+ OnCommunityUserUnbanned = 'onCommunityUserUnbanned',
9
+ }
@@ -0,0 +1,60 @@
1
+ import { getActiveClient } from '~/client/api';
2
+ import { ENABLE_CACHE_MESSAGE } from '~/utils/constants';
3
+ import { dropFromCache } from '~/cache/api';
4
+ import { SearchCommunityMembersLiveCollectionController } from './searchMembers/SearchCommunityMembersLiveCollectionController';
5
+
6
+ /* begin_public_function
7
+ id: community.membership.query
8
+ */
9
+ /**
10
+ * ```js
11
+ * import { searchMembers } from '@amityco/ts-sdk-react-native'
12
+ *
13
+ * let communityMembers = []
14
+ * const unsub = searchMembers({
15
+ * communityId: Amity.Community['communityId'],
16
+ * }, response => merge(communityMembers, response.data))
17
+ * ```
18
+ *
19
+ * Observe all mutations on a list of {@link Amity.CommunityUser}s
20
+ *
21
+ * @param params for querying community users
22
+ * @param callback the function to call when new data are available
23
+ * @returns An {@link Amity.Unsubscriber} function to run when willing to stop observing the community users
24
+ *
25
+ * @category Community Live Collection
26
+ */
27
+ export const searchMembers = (
28
+ params: Amity.SearchCommunityMemberLiveCollection,
29
+ callback: Amity.LiveCollectionCallback<Amity.Membership<'community'>>,
30
+ config?: Amity.LiveCollectionConfig,
31
+ ) => {
32
+ const { log, cache } = getActiveClient();
33
+
34
+ if (!cache) {
35
+ console.log(ENABLE_CACHE_MESSAGE);
36
+ }
37
+
38
+ const timestamp = Date.now();
39
+ log(`getMembers(tmpid: ${timestamp}) > listen`);
40
+
41
+ const searchCommunityMemberLiveCollection = new SearchCommunityMembersLiveCollectionController(
42
+ params,
43
+ resp => {
44
+ callback(resp);
45
+ },
46
+ );
47
+ const disposers = searchCommunityMemberLiveCollection.startSubscription();
48
+
49
+ const cacheKey = searchCommunityMemberLiveCollection.getCacheKey();
50
+
51
+ disposers.push(() => {
52
+ dropFromCache(cacheKey);
53
+ });
54
+
55
+ return () => {
56
+ log(`getMembers(tmpid: ${timestamp}) > dispose`);
57
+ disposers.forEach(fn => fn());
58
+ };
59
+ };
60
+ /* end_public_function */
@@ -0,0 +1,155 @@
1
+ import hash from 'object-hash';
2
+ import { pullFromCache, pushToCache } from '~/cache/api';
3
+ import { CommunitiesPaginationController } from './CommunitiesPaginationController';
4
+ import { CommunitiesQueryStreamController } from './CommunitiesQueryStreamController';
5
+ import { LiveCollectionController } from '~/core/liveCollection/LiveCollectionController';
6
+ import {
7
+ onCommunityCreated,
8
+ onCommunityDeleted,
9
+ onCommunityUpdated,
10
+ } from '~/communityRepository/events';
11
+ import {
12
+ filterByCommunityMembership,
13
+ filterByPropEquality,
14
+ sortByDisplayName,
15
+ sortByFirstCreated,
16
+ sortByLastCreated,
17
+ } from '~/core/query';
18
+ import { prepareCommunityPayload } from '~/communityRepository/utils';
19
+ import { getActiveClient } from '~/client';
20
+ import { EnumCommunityActions } from './enums';
21
+ import { EnumCommunityMemberActions } from '~/communityRepository/communityMembership/observers/getMembers/enums';
22
+ import {
23
+ onCommunityJoined,
24
+ onCommunityLeft,
25
+ onCommunityUserChanged,
26
+ } from '~/communityRepository/communityMembership';
27
+
28
+ export class CommunityLiveCollectionController extends LiveCollectionController<
29
+ 'community',
30
+ Amity.CommunityLiveCollection,
31
+ Amity.Community,
32
+ CommunitiesPaginationController
33
+ > {
34
+ private queryStreamController: CommunitiesQueryStreamController;
35
+
36
+ private query: Amity.CommunityLiveCollection;
37
+
38
+ constructor(
39
+ query: Amity.CommunityLiveCollection,
40
+ callback: Amity.LiveCollectionCallback<Amity.Community>,
41
+ ) {
42
+ const queryStreamId = hash(query);
43
+ const cacheKey = ['community', 'collection', queryStreamId];
44
+ const paginationController = new CommunitiesPaginationController(query);
45
+
46
+ super(paginationController, queryStreamId, cacheKey, callback);
47
+
48
+ this.query = query;
49
+ this.queryStreamController = new CommunitiesQueryStreamController(
50
+ this.query,
51
+ this.cacheKey,
52
+ this.notifyChange.bind(this),
53
+ prepareCommunityPayload,
54
+ );
55
+
56
+ this.callback = callback.bind(this);
57
+ this.loadPage({ initial: true });
58
+ }
59
+
60
+ protected setup() {
61
+ const collection = pullFromCache<Amity.CommunityLiveCollectionCache>(this.cacheKey)?.data;
62
+ if (!collection) {
63
+ pushToCache(this.cacheKey, {
64
+ data: [],
65
+ params: {},
66
+ });
67
+ }
68
+ }
69
+
70
+ protected async persistModel(queryPayload: Amity.CommunityPayload & Amity.Pagination) {
71
+ await this.queryStreamController.saveToMainDB(queryPayload);
72
+ }
73
+
74
+ protected persistQueryStream({
75
+ response,
76
+ direction,
77
+ refresh,
78
+ }: Amity.LiveCollectionPersistQueryStreamParams<'community'>) {
79
+ this.queryStreamController.appendToQueryStream(response, direction, refresh);
80
+ }
81
+
82
+ startSubscription() {
83
+ return this.queryStreamController.subscribeRTE([
84
+ { fn: onCommunityCreated, action: EnumCommunityActions.OnCommunityCreated },
85
+ { fn: onCommunityDeleted, action: EnumCommunityActions.OnCommunityDeleted },
86
+ { fn: onCommunityUpdated, action: EnumCommunityActions.OnCommunityUpdated },
87
+ { fn: onCommunityJoined, action: EnumCommunityMemberActions.OnCommunityJoined },
88
+ { fn: onCommunityLeft, action: EnumCommunityMemberActions.OnCommunityLeft },
89
+ { fn: onCommunityUserChanged, action: EnumCommunityMemberActions.OnMemberCountChanged },
90
+ ]);
91
+ }
92
+
93
+ notifyChange({ origin, loading, error }: Amity.LiveCollectionNotifyParams) {
94
+ const collection = pullFromCache<Amity.CommunityLiveCollectionCache>(this.cacheKey)?.data;
95
+ if (!collection) return;
96
+
97
+ const data = this.applyFilter(
98
+ collection.data
99
+ .map(id => pullFromCache<Amity.Community>(['community', 'get', id])!)
100
+ .filter(Boolean)
101
+ .map(({ data }) => data) ?? [],
102
+ );
103
+
104
+ if (!this.shouldNotify(data) && origin === 'event') return;
105
+
106
+ this.callback({
107
+ onNextPage: () => this.loadPage({ direction: Amity.LiveCollectionPageDirection.NEXT }),
108
+ data,
109
+ hasNextPage: !!this.paginationController.getNextToken(),
110
+ loading,
111
+ error,
112
+ });
113
+ }
114
+
115
+ applyFilter(data: Amity.Community[]) {
116
+ const { userId } = getActiveClient();
117
+
118
+ let communities = data;
119
+
120
+ if (this.query.includeDeleted) {
121
+ communities = filterByPropEquality(communities, 'isDeleted', false);
122
+ }
123
+
124
+ if (this.query.categoryId) {
125
+ communities = communities.filter(c => c.categoryIds?.includes(this.query.categoryId!));
126
+ }
127
+
128
+ if (this.query.tags) {
129
+ communities = communities.filter(c => c.tags?.some(t => this.query.tags?.includes(t)));
130
+ }
131
+
132
+ if (this.query.membership && userId) {
133
+ communities = filterByCommunityMembership(communities, this.query.membership, userId);
134
+ }
135
+
136
+ if (!this.query.displayName) {
137
+ const sortFn = (() => {
138
+ switch (this.query.sortBy) {
139
+ case 'firstCreated':
140
+ return sortByFirstCreated;
141
+ case 'lastCreated':
142
+ return sortByLastCreated;
143
+ case 'displayName':
144
+ return sortByDisplayName;
145
+ default:
146
+ return sortByLastCreated;
147
+ }
148
+ })();
149
+
150
+ communities = communities.sort(sortFn);
151
+ }
152
+
153
+ return communities;
154
+ }
155
+ }
@@ -0,0 +1,31 @@
1
+ import { PaginationController } from '~/core/liveCollection/PaginationController';
2
+ import { COLLECTION_DEFAULT_PAGINATION_LIMIT } from '~/utils/constants';
3
+ import { inferIsDeleted } from '~/utils/inferIsDeleted';
4
+
5
+ /**
6
+ * TODO: handle cache receive cache option, and cache policy
7
+ * TODO: check if querybyIds is supported
8
+ */
9
+ export class CommunitiesPaginationController extends PaginationController<
10
+ 'community',
11
+ Amity.CommunityLiveCollection
12
+ > {
13
+ async getRequest(queryParams: Amity.CommunityLiveCollection, token: string | undefined) {
14
+ const { limit = COLLECTION_DEFAULT_PAGINATION_LIMIT, ...params } = queryParams;
15
+ const options = token ? { token } : { limit };
16
+
17
+ const { data: queryResponse } = await this.http.get<Amity.CommunityPayload & Amity.Pagination>(
18
+ `/api/v3/communities`,
19
+ {
20
+ params: {
21
+ ...params,
22
+ isDeleted: inferIsDeleted(params.includeDeleted),
23
+ keyword: params.displayName,
24
+ filter: params.membership,
25
+ options,
26
+ },
27
+ },
28
+ );
29
+ return queryResponse;
30
+ }
31
+ }
@@ -0,0 +1,89 @@
1
+ import { QueryStreamController } from '~/core/liveCollection/QueryStreamController';
2
+ import { pullFromCache, pushToCache } from '~/cache/api';
3
+ import { ingestInCache } from '~/cache/api/ingestInCache';
4
+ import { getResolver } from '~/core/model';
5
+ import { getActiveClient } from '~/client';
6
+ import { saveCommunityUsers } from '~/communityRepository/utils/saveCommunityUsers';
7
+ import { EnumCommunityActions } from './enums';
8
+ import { EnumCommunityMemberActions } from '~/communityRepository/communityMembership/observers/getMembers/enums';
9
+
10
+ export class CommunitiesQueryStreamController extends QueryStreamController<
11
+ Amity.CommunityPayload,
12
+ Amity.CommunityLiveCollection
13
+ > {
14
+ private notifyChange: (params: Amity.LiveCollectionNotifyParams) => void;
15
+
16
+ private preparePayload: (response: Amity.CommunityPayload) => Amity.ProcessedCommunityPayload;
17
+
18
+ constructor(
19
+ query: Amity.CommunityLiveCollection,
20
+ cacheKey: string[],
21
+ notifyChange: (params: Amity.LiveCollectionNotifyParams) => void,
22
+ preparePayload: (response: Amity.CommunityPayload) => Amity.ProcessedCommunityPayload,
23
+ ) {
24
+ super(query, cacheKey);
25
+ this.notifyChange = notifyChange;
26
+ this.preparePayload = preparePayload;
27
+ }
28
+
29
+ async saveToMainDB(response: Amity.CommunityPayload) {
30
+ const processedPayload = await this.preparePayload(response);
31
+
32
+ const client = getActiveClient();
33
+ const cachedAt = client.cache && Date.now();
34
+
35
+ if (client.cache) {
36
+ ingestInCache(processedPayload, { cachedAt });
37
+ saveCommunityUsers(response.communities, response.communityUsers);
38
+ }
39
+ }
40
+
41
+ appendToQueryStream(
42
+ response: Amity.CommunityPayload & Partial<Amity.Pagination>,
43
+ direction: Amity.LiveCollectionPageDirection,
44
+ refresh = false,
45
+ ) {
46
+ if (refresh) {
47
+ pushToCache(this.cacheKey, {
48
+ data: response.communities.map(getResolver('community')),
49
+ });
50
+ } else {
51
+ const collection = pullFromCache<Amity.CommunityLiveCollectionCache>(this.cacheKey)?.data;
52
+
53
+ const communities = collection?.data ?? [];
54
+
55
+ pushToCache(this.cacheKey, {
56
+ ...collection,
57
+ data: [...new Set([...communities, ...response.communities.map(getResolver('community'))])],
58
+ });
59
+ }
60
+ }
61
+
62
+ reactor(action: EnumCommunityActions | EnumCommunityMemberActions) {
63
+ return (community: Amity.Community) => {
64
+ const collection = pullFromCache<Amity.CommunityLiveCollectionCache>(this.cacheKey)?.data;
65
+ if (!collection) return;
66
+
67
+ if (this.query.displayName && action === EnumCommunityActions.OnCommunityCreated) {
68
+ return;
69
+ }
70
+
71
+ /*
72
+ * Simply update a collection and let responder decide what to do with data
73
+ */
74
+ collection.data = [...new Set([community.communityId, ...collection.data])];
75
+
76
+ pushToCache(this.cacheKey, collection);
77
+ this.notifyChange({ origin: Amity.LiveDataOrigin.EVENT, loading: false });
78
+ };
79
+ }
80
+
81
+ subscribeRTE(
82
+ createSubscriber: {
83
+ fn: (reactor: (channel: Amity.Community) => void) => Amity.Unsubscriber;
84
+ action: EnumCommunityActions | EnumCommunityMemberActions;
85
+ }[],
86
+ ) {
87
+ return createSubscriber.map(subscriber => subscriber.fn(this.reactor(subscriber.action)));
88
+ }
89
+ }
@@ -0,0 +1,5 @@
1
+ export enum EnumCommunityActions {
2
+ OnCommunityCreated = 'onCommunityCreated',
3
+ OnCommunityDeleted = 'onCommunityDeleted',
4
+ OnCommunityUpdated = 'onCommunityUpdated',
5
+ }