@stream-io/feeds-client 0.2.12 → 0.2.13

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 (26) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/cjs/index.js +1 -1
  3. package/dist/cjs/react-bindings.js +22 -14
  4. package/dist/cjs/react-bindings.js.map +1 -1
  5. package/dist/es/index.mjs +2 -2
  6. package/dist/es/react-bindings.mjs +22 -14
  7. package/dist/es/react-bindings.mjs.map +1 -1
  8. package/dist/{index-o7AeSkxa.js → index-RzB4c4g6.js} +81 -9
  9. package/dist/index-RzB4c4g6.js.map +1 -0
  10. package/dist/{index-D7QtnkUs.mjs → index-gvcJhGPH.mjs} +81 -9
  11. package/dist/index-gvcJhGPH.mjs.map +1 -0
  12. package/dist/tsconfig.tsbuildinfo +1 -1
  13. package/dist/types/bindings/react/hooks/feed-state-hooks/useAggregatedActivities.d.ts +9 -4
  14. package/dist/types/bindings/react/hooks/feed-state-hooks/useAggregatedActivities.d.ts.map +1 -1
  15. package/dist/types/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivityRead.d.ts.map +1 -1
  16. package/dist/types/feed/event-handlers/notification-feed/handle-notification-feed-updated.d.ts +8 -1
  17. package/dist/types/feed/event-handlers/notification-feed/handle-notification-feed-updated.d.ts.map +1 -1
  18. package/dist/types/feed/feed.d.ts.map +1 -1
  19. package/package.json +1 -1
  20. package/src/bindings/react/hooks/feed-state-hooks/useAggregatedActivities.ts +28 -4
  21. package/src/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivityRead.ts +4 -5
  22. package/src/feed/event-handlers/notification-feed/handle-notification-feed-updated.test.ts +309 -11
  23. package/src/feed/event-handlers/notification-feed/handle-notification-feed-updated.ts +89 -6
  24. package/src/feed/feed.ts +21 -1
  25. package/dist/index-D7QtnkUs.mjs.map +0 -1
  26. package/dist/index-o7AeSkxa.js.map +0 -1
@@ -1,10 +1,15 @@
1
1
  import type { Feed, FeedState } from '@self';
2
- declare const selector: ({ aggregated_activities }: FeedState) => {
3
- aggregated_activities: import("@self").AggregatedActivityResponse[] | undefined;
2
+ declare const selector: ({ is_loading_activities, next, aggregated_activities, }: FeedState) => {
3
+ is_loading: boolean;
4
+ has_next_page: boolean;
5
+ aggregated_activities: import("@self").AggregatedActivityResponse[];
6
+ };
7
+ type UseAggregatedActivitiesReturnType = ReturnType<typeof selector> & {
8
+ loadNextPage: () => Promise<void>;
4
9
  };
5
- type UseAggregatedActivitiesReturnType = ReturnType<typeof selector>;
6
10
  /**
7
- * A React hook that returns a reactive object containing the current aggregated activities.
11
+ * A React hook that returns a reactive object containing the current aggregated activities,
12
+ * loading state and whether there is a next page to paginate to or not.
8
13
  */
9
14
  export declare function useAggregatedActivities(feedFromProps: Feed): UseAggregatedActivitiesReturnType;
10
15
  export declare function useAggregatedActivities(feedFromProps?: Feed): UseAggregatedActivitiesReturnType | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"useAggregatedActivities.d.ts","sourceRoot":"","sources":["../../../../../../src/bindings/react/hooks/feed-state-hooks/useAggregatedActivities.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAI7C,QAAA,MAAM,QAAQ,GAAI,2BAA2B,SAAS;;CAEpD,CAAC;AAEH,KAAK,iCAAiC,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAErE;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,IAAI,GAClB,iCAAiC,CAAC;AACrC,wBAAgB,uBAAuB,CACrC,aAAa,CAAC,EAAE,IAAI,GACnB,iCAAiC,GAAG,SAAS,CAAC"}
1
+ {"version":3,"file":"useAggregatedActivities.d.ts","sourceRoot":"","sources":["../../../../../../src/bindings/react/hooks/feed-state-hooks/useAggregatedActivities.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAM7C,QAAA,MAAM,QAAQ,GAAI,yDAIf,SAAS;;;;CAIV,CAAC;AAEH,KAAK,iCAAiC,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,GAAG;IACrE,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACnC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,IAAI,GAClB,iCAAiC,CAAC;AACrC,wBAAgB,uBAAuB,CACrC,aAAa,CAAC,EAAE,IAAI,GACnB,iCAAiC,GAAG,SAAS,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useIsAggregatedActivityRead.d.ts","sourceRoot":"","sources":["../../../../../../src/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivityRead.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,0BAA0B,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAE9D,eAAO,MAAM,2BAA2B,GAAI,8CAGzC;IACD,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,kBAAkB,EAAE,0BAA0B,CAAC;CAChD,YAiBA,CAAC"}
1
+ {"version":3,"file":"useIsAggregatedActivityRead.d.ts","sourceRoot":"","sources":["../../../../../../src/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivityRead.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,0BAA0B,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAE9D,eAAO,MAAM,2BAA2B,GAAI,8CAGzC;IACD,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,kBAAkB,EAAE,0BAA0B,CAAC;CAChD,YAgBA,CAAC"}
@@ -1,7 +1,14 @@
1
1
  import type { Feed } from '../../../feed';
2
2
  import type { AggregatedActivityResponse, NotificationFeedUpdatedEvent, NotificationStatusResponse } from '../../../gen/models';
3
3
  import type { EventPayload, UpdateStateResult } from '../../../types-internal';
4
- export declare const updateNotificationFeedFromEvent: (event: NotificationFeedUpdatedEvent) => UpdateStateResult<{
4
+ export declare const addAggregatedActivitiesToState: (newAggregatedActivities: AggregatedActivityResponse[], aggregatedActivities: AggregatedActivityResponse[] | undefined, position: "start" | "end") => UpdateStateResult<{
5
+ aggregated_activities: AggregatedActivityResponse[];
6
+ }>;
7
+ export declare const updateNotificationStatus: (newNotificationStatus?: NotificationStatusResponse, currentNotificationStatus?: NotificationStatusResponse) => {
8
+ changed: boolean;
9
+ notification_status: NotificationStatusResponse | undefined;
10
+ };
11
+ export declare const updateNotificationFeedFromEvent: (event: NotificationFeedUpdatedEvent, currentAggregatedActivities?: AggregatedActivityResponse[], currentNotificationStatus?: NotificationStatusResponse) => UpdateStateResult<{
5
12
  data?: {
6
13
  notification_status?: NotificationStatusResponse;
7
14
  aggregated_activities?: AggregatedActivityResponse[];
@@ -1 +1 @@
1
- {"version":3,"file":"handle-notification-feed-updated.d.ts","sourceRoot":"","sources":["../../../../../src/feed/event-handlers/notification-feed/handle-notification-feed-updated.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,EACV,0BAA0B,EAC1B,4BAA4B,EAC5B,0BAA0B,EAC3B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE/E,eAAO,MAAM,+BAA+B,GAC1C,OAAO,4BAA4B,KAClC,iBAAiB,CAAC;IACnB,IAAI,CAAC,EAAE;QACL,mBAAmB,CAAC,EAAE,0BAA0B,CAAC;QACjD,qBAAqB,CAAC,EAAE,0BAA0B,EAAE,CAAC;KACtD,CAAC;CACH,CAyBA,CAAC;AAEF,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,YAAY,CAAC,iCAAiC,CAAC,QASvD"}
1
+ {"version":3,"file":"handle-notification-feed-updated.d.ts","sourceRoot":"","sources":["../../../../../src/feed/event-handlers/notification-feed/handle-notification-feed-updated.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,EACV,0BAA0B,EAC1B,4BAA4B,EAC5B,0BAA0B,EAC3B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAG/E,eAAO,MAAM,8BAA8B,GACzC,yBAAyB,0BAA0B,EAAE,EACrD,sBAAsB,0BAA0B,EAAE,GAAG,SAAS,EAC9D,UAAU,OAAO,GAAG,KAAK;2BAGA,0BAA0B,EAAE;EA4BtD,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,wBAAwB,0BAA0B,EAClD,4BAA4B,0BAA0B;;;CAoBvD,CAAC;AAEF,eAAO,MAAM,+BAA+B,GAC1C,OAAO,4BAA4B,EACnC,8BAA8B,0BAA0B,EAAE,EAC1D,4BAA4B,0BAA0B,KACrD,iBAAiB,CAAC;IACnB,IAAI,CAAC,EAAE;QACL,mBAAmB,CAAC,EAAE,0BAA0B,CAAC;QACjD,qBAAqB,CAAC,EAAE,0BAA0B,EAAE,CAAC;KACtD,CAAC;CACH,CAyCA,CAAC;AAEF,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,YAAY,CAAC,iCAAiC,CAAC,QAavD"}
@@ -1 +1 @@
1
- {"version":3,"file":"feed.d.ts","sourceRoot":"","sources":["../../../src/feed/feed.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"feed.d.ts","sourceRoot":"","sources":["../../../src/feed/feed.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream-io/feeds-client",
3
- "version": "0.2.12",
3
+ "version": "0.2.13",
4
4
  "packageManager": "yarn@3.2.4",
5
5
  "main": "./dist/es/index.mjs",
6
6
  "exports": {
@@ -1,15 +1,26 @@
1
1
  import type { Feed, FeedState } from '@self';
2
2
  import { useStateStore } from '@stream-io/state-store/react-bindings';
3
3
  import { useFeedContext } from '../../contexts/StreamFeedContext';
4
+ import { useMemo } from 'react';
5
+ import { useStableCallback } from '../internal';
4
6
 
5
- const selector = ({ aggregated_activities }: FeedState) => ({
7
+ const selector = ({
8
+ is_loading_activities,
9
+ next,
10
+ aggregated_activities = [],
11
+ }: FeedState) => ({
12
+ is_loading: is_loading_activities,
13
+ has_next_page: typeof next !== 'undefined',
6
14
  aggregated_activities,
7
15
  });
8
16
 
9
- type UseAggregatedActivitiesReturnType = ReturnType<typeof selector>;
17
+ type UseAggregatedActivitiesReturnType = ReturnType<typeof selector> & {
18
+ loadNextPage: () => Promise<void>;
19
+ };
10
20
 
11
21
  /**
12
- * A React hook that returns a reactive object containing the current aggregated activities.
22
+ * A React hook that returns a reactive object containing the current aggregated activities,
23
+ * loading state and whether there is a next page to paginate to or not.
13
24
  */
14
25
  export function useAggregatedActivities(
15
26
  feedFromProps: Feed,
@@ -21,5 +32,18 @@ export function useAggregatedActivities(feedFromProps?: Feed) {
21
32
  const feedFromContext = useFeedContext();
22
33
  const feed = feedFromProps ?? feedFromContext;
23
34
 
24
- return useStateStore(feed?.state, selector);
35
+ const data = useStateStore(feed?.state, selector);
36
+
37
+ const loadNextPage = useStableCallback(async () => {
38
+ if (!feed || !data?.has_next_page || data?.is_loading) {
39
+ return;
40
+ }
41
+
42
+ await feed.getNextPage();
43
+ });
44
+
45
+ return useMemo(
46
+ () => (data ? { ...data, loadNextPage } : undefined),
47
+ [data, loadNextPage],
48
+ );
25
49
  }
@@ -13,17 +13,16 @@ export const useIsAggregatedActivityRead = ({
13
13
  const feedFromContext = useFeedContext();
14
14
  const feed = feedFromProps ?? feedFromContext;
15
15
 
16
- const { read_activities: readActivities /* last_read_at: lastReadAt */ } =
16
+ const { read_activities: readActivities, last_read_at: lastReadAt } =
17
17
  useNotificationStatus(feed) ?? {};
18
18
 
19
19
  const group = aggregatedActivity.group;
20
20
 
21
21
  return useMemo(
22
22
  () =>
23
- // FIXME: This part of the condition does not work as marking individual groups as read also updates the last_read_at. Should be uncommented once it's fixed on the backend.
24
- // (lastReadAt &&
25
- // aggregatedActivity.updated_at.getTime() <= lastReadAt.getTime()) ||
23
+ (lastReadAt &&
24
+ aggregatedActivity.updated_at.getTime() <= lastReadAt.getTime()) ||
26
25
  (readActivities ?? []).includes(group),
27
- [readActivities, group],
26
+ [lastReadAt, aggregatedActivity.updated_at, readActivities, group],
28
27
  );
29
28
  };
@@ -4,7 +4,11 @@ import type {
4
4
  NotificationStatusResponse,
5
5
  AggregatedActivityResponse,
6
6
  } from '../../../gen/models';
7
- import { updateNotificationFeedFromEvent } from './handle-notification-feed-updated';
7
+ import {
8
+ updateNotificationFeedFromEvent,
9
+ addAggregatedActivitiesToState,
10
+ updateNotificationStatus,
11
+ } from './handle-notification-feed-updated';
8
12
 
9
13
  const createMockNotificationFeedUpdatedEvent = (
10
14
  overrides: Partial<NotificationFeedUpdatedEvent> = {},
@@ -30,6 +34,7 @@ const createMockAggregatedActivity = (
30
34
  activity_count: 1,
31
35
  created_at: new Date(),
32
36
  group: 'test-group',
37
+ user_count_truncated: false,
33
38
  score: 1,
34
39
  updated_at: new Date(),
35
40
  user_count: 1,
@@ -42,7 +47,34 @@ describe('notification-feed-utils', () => {
42
47
  it('should return unchanged if event has no notification_status or aggregated_activities', () => {
43
48
  const event = createMockNotificationFeedUpdatedEvent();
44
49
 
45
- const result = updateNotificationFeedFromEvent(event);
50
+ const result = updateNotificationFeedFromEvent(event, [], {
51
+ unread: 0,
52
+ unseen: 0,
53
+ read_activities: [],
54
+ seen_activities: [],
55
+ });
56
+
57
+ expect(result.changed).toBe(false);
58
+ });
59
+
60
+ it(`shouldn't update notification_status when event has notification_status but currentNotificationStatus is undefined`, () => {
61
+ const event = createMockNotificationFeedUpdatedEvent({
62
+ notification_status: createMockNotificationStatus(),
63
+ });
64
+ const result = updateNotificationFeedFromEvent(event, [], undefined);
65
+
66
+ expect(result.changed).toBe(false);
67
+ });
68
+
69
+ it(`shouldn't update aggregated_activities when event has aggregated_activities but currentAggregatedActivities is undefined`, () => {
70
+ const event = createMockNotificationFeedUpdatedEvent({
71
+ aggregated_activities: [createMockAggregatedActivity()],
72
+ });
73
+ const result = updateNotificationFeedFromEvent(
74
+ event,
75
+ undefined,
76
+ createMockNotificationStatus(),
77
+ );
46
78
 
47
79
  expect(result.changed).toBe(false);
48
80
  });
@@ -52,15 +84,23 @@ describe('notification-feed-utils', () => {
52
84
  unread: 5,
53
85
  unseen: 3,
54
86
  read_activities: ['activity1', 'activity2'],
87
+ seen_activities: [],
55
88
  });
56
89
  const event = createMockNotificationFeedUpdatedEvent({
57
90
  notification_status: notificationStatus,
58
91
  });
59
92
 
60
- const result = updateNotificationFeedFromEvent(event);
93
+ const result = updateNotificationFeedFromEvent(event, [], {
94
+ unread: 0,
95
+ unseen: 0,
96
+ read_activities: [],
97
+ seen_activities: [],
98
+ });
61
99
 
62
100
  expect(result.changed).toBe(true);
63
- expect(result.data?.notification_status).toBe(notificationStatus);
101
+ expect(result.data?.notification_status).toStrictEqual(
102
+ notificationStatus,
103
+ );
64
104
  expect(result.data?.aggregated_activities).toBeUndefined();
65
105
  });
66
106
 
@@ -73,10 +113,17 @@ describe('notification-feed-utils', () => {
73
113
  aggregated_activities: aggregatedActivities,
74
114
  });
75
115
 
76
- const result = updateNotificationFeedFromEvent(event);
116
+ const result = updateNotificationFeedFromEvent(event, [], {
117
+ unread: 0,
118
+ unseen: 0,
119
+ read_activities: [],
120
+ seen_activities: [],
121
+ });
77
122
 
78
123
  expect(result.changed).toBe(true);
79
- expect(result.data?.aggregated_activities).toBe(aggregatedActivities);
124
+ expect(result.data?.aggregated_activities).toStrictEqual(
125
+ aggregatedActivities,
126
+ );
80
127
  expect(result.data?.notification_status).toBeUndefined();
81
128
  });
82
129
 
@@ -93,11 +140,23 @@ describe('notification-feed-utils', () => {
93
140
  aggregated_activities: aggregatedActivities,
94
141
  });
95
142
 
96
- const result = updateNotificationFeedFromEvent(event);
143
+ const result = updateNotificationFeedFromEvent(event, [], {
144
+ unread: 0,
145
+ unseen: 0,
146
+ read_activities: [],
147
+ seen_activities: [],
148
+ });
97
149
 
98
150
  expect(result.changed).toBe(true);
99
- expect(result.data?.notification_status).toBe(notificationStatus);
100
- expect(result.data?.aggregated_activities).toBe(aggregatedActivities);
151
+ expect(result.data?.notification_status?.unread).toBe(
152
+ notificationStatus.unread,
153
+ );
154
+ expect(result.data?.notification_status?.unseen).toBe(
155
+ notificationStatus.unseen,
156
+ );
157
+ expect(result.data?.aggregated_activities).toStrictEqual(
158
+ aggregatedActivities,
159
+ );
101
160
  });
102
161
 
103
162
  it('should handle notification_status with all fields', () => {
@@ -105,16 +164,255 @@ describe('notification-feed-utils', () => {
105
164
  unread: 10,
106
165
  unseen: 5,
107
166
  last_seen_at: new Date('2023-01-01'),
167
+ seen_activities: [],
108
168
  read_activities: ['activity1', 'activity2', 'activity3'],
109
169
  });
110
170
  const event = createMockNotificationFeedUpdatedEvent({
111
171
  notification_status: notificationStatus,
112
172
  });
113
173
 
114
- const result = updateNotificationFeedFromEvent(event);
174
+ const result = updateNotificationFeedFromEvent(event, [], {
175
+ unread: 0,
176
+ unseen: 0,
177
+ read_activities: [],
178
+ seen_activities: [],
179
+ });
180
+
181
+ expect(result.changed).toBe(true);
182
+ expect(result.data?.notification_status).toStrictEqual(
183
+ notificationStatus,
184
+ );
185
+ });
186
+ });
187
+
188
+ describe('addAggregatedActivitiesToState', () => {
189
+ it('should add new activities when none exist', () => {
190
+ const newActivities = [
191
+ createMockAggregatedActivity({ group: 'group1' }),
192
+ createMockAggregatedActivity({ group: 'group2' }),
193
+ ];
194
+
195
+ const result = addAggregatedActivitiesToState(
196
+ newActivities,
197
+ undefined,
198
+ 'start',
199
+ );
200
+
201
+ expect(result.changed).toBe(true);
202
+ expect(result.aggregated_activities).toStrictEqual(newActivities);
203
+ });
204
+
205
+ it('should add new activities to existing ones', () => {
206
+ const existingActivities = [
207
+ createMockAggregatedActivity({ group: 'existing1' }),
208
+ ];
209
+ const newActivities = [
210
+ createMockAggregatedActivity({ group: 'new1' }),
211
+ createMockAggregatedActivity({ group: 'new2' }),
212
+ ];
213
+
214
+ const result = addAggregatedActivitiesToState(
215
+ newActivities,
216
+ existingActivities,
217
+ 'start',
218
+ );
219
+
220
+ expect(result.changed).toBe(true);
221
+ expect(result.aggregated_activities).toStrictEqual([
222
+ ...newActivities,
223
+ ...existingActivities,
224
+ ]);
225
+ });
226
+
227
+ it('should add new activities at the end when position is end', () => {
228
+ const existingActivities = [
229
+ createMockAggregatedActivity({ group: 'existing1' }),
230
+ ];
231
+ const newActivities = [createMockAggregatedActivity({ group: 'new1' })];
232
+
233
+ const result = addAggregatedActivitiesToState(
234
+ newActivities,
235
+ existingActivities,
236
+ 'end',
237
+ );
238
+
239
+ expect(result.changed).toBe(true);
240
+ expect(result.aggregated_activities).toStrictEqual([
241
+ ...existingActivities,
242
+ ...newActivities,
243
+ ]);
244
+ });
245
+
246
+ it('should update existing activities with same group (upsert)', () => {
247
+ const baseDate = new Date('2023-01-01');
248
+ const existingActivities = [
249
+ createMockAggregatedActivity({
250
+ group: 'group1',
251
+ activity_count: 1,
252
+ score: 10,
253
+ updated_at: baseDate,
254
+ }),
255
+ createMockAggregatedActivity({
256
+ group: 'group2',
257
+ activity_count: 2,
258
+ score: 20,
259
+ }),
260
+ ];
261
+ const newActivities = [
262
+ createMockAggregatedActivity({
263
+ group: 'group1',
264
+ activity_count: 3,
265
+ score: 30,
266
+ updated_at: new Date('2023-01-02'),
267
+ }),
268
+ createMockAggregatedActivity({
269
+ group: 'group3',
270
+ activity_count: 4,
271
+ score: 40,
272
+ }),
273
+ ];
274
+
275
+ const result = addAggregatedActivitiesToState(
276
+ newActivities,
277
+ existingActivities,
278
+ 'start',
279
+ );
115
280
 
116
281
  expect(result.changed).toBe(true);
117
- expect(result.data?.notification_status).toBe(notificationStatus);
282
+ expect(result.aggregated_activities).toHaveLength(3);
283
+
284
+ // Check that group1 was updated
285
+ const updatedGroup1 = result.aggregated_activities.find(
286
+ (a) => a.group === 'group1',
287
+ );
288
+ expect(updatedGroup1?.activity_count).toBe(3);
289
+ expect(updatedGroup1?.score).toBe(30);
290
+ expect(updatedGroup1?.updated_at).toEqual(new Date('2023-01-02'));
291
+
292
+ // Check that group2 remains unchanged
293
+ const unchangedGroup2 = result.aggregated_activities.find(
294
+ (a) => a.group === 'group2',
295
+ );
296
+ expect(unchangedGroup2?.activity_count).toBe(2);
297
+ expect(unchangedGroup2?.score).toBe(20);
298
+
299
+ // Check that group3 was added
300
+ const newGroup3 = result.aggregated_activities.find(
301
+ (a) => a.group === 'group3',
302
+ );
303
+ expect(newGroup3?.activity_count).toBe(4);
304
+ expect(newGroup3?.score).toBe(40);
305
+ });
306
+
307
+ it('should handle mixed new and existing activities', () => {
308
+ const existingActivities = [
309
+ createMockAggregatedActivity({ group: 'existing1' }),
310
+ createMockAggregatedActivity({ group: 'existing2' }),
311
+ ];
312
+ const newActivities = [
313
+ createMockAggregatedActivity({ group: 'existing1', activity_count: 5 }), // Update existing
314
+ createMockAggregatedActivity({ group: 'new1' }), // Add new
315
+ createMockAggregatedActivity({ group: 'existing2', score: 100 }), // Update existing
316
+ createMockAggregatedActivity({ group: 'new2' }), // Add new
317
+ ];
318
+
319
+ const result = addAggregatedActivitiesToState(
320
+ newActivities,
321
+ existingActivities,
322
+ 'start',
323
+ );
324
+
325
+ expect(result.changed).toBe(true);
326
+ expect(result.aggregated_activities).toHaveLength(4);
327
+
328
+ // Check that existing1 was updated
329
+ const updatedExisting1 = result.aggregated_activities.find(
330
+ (a) => a.group === 'existing1',
331
+ );
332
+ expect(updatedExisting1?.activity_count).toBe(5);
333
+
334
+ // Check that existing2 was updated
335
+ const updatedExisting2 = result.aggregated_activities.find(
336
+ (a) => a.group === 'existing2',
337
+ );
338
+ expect(updatedExisting2?.score).toBe(100);
339
+
340
+ // Check that new activities were added
341
+ expect(
342
+ result.aggregated_activities.find((a) => a.group === 'new1'),
343
+ ).toBeDefined();
344
+ expect(
345
+ result.aggregated_activities.find((a) => a.group === 'new2'),
346
+ ).toBeDefined();
347
+ });
348
+
349
+ it('should preserve order when adding at start', () => {
350
+ const existingActivities = [
351
+ createMockAggregatedActivity({ group: 'existing1' }),
352
+ createMockAggregatedActivity({ group: 'existing2' }),
353
+ ];
354
+ const newActivities = [
355
+ createMockAggregatedActivity({ group: 'new1' }),
356
+ createMockAggregatedActivity({ group: 'new2' }),
357
+ ];
358
+
359
+ const result = addAggregatedActivitiesToState(
360
+ newActivities,
361
+ existingActivities,
362
+ 'start',
363
+ );
364
+
365
+ expect(result.aggregated_activities).toStrictEqual([
366
+ ...newActivities,
367
+ ...existingActivities,
368
+ ]);
369
+ });
370
+
371
+ it('should preserve order when adding at end', () => {
372
+ const existingActivities = [
373
+ createMockAggregatedActivity({ group: 'existing1' }),
374
+ createMockAggregatedActivity({ group: 'existing2' }),
375
+ ];
376
+ const newActivities = [
377
+ createMockAggregatedActivity({ group: 'new1' }),
378
+ createMockAggregatedActivity({ group: 'new2' }),
379
+ ];
380
+
381
+ const result = addAggregatedActivitiesToState(
382
+ newActivities,
383
+ existingActivities,
384
+ 'end',
385
+ );
386
+
387
+ expect(result.aggregated_activities).toStrictEqual([
388
+ ...existingActivities,
389
+ ...newActivities,
390
+ ]);
391
+ });
392
+ });
393
+
394
+ describe('updateNotificationStatus', () => {
395
+ it('should replace old state with new one', () => {
396
+ const newNotificationStatus = createMockNotificationStatus({
397
+ unread: 5,
398
+ unseen: 3,
399
+ read_activities: ['activity1', 'activity2'],
400
+ seen_activities: ['activity3', 'activity4'],
401
+ });
402
+
403
+ const currentNotificationStatus = createMockNotificationStatus({
404
+ unread: 2,
405
+ unseen: 1,
406
+ read_activities: ['activity5', 'activity6'],
407
+ seen_activities: ['activity7', 'activity8'],
408
+ });
409
+
410
+ const result = updateNotificationStatus(
411
+ newNotificationStatus,
412
+ currentNotificationStatus,
413
+ );
414
+
415
+ expect(result.notification_status).toStrictEqual(newNotificationStatus);
118
416
  });
119
417
  });
120
418
  });
@@ -5,9 +5,72 @@ import type {
5
5
  NotificationStatusResponse,
6
6
  } from '../../../gen/models';
7
7
  import type { EventPayload, UpdateStateResult } from '../../../types-internal';
8
+ import { uniqueArrayMerge } from '../../../utils';
9
+
10
+ export const addAggregatedActivitiesToState = (
11
+ newAggregatedActivities: AggregatedActivityResponse[],
12
+ aggregatedActivities: AggregatedActivityResponse[] | undefined,
13
+ position: 'start' | 'end',
14
+ ) => {
15
+ let result: UpdateStateResult<{
16
+ aggregated_activities: AggregatedActivityResponse[];
17
+ }>;
18
+ if (newAggregatedActivities.length === 0) {
19
+ result = {
20
+ changed: false,
21
+ aggregated_activities: [],
22
+ };
23
+ } else {
24
+ result = {
25
+ changed: true,
26
+ aggregated_activities: [],
27
+ };
28
+ }
29
+
30
+ result.aggregated_activities =
31
+ position === 'start'
32
+ ? uniqueArrayMerge(
33
+ newAggregatedActivities,
34
+ aggregatedActivities ?? [],
35
+ (a) => a.group,
36
+ )
37
+ : uniqueArrayMerge(
38
+ aggregatedActivities ?? [],
39
+ newAggregatedActivities,
40
+ (a) => a.group,
41
+ );
42
+
43
+ return result;
44
+ };
45
+
46
+ export const updateNotificationStatus = (
47
+ newNotificationStatus?: NotificationStatusResponse,
48
+ currentNotificationStatus?: NotificationStatusResponse,
49
+ ) => {
50
+ if (!newNotificationStatus && !currentNotificationStatus) {
51
+ return {
52
+ changed: false,
53
+ notification_status: undefined,
54
+ };
55
+ } else if (!newNotificationStatus) {
56
+ return {
57
+ changed: false,
58
+ notification_status: currentNotificationStatus,
59
+ };
60
+ } else {
61
+ return {
62
+ changed: true,
63
+ notification_status: {
64
+ ...newNotificationStatus,
65
+ },
66
+ };
67
+ }
68
+ };
8
69
 
9
70
  export const updateNotificationFeedFromEvent = (
10
71
  event: NotificationFeedUpdatedEvent,
72
+ currentAggregatedActivities?: AggregatedActivityResponse[],
73
+ currentNotificationStatus?: NotificationStatusResponse,
11
74
  ): UpdateStateResult<{
12
75
  data?: {
13
76
  notification_status?: NotificationStatusResponse;
@@ -19,15 +82,31 @@ export const updateNotificationFeedFromEvent = (
19
82
  aggregated_activities?: AggregatedActivityResponse[];
20
83
  } = {};
21
84
 
22
- if (event.notification_status) {
23
- updates.notification_status = event.notification_status;
85
+ if (event.notification_status && currentNotificationStatus) {
86
+ const notificationStatusResult = updateNotificationStatus(
87
+ event.notification_status,
88
+ currentNotificationStatus,
89
+ );
90
+
91
+ if (notificationStatusResult.changed) {
92
+ updates.notification_status =
93
+ notificationStatusResult.notification_status;
94
+ }
24
95
  }
25
96
 
26
- if (event.aggregated_activities) {
27
- updates.aggregated_activities = event.aggregated_activities;
97
+ if (event.aggregated_activities && currentAggregatedActivities) {
98
+ const aggregatedActivitiesResult = addAggregatedActivitiesToState(
99
+ event.aggregated_activities,
100
+ currentAggregatedActivities,
101
+ 'start',
102
+ );
103
+
104
+ if (aggregatedActivitiesResult.changed) {
105
+ updates.aggregated_activities =
106
+ aggregatedActivitiesResult.aggregated_activities;
107
+ }
28
108
  }
29
109
 
30
- // Only return changed if we have actual updates
31
110
  if (Object.keys(updates).length > 0) {
32
111
  return {
33
112
  changed: true,
@@ -44,7 +123,11 @@ export function handleNotificationFeedUpdated(
44
123
  this: Feed,
45
124
  event: EventPayload<'feeds.notification_feed.updated'>,
46
125
  ) {
47
- const result = updateNotificationFeedFromEvent(event);
126
+ const result = updateNotificationFeedFromEvent(
127
+ event,
128
+ this.currentState.aggregated_activities,
129
+ this.currentState.notification_status,
130
+ );
48
131
  if (result.changed) {
49
132
  this.state.partialNext({
50
133
  notification_status: result.data?.notification_status,