@stream-io/feeds-client 0.3.51 → 1.1.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.
- package/CHANGELOG.md +21 -0
- package/dist/cjs/index.js +2 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/react-bindings.js +5 -19
- package/dist/cjs/react-bindings.js.map +1 -1
- package/dist/es/index.mjs +15 -14
- package/dist/es/index.mjs.map +1 -1
- package/dist/es/react-bindings.mjs +5 -19
- package/dist/es/react-bindings.mjs.map +1 -1
- package/dist/{feeds-client-B4zeBggL.js → feeds-client-C1c6lcS3.js} +705 -214
- package/dist/feeds-client-C1c6lcS3.js.map +1 -0
- package/dist/{feeds-client-DeAqnd1a.mjs → feeds-client-jtUTE4AC.mjs} +711 -220
- package/dist/feeds-client-jtUTE4AC.mjs.map +1 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/dist/types/activity-with-state-updates/activity-with-state-updates.d.ts.map +1 -1
- package/dist/types/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivityRead.d.ts +6 -2
- package/dist/types/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivityRead.d.ts.map +1 -1
- package/dist/types/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivitySeen.d.ts +6 -2
- package/dist/types/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivitySeen.d.ts.map +1 -1
- package/dist/types/feed/activity-filter.d.ts +11 -0
- package/dist/types/feed/activity-filter.d.ts.map +1 -0
- package/dist/types/feed/event-handlers/activity/handle-activity-added.d.ts +3 -2
- package/dist/types/feed/event-handlers/activity/handle-activity-added.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/activity/handle-activity-deleted.d.ts +3 -2
- package/dist/types/feed/event-handlers/activity/handle-activity-deleted.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/activity/handle-activity-feedback.d.ts +5 -0
- package/dist/types/feed/event-handlers/activity/handle-activity-feedback.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/activity/handle-activity-pinned.d.ts +3 -2
- package/dist/types/feed/event-handlers/activity/handle-activity-pinned.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/activity/handle-activity-unpinned.d.ts +3 -2
- package/dist/types/feed/event-handlers/activity/handle-activity-unpinned.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/activity/handle-activity-updated.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/activity/index.d.ts +3 -1
- package/dist/types/feed/event-handlers/activity/index.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/activity-updater.d.ts +1 -0
- package/dist/types/feed/event-handlers/activity-updater.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/add-aggregated-activities-to-state.d.ts +1 -1
- package/dist/types/feed/event-handlers/add-aggregated-activities-to-state.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/bookmark/handle-bookmark-added.d.ts +6 -5
- package/dist/types/feed/event-handlers/bookmark/handle-bookmark-added.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/bookmark/handle-bookmark-deleted.d.ts +6 -5
- package/dist/types/feed/event-handlers/bookmark/handle-bookmark-deleted.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/bookmark/handle-bookmark-updated.d.ts +6 -5
- package/dist/types/feed/event-handlers/bookmark/handle-bookmark-updated.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/comment/handle-comment-updated.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/feed/handle-feed-deleted.d.ts +4 -0
- package/dist/types/feed/event-handlers/feed/handle-feed-deleted.d.ts.map +1 -0
- package/dist/types/feed/event-handlers/feed/handle-feed-updated.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/feed/index.d.ts +1 -0
- package/dist/types/feed/event-handlers/feed/index.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/feed-member/handle-feed-member-added.d.ts +3 -2
- package/dist/types/feed/event-handlers/feed-member/handle-feed-member-added.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/feed-member/handle-feed-member-removed.d.ts +3 -2
- package/dist/types/feed/event-handlers/feed-member/handle-feed-member-removed.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/feed-member/handle-feed-member-updated.d.ts +3 -2
- package/dist/types/feed/event-handlers/feed-member/handle-feed-member-updated.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/follow/handle-follow-created.d.ts +2 -2
- package/dist/types/feed/event-handlers/follow/handle-follow-created.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/follow/handle-follow-updated.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/notification-feed/handle-notification-feed-updated.d.ts +3 -2
- package/dist/types/feed/event-handlers/notification-feed/handle-notification-feed-updated.d.ts.map +1 -1
- package/dist/types/feed/feed.d.ts +17 -12
- package/dist/types/feed/feed.d.ts.map +1 -1
- package/dist/types/feeds-client/apply-new-activity-to-active-feeds.d.ts +4 -0
- package/dist/types/feeds-client/apply-new-activity-to-active-feeds.d.ts.map +1 -0
- package/dist/types/feeds-client/feeds-client.d.ts +29 -8
- package/dist/types/feeds-client/feeds-client.d.ts.map +1 -1
- package/dist/types/gen/feeds/FeedsApi.d.ts +6 -4
- package/dist/types/gen/feeds/FeedsApi.d.ts.map +1 -1
- package/dist/types/gen/models/index.d.ts +40 -2
- package/dist/types/gen/models/index.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/types.d.ts +15 -0
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/utils/state-update-queue.d.ts +11 -2
- package/dist/types/utils/state-update-queue.d.ts.map +1 -1
- package/dist/types/utils/unique-array-merge.d.ts +1 -1
- package/dist/types/utils/unique-array-merge.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/activity-with-state-updates/activity-with-state-updates.ts +8 -2
- package/src/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivityRead.ts +6 -20
- package/src/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivitySeen.ts +6 -20
- package/src/feed/activity-filter.ts +44 -0
- package/src/feed/event-handlers/activity/handle-activity-added.ts +22 -8
- package/src/feed/event-handlers/activity/handle-activity-deleted.ts +28 -2
- package/src/feed/event-handlers/activity/handle-activity-feedback.ts +17 -7
- package/src/feed/event-handlers/activity/handle-activity-pinned.ts +25 -3
- package/src/feed/event-handlers/activity/handle-activity-unpinned.ts +25 -2
- package/src/feed/event-handlers/activity/handle-activity-updated.ts +5 -1
- package/src/feed/event-handlers/activity/index.ts +3 -1
- package/src/feed/event-handlers/add-aggregated-activities-to-state.ts +11 -2
- package/src/feed/event-handlers/bookmark/handle-bookmark-added.ts +20 -11
- package/src/feed/event-handlers/bookmark/handle-bookmark-deleted.ts +21 -11
- package/src/feed/event-handlers/bookmark/handle-bookmark-updated.ts +24 -10
- package/src/feed/event-handlers/comment/handle-comment-updated.ts +11 -10
- package/src/feed/event-handlers/feed/handle-feed-deleted.ts +12 -0
- package/src/feed/event-handlers/feed/handle-feed-updated.ts +8 -0
- package/src/feed/event-handlers/feed/index.ts +1 -0
- package/src/feed/event-handlers/feed-member/handle-feed-member-added.ts +25 -2
- package/src/feed/event-handlers/feed-member/handle-feed-member-removed.ts +25 -2
- package/src/feed/event-handlers/feed-member/handle-feed-member-updated.ts +25 -2
- package/src/feed/event-handlers/follow/handle-follow-created.ts +18 -1
- package/src/feed/event-handlers/follow/handle-follow-updated.ts +14 -0
- package/src/feed/event-handlers/notification-feed/handle-notification-feed-updated.ts +68 -2
- package/src/feed/event-handlers/story-feeds/handle-story-feeds-updated.ts +1 -1
- package/src/feed/feed.ts +79 -26
- package/src/feeds-client/apply-new-activity-to-active-feeds.ts +9 -0
- package/src/feeds-client/feeds-client.ts +301 -28
- package/src/gen/feeds/FeedsApi.ts +79 -12
- package/src/gen/model-decoders/decoders.ts +7 -0
- package/src/gen/models/index.ts +66 -4
- package/src/index.ts +1 -0
- package/src/types.ts +17 -0
- package/src/utils/state-update-queue.ts +42 -28
- package/src/utils/unique-array-merge.ts +11 -3
- package/dist/feeds-client-B4zeBggL.js.map +0 -1
- package/dist/feeds-client-DeAqnd1a.mjs.map +0 -1
- package/dist/types/feed/event-handlers/activity/handle-activity-marked.d.ts +0 -12
- package/dist/types/feed/event-handlers/activity/handle-activity-marked.d.ts.map +0 -1
- package/src/feed/event-handlers/activity/handle-activity-marked.ts +0 -68
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stream-io/feeds-client",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"packageManager": "yarn@3.2.4",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"module": "./dist/es/index.mjs",
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"CHANGELOG.md"
|
|
51
51
|
],
|
|
52
52
|
"dependencies": {
|
|
53
|
+
"@stream-io/filter": "^1.0.0",
|
|
53
54
|
"@stream-io/logger": "^2.0.0",
|
|
54
55
|
"@stream-io/state-store": "^1.1.6",
|
|
55
56
|
"axios": "^1.7.7"
|
|
@@ -42,7 +42,9 @@ export class ActivityWithStateUpdates {
|
|
|
42
42
|
constructor(
|
|
43
43
|
public readonly id: string,
|
|
44
44
|
private readonly feedsClient: FeedsClient,
|
|
45
|
-
{ fromResponse }: { fromResponse?: ActivityResponse } = {
|
|
45
|
+
{ fromResponse }: { fromResponse?: ActivityResponse } = {
|
|
46
|
+
fromResponse: undefined,
|
|
47
|
+
},
|
|
46
48
|
) {
|
|
47
49
|
this.state = new StateStore<ActivityState>({
|
|
48
50
|
activity: undefined,
|
|
@@ -104,7 +106,7 @@ export class ActivityWithStateUpdates {
|
|
|
104
106
|
});
|
|
105
107
|
|
|
106
108
|
if (this.feed) {
|
|
107
|
-
this.feed.
|
|
109
|
+
this.feed.onNewActivity = () => 'ignore';
|
|
108
110
|
}
|
|
109
111
|
|
|
110
112
|
if (comments) {
|
|
@@ -177,6 +179,10 @@ export class ActivityWithStateUpdates {
|
|
|
177
179
|
[initialState],
|
|
178
180
|
[],
|
|
179
181
|
'start',
|
|
182
|
+
{
|
|
183
|
+
hasOwnFields: initialState.current_feed?.own_capabilities !== undefined,
|
|
184
|
+
backfillOwnFields: false,
|
|
185
|
+
},
|
|
180
186
|
);
|
|
181
187
|
this.feed?.state.partialNext({
|
|
182
188
|
activities,
|
|
@@ -1,30 +1,16 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
2
|
-
|
|
3
|
-
import { useFeedContext } from '../../contexts/StreamFeedContext';
|
|
4
|
-
import { useNotificationStatus } from './useNotificationStatus';
|
|
5
1
|
import type { Feed } from '../../../../feed';
|
|
6
2
|
import type { AggregatedActivityResponse } from '../../../../gen/models';
|
|
7
3
|
|
|
4
|
+
/**
|
|
5
|
+
* @deprecated use aggregatedActivity.is_read instead
|
|
6
|
+
* @returns
|
|
7
|
+
*/
|
|
8
8
|
export const useIsAggregatedActivityRead = ({
|
|
9
|
-
feed:
|
|
9
|
+
feed: _,
|
|
10
10
|
aggregatedActivity,
|
|
11
11
|
}: {
|
|
12
12
|
feed?: Feed;
|
|
13
13
|
aggregatedActivity: AggregatedActivityResponse;
|
|
14
14
|
}) => {
|
|
15
|
-
|
|
16
|
-
const feed = feedFromProps ?? feedFromContext;
|
|
17
|
-
|
|
18
|
-
const { read_activities: readActivities, last_read_at: lastReadAt } =
|
|
19
|
-
useNotificationStatus(feed) ?? {};
|
|
20
|
-
|
|
21
|
-
const group = aggregatedActivity.group;
|
|
22
|
-
|
|
23
|
-
return useMemo(
|
|
24
|
-
() =>
|
|
25
|
-
(lastReadAt &&
|
|
26
|
-
aggregatedActivity.updated_at.getTime() <= lastReadAt.getTime()) ||
|
|
27
|
-
(readActivities ?? []).includes(group),
|
|
28
|
-
[lastReadAt, aggregatedActivity.updated_at, readActivities, group],
|
|
29
|
-
);
|
|
15
|
+
return aggregatedActivity.is_read;
|
|
30
16
|
};
|
|
@@ -1,30 +1,16 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
2
|
-
|
|
3
|
-
import { useFeedContext } from '../../contexts/StreamFeedContext';
|
|
4
|
-
import { useNotificationStatus } from './useNotificationStatus';
|
|
5
1
|
import type { Feed } from '../../../../feed';
|
|
6
2
|
import type { AggregatedActivityResponse } from '../../../../gen/models';
|
|
7
3
|
|
|
4
|
+
/**
|
|
5
|
+
* @deprecated use aggregatedActivity.is_seen instead
|
|
6
|
+
* @returns
|
|
7
|
+
*/
|
|
8
8
|
export const useIsAggregatedActivitySeen = ({
|
|
9
|
-
feed:
|
|
9
|
+
feed: _,
|
|
10
10
|
aggregatedActivity,
|
|
11
11
|
}: {
|
|
12
12
|
feed?: Feed;
|
|
13
13
|
aggregatedActivity: AggregatedActivityResponse;
|
|
14
14
|
}) => {
|
|
15
|
-
|
|
16
|
-
const feed = feedFromProps ?? feedFromContext;
|
|
17
|
-
|
|
18
|
-
const { seen_activities: seenActivities, last_seen_at: lastSeenAt } =
|
|
19
|
-
useNotificationStatus(feed) ?? {};
|
|
20
|
-
|
|
21
|
-
const group = aggregatedActivity.group;
|
|
22
|
-
|
|
23
|
-
return useMemo(
|
|
24
|
-
() =>
|
|
25
|
-
(lastSeenAt &&
|
|
26
|
-
aggregatedActivity.updated_at.getTime() < lastSeenAt.getTime()) ||
|
|
27
|
-
(seenActivities ?? []).includes(group),
|
|
28
|
-
[lastSeenAt, aggregatedActivity.updated_at, seenActivities, group],
|
|
29
|
-
);
|
|
15
|
+
return aggregatedActivity.is_seen;
|
|
30
16
|
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { itemMatchesFilter, resolveDotPathValue } from '@stream-io/filter';
|
|
2
|
+
import type { ActivityResponse, GetOrCreateFeedRequest } from '../gen/models';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Resolvers that map feed filter field names to activity properties.
|
|
6
|
+
* - activity_type: API filter key maps to activity.type
|
|
7
|
+
* - within_bounds: API filter key maps to activity.location (for bounds check)
|
|
8
|
+
*/
|
|
9
|
+
const activityResolvers = [
|
|
10
|
+
{
|
|
11
|
+
matchesField: (field: string) => field === 'activity_type',
|
|
12
|
+
resolve: (activity: ActivityResponse) => activity.type,
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
matchesField: (field: string) => field === 'within_bounds',
|
|
16
|
+
resolve: (activity: ActivityResponse) => activity.location,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
matchesField: () => true,
|
|
20
|
+
resolve: (item: any, path: any) => resolveDotPathValue(item, path),
|
|
21
|
+
},
|
|
22
|
+
] as const;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Returns true if the activity matches the feed's getOrCreate filter (e.g. filter_tags, activity_type, within_bounds).
|
|
26
|
+
* Use this inside onNewActivity to only add activities that match the current feed filter.
|
|
27
|
+
*
|
|
28
|
+
* @param activity - The activity to check
|
|
29
|
+
* @param requestConfig - The last getOrCreate request config (contains the filter). If omitted or filter is empty, returns true.
|
|
30
|
+
* @returns true if the activity matches the filter or there is no filter
|
|
31
|
+
*/
|
|
32
|
+
export function activityFilter(
|
|
33
|
+
activity: ActivityResponse,
|
|
34
|
+
requestConfig?: GetOrCreateFeedRequest,
|
|
35
|
+
): boolean {
|
|
36
|
+
const filter = requestConfig?.filter;
|
|
37
|
+
if (!filter || typeof filter !== 'object') {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
return itemMatchesFilter(activity, filter, {
|
|
41
|
+
resolvers: [...activityResolvers],
|
|
42
|
+
arrayEqMode: 'contains',
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -7,7 +7,13 @@ export function addActivitiesToState(
|
|
|
7
7
|
newActivities: ActivityResponse[],
|
|
8
8
|
activities: ActivityResponse[] | undefined,
|
|
9
9
|
position: 'start' | 'end',
|
|
10
|
-
{
|
|
10
|
+
{
|
|
11
|
+
hasOwnFields,
|
|
12
|
+
backfillOwnFields,
|
|
13
|
+
}: { hasOwnFields: boolean; backfillOwnFields: boolean } = {
|
|
14
|
+
hasOwnFields: true,
|
|
15
|
+
backfillOwnFields: true,
|
|
16
|
+
},
|
|
11
17
|
) {
|
|
12
18
|
if (activities === undefined) {
|
|
13
19
|
return {
|
|
@@ -34,7 +40,10 @@ export function addActivitiesToState(
|
|
|
34
40
|
...activities,
|
|
35
41
|
...(position === 'end' ? newActivitiesDeduplicated : []),
|
|
36
42
|
];
|
|
37
|
-
this.
|
|
43
|
+
this.activitiesAddedOrUpdated(newActivitiesDeduplicated, {
|
|
44
|
+
hasOwnFields,
|
|
45
|
+
backfillOwnFields,
|
|
46
|
+
});
|
|
38
47
|
|
|
39
48
|
result = { changed: true, activities: updatedActivities };
|
|
40
49
|
}
|
|
@@ -46,17 +55,22 @@ export function handleActivityAdded(
|
|
|
46
55
|
this: Feed,
|
|
47
56
|
event: EventPayload<'feeds.activity.added'>,
|
|
48
57
|
) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
58
|
+
const currentUser = this.client.state.getLatestValue().connected_user;
|
|
59
|
+
const decision = this.resolveNewActivityDecision(
|
|
60
|
+
event.activity,
|
|
61
|
+
currentUser,
|
|
62
|
+
false,
|
|
63
|
+
);
|
|
64
|
+
if (decision === 'ignore') {
|
|
65
|
+
return;
|
|
53
66
|
}
|
|
67
|
+
const position = decision === 'add-to-end' ? 'end' : 'start';
|
|
54
68
|
const currentActivities = this.currentState.activities;
|
|
55
69
|
const result = addActivitiesToState.bind(this)(
|
|
56
70
|
[event.activity],
|
|
57
71
|
currentActivities,
|
|
58
|
-
|
|
59
|
-
{
|
|
72
|
+
position,
|
|
73
|
+
{ hasOwnFields: false, backfillOwnFields: true },
|
|
60
74
|
);
|
|
61
75
|
if (result.changed) {
|
|
62
76
|
const activity = event.activity;
|
|
@@ -3,7 +3,13 @@ import type {
|
|
|
3
3
|
ActivityPinResponse,
|
|
4
4
|
ActivityResponse,
|
|
5
5
|
} from '../../../gen/models';
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
EventPayload,
|
|
8
|
+
PartializeAllBut,
|
|
9
|
+
UpdateStateResult,
|
|
10
|
+
} from '../../../types-internal';
|
|
11
|
+
import { getStateUpdateQueueId, shouldUpdateState } from '../../../utils';
|
|
12
|
+
import { eventTriggeredByConnectedUser } from '../../../utils/event-triggered-by-connected-user';
|
|
7
13
|
|
|
8
14
|
export function removeActivityFromState(
|
|
9
15
|
this: Feed,
|
|
@@ -45,10 +51,30 @@ export const removePinnedActivityFromState = (
|
|
|
45
51
|
}
|
|
46
52
|
};
|
|
47
53
|
|
|
54
|
+
export type ActivityDeletedPayload = PartializeAllBut<
|
|
55
|
+
EventPayload<'feeds.activity.deleted'>,
|
|
56
|
+
'activity'
|
|
57
|
+
>;
|
|
58
|
+
|
|
48
59
|
export function handleActivityDeleted(
|
|
49
60
|
this: Feed,
|
|
50
|
-
event:
|
|
61
|
+
event: ActivityDeletedPayload,
|
|
62
|
+
fromWs?: boolean,
|
|
51
63
|
) {
|
|
64
|
+
if (
|
|
65
|
+
!shouldUpdateState({
|
|
66
|
+
stateUpdateQueueId: getStateUpdateQueueId(event, 'activity-deleted'),
|
|
67
|
+
stateUpdateQueue: this.stateUpdateQueue,
|
|
68
|
+
watch: this.currentState.watch,
|
|
69
|
+
fromWs,
|
|
70
|
+
isTriggeredByConnectedUser: eventTriggeredByConnectedUser.call(
|
|
71
|
+
this,
|
|
72
|
+
event,
|
|
73
|
+
),
|
|
74
|
+
})
|
|
75
|
+
) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
52
78
|
const {
|
|
53
79
|
activities: currentActivities,
|
|
54
80
|
pinned_activities: currentPinnedActivities,
|
|
@@ -2,12 +2,16 @@ import { updateEntityInArray } from '../../../utils';
|
|
|
2
2
|
import { isPin } from '../is-activity-pin';
|
|
3
3
|
import type { Feed } from '../../feed';
|
|
4
4
|
import type { EventPayload } from '../../../types-internal';
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
ActivityFeedbackEventPayload,
|
|
7
|
+
ActivityPinResponse,
|
|
8
|
+
ActivityResponse,
|
|
9
|
+
} from '../../../gen/models';
|
|
6
10
|
|
|
7
|
-
const updateActivityFromFeedback = <
|
|
11
|
+
export const updateActivityFromFeedback = <
|
|
8
12
|
T extends ActivityResponse | ActivityPinResponse,
|
|
9
13
|
>(
|
|
10
|
-
feedback: ActivityFeedbackEventPayload,
|
|
14
|
+
feedback: Pick<ActivityFeedbackEventPayload, 'activity_id' | 'value'>,
|
|
11
15
|
activities: T[] | undefined,
|
|
12
16
|
) => {
|
|
13
17
|
if (!activities) {
|
|
@@ -18,10 +22,16 @@ const updateActivityFromFeedback = <
|
|
|
18
22
|
}
|
|
19
23
|
return updateEntityInArray<T>({
|
|
20
24
|
entities: activities,
|
|
21
|
-
matcher: (e) =>
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
matcher: (e) => {
|
|
26
|
+
const newHidden = feedback.value === 'true';
|
|
27
|
+
if (isPin(e)) {
|
|
28
|
+
return (
|
|
29
|
+
e.activity.id === feedback.activity_id &&
|
|
30
|
+
e.activity.hidden !== newHidden
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
return e.id === feedback.activity_id && e.hidden !== newHidden;
|
|
34
|
+
},
|
|
25
35
|
updater: (e) => {
|
|
26
36
|
if (isPin(e)) {
|
|
27
37
|
return {
|
|
@@ -1,11 +1,34 @@
|
|
|
1
1
|
import type { ActivityPinResponse } from '../../../gen/models';
|
|
2
|
-
import type { EventPayload } from '../../../types-internal';
|
|
2
|
+
import type { EventPayload, PartializeAllBut } from '../../../types-internal';
|
|
3
3
|
import type { Feed } from '../../feed';
|
|
4
|
+
import { getStateUpdateQueueId, shouldUpdateState } from '../../../utils';
|
|
5
|
+
import { eventTriggeredByConnectedUser } from '../../../utils/event-triggered-by-connected-user';
|
|
6
|
+
|
|
7
|
+
export type ActivityPinnedPayload = PartializeAllBut<
|
|
8
|
+
EventPayload<'feeds.activity.pinned'>,
|
|
9
|
+
'pinned_activity'
|
|
10
|
+
>;
|
|
4
11
|
|
|
5
12
|
export function handleActivityPinned(
|
|
6
13
|
this: Feed,
|
|
7
|
-
event:
|
|
14
|
+
event: ActivityPinnedPayload,
|
|
15
|
+
fromWs?: boolean,
|
|
8
16
|
) {
|
|
17
|
+
if (
|
|
18
|
+
!shouldUpdateState({
|
|
19
|
+
stateUpdateQueueId: getStateUpdateQueueId(event, 'activity-pinned'),
|
|
20
|
+
stateUpdateQueue: this.stateUpdateQueue,
|
|
21
|
+
watch: this.currentState.watch,
|
|
22
|
+
fromWs,
|
|
23
|
+
isTriggeredByConnectedUser: eventTriggeredByConnectedUser.call(
|
|
24
|
+
this,
|
|
25
|
+
event,
|
|
26
|
+
),
|
|
27
|
+
})
|
|
28
|
+
) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
9
32
|
this.state.next((currentState) => {
|
|
10
33
|
const newState = {
|
|
11
34
|
...currentState,
|
|
@@ -17,7 +40,6 @@ export function handleActivityPinned(
|
|
|
17
40
|
const pinnedActivity: ActivityPinResponse = {
|
|
18
41
|
...event.pinned_activity,
|
|
19
42
|
user: event.user!,
|
|
20
|
-
feed: event.fid,
|
|
21
43
|
updated_at: new Date(),
|
|
22
44
|
};
|
|
23
45
|
|
|
@@ -1,10 +1,33 @@
|
|
|
1
|
-
import type { EventPayload } from '../../../types-internal';
|
|
1
|
+
import type { EventPayload, PartializeAllBut } from '../../../types-internal';
|
|
2
2
|
import type { Feed, FeedState } from '../../feed';
|
|
3
|
+
import { getStateUpdateQueueId, shouldUpdateState } from '../../../utils';
|
|
4
|
+
import { eventTriggeredByConnectedUser } from '../../../utils/event-triggered-by-connected-user';
|
|
5
|
+
|
|
6
|
+
export type ActivityUnpinnedPayload = PartializeAllBut<
|
|
7
|
+
EventPayload<'feeds.activity.unpinned'>,
|
|
8
|
+
'pinned_activity'
|
|
9
|
+
>;
|
|
3
10
|
|
|
4
11
|
export function handleActivityUnpinned(
|
|
5
12
|
this: Feed,
|
|
6
|
-
event:
|
|
13
|
+
event: ActivityUnpinnedPayload,
|
|
14
|
+
fromWs?: boolean,
|
|
7
15
|
) {
|
|
16
|
+
if (
|
|
17
|
+
!shouldUpdateState({
|
|
18
|
+
stateUpdateQueueId: getStateUpdateQueueId(event, 'activity-unpinned'),
|
|
19
|
+
stateUpdateQueue: this.stateUpdateQueue,
|
|
20
|
+
watch: this.currentState.watch,
|
|
21
|
+
fromWs,
|
|
22
|
+
isTriggeredByConnectedUser: eventTriggeredByConnectedUser.call(
|
|
23
|
+
this,
|
|
24
|
+
event,
|
|
25
|
+
),
|
|
26
|
+
})
|
|
27
|
+
) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
8
31
|
this.state.next((currentState) => {
|
|
9
32
|
let newState: FeedState | undefined;
|
|
10
33
|
|
|
@@ -90,7 +90,11 @@ export function handleActivityUpdated(
|
|
|
90
90
|
];
|
|
91
91
|
|
|
92
92
|
if (result1?.changed || result2.changed) {
|
|
93
|
-
this.
|
|
93
|
+
this.activitiesAddedOrUpdated([payload.activity], {
|
|
94
|
+
hasOwnFields:
|
|
95
|
+
payload.activity.current_feed?.own_capabilities !== undefined,
|
|
96
|
+
backfillOwnFields: false,
|
|
97
|
+
});
|
|
94
98
|
|
|
95
99
|
this.state.partialNext({
|
|
96
100
|
activities: result1?.changed ? result1.entities : currentActivities,
|
|
@@ -5,4 +5,6 @@ export * from './handle-activity-updated';
|
|
|
5
5
|
export * from './handle-activity-reaction-added';
|
|
6
6
|
export * from './handle-activity-reaction-deleted';
|
|
7
7
|
export * from './handle-activity-reaction-updated';
|
|
8
|
-
export * from './handle-activity-
|
|
8
|
+
export * from './handle-activity-pinned';
|
|
9
|
+
export * from './handle-activity-unpinned';
|
|
10
|
+
export * from './handle-activity-feedback';
|
|
@@ -6,7 +6,7 @@ import { updateActivity } from './activity-updater';
|
|
|
6
6
|
export const addAggregatedActivitiesToState = (
|
|
7
7
|
newAggregatedActivities: AggregatedActivityResponse[],
|
|
8
8
|
aggregatedActivities: AggregatedActivityResponse[] | undefined,
|
|
9
|
-
position: 'start' | 'end' | 'replace',
|
|
9
|
+
position: 'start' | 'end' | 'replace-then-end' | 'replace-then-start',
|
|
10
10
|
) => {
|
|
11
11
|
let result: UpdateStateResult<{
|
|
12
12
|
aggregated_activities: AggregatedActivityResponse[];
|
|
@@ -58,11 +58,20 @@ export const addAggregatedActivitiesToState = (
|
|
|
58
58
|
(a) => a.group,
|
|
59
59
|
);
|
|
60
60
|
break;
|
|
61
|
-
case 'replace':
|
|
61
|
+
case 'replace-then-end':
|
|
62
62
|
result.aggregated_activities = replaceUniqueArrayMerge(
|
|
63
63
|
aggregatedActivities ?? [],
|
|
64
64
|
newAggregatedActivities,
|
|
65
65
|
(a) => a.group,
|
|
66
|
+
'end',
|
|
67
|
+
);
|
|
68
|
+
break;
|
|
69
|
+
case 'replace-then-start':
|
|
70
|
+
result.aggregated_activities = replaceUniqueArrayMerge(
|
|
71
|
+
aggregatedActivities ?? [],
|
|
72
|
+
newAggregatedActivities,
|
|
73
|
+
(a) => a.group,
|
|
74
|
+
'start',
|
|
66
75
|
);
|
|
67
76
|
break;
|
|
68
77
|
}
|
|
@@ -2,10 +2,15 @@ import type { Feed } from '../../../feed';
|
|
|
2
2
|
import type {
|
|
3
3
|
ActivityPinResponse,
|
|
4
4
|
ActivityResponse,
|
|
5
|
-
BookmarkAddedEvent,
|
|
6
5
|
} from '../../../gen/models';
|
|
7
|
-
import type { EventPayload } from '../../../types-internal';
|
|
6
|
+
import type { EventPayload, PartializeAllBut } from '../../../types-internal';
|
|
8
7
|
import { updateEntityInArray } from '../../../utils';
|
|
8
|
+
import { isSameBookmark } from './handle-bookmark-deleted';
|
|
9
|
+
|
|
10
|
+
export type BookmarkAddedPayload = PartializeAllBut<
|
|
11
|
+
EventPayload<'feeds.bookmark.added'>,
|
|
12
|
+
'bookmark'
|
|
13
|
+
>;
|
|
9
14
|
|
|
10
15
|
const sharedUpdateActivity = ({
|
|
11
16
|
currentActivity,
|
|
@@ -13,7 +18,7 @@ const sharedUpdateActivity = ({
|
|
|
13
18
|
eventBelongsToCurrentUser,
|
|
14
19
|
}: {
|
|
15
20
|
currentActivity: ActivityResponse;
|
|
16
|
-
event:
|
|
21
|
+
event: BookmarkAddedPayload;
|
|
17
22
|
eventBelongsToCurrentUser: boolean;
|
|
18
23
|
}): ActivityResponse => {
|
|
19
24
|
let newOwnBookmarks = currentActivity.own_bookmarks;
|
|
@@ -30,13 +35,16 @@ const sharedUpdateActivity = ({
|
|
|
30
35
|
};
|
|
31
36
|
|
|
32
37
|
export const addBookmarkToActivities = (
|
|
33
|
-
event:
|
|
38
|
+
event: BookmarkAddedPayload,
|
|
34
39
|
activities: ActivityResponse[] | undefined,
|
|
35
40
|
eventBelongsToCurrentUser: boolean,
|
|
36
41
|
) =>
|
|
37
42
|
updateEntityInArray({
|
|
38
43
|
entities: activities,
|
|
39
|
-
matcher: (activity) =>
|
|
44
|
+
matcher: (activity) =>
|
|
45
|
+
activity.id === event.bookmark.activity.id &&
|
|
46
|
+
(!eventBelongsToCurrentUser ||
|
|
47
|
+
!activity.own_bookmarks.some((b) => isSameBookmark(b, event.bookmark))),
|
|
40
48
|
updater: (matchedActivity) =>
|
|
41
49
|
sharedUpdateActivity({
|
|
42
50
|
currentActivity: matchedActivity,
|
|
@@ -46,14 +54,18 @@ export const addBookmarkToActivities = (
|
|
|
46
54
|
});
|
|
47
55
|
|
|
48
56
|
export const addBookmarkToPinnedActivities = (
|
|
49
|
-
event:
|
|
57
|
+
event: BookmarkAddedPayload,
|
|
50
58
|
pinnedActivities: ActivityPinResponse[] | undefined,
|
|
51
59
|
eventBelongsToCurrentUser: boolean,
|
|
52
60
|
) =>
|
|
53
61
|
updateEntityInArray({
|
|
54
62
|
entities: pinnedActivities,
|
|
55
63
|
matcher: (pinnedActivity) =>
|
|
56
|
-
pinnedActivity.activity.id === event.bookmark.activity.id
|
|
64
|
+
pinnedActivity.activity.id === event.bookmark.activity.id &&
|
|
65
|
+
(!eventBelongsToCurrentUser ||
|
|
66
|
+
!pinnedActivity.activity.own_bookmarks.some((b) =>
|
|
67
|
+
isSameBookmark(b, event.bookmark),
|
|
68
|
+
)),
|
|
57
69
|
updater: (matchedPinnedActivity) => {
|
|
58
70
|
const newActivity = sharedUpdateActivity({
|
|
59
71
|
currentActivity: matchedPinnedActivity.activity,
|
|
@@ -72,10 +84,7 @@ export const addBookmarkToPinnedActivities = (
|
|
|
72
84
|
},
|
|
73
85
|
});
|
|
74
86
|
|
|
75
|
-
export function handleBookmarkAdded(
|
|
76
|
-
this: Feed,
|
|
77
|
-
event: EventPayload<'feeds.bookmark.added'>,
|
|
78
|
-
) {
|
|
87
|
+
export function handleBookmarkAdded(this: Feed, event: BookmarkAddedPayload) {
|
|
79
88
|
const {
|
|
80
89
|
activities: currentActivities,
|
|
81
90
|
pinned_activities: currentPinnedActivities,
|
|
@@ -2,14 +2,16 @@ import type { Feed } from '../../../feed';
|
|
|
2
2
|
import type {
|
|
3
3
|
ActivityPinResponse,
|
|
4
4
|
ActivityResponse,
|
|
5
|
-
BookmarkDeletedEvent,
|
|
6
5
|
BookmarkResponse,
|
|
7
6
|
} from '../../../gen/models';
|
|
8
|
-
import type { EventPayload } from '../../../types-internal';
|
|
7
|
+
import type { EventPayload, PartializeAllBut } from '../../../types-internal';
|
|
9
8
|
import { updateEntityInArray } from '../../../utils';
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
export type BookmarkDeletedPayload = PartializeAllBut<
|
|
11
|
+
EventPayload<'feeds.bookmark.deleted'>,
|
|
12
|
+
'bookmark'
|
|
13
|
+
>;
|
|
14
|
+
|
|
13
15
|
export const isSameBookmark = (
|
|
14
16
|
bookmark1: BookmarkResponse,
|
|
15
17
|
bookmark2: BookmarkResponse,
|
|
@@ -17,7 +19,8 @@ export const isSameBookmark = (
|
|
|
17
19
|
return (
|
|
18
20
|
bookmark1.user.id === bookmark2.user.id &&
|
|
19
21
|
bookmark1.activity.id === bookmark2.activity.id &&
|
|
20
|
-
bookmark1.folder?.id === bookmark2.folder?.id
|
|
22
|
+
bookmark1.folder?.id === bookmark2.folder?.id &&
|
|
23
|
+
bookmark1.updated_at.getTime() === bookmark2.updated_at.getTime()
|
|
21
24
|
);
|
|
22
25
|
};
|
|
23
26
|
|
|
@@ -27,7 +30,7 @@ const sharedUpdateActivity = ({
|
|
|
27
30
|
eventBelongsToCurrentUser,
|
|
28
31
|
}: {
|
|
29
32
|
currentActivity: ActivityResponse;
|
|
30
|
-
event:
|
|
33
|
+
event: BookmarkDeletedPayload;
|
|
31
34
|
eventBelongsToCurrentUser: boolean;
|
|
32
35
|
}): ActivityResponse => {
|
|
33
36
|
let newOwnBookmarks = currentActivity.own_bookmarks;
|
|
@@ -46,13 +49,16 @@ const sharedUpdateActivity = ({
|
|
|
46
49
|
};
|
|
47
50
|
|
|
48
51
|
export const removeBookmarkFromActivities = (
|
|
49
|
-
event:
|
|
52
|
+
event: BookmarkDeletedPayload,
|
|
50
53
|
activities: ActivityResponse[] | undefined,
|
|
51
54
|
eventBelongsToCurrentUser: boolean,
|
|
52
55
|
) =>
|
|
53
56
|
updateEntityInArray({
|
|
54
57
|
entities: activities,
|
|
55
|
-
matcher: (activity) =>
|
|
58
|
+
matcher: (activity) =>
|
|
59
|
+
activity.id === event.bookmark.activity.id &&
|
|
60
|
+
(!eventBelongsToCurrentUser ||
|
|
61
|
+
activity.own_bookmarks.some((b) => isSameBookmark(b, event.bookmark))),
|
|
56
62
|
updater: (matchedActivity) =>
|
|
57
63
|
sharedUpdateActivity({
|
|
58
64
|
currentActivity: matchedActivity,
|
|
@@ -62,14 +68,18 @@ export const removeBookmarkFromActivities = (
|
|
|
62
68
|
});
|
|
63
69
|
|
|
64
70
|
export const removeBookmarkFromPinnedActivities = (
|
|
65
|
-
event:
|
|
71
|
+
event: BookmarkDeletedPayload,
|
|
66
72
|
pinnedActivities: ActivityPinResponse[] | undefined,
|
|
67
73
|
eventBelongsToCurrentUser: boolean,
|
|
68
74
|
) =>
|
|
69
75
|
updateEntityInArray({
|
|
70
76
|
entities: pinnedActivities,
|
|
71
77
|
matcher: (pinnedActivity) =>
|
|
72
|
-
pinnedActivity.activity.id === event.bookmark.activity.id
|
|
78
|
+
pinnedActivity.activity.id === event.bookmark.activity.id &&
|
|
79
|
+
(!eventBelongsToCurrentUser ||
|
|
80
|
+
pinnedActivity.activity.own_bookmarks.some((b) =>
|
|
81
|
+
isSameBookmark(b, event.bookmark),
|
|
82
|
+
)),
|
|
73
83
|
updater: (matchedPinnedActivity) => {
|
|
74
84
|
const newActivity = sharedUpdateActivity({
|
|
75
85
|
currentActivity: matchedPinnedActivity.activity,
|
|
@@ -90,7 +100,7 @@ export const removeBookmarkFromPinnedActivities = (
|
|
|
90
100
|
|
|
91
101
|
export function handleBookmarkDeleted(
|
|
92
102
|
this: Feed,
|
|
93
|
-
event:
|
|
103
|
+
event: BookmarkDeletedPayload,
|
|
94
104
|
) {
|
|
95
105
|
const {
|
|
96
106
|
activities: currentActivities,
|