@amityco/ts-sdk-react-native 7.0.3-d7a9877.0 → 7.1.1-0e753e3.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 (95) hide show
  1. package/dist/@types/core/events.d.ts +2 -1
  2. package/dist/@types/core/events.d.ts.map +1 -1
  3. package/dist/@types/core/model.d.ts +2 -0
  4. package/dist/@types/core/model.d.ts.map +1 -1
  5. package/dist/@types/core/readReceipt.d.ts +12 -1
  6. package/dist/@types/core/readReceipt.d.ts.map +1 -1
  7. package/dist/@types/domains/channel.d.ts +10 -0
  8. package/dist/@types/domains/channel.d.ts.map +1 -1
  9. package/dist/@types/domains/client.d.ts +2 -0
  10. package/dist/@types/domains/client.d.ts.map +1 -1
  11. package/dist/channelRepository/api/markChannelsAsReadBySegment.d.ts +16 -0
  12. package/dist/channelRepository/api/markChannelsAsReadBySegment.d.ts.map +1 -0
  13. package/dist/channelRepository/events/onChannelDeleted.d.ts.map +1 -1
  14. package/dist/channelRepository/events/onChannelLeft.d.ts.map +1 -1
  15. package/dist/{marker → channelRepository}/events/onChannelUnreadUpdatedLocal.d.ts +2 -2
  16. package/dist/channelRepository/events/onChannelUnreadUpdatedLocal.d.ts.map +1 -0
  17. package/dist/channelRepository/internalApi/getTotalChannelsUnread.d.ts +11 -0
  18. package/dist/channelRepository/internalApi/getTotalChannelsUnread.d.ts.map +1 -0
  19. package/dist/channelRepository/observers/getChannel.d.ts.map +1 -1
  20. package/dist/channelRepository/observers/getChannels/ChannelLiveCollectionController.d.ts.map +1 -1
  21. package/dist/channelRepository/observers/getTotalChannelsUnread.d.ts +20 -0
  22. package/dist/channelRepository/observers/getTotalChannelsUnread.d.ts.map +1 -0
  23. package/dist/channelRepository/observers/index.d.ts +1 -0
  24. package/dist/channelRepository/observers/index.d.ts.map +1 -1
  25. package/dist/channelRepository/utils/constructChannelDynamicValue.d.ts.map +1 -1
  26. package/dist/channelRepository/utils/getLegacyChannelUnread.d.ts +2 -0
  27. package/dist/channelRepository/utils/getLegacyChannelUnread.d.ts.map +1 -0
  28. package/dist/channelRepository/utils/prepareChannelPayload.d.ts.map +1 -1
  29. package/dist/client/api/createClient.d.ts +1 -0
  30. package/dist/client/api/createClient.d.ts.map +1 -1
  31. package/dist/client/api/enableUnreadCount.d.ts.map +1 -1
  32. package/dist/client/api/login.d.ts.map +1 -1
  33. package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngine.d.ts +33 -0
  34. package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngine.d.ts.map +1 -0
  35. package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngineOnLoginHandler.d.ts +3 -0
  36. package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngineOnLoginHandler.d.ts.map +1 -0
  37. package/dist/client/utils/ReadReceiptSync/readReceiptSyncEngine.d.ts +2 -4
  38. package/dist/client/utils/ReadReceiptSync/readReceiptSyncEngine.d.ts.map +1 -1
  39. package/dist/client/utils/endpoints.d.ts +1 -0
  40. package/dist/client/utils/endpoints.d.ts.map +1 -1
  41. package/dist/client/utils/setClientToken.d.ts.map +1 -1
  42. package/dist/commentRepository/events/utils.d.ts.map +1 -1
  43. package/dist/core/events.d.ts +3 -3
  44. package/dist/core/events.d.ts.map +1 -1
  45. package/dist/core/model/idResolvers.d.ts.map +1 -1
  46. package/dist/index.cjs.js +616 -58
  47. package/dist/index.esm.js +616 -58
  48. package/dist/index.umd.js +3 -3
  49. package/dist/marker/events/onChannelUnreadInfoUpdatedLocal.d.ts +12 -0
  50. package/dist/marker/events/onChannelUnreadInfoUpdatedLocal.d.ts.map +1 -0
  51. package/dist/messageRepository/events/onMessageCreated.d.ts.map +1 -1
  52. package/dist/messageRepository/observers/getMessage.d.ts.map +1 -1
  53. package/dist/messageRepository/utils/markReadMessage.d.ts.map +1 -1
  54. package/dist/reactionRepository/api/addReaction.d.ts.map +1 -1
  55. package/dist/reactionRepository/api/removeReaction.d.ts.map +1 -1
  56. package/dist/reactionRepository/observers/getReactions/ReactionPaginationController.d.ts.map +1 -1
  57. package/package.json +1 -1
  58. package/src/@types/core/events.ts +2 -1
  59. package/src/@types/core/model.ts +4 -0
  60. package/src/@types/core/readReceipt.ts +14 -1
  61. package/src/@types/domains/channel.ts +13 -0
  62. package/src/@types/domains/client.ts +3 -0
  63. package/src/channelRepository/api/markChannelsAsReadBySegment.ts +29 -0
  64. package/src/channelRepository/events/onChannelDeleted.ts +17 -4
  65. package/src/channelRepository/events/onChannelLeft.ts +11 -3
  66. package/src/{marker → channelRepository}/events/onChannelUnreadUpdatedLocal.ts +3 -3
  67. package/src/channelRepository/internalApi/getTotalChannelsUnread.ts +38 -0
  68. package/src/channelRepository/observers/getChannel.ts +3 -1
  69. package/src/channelRepository/observers/getChannels/ChannelLiveCollectionController.ts +6 -1
  70. package/src/channelRepository/observers/getTotalChannelsUnread.ts +129 -0
  71. package/src/channelRepository/observers/index.ts +1 -0
  72. package/src/channelRepository/utils/constructChannelDynamicValue.ts +12 -2
  73. package/src/channelRepository/utils/getLegacyChannelUnread.ts +5 -0
  74. package/src/channelRepository/utils/prepareChannelPayload.ts +68 -17
  75. package/src/client/api/createClient.ts +7 -1
  76. package/src/client/api/enableUnreadCount.ts +1 -0
  77. package/src/client/api/login.ts +5 -1
  78. package/src/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngine.ts +267 -0
  79. package/src/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngineOnLoginHandler.ts +21 -0
  80. package/src/client/utils/ReadReceiptSync/readReceiptSyncEngine.ts +74 -99
  81. package/src/client/utils/endpoints.ts +1 -0
  82. package/src/client/utils/setClientToken.ts +8 -0
  83. package/src/commentRepository/events/utils.ts +73 -0
  84. package/src/core/model/idResolvers.ts +2 -0
  85. package/src/fileRepository/api/uploadFile.ts +1 -1
  86. package/src/fileRepository/api/uploadImage.ts +1 -1
  87. package/src/fileRepository/api/uploadVideo.ts +1 -1
  88. package/src/marker/events/onChannelUnreadInfoUpdatedLocal.ts +29 -0
  89. package/src/messageRepository/events/onMessageCreated.ts +45 -1
  90. package/src/messageRepository/observers/getMessage.ts +0 -1
  91. package/src/messageRepository/utils/markReadMessage.ts +10 -3
  92. package/src/reactionRepository/api/addReaction.ts +8 -0
  93. package/src/reactionRepository/api/removeReaction.ts +8 -0
  94. package/src/reactionRepository/observers/getReactions/ReactionPaginationController.ts +8 -0
  95. package/dist/marker/events/onChannelUnreadUpdatedLocal.d.ts.map +0 -1
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Internal used only
3
+ *
4
+ * Fired when an {@link Amity.channelUnreadInfo} has been updated.
5
+ *
6
+ * @param callback The function to call when the event was fired
7
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
8
+ *
9
+ * @category ChannelMarker Events
10
+ */
11
+ export declare const onChannelUnreadInfoUpdatedLocal: (callback: Amity.Listener<Amity.Events['local.channelUnreadInfo.updated']>) => Amity.Unsubscriber;
12
+ //# sourceMappingURL=onChannelUnreadInfoUpdatedLocal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onChannelUnreadInfoUpdatedLocal.d.ts","sourceRoot":"","sources":["../../../src/marker/events/onChannelUnreadInfoUpdatedLocal.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AACH,eAAO,MAAM,+BAA+B,aAChC,MAAM,QAAQ,CAAC,MAAM,MAAM,CAAC,iCAAiC,CAAC,CAAC,KACxE,MAAM,YAaR,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"onMessageCreated.d.ts","sourceRoot":"","sources":["../../../src/messageRepository/events/onMessageCreated.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,oBAAoB,aACrB,MAAM,QAAQ,CAAC,MAAM,eAAe,CAAC,KAC9C,MAAM,YA+BR,CAAC;AAEF,eAAO,MAAM,qBAAqB,aACtB,MAAM,QAAQ,CAAC,MAAM,eAAe,CAAC,KAC9C,MAAM,YAoBR,CAAC"}
1
+ {"version":3,"file":"onMessageCreated.d.ts","sourceRoot":"","sources":["../../../src/messageRepository/events/onMessageCreated.ts"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,oBAAoB,aACrB,MAAM,QAAQ,CAAC,MAAM,eAAe,CAAC,KAC9C,MAAM,YA0ER,CAAC;AAEF,eAAO,MAAM,qBAAqB,aACtB,MAAM,QAAQ,CAAC,MAAM,eAAe,CAAC,KAC9C,MAAM,YAoBR,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"getMessage.d.ts","sourceRoot":"","sources":["../../../src/messageRepository/observers/getMessage.ts"],"names":[],"mappings":"AAoBA;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,UAAU,cACV,MAAM,OAAO,CAAC,WAAW,CAAC,YAC3B,MAAM,kBAAkB,CAAC,MAAM,OAAO,CAAC,KAChD,MAAM,YAmBR,CAAC"}
1
+ {"version":3,"file":"getMessage.d.ts","sourceRoot":"","sources":["../../../src/messageRepository/observers/getMessage.ts"],"names":[],"mappings":"AAmBA;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,UAAU,cACV,MAAM,OAAO,CAAC,WAAW,CAAC,YAC3B,MAAM,kBAAkB,CAAC,MAAM,OAAO,CAAC,KAChD,MAAM,YAmBR,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"markReadMessage.d.ts","sourceRoot":"","sources":["../../../src/messageRepository/utils/markReadMessage.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,eAAe,YAAa,MAAM,eAAe,SAK7D,CAAC"}
1
+ {"version":3,"file":"markReadMessage.d.ts","sourceRoot":"","sources":["../../../src/messageRepository/utils/markReadMessage.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,eAAe,YAAa,MAAM,eAAe,SAU7D,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"addReaction.d.ts","sourceRoot":"","sources":["../../../src/reactionRepository/api/addReaction.ts"],"names":[],"mappings":"AAWA;;;;;;;;;;;;;;;KAeK;AACL,eAAO,MAAM,WAAW;oBACP,MAAM,QAAQ,CAAC,eAAe,CAAC,eACjC,MAAM,QAAQ,CAAC,aAAa,CAAC,gBAC5B,MAAM,eAAe,CAAC,cAAc,CAAC,GAClD,QAAQ,OAAO,CAAC;IA4EnB;;;;;;;;;;;;;;SAcK;kCAEY,MAAM,aAAa,eACrB,MAAM,QAAQ,CAAC,aAAa,CAAC,gBAC5B,MAAM,eAAe,CAAC,cAAc,CAAC,GAClD,OAAO,GAAG,SAAS;CAtBrB,CAAC"}
1
+ {"version":3,"file":"addReaction.d.ts","sourceRoot":"","sources":["../../../src/reactionRepository/api/addReaction.ts"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;;;KAeK;AACL,eAAO,MAAM,WAAW;oBACP,MAAM,QAAQ,CAAC,eAAe,CAAC,eACjC,MAAM,QAAQ,CAAC,aAAa,CAAC,gBAC5B,MAAM,eAAe,CAAC,cAAc,CAAC,GAClD,QAAQ,OAAO,CAAC;IAmFnB;;;;;;;;;;;;;;SAcK;kCAEY,MAAM,aAAa,eACrB,MAAM,QAAQ,CAAC,aAAa,CAAC,gBAC5B,MAAM,eAAe,CAAC,cAAc,CAAC,GAClD,OAAO,GAAG,SAAS;CAtBrB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"removeReaction.d.ts","sourceRoot":"","sources":["../../../src/reactionRepository/api/removeReaction.ts"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;;;KAeK;AACL,eAAO,MAAM,cAAc;oBACV,MAAM,QAAQ,CAAC,eAAe,CAAC,eACjC,MAAM,QAAQ,CAAC,aAAa,CAAC,gBAC5B,MAAM,eAAe,CAAC,cAAc,CAAC,GAClD,QAAQ,OAAO,CAAC;IA+EnB;;;;;;;;;;;;;;SAcK;kCAEY,MAAM,aAAa,eACrB,MAAM,QAAQ,CAAC,aAAa,CAAC,gBAC5B,MAAM,eAAe,CAAC,cAAc,CAAC,GAClD,OAAO,GAAG,SAAS;CAtBrB,CAAC"}
1
+ {"version":3,"file":"removeReaction.d.ts","sourceRoot":"","sources":["../../../src/reactionRepository/api/removeReaction.ts"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;KAeK;AACL,eAAO,MAAM,cAAc;oBACV,MAAM,QAAQ,CAAC,eAAe,CAAC,eACjC,MAAM,QAAQ,CAAC,aAAa,CAAC,gBAC5B,MAAM,eAAe,CAAC,cAAc,CAAC,GAClD,QAAQ,OAAO,CAAC;IAsFnB;;;;;;;;;;;;;;SAcK;kCAEY,MAAM,aAAa,eACrB,MAAM,QAAQ,CAAC,aAAa,CAAC,gBAC5B,MAAM,eAAe,CAAC,cAAc,CAAC,GAClD,OAAO,GAAG,SAAS;CAtBrB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ReactionPaginationController.d.ts","sourceRoot":"","sources":["../../../../src/reactionRepository/observers/getReactions/ReactionPaginationController.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,4CAA4C,CAAC;AAIlF,qBAAa,4BAA6B,SAAQ,oBAAoB,CACpE,UAAU,EACV,KAAK,CAAC,sBAAsB,CAC7B;IACO,UAAU,CAAC,WAAW,EAAE,KAAK,CAAC,sBAAsB,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS;CAoBtF"}
1
+ {"version":3,"file":"ReactionPaginationController.d.ts","sourceRoot":"","sources":["../../../../src/reactionRepository/observers/getReactions/ReactionPaginationController.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,4CAA4C,CAAC;AAKlF,qBAAa,4BAA6B,SAAQ,oBAAoB,CACpE,UAAU,EACV,KAAK,CAAC,sBAAsB,CAC7B;IACO,UAAU,CAAC,WAAW,EAAE,KAAK,CAAC,sBAAsB,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS;CA2BtF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amityco/ts-sdk-react-native",
3
- "version": "7.0.3-d7a9877.0",
3
+ "version": "7.1.1-0e753e3.0",
4
4
  "license": "CC-BY-ND-4.0",
5
5
  "author": "amity.co <developers@amity.co> (https://amity.co)",
6
6
  "description": "Amity Social Cloud Typescript SDK",
@@ -237,7 +237,8 @@ declare global {
237
237
  };
238
238
 
239
239
  'local.subChannelUnread.updated': Amity.SubChannelUnreadInfo;
240
- 'local.channelUnread.updated': Amity.ChannelUnreadInfo;
240
+ 'local.channelUnreadInfo.updated': Amity.ChannelUnreadInfo;
241
+ 'local.channelUnread.updated': Amity.ChannelUnread;
241
242
 
242
243
  'local.story.created': Amity.StoryPayload;
243
244
  'local.story.updated': Amity.StoryPayload;
@@ -25,6 +25,8 @@ declare global {
25
25
  channelUnreadInfo: Amity.ChannelUnreadInfo;
26
26
  subChannelUnreadInfo: Amity.SubChannelUnreadInfo;
27
27
 
28
+ channelUnread: Amity.ChannelUnread;
29
+
28
30
  channelMarker: Amity.ChannelMarker;
29
31
  subChannelMarker: Amity.SubChannelMarker;
30
32
  messageMarker: Amity.MessageMarker;
@@ -84,6 +86,8 @@ declare global {
84
86
  channelUnreadInfo: Pick<Amity.ChannelUnreadInfo, 'channelId'>;
85
87
  subChannelUnreadInfo: Pick<Amity.SubChannelUnreadInfo, 'subChannelId'>;
86
88
 
89
+ channelUnread: Pick<Amity.ChannelUnread, 'channelId'>;
90
+
87
91
  channelMarker: Pick<Amity.ChannelMarker, 'entityId' | 'userId'>;
88
92
  subChannelMarker: Pick<Amity.SubChannelMarker, 'feedId' | 'entityId' | 'userId'>;
89
93
  messageMarker: Pick<Amity.MessageMarker, 'feedId' | 'contentId' | 'creatorId'>;
@@ -8,12 +8,25 @@ declare global {
8
8
  }
9
9
 
10
10
  type ReadReceipt = {
11
- subChannelId: Amity.SubChannel['subChannelId'];
11
+ channelId: Amity.Channel['channelId'];
12
12
  latestSegment: number;
13
13
  latestSyncSegment: number;
14
14
  };
15
15
 
16
16
  type ReadReceiptSyncJob = {
17
+ channelId: Amity.Channel['channelId'];
18
+ segment: number;
19
+ syncState: ReadReceiptSyncState;
20
+ retryCount: number;
21
+ };
22
+
23
+ type LegacyReadReceipt = {
24
+ subChannelId: Amity.SubChannel['subChannelId'];
25
+ latestSegment: number;
26
+ latestSyncSegment: number;
27
+ };
28
+
29
+ type LegacyReadReceiptSyncJob = {
17
30
  subChannelId: Amity.SubChannel['subChannelId'];
18
31
  segment: number;
19
32
  syncState: ReadReceiptSyncState;
@@ -84,6 +84,8 @@ declare global {
84
84
  > & {
85
85
  isMentioned: boolean;
86
86
  subChannelsUnreadCount: number;
87
+ // legacy unread count does not use the maker service
88
+ unreadCount: number;
87
89
  };
88
90
 
89
91
  /* public type */
@@ -137,5 +139,16 @@ declare global {
137
139
  Amity.Membership<'channel'>['userId'],
138
140
  Pick<QueryChannelMembers, 'page'>
139
141
  >;
142
+
143
+ // Use for channel's unread count value stored in the local cache
144
+ type ChannelUnread = {
145
+ channelId: Amity.Channel['channelId'];
146
+ unreadCount: number;
147
+ isMentioned: boolean;
148
+ readToSegment: number | null;
149
+ lastSegment: number;
150
+ lastMentionedSegment: number | null;
151
+ isDeleted: boolean;
152
+ };
140
153
  }
141
154
  }
@@ -46,6 +46,7 @@ declare global {
46
46
 
47
47
  log: Logger;
48
48
  http: AxiosInstance;
49
+ upload: AxiosInstance;
49
50
  mqtt?: Amity.MqttClient;
50
51
  ws?: SocketIOClient.Socket;
51
52
  emitter: Emitter<Amity.Events>;
@@ -66,6 +67,8 @@ declare global {
66
67
 
67
68
  isUnreadCountEnabled: boolean;
68
69
 
70
+ useLegacyUnreadCount: boolean;
71
+
69
72
  use: () => void;
70
73
 
71
74
  accessTokenExpiryWatcher: (sessionHandler: Amity.SessionHandler) => Amity.Unsubscriber;
@@ -0,0 +1,29 @@
1
+ import { getActiveClient } from '~/client/api/activeClient';
2
+
3
+ /**
4
+ *
5
+ * Mark subChannel as read by readToSegment
6
+ *
7
+ * @param subChannelIds the IDs of the {@link Amity.SubChannel} to update
8
+ * @param readToSegment the segment to mark as read
9
+ * @returns a success boolean if the {@link Amity.SubChannel} was updated
10
+ *
11
+ * @category Channel API
12
+ * @async
13
+ */
14
+
15
+ export const markChannelsAsReadBySegment = async (
16
+ readings: {
17
+ channelId: Amity.Channel['channelId'];
18
+ readToSegment: number;
19
+ }[],
20
+ ): Promise<boolean> => {
21
+ const client = getActiveClient();
22
+
23
+ try {
24
+ await client.http.post<Amity.MarkAsReadPayload>('api/v3/channels/seen', { channels: readings });
25
+ return true;
26
+ } catch (e) {
27
+ return false;
28
+ }
29
+ };
@@ -6,6 +6,7 @@ import { ingestInCache } from '~/cache/api/ingestInCache';
6
6
  import { prepareChannelPayload } from '../utils/prepareChannelPayload';
7
7
  import { addFlagIsDeletedSubChannelUnreadByChannelId } from '~/marker/utils/addFlagIsDeletedSubChannelUnreadByChannelId';
8
8
  import { deleteChannelUnreadByChannelId } from '../../marker/utils/deleteChannelUnreadByChannelId';
9
+ import { dropFromCache, pullFromCache, pushToCache } from '~/cache/api';
9
10
 
10
11
  type CallbackFn = (channel: Amity.StaticInternalChannel) => void;
11
12
  const callbacks: CallbackFn[] = [];
@@ -28,12 +29,24 @@ export const onChannelDeleted = (callback: Amity.Listener<Amity.StaticInternalCh
28
29
  const filter = async (payload: Amity.ChannelPayload) => {
29
30
  const data = await prepareChannelPayload(payload);
30
31
 
31
- if (client.isUnreadCountEnabled && client.getMarkerSyncConsistentMode()) {
32
- data.channels.forEach(channel => {
32
+ const isConsistentMode = client.getMarkerSyncConsistentMode() && client.isUnreadCountEnabled;
33
+ const isLegacyUnreadCount = client.useLegacyUnreadCount;
34
+
35
+ data.channels.forEach(channel => {
36
+ if (isConsistentMode) {
33
37
  addFlagIsDeletedSubChannelUnreadByChannelId(channel.channelId);
34
38
  deleteChannelUnreadByChannelId(channel.channelId);
35
- });
36
- }
39
+ } else if (isLegacyUnreadCount) {
40
+ const cacheKey = ['channelUnread', 'get', channel.channelId];
41
+ const cache = pullFromCache<Amity.ChannelUnread>(cacheKey);
42
+ if (cache) {
43
+ pushToCache(cacheKey, {
44
+ ...cache,
45
+ isDeleted: true,
46
+ });
47
+ }
48
+ }
49
+ });
37
50
 
38
51
  ingestInCache(data);
39
52
  callbacks.forEach(cb => cb(data.channels[0]));
@@ -6,6 +6,7 @@ import { ingestInCache } from '~/cache/api/ingestInCache';
6
6
  import { prepareChannelPayload } from '../utils';
7
7
  import { deleteChannelUnreadByChannelId } from '../../marker/utils/deleteChannelUnreadByChannelId';
8
8
  import { addFlagIsDeletedSubChannelUnreadByChannelId } from '~/marker/utils/addFlagIsDeletedSubChannelUnreadByChannelId';
9
+ import { dropFromCache } from '~/cache/api';
9
10
 
10
11
  type CallbackFn = (
11
12
  channel: Amity.StaticInternalChannel,
@@ -40,10 +41,17 @@ export const onChannelLeft = (
40
41
  isMessagePreviewUpdated: isLeftByMe,
41
42
  });
42
43
 
43
- if (client.isUnreadCountEnabled && client.getMarkerSyncConsistentMode() && isLeftByMe) {
44
+ const isConsistentMode = client.getMarkerSyncConsistentMode() && client.isUnreadCountEnabled;
45
+ const isLegacyUnreadCount = client.useLegacyUnreadCount;
46
+
47
+ if (isLeftByMe) {
44
48
  preparedPayload.channels.forEach(channel => {
45
- addFlagIsDeletedSubChannelUnreadByChannelId(channel.channelId);
46
- deleteChannelUnreadByChannelId(channel.channelId);
49
+ if (isConsistentMode) {
50
+ addFlagIsDeletedSubChannelUnreadByChannelId(channel.channelId);
51
+ deleteChannelUnreadByChannelId(channel.channelId);
52
+ } else if (isLegacyUnreadCount) {
53
+ dropFromCache(['channelUnread', 'get', channel.channelId]);
54
+ }
47
55
  });
48
56
  }
49
57
 
@@ -4,12 +4,12 @@ import { createEventSubscriber } from '~/core/events';
4
4
  /**
5
5
  * Internal used only
6
6
  *
7
- * Fired when an {@link Amity.userMessageFeedMarkers} has been resolved by Object Rsesolver
7
+ * Fired when an {@link Amity.ChannelUnread} has been updated.
8
8
  *
9
9
  * @param callback The function to call when the event was fired
10
10
  * @returns an {@link Amity.Unsubscriber} function to stop listening
11
11
  *
12
- * @category MessageMarker Events
12
+ * @category Channel Events
13
13
  */
14
14
  export const onChannelUnreadUpdatedLocal = (
15
15
  callback: Amity.Listener<Amity.Events['local.channelUnread.updated']>,
@@ -22,7 +22,7 @@ export const onChannelUnreadUpdatedLocal = (
22
22
 
23
23
  return createEventSubscriber(
24
24
  client,
25
- 'channelMarker/onChannelUnreadUpdatedLocal',
25
+ 'channel/onChannelUnreadUpdatedLocal',
26
26
  'local.channelUnread.updated',
27
27
  filter,
28
28
  );
@@ -0,0 +1,38 @@
1
+ import { queryCache } from '~/cache/api';
2
+ import { getActiveClient } from '~/client/api/activeClient';
3
+
4
+ /**
5
+ *
6
+ * Calculate user unread from {@link Amity.ChannelUnread} objects
7
+ *
8
+ * @returns the {@link Amity.UserUnread} objects
9
+ *
10
+ * @category Channel API
11
+ * @async
12
+ */
13
+
14
+ export const getTotalChannelsUnread = (): Amity.Cached<Amity.UserUnread> => {
15
+ const client = getActiveClient();
16
+ client.log('channel/getTotalChannelsUnread.locally');
17
+
18
+ const cachedChannelsUnread =
19
+ queryCache<Amity.ChannelUnread>(['channelUnread', 'get'])?.filter(({ data }) => {
20
+ return !data.isDeleted;
21
+ }) || [];
22
+
23
+ const totalChannelsUnread: Amity.UserUnread = cachedChannelsUnread?.reduce(
24
+ (acc, { data }) => {
25
+ acc.unreadCount += data.unreadCount;
26
+ acc.isMentioned = acc.isMentioned || data.isMentioned;
27
+ return acc;
28
+ },
29
+ { unreadCount: 0, isMentioned: false as boolean },
30
+ ) || { unreadCount: 0, isMentioned: false };
31
+
32
+ const cachedAt = client.cache && Date.now();
33
+
34
+ return {
35
+ data: totalChannelsUnread,
36
+ cachedAt,
37
+ };
38
+ };
@@ -32,8 +32,9 @@ import { isEqual } from '~/utils/isEqual';
32
32
  import { updateChannelCache } from '../utils/updateChannelCache';
33
33
  import { onChannelMarkerUpdated } from '~/marker/events/onChannelMarkerUpdated';
34
34
  import { onSubChannelCreated } from '~/subChannelRepository';
35
- import { onChannelUnreadUpdatedLocal } from '~/marker/events/onChannelUnreadUpdatedLocal';
35
+ import { onChannelUnreadInfoUpdatedLocal } from '~/marker/events/onChannelUnreadInfoUpdatedLocal';
36
36
  import { constructChannelObject } from '../utils/constructChannelObject';
37
+ import { onChannelUnreadUpdatedLocal } from '../events/onChannelUnreadUpdatedLocal';
37
38
 
38
39
  /* begin_public_function
39
40
  id: channel.get
@@ -295,6 +296,7 @@ export const getChannel = (
295
296
  'channel',
296
297
  ),
297
298
  convertEventPayload(onSubChannelCreated, 'channelId', 'channel'),
299
+ convertEventPayload(onChannelUnreadInfoUpdatedLocal, 'channelId', 'channel'),
298
300
  convertEventPayload(onChannelUnreadUpdatedLocal, 'channelId', 'channel'),
299
301
  ],
300
302
  {
@@ -55,8 +55,9 @@ import { prepareUnreadCountInfo } from '~/channelRepository/utils/prepareUnreadC
55
55
  import { resolveUnreadInfoOnChannelEvent } from '~/channelRepository/utils/resolveUnreadInfoOnChannelEvent';
56
56
  import { onChannelResolved } from '~/channelRepository/events/onChannelResolved';
57
57
  import { onUserMessageFeedMarkerResolved } from '~/marker/events/onUserMessageFeedMarkerResolved';
58
- import { onChannelUnreadUpdatedLocal } from '~/marker/events/onChannelUnreadUpdatedLocal';
58
+ import { onChannelUnreadInfoUpdatedLocal } from '~/marker/events/onChannelUnreadInfoUpdatedLocal';
59
59
  import { constructChannelObject } from '~/channelRepository/utils/constructChannelObject';
60
+ import { onChannelUnreadUpdatedLocal } from '~/channelRepository/events/onChannelUnreadUpdatedLocal';
60
61
 
61
62
  export class ChannelLiveCollectionController extends LiveCollectionController<
62
63
  'channel',
@@ -566,6 +567,10 @@ export class ChannelLiveCollectionController extends LiveCollectionController<
566
567
  },
567
568
  action: Amity.ChannelActionType.OnResolveUnread,
568
569
  },
570
+ {
571
+ fn: convertEventPayload(onChannelUnreadInfoUpdatedLocal, 'channelId', 'channel'),
572
+ action: Amity.ChannelActionType.OnUpdate,
573
+ },
569
574
  {
570
575
  fn: convertEventPayload(onChannelUnreadUpdatedLocal, 'channelId', 'channel'),
571
576
  action: Amity.ChannelActionType.OnUpdate,
@@ -0,0 +1,129 @@
1
+ import { getActiveUser } from '~/client/api/activeUser';
2
+ import { getTotalChannelsUnread as _getTotalChannelsUnread } from '../internalApi/getTotalChannelsUnread';
3
+ import { onChannelUnreadUpdatedLocal } from '../events/onChannelUnreadUpdatedLocal';
4
+ import { ASCApiError, ASCError } from '~/core/errors';
5
+ import { getActiveClient } from '~/client';
6
+ import { convertGetterPropsToStatic } from '~/utils/object';
7
+ import { createQuery, runQuery } from '~/core/query';
8
+ import {
9
+ UNSYNCED_OBJECT_CACHED_AT_MESSAGE,
10
+ UNSYNCED_OBJECT_CACHED_AT_VALUE,
11
+ } from '~/utils/constants';
12
+ import { isEqual } from '~/utils/isEqual';
13
+
14
+ /* begin_public_function
15
+ id: totalChannelsUnread.get
16
+ */
17
+ /**
18
+ * ```js
19
+ * import { ChannelRepository } from '@amityco/ts-sdk';
20
+ *
21
+ * let totalChannelsUnread;
22
+ *
23
+ * const unsubscribe = ChannelRepository.getTotalChannelsUnread(response => {
24
+ * unread = response.data;
25
+ * });
26
+ * ```
27
+ *
28
+ * Observe all mutation on a given {@link Amity.UserUnread}
29
+ *
30
+ * @returns An {@link Amity.UserUnread} function to run when willing to stop observing the message
31
+ *
32
+ * @category User Unread Live Object
33
+ *
34
+ */
35
+
36
+ export const getTotalChannelsUnread = (
37
+ callback: Amity.LiveObjectCallback<Amity.UserUnread | undefined>,
38
+ ): Amity.Unsubscriber => {
39
+ const { _id: userId } = getActiveUser();
40
+
41
+ if (!userId)
42
+ throw new ASCError(
43
+ 'The _id has not been defined in ActiveUser',
44
+ Amity.ClientError.UNKNOWN_ERROR,
45
+ Amity.ErrorLevel.ERROR,
46
+ );
47
+
48
+ const { log, cache } = getActiveClient();
49
+
50
+ if (!cache) {
51
+ console.log('For using Live Object feature you need to enable Cache!');
52
+ }
53
+
54
+ const timestamp = Date.now();
55
+ log(`liveTotalChannelsUnread(tmpid: ${timestamp}) > listen`);
56
+
57
+ const disposers: Amity.Unsubscriber[] = [];
58
+
59
+ let isUnsyncedModel = false; // for messages
60
+
61
+ let model: Amity.UserUnread | undefined;
62
+
63
+ const dispatcher = (data: Amity.LiveObject<Amity.UserUnread | undefined>) => {
64
+ const { data: userUnread } = data;
65
+
66
+ const callbackModel = userUnread
67
+ ? {
68
+ unreadCount: userUnread.unreadCount,
69
+ isMentioned: userUnread.isMentioned,
70
+ }
71
+ : undefined;
72
+
73
+ model = callbackModel ? convertGetterPropsToStatic(callbackModel) : callbackModel;
74
+
75
+ callback({
76
+ data: callbackModel
77
+ ? { ...callbackModel, isMentioned: callbackModel.isMentioned }
78
+ : callbackModel,
79
+
80
+ loading: data.loading,
81
+ error: data.error,
82
+ });
83
+ };
84
+
85
+ const realtimeRouter = (userUnread: Amity.UserUnread) => {
86
+ if (isEqual(model, userUnread)) return;
87
+
88
+ dispatcher({
89
+ loading: false,
90
+ data: userUnread,
91
+ });
92
+ };
93
+
94
+ const onFetch = () => {
95
+ const query = createQuery(async () => _getTotalChannelsUnread());
96
+
97
+ runQuery(query, ({ error, data, loading, origin, cachedAt }) => {
98
+ if (cachedAt === UNSYNCED_OBJECT_CACHED_AT_VALUE) {
99
+ dispatcher({
100
+ data,
101
+ origin,
102
+ loading: false,
103
+ error: new ASCApiError(
104
+ UNSYNCED_OBJECT_CACHED_AT_MESSAGE,
105
+ Amity.ClientError.DISALOOW_UNSYNCED_OBJECT,
106
+ Amity.ErrorLevel.ERROR,
107
+ ),
108
+ });
109
+
110
+ isUnsyncedModel = true;
111
+ disposers.forEach(fn => fn());
112
+ } else if (!isUnsyncedModel) {
113
+ dispatcher({ loading, data, origin, error });
114
+ }
115
+
116
+ if (error) {
117
+ disposers.forEach(fn => fn());
118
+ }
119
+ });
120
+ };
121
+
122
+ disposers.push(onChannelUnreadUpdatedLocal(realtimeRouter));
123
+
124
+ onFetch();
125
+
126
+ return () => {
127
+ disposers.forEach(fn => fn());
128
+ };
129
+ };
@@ -1,2 +1,3 @@
1
1
  export * from './getChannel';
2
2
  export * from './getChannels';
3
+ export * from './getTotalChannelsUnread';
@@ -1,17 +1,27 @@
1
+ import { get } from 'http';
1
2
  import { shallowClone } from '~/utils/shallowClone';
2
3
  import { getChannelIsMentioned } from './getChannelIsMentioned';
3
4
  import { getSubChannelsUnreadCount } from './getSubChannelsUnreadCount';
5
+ import { getActiveClient } from '~/client/api/activeClient';
6
+ import { getLegacyChannelUnread } from './getLegacyChannelUnread';
4
7
 
5
8
  export const constructChannelDynamicValue = (
6
9
  channel: Amity.StaticInternalChannel,
7
10
  ): Amity.InternalChannel => {
11
+ const client = getActiveClient();
8
12
  const { messageCount, ...rest } = channel;
13
+
9
14
  return shallowClone(rest, {
10
- get isMentioned() {
11
- return getChannelIsMentioned(rest);
15
+ get unreadCount() {
16
+ return getLegacyChannelUnread(rest.channelId)?.unreadCount ?? 0;
12
17
  },
13
18
  get subChannelsUnreadCount() {
14
19
  return getSubChannelsUnreadCount(rest);
15
20
  },
21
+ get isMentioned() {
22
+ if (client.useLegacyUnreadCount)
23
+ return getLegacyChannelUnread(rest.channelId)?.isMentioned ?? false;
24
+ return getChannelIsMentioned(rest);
25
+ },
16
26
  });
17
27
  };
@@ -0,0 +1,5 @@
1
+ import { pullFromCache } from '~/cache/api/pullFromCache';
2
+
3
+ export const getLegacyChannelUnread = (channelId: string) => {
4
+ return pullFromCache<Amity.ChannelUnreadInfo>(['channelUnread', 'get', channelId])?.data;
5
+ };
@@ -5,9 +5,8 @@ import { getChannelMarkers } from '~/marker/api/getChannelMarkers';
5
5
  import { updateChannelMessagePreviewCache } from '~/messagePreview/utils';
6
6
  import { getActiveClient } from '~/client/api/activeClient';
7
7
  import { pullFromCache } from '~/cache/api/pullFromCache';
8
- import { getSubChannelsUnreadCount } from './getSubChannelsUnreadCount';
9
- import { getChannelIsMentioned } from './getChannelIsMentioned';
10
8
  import { convertRawUserToInternalUser } from '~/userRepository/utils/convertRawUserToInternalUser';
9
+ import { pushToCache } from '~/cache/api';
11
10
 
12
11
  export const MARKER_INCLUDED_CHANNEL_TYPE = ['broadcast', 'conversation', 'community'];
13
12
  export const isUnreadCountSupport = ({ type }: Pick<Amity.RawChannel, 'type'>) =>
@@ -48,6 +47,48 @@ export const preUpdateChannelCache = (
48
47
  });
49
48
  };
50
49
 
50
+ const updateChannelUnread = ({
51
+ currentUserId,
52
+ channels,
53
+ channelUsers,
54
+ }: {
55
+ currentUserId: Amity.User['userId'];
56
+ channels: Amity.RawChannel[];
57
+ channelUsers: Amity.RawMembership<'channel'>[];
58
+ }) => {
59
+ for (let i = 0; i < channels.length; i += 1) {
60
+ const cacheKey = ['channelUnread', 'get', channels[i].channelId];
61
+ const channelUser = channelUsers.find(
62
+ channelUser =>
63
+ channelUser.channelId === channels[i].channelId && channelUser.userId === currentUserId,
64
+ );
65
+
66
+ let unreadCount = 0;
67
+ let readToSegment = null;
68
+ let lastMentionedSegment = null;
69
+ let isMentioned = false;
70
+
71
+ if (channelUser) {
72
+ readToSegment = channelUser.readToSegment;
73
+ lastMentionedSegment = channelUser.lastMentionedSegment;
74
+ unreadCount = Math.max(channels[i].messageCount - readToSegment, 0);
75
+ isMentioned = lastMentionedSegment > readToSegment;
76
+ }
77
+
78
+ const cacheChannelUnread: Amity.ChannelUnread = {
79
+ channelId: channels[i].channelId,
80
+ lastSegment: channels[i].messageCount,
81
+ readToSegment,
82
+ lastMentionedSegment,
83
+ unreadCount,
84
+ isMentioned,
85
+ isDeleted: channels[i].isDeleted || false,
86
+ };
87
+
88
+ pushToCache(cacheKey, cacheChannelUnread);
89
+ }
90
+ };
91
+
51
92
  export const prepareChannelPayload = async (
52
93
  rawPayload: Amity.ChannelPayload,
53
94
  options: { isMessagePreviewUpdated?: boolean } = { isMessagePreviewUpdated: true },
@@ -64,28 +105,38 @@ export const prepareChannelPayload = async (
64
105
  updateChannelMessagePreviewCache(rawPayload);
65
106
  }
66
107
 
67
- const markerIds = rawPayload.channels
68
- // filter channel by type. Only conversation, community and broadcast type are included.
69
- .filter(isUnreadCountSupport)
70
- .map(({ channelInternalId }) => channelInternalId);
71
-
72
- if (markerIds.length > 0) {
73
- // since the get markers method requires a channel cache to function with the reducer.
74
- preUpdateChannelCache(rawPayload, { isMessagePreviewUpdated: options.isMessagePreviewUpdated });
75
-
76
- try {
77
- await getChannelMarkers(markerIds);
78
- } catch (e) {
79
- // empty block (from the spec, allow marker fetch to fail without having to do anything)
108
+ if (client.useLegacyUnreadCount) {
109
+ updateChannelUnread({
110
+ channels: rawPayload.channels,
111
+ channelUsers: rawPayload.channelUsers,
112
+ currentUserId: client.userId!,
113
+ });
114
+ } else {
115
+ const markerIds = rawPayload.channels
116
+ // filter channel by type. Only conversation, community and broadcast type are included.
117
+ .filter(isUnreadCountSupport)
118
+ .map(({ channelInternalId }) => channelInternalId);
119
+
120
+ if (markerIds.length > 0) {
121
+ // since the get markers method requires a channel cache to function with the reducer.
122
+ preUpdateChannelCache(rawPayload, {
123
+ isMessagePreviewUpdated: options.isMessagePreviewUpdated,
124
+ });
125
+
126
+ try {
127
+ await getChannelMarkers(markerIds);
128
+ } catch (e) {
129
+ // empty block (from the spec, allow marker fetch to fail without having to do anything)
130
+ }
80
131
  }
81
132
  }
82
133
 
83
- // attach marker to channel
134
+ // convert raw channel to internal channel
84
135
  const channels = rawPayload.channels.map(payload =>
85
136
  convertFromRaw(payload, { isMessagePreviewUpdated: options.isMessagePreviewUpdated }),
86
137
  );
87
138
 
88
- // user marker to channel users
139
+ // convert raw channel user to membership (add user object)
89
140
  const channelUsers: Amity.Membership<'channel'>[] = rawPayload.channelUsers.map(channelUser => {
90
141
  return convertRawMembershipToMembership<'channel'>(channelUser);
91
142
  });