@stream-io/feeds-client 0.1.10 → 0.1.11
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 +13 -0
- package/dist/@react-bindings/contexts/StreamFeedContext.d.ts +1 -1
- package/dist/@react-bindings/contexts/StreamFeedsContext.d.ts +1 -1
- package/dist/@react-bindings/hooks/feed-state-hooks/useComments.d.ts +1 -1
- package/dist/@react-bindings/hooks/feed-state-hooks/useFeedActivities.d.ts +1 -1
- package/dist/@react-bindings/hooks/feed-state-hooks/useFeedMetadata.d.ts +1 -1
- package/dist/@react-bindings/hooks/feed-state-hooks/useFollowers.d.ts +1 -1
- package/dist/@react-bindings/hooks/feed-state-hooks/useFollowing.d.ts +1 -1
- package/dist/@react-bindings/hooks/feed-state-hooks/useOwnCapabilities.d.ts +1 -1
- package/dist/@react-bindings/hooks/feed-state-hooks/useOwnFollows.d.ts +1 -1
- package/dist/@react-bindings/hooks/useCreateFeedsClient.d.ts +1 -1
- package/dist/@react-bindings/wrappers/StreamFeed.d.ts +1 -1
- package/dist/index-react-bindings.browser.cjs +1589 -1518
- package/dist/index-react-bindings.browser.cjs.map +1 -1
- package/dist/index-react-bindings.browser.js +1589 -1518
- package/dist/index-react-bindings.browser.js.map +1 -1
- package/dist/index-react-bindings.node.cjs +1589 -1518
- package/dist/index-react-bindings.node.cjs.map +1 -1
- package/dist/index-react-bindings.node.js +1589 -1518
- package/dist/index-react-bindings.node.js.map +1 -1
- package/dist/index.browser.cjs +1607 -1533
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.js +1605 -1534
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.node.cjs +1607 -1533
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.js +1605 -1534
- package/dist/index.node.js.map +1 -1
- package/dist/src/common/ActivitySearchSource.d.ts +1 -1
- package/dist/src/common/FeedSearchSource.d.ts +2 -2
- package/dist/src/common/Poll.d.ts +1 -1
- package/dist/src/common/UserSearchSource.d.ts +1 -1
- package/dist/src/common/real-time/StableWSConnection.d.ts +3 -3
- package/dist/src/feed/event-handlers/activity/handle-activity-added.d.ts +7 -0
- package/dist/src/feed/event-handlers/activity/handle-activity-deleted.d.ts +8 -0
- package/dist/src/feed/event-handlers/activity/handle-activity-reaction-added.d.ts +8 -0
- package/dist/src/feed/event-handlers/activity/handle-activity-reaction-deleted.d.ts +8 -0
- package/dist/src/feed/event-handlers/activity/handle-activity-removed-from-feed.d.ts +3 -0
- package/dist/src/feed/event-handlers/activity/handle-activity-updated.d.ts +8 -0
- package/dist/src/feed/event-handlers/activity/index.d.ts +6 -0
- package/dist/src/feed/event-handlers/bookmark/handle-bookmark-added.d.ts +8 -0
- package/dist/src/feed/event-handlers/bookmark/handle-bookmark-deleted.d.ts +9 -0
- package/dist/src/feed/event-handlers/bookmark/handle-bookmark-updated.d.ts +8 -0
- package/dist/src/feed/event-handlers/bookmark/index.d.ts +3 -0
- package/dist/src/feed/event-handlers/comment/handle-comment-added.d.ts +3 -0
- package/dist/src/feed/event-handlers/comment/handle-comment-deleted.d.ts +3 -0
- package/dist/src/feed/event-handlers/comment/handle-comment-reaction.d.ts +3 -0
- package/dist/src/feed/event-handlers/comment/handle-comment-updated.d.ts +3 -0
- package/dist/src/feed/event-handlers/comment/index.d.ts +4 -0
- package/dist/src/feed/event-handlers/feed/handle-feed-updated.d.ts +3 -0
- package/dist/src/feed/event-handlers/feed/index.d.ts +1 -0
- package/dist/src/feed/event-handlers/feed-member/handle-feed-member-added.d.ts +3 -0
- package/dist/src/feed/event-handlers/feed-member/handle-feed-member-removed.d.ts +3 -0
- package/dist/src/feed/event-handlers/feed-member/handle-feed-member-updated.d.ts +3 -0
- package/dist/src/feed/event-handlers/feed-member/index.d.ts +3 -0
- package/dist/src/feed/event-handlers/follow/handle-follow-created.d.ts +7 -0
- package/dist/src/feed/event-handlers/follow/handle-follow-deleted.d.ts +7 -0
- package/dist/src/feed/event-handlers/follow/handle-follow-updated.d.ts +3 -0
- package/dist/src/feed/event-handlers/follow/index.d.ts +3 -0
- package/dist/src/feed/event-handlers/index.d.ts +7 -0
- package/dist/src/feed/event-handlers/notification-feed/handle-notification-feed-updated.d.ts +3 -0
- package/dist/src/feed/event-handlers/notification-feed/index.d.ts +1 -0
- package/dist/src/{Feed.d.ts → feed/feed.d.ts} +15 -34
- package/dist/src/feed/index.d.ts +2 -0
- package/dist/src/{FeedsClient.d.ts → feeds-client.d.ts} +6 -5
- package/dist/src/gen/models/index.d.ts +5 -0
- package/dist/src/gen-imports.d.ts +1 -1
- package/dist/src/test-utils/index.d.ts +1 -0
- package/dist/src/test-utils/response-generators.d.ts +9 -0
- package/dist/src/types-internal.d.ts +7 -0
- package/dist/src/types.d.ts +1 -1
- package/dist/src/utils/check-has-another-page.d.ts +1 -0
- package/dist/src/utils/constants.d.ts +3 -0
- package/dist/src/utils/index.d.ts +5 -0
- package/dist/src/utils/state-update-queue.d.ts +6 -0
- package/dist/src/utils/type-assertions.d.ts +7 -0
- package/dist/src/utils/unique-array-merge.d.ts +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/index.ts +2 -2
- package/package.json +2 -1
- package/src/common/ActivitySearchSource.ts +1 -1
- package/src/common/FeedSearchSource.ts +2 -2
- package/src/common/Poll.ts +1 -1
- package/src/common/UserSearchSource.ts +1 -1
- package/src/{state-updates → feed/event-handlers/activity}/activity-reaction-utils.test.ts +12 -2
- package/src/{state-updates → feed/event-handlers/activity}/activity-utils.test.ts +3 -2
- package/src/{state-updates/activity-utils.ts → feed/event-handlers/activity/handle-activity-added.ts} +16 -36
- package/src/feed/event-handlers/activity/handle-activity-deleted.ts +30 -0
- package/src/feed/event-handlers/activity/handle-activity-reaction-added.ts +67 -0
- package/src/feed/event-handlers/activity/handle-activity-reaction-deleted.ts +75 -0
- package/src/feed/event-handlers/activity/handle-activity-removed-from-feed.ts +16 -0
- package/src/feed/event-handlers/activity/handle-activity-updated.ts +47 -0
- package/src/feed/event-handlers/activity/index.ts +6 -0
- package/src/{state-updates → feed/event-handlers/bookmark}/bookmark-utils.test.ts +2 -2
- package/src/feed/event-handlers/bookmark/handle-bookmark-added.ts +63 -0
- package/src/feed/event-handlers/bookmark/handle-bookmark-deleted.ts +84 -0
- package/src/feed/event-handlers/bookmark/handle-bookmark-updated.ts +76 -0
- package/src/feed/event-handlers/bookmark/index.ts +3 -0
- package/src/feed/event-handlers/comment/handle-comment-added.ts +38 -0
- package/src/feed/event-handlers/comment/handle-comment-deleted.ts +35 -0
- package/src/feed/event-handlers/comment/handle-comment-reaction.ts +61 -0
- package/src/feed/event-handlers/comment/handle-comment-updated.ts +35 -0
- package/src/feed/event-handlers/comment/index.ts +4 -0
- package/src/feed/event-handlers/feed/handle-feed-updated.ts +9 -0
- package/src/feed/event-handlers/feed/index.ts +1 -0
- package/src/feed/event-handlers/feed-member/handle-feed-member-added.ts +31 -0
- package/src/feed/event-handlers/feed-member/handle-feed-member-removed.ts +24 -0
- package/src/feed/event-handlers/feed-member/handle-feed-member-updated.ts +40 -0
- package/src/feed/event-handlers/feed-member/index.ts +3 -0
- package/src/feed/event-handlers/follow/handle-follow-created.test.ts +246 -0
- package/src/feed/event-handlers/follow/handle-follow-created.ts +93 -0
- package/src/feed/event-handlers/follow/handle-follow-deleted.test.ts +264 -0
- package/src/feed/event-handlers/follow/handle-follow-deleted.ts +95 -0
- package/src/feed/event-handlers/follow/handle-follow-updated.test.ts +174 -0
- package/src/feed/event-handlers/follow/handle-follow-updated.ts +88 -0
- package/src/feed/event-handlers/follow/index.ts +3 -0
- package/src/feed/event-handlers/index.ts +7 -0
- package/src/feed/event-handlers/notification-feed/handle-notification-feed-updated.ts +10 -0
- package/src/feed/event-handlers/notification-feed/index.ts +1 -0
- package/src/{Feed.ts → feed/feed.ts} +72 -483
- package/src/feed/index.ts +2 -0
- package/src/{FeedsClient.ts → feeds-client.ts} +26 -8
- package/src/gen/model-decoders/decoders.ts +7 -0
- package/src/gen/models/index.ts +10 -0
- package/src/gen-imports.ts +1 -1
- package/src/test-utils/index.ts +1 -0
- package/src/test-utils/response-generators.ts +102 -0
- package/src/types-internal.ts +11 -0
- package/src/types.ts +1 -1
- package/src/utils/check-has-another-page.ts +6 -0
- package/src/utils/constants.ts +3 -0
- package/src/utils/index.ts +5 -0
- package/src/{state-updates → utils}/state-update-queue.test.ts +6 -6
- package/src/utils/state-update-queue.ts +42 -0
- package/src/utils/type-assertions.ts +22 -0
- package/src/{utils.test.ts → utils/unique-array-merge.test.ts} +7 -3
- package/src/utils/unique-array-merge.ts +19 -0
- package/dist/src/state-updates/activity-reaction-utils.d.ts +0 -10
- package/dist/src/state-updates/activity-utils.d.ts +0 -13
- package/dist/src/state-updates/bookmark-utils.d.ts +0 -14
- package/dist/src/state-updates/follow-utils.d.ts +0 -19
- package/dist/src/state-updates/state-update-queue.d.ts +0 -15
- package/dist/src/utils.d.ts +0 -10
- package/src/state-updates/activity-reaction-utils.ts +0 -107
- package/src/state-updates/bookmark-utils.ts +0 -167
- package/src/state-updates/follow-utils.test.ts +0 -552
- package/src/state-updates/follow-utils.ts +0 -126
- package/src/state-updates/state-update-queue.ts +0 -35
- package/src/utils.ts +0 -48
- /package/dist/src/{ModerationClient.d.ts → moderation-client.d.ts} +0 -0
- /package/src/{ModerationClient.ts → moderation-client.ts} +0 -0
package/dist/index.browser.cjs
CHANGED
|
@@ -1231,6 +1231,12 @@ decoders.ThreadedCommentResponse = (input) => {
|
|
|
1231
1231
|
};
|
|
1232
1232
|
return decode(typeMappings, input);
|
|
1233
1233
|
};
|
|
1234
|
+
decoders.UnfollowResponse = (input) => {
|
|
1235
|
+
const typeMappings = {
|
|
1236
|
+
follow: { type: 'FollowResponse', isSingle: true },
|
|
1237
|
+
};
|
|
1238
|
+
return decode(typeMappings, input);
|
|
1239
|
+
};
|
|
1234
1240
|
decoders.UnpinActivityResponse = (input) => {
|
|
1235
1241
|
const typeMappings = {
|
|
1236
1242
|
activity: { type: 'ActivityResponse', isSingle: true },
|
|
@@ -3751,1632 +3757,1690 @@ const decodeWSEvent = (data) => {
|
|
|
3751
3757
|
}
|
|
3752
3758
|
};
|
|
3753
3759
|
|
|
3754
|
-
class
|
|
3755
|
-
constructor(
|
|
3756
|
-
this.
|
|
3757
|
-
this.group = group;
|
|
3758
|
-
this.id = id;
|
|
3759
|
-
}
|
|
3760
|
-
delete(request) {
|
|
3761
|
-
return this.feedsApi.deleteFeed({
|
|
3762
|
-
feed_id: this.id,
|
|
3763
|
-
feed_group_id: this.group,
|
|
3764
|
-
...request,
|
|
3765
|
-
});
|
|
3766
|
-
}
|
|
3767
|
-
getOrCreate(request) {
|
|
3768
|
-
return this.feedsApi.getOrCreateFeed({
|
|
3769
|
-
feed_id: this.id,
|
|
3770
|
-
feed_group_id: this.group,
|
|
3771
|
-
...request,
|
|
3772
|
-
});
|
|
3773
|
-
}
|
|
3774
|
-
update(request) {
|
|
3775
|
-
return this.feedsApi.updateFeed({
|
|
3776
|
-
feed_id: this.id,
|
|
3777
|
-
feed_group_id: this.group,
|
|
3778
|
-
...request,
|
|
3779
|
-
});
|
|
3780
|
-
}
|
|
3781
|
-
markActivity(request) {
|
|
3782
|
-
return this.feedsApi.markActivity({
|
|
3783
|
-
feed_id: this.id,
|
|
3784
|
-
feed_group_id: this.group,
|
|
3785
|
-
...request,
|
|
3786
|
-
});
|
|
3787
|
-
}
|
|
3788
|
-
unpinActivity(request) {
|
|
3789
|
-
return this.feedsApi.unpinActivity({
|
|
3790
|
-
feed_id: this.id,
|
|
3791
|
-
feed_group_id: this.group,
|
|
3792
|
-
...request,
|
|
3793
|
-
});
|
|
3794
|
-
}
|
|
3795
|
-
pinActivity(request) {
|
|
3796
|
-
return this.feedsApi.pinActivity({
|
|
3797
|
-
feed_id: this.id,
|
|
3798
|
-
feed_group_id: this.group,
|
|
3799
|
-
...request,
|
|
3800
|
-
});
|
|
3801
|
-
}
|
|
3802
|
-
updateFeedMembers(request) {
|
|
3803
|
-
return this.feedsApi.updateFeedMembers({
|
|
3804
|
-
feed_id: this.id,
|
|
3805
|
-
feed_group_id: this.group,
|
|
3806
|
-
...request,
|
|
3807
|
-
});
|
|
3808
|
-
}
|
|
3809
|
-
acceptFeedMemberInvite(request) {
|
|
3810
|
-
return this.feedsApi.acceptFeedMemberInvite({
|
|
3811
|
-
feed_id: this.id,
|
|
3812
|
-
feed_group_id: this.group,
|
|
3813
|
-
...request,
|
|
3814
|
-
});
|
|
3815
|
-
}
|
|
3816
|
-
queryFeedMembers(request) {
|
|
3817
|
-
return this.feedsApi.queryFeedMembers({
|
|
3818
|
-
feed_id: this.id,
|
|
3819
|
-
feed_group_id: this.group,
|
|
3820
|
-
...request,
|
|
3821
|
-
});
|
|
3760
|
+
class ModerationApi {
|
|
3761
|
+
constructor(apiClient) {
|
|
3762
|
+
this.apiClient = apiClient;
|
|
3822
3763
|
}
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3764
|
+
async ban(request) {
|
|
3765
|
+
const body = {
|
|
3766
|
+
target_user_id: request?.target_user_id,
|
|
3767
|
+
banned_by_id: request?.banned_by_id,
|
|
3768
|
+
channel_cid: request?.channel_cid,
|
|
3769
|
+
delete_messages: request?.delete_messages,
|
|
3770
|
+
ip_ban: request?.ip_ban,
|
|
3771
|
+
reason: request?.reason,
|
|
3772
|
+
shadow: request?.shadow,
|
|
3773
|
+
timeout: request?.timeout,
|
|
3774
|
+
banned_by: request?.banned_by,
|
|
3775
|
+
};
|
|
3776
|
+
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/ban', undefined, undefined, body, 'application/json');
|
|
3777
|
+
decoders.BanResponse?.(response.body);
|
|
3778
|
+
return { ...response.body, metadata: response.metadata };
|
|
3829
3779
|
}
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3780
|
+
async upsertConfig(request) {
|
|
3781
|
+
const body = {
|
|
3782
|
+
key: request?.key,
|
|
3783
|
+
async: request?.async,
|
|
3784
|
+
team: request?.team,
|
|
3785
|
+
ai_image_config: request?.ai_image_config,
|
|
3786
|
+
ai_text_config: request?.ai_text_config,
|
|
3787
|
+
ai_video_config: request?.ai_video_config,
|
|
3788
|
+
automod_platform_circumvention_config: request?.automod_platform_circumvention_config,
|
|
3789
|
+
automod_semantic_filters_config: request?.automod_semantic_filters_config,
|
|
3790
|
+
automod_toxicity_config: request?.automod_toxicity_config,
|
|
3791
|
+
aws_rekognition_config: request?.aws_rekognition_config,
|
|
3792
|
+
block_list_config: request?.block_list_config,
|
|
3793
|
+
bodyguard_config: request?.bodyguard_config,
|
|
3794
|
+
google_vision_config: request?.google_vision_config,
|
|
3795
|
+
rule_builder_config: request?.rule_builder_config,
|
|
3796
|
+
velocity_filter_config: request?.velocity_filter_config,
|
|
3797
|
+
video_call_rule_config: request?.video_call_rule_config,
|
|
3798
|
+
};
|
|
3799
|
+
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/config', undefined, undefined, body, 'application/json');
|
|
3800
|
+
decoders.UpsertConfigResponse?.(response.body);
|
|
3801
|
+
return { ...response.body, metadata: response.metadata };
|
|
3836
3802
|
}
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
result = {
|
|
3844
|
-
changed: true,
|
|
3845
|
-
activities,
|
|
3803
|
+
async deleteConfig(request) {
|
|
3804
|
+
const queryParams = {
|
|
3805
|
+
team: request?.team,
|
|
3806
|
+
};
|
|
3807
|
+
const pathParams = {
|
|
3808
|
+
key: request?.key,
|
|
3846
3809
|
};
|
|
3810
|
+
const response = await this.apiClient.sendRequest('DELETE', '/api/v2/moderation/config/{key}', pathParams, queryParams);
|
|
3811
|
+
decoders.DeleteModerationConfigResponse?.(response.body);
|
|
3812
|
+
return { ...response.body, metadata: response.metadata };
|
|
3847
3813
|
}
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3814
|
+
async getConfig(request) {
|
|
3815
|
+
const queryParams = {
|
|
3816
|
+
team: request?.team,
|
|
3817
|
+
};
|
|
3818
|
+
const pathParams = {
|
|
3819
|
+
key: request?.key,
|
|
3852
3820
|
};
|
|
3821
|
+
const response = await this.apiClient.sendRequest('GET', '/api/v2/moderation/config/{key}', pathParams, queryParams);
|
|
3822
|
+
decoders.GetConfigResponse?.(response.body);
|
|
3823
|
+
return { ...response.body, metadata: response.metadata };
|
|
3853
3824
|
}
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
...(position === 'start' ? newActivitiesDeduplicated : []),
|
|
3866
|
-
...activities,
|
|
3867
|
-
...(position === 'end' ? newActivitiesDeduplicated : []),
|
|
3868
|
-
];
|
|
3869
|
-
result = { changed: true, activities: updatedActivities };
|
|
3825
|
+
async queryModerationConfigs(request) {
|
|
3826
|
+
const body = {
|
|
3827
|
+
limit: request?.limit,
|
|
3828
|
+
next: request?.next,
|
|
3829
|
+
prev: request?.prev,
|
|
3830
|
+
sort: request?.sort,
|
|
3831
|
+
filter: request?.filter,
|
|
3832
|
+
};
|
|
3833
|
+
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/configs', undefined, undefined, body, 'application/json');
|
|
3834
|
+
decoders.QueryModerationConfigsResponse?.(response.body);
|
|
3835
|
+
return { ...response.body, metadata: response.metadata };
|
|
3870
3836
|
}
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
...updatedActivityResponse,
|
|
3880
|
-
own_reactions: activity.own_reactions,
|
|
3881
|
-
own_bookmarks: activity.own_bookmarks,
|
|
3882
|
-
latest_reactions: activity.latest_reactions,
|
|
3883
|
-
reaction_groups: activity.reaction_groups,
|
|
3837
|
+
async flag(request) {
|
|
3838
|
+
const body = {
|
|
3839
|
+
entity_id: request?.entity_id,
|
|
3840
|
+
entity_type: request?.entity_type,
|
|
3841
|
+
entity_creator_id: request?.entity_creator_id,
|
|
3842
|
+
reason: request?.reason,
|
|
3843
|
+
custom: request?.custom,
|
|
3844
|
+
moderation_payload: request?.moderation_payload,
|
|
3884
3845
|
};
|
|
3885
|
-
|
|
3846
|
+
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/flag', undefined, undefined, body, 'application/json');
|
|
3847
|
+
decoders.FlagResponse?.(response.body);
|
|
3848
|
+
return { ...response.body, metadata: response.metadata };
|
|
3886
3849
|
}
|
|
3887
|
-
|
|
3888
|
-
|
|
3850
|
+
async mute(request) {
|
|
3851
|
+
const body = {
|
|
3852
|
+
target_ids: request?.target_ids,
|
|
3853
|
+
timeout: request?.timeout,
|
|
3854
|
+
};
|
|
3855
|
+
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/mute', undefined, undefined, body, 'application/json');
|
|
3856
|
+
decoders.MuteResponse?.(response.body);
|
|
3857
|
+
return { ...response.body, metadata: response.metadata };
|
|
3889
3858
|
}
|
|
3890
|
-
|
|
3891
|
-
const
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3859
|
+
async queryReviewQueue(request) {
|
|
3860
|
+
const body = {
|
|
3861
|
+
limit: request?.limit,
|
|
3862
|
+
lock_count: request?.lock_count,
|
|
3863
|
+
lock_duration: request?.lock_duration,
|
|
3864
|
+
lock_items: request?.lock_items,
|
|
3865
|
+
next: request?.next,
|
|
3866
|
+
prev: request?.prev,
|
|
3867
|
+
stats_only: request?.stats_only,
|
|
3868
|
+
sort: request?.sort,
|
|
3869
|
+
filter: request?.filter,
|
|
3870
|
+
};
|
|
3871
|
+
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/review_queue', undefined, undefined, body, 'application/json');
|
|
3872
|
+
decoders.QueryReviewQueueResponse?.(response.body);
|
|
3873
|
+
return { ...response.body, metadata: response.metadata };
|
|
3897
3874
|
}
|
|
3898
|
-
|
|
3899
|
-
|
|
3875
|
+
async submitAction(request) {
|
|
3876
|
+
const body = {
|
|
3877
|
+
action_type: request?.action_type,
|
|
3878
|
+
item_id: request?.item_id,
|
|
3879
|
+
ban: request?.ban,
|
|
3880
|
+
custom: request?.custom,
|
|
3881
|
+
delete_activity: request?.delete_activity,
|
|
3882
|
+
delete_message: request?.delete_message,
|
|
3883
|
+
delete_reaction: request?.delete_reaction,
|
|
3884
|
+
delete_user: request?.delete_user,
|
|
3885
|
+
mark_reviewed: request?.mark_reviewed,
|
|
3886
|
+
unban: request?.unban,
|
|
3887
|
+
};
|
|
3888
|
+
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/submit_action', undefined, undefined, body, 'application/json');
|
|
3889
|
+
decoders.SubmitActionResponse?.(response.body);
|
|
3890
|
+
return { ...response.body, metadata: response.metadata };
|
|
3900
3891
|
}
|
|
3901
|
-
}
|
|
3892
|
+
}
|
|
3902
3893
|
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
if (index !== -1) {
|
|
3906
|
-
const newActivities = [...activities];
|
|
3907
|
-
newActivities[index] = updatedActivity;
|
|
3908
|
-
return { changed: true, activities: newActivities };
|
|
3909
|
-
}
|
|
3910
|
-
else {
|
|
3911
|
-
return { changed: false, activities };
|
|
3912
|
-
}
|
|
3913
|
-
};
|
|
3914
|
-
const addReactionToActivity = (event, activity, isCurrentUser) => {
|
|
3915
|
-
// Update own_reactions if the reaction is from the current user
|
|
3916
|
-
const ownReactions = [...(activity.own_reactions || [])];
|
|
3917
|
-
if (isCurrentUser) {
|
|
3918
|
-
ownReactions.push(event.reaction);
|
|
3919
|
-
}
|
|
3920
|
-
return {
|
|
3921
|
-
...activity,
|
|
3922
|
-
own_reactions: ownReactions,
|
|
3923
|
-
latest_reactions: event.activity.latest_reactions,
|
|
3924
|
-
reaction_groups: event.activity.reaction_groups,
|
|
3925
|
-
changed: true,
|
|
3926
|
-
};
|
|
3927
|
-
};
|
|
3928
|
-
const removeReactionFromActivity = (event, activity, isCurrentUser) => {
|
|
3929
|
-
// Update own_reactions if the reaction is from the current user
|
|
3930
|
-
const ownReactions = isCurrentUser
|
|
3931
|
-
? (activity.own_reactions || []).filter((r) => !(r.type === event.reaction.type &&
|
|
3932
|
-
r.user.id === event.reaction.user.id))
|
|
3933
|
-
: activity.own_reactions;
|
|
3934
|
-
return {
|
|
3935
|
-
...activity,
|
|
3936
|
-
own_reactions: ownReactions,
|
|
3937
|
-
latest_reactions: event.activity.latest_reactions,
|
|
3938
|
-
reaction_groups: event.activity.reaction_groups,
|
|
3939
|
-
changed: true,
|
|
3940
|
-
};
|
|
3941
|
-
};
|
|
3942
|
-
const addReactionToActivities = (event, activities, isCurrentUser) => {
|
|
3943
|
-
if (!activities) {
|
|
3944
|
-
return { changed: false, activities: [] };
|
|
3945
|
-
}
|
|
3946
|
-
const activityIndex = activities.findIndex((a) => a.id === event.activity.id);
|
|
3947
|
-
if (activityIndex === -1) {
|
|
3948
|
-
return { changed: false, activities };
|
|
3949
|
-
}
|
|
3950
|
-
const activity = activities[activityIndex];
|
|
3951
|
-
const updatedActivity = addReactionToActivity(event, activity, isCurrentUser);
|
|
3952
|
-
return updateActivityInActivities$1(updatedActivity, activities);
|
|
3953
|
-
};
|
|
3954
|
-
const removeReactionFromActivities = (event, activities, isCurrentUser) => {
|
|
3955
|
-
if (!activities) {
|
|
3956
|
-
return { changed: false, activities: [] };
|
|
3957
|
-
}
|
|
3958
|
-
const activityIndex = activities.findIndex((a) => a.id === event.activity.id);
|
|
3959
|
-
if (activityIndex === -1) {
|
|
3960
|
-
return { changed: false, activities };
|
|
3961
|
-
}
|
|
3962
|
-
const activity = activities[activityIndex];
|
|
3963
|
-
const updatedActivity = removeReactionFromActivity(event, activity, isCurrentUser);
|
|
3964
|
-
return updateActivityInActivities$1(updatedActivity, activities);
|
|
3965
|
-
};
|
|
3966
|
-
|
|
3967
|
-
// Helper function to check if two bookmarks are the same
|
|
3968
|
-
// A bookmark is identified by activity_id + folder_id + user_id
|
|
3969
|
-
const isSameBookmark = (bookmark1, bookmark2) => {
|
|
3970
|
-
return (bookmark1.user.id === bookmark2.user.id &&
|
|
3971
|
-
bookmark1.activity.id === bookmark2.activity.id &&
|
|
3972
|
-
bookmark1.folder?.id === bookmark2.folder?.id);
|
|
3973
|
-
};
|
|
3974
|
-
const updateActivityInActivities = (updatedActivity, activities) => {
|
|
3975
|
-
const index = activities.findIndex((a) => a.id === updatedActivity.id);
|
|
3976
|
-
if (index !== -1) {
|
|
3977
|
-
const newActivities = [...activities];
|
|
3978
|
-
newActivities[index] = updatedActivity;
|
|
3979
|
-
return { changed: true, activities: newActivities };
|
|
3980
|
-
}
|
|
3981
|
-
else {
|
|
3982
|
-
return { changed: false, activities };
|
|
3983
|
-
}
|
|
3984
|
-
};
|
|
3985
|
-
const addBookmarkToActivity = (event, activity, isCurrentUser) => {
|
|
3986
|
-
// Update own_bookmarks if the bookmark is from the current user
|
|
3987
|
-
const ownBookmarks = [...(activity.own_bookmarks || [])];
|
|
3988
|
-
if (isCurrentUser) {
|
|
3989
|
-
ownBookmarks.push(event.bookmark);
|
|
3990
|
-
}
|
|
3991
|
-
return {
|
|
3992
|
-
...activity,
|
|
3993
|
-
own_bookmarks: ownBookmarks,
|
|
3994
|
-
changed: true,
|
|
3995
|
-
};
|
|
3996
|
-
};
|
|
3997
|
-
const removeBookmarkFromActivity = (event, activity, isCurrentUser) => {
|
|
3998
|
-
// Update own_bookmarks if the bookmark is from the current user
|
|
3999
|
-
const ownBookmarks = isCurrentUser
|
|
4000
|
-
? (activity.own_bookmarks || []).filter((bookmark) => !isSameBookmark(bookmark, event.bookmark))
|
|
4001
|
-
: activity.own_bookmarks;
|
|
4002
|
-
return {
|
|
4003
|
-
...activity,
|
|
4004
|
-
own_bookmarks: ownBookmarks,
|
|
4005
|
-
changed: true,
|
|
4006
|
-
};
|
|
4007
|
-
};
|
|
4008
|
-
const updateBookmarkInActivity = (event, activity, isCurrentUser) => {
|
|
4009
|
-
// Update own_bookmarks if the bookmark is from the current user
|
|
4010
|
-
let ownBookmarks = activity.own_bookmarks || [];
|
|
4011
|
-
if (isCurrentUser) {
|
|
4012
|
-
const bookmarkIndex = ownBookmarks.findIndex((bookmark) => isSameBookmark(bookmark, event.bookmark));
|
|
4013
|
-
if (bookmarkIndex !== -1) {
|
|
4014
|
-
ownBookmarks = [...ownBookmarks];
|
|
4015
|
-
ownBookmarks[bookmarkIndex] = event.bookmark;
|
|
4016
|
-
}
|
|
4017
|
-
}
|
|
4018
|
-
return {
|
|
4019
|
-
...activity,
|
|
4020
|
-
own_bookmarks: ownBookmarks,
|
|
4021
|
-
changed: true,
|
|
4022
|
-
};
|
|
4023
|
-
};
|
|
4024
|
-
const addBookmarkToActivities = (event, activities, isCurrentUser) => {
|
|
4025
|
-
if (!activities) {
|
|
4026
|
-
return { changed: false, activities: [] };
|
|
4027
|
-
}
|
|
4028
|
-
const activityIndex = activities.findIndex((a) => a.id === event.bookmark.activity.id);
|
|
4029
|
-
if (activityIndex === -1) {
|
|
4030
|
-
return { changed: false, activities };
|
|
4031
|
-
}
|
|
4032
|
-
const activity = activities[activityIndex];
|
|
4033
|
-
const updatedActivity = addBookmarkToActivity(event, activity, isCurrentUser);
|
|
4034
|
-
return updateActivityInActivities(updatedActivity, activities);
|
|
4035
|
-
};
|
|
4036
|
-
const removeBookmarkFromActivities = (event, activities, isCurrentUser) => {
|
|
4037
|
-
if (!activities) {
|
|
4038
|
-
return { changed: false, activities: [] };
|
|
4039
|
-
}
|
|
4040
|
-
const activityIndex = activities.findIndex((a) => a.id === event.bookmark.activity.id);
|
|
4041
|
-
if (activityIndex === -1) {
|
|
4042
|
-
return { changed: false, activities };
|
|
4043
|
-
}
|
|
4044
|
-
const activity = activities[activityIndex];
|
|
4045
|
-
const updatedActivity = removeBookmarkFromActivity(event, activity, isCurrentUser);
|
|
4046
|
-
return updateActivityInActivities(updatedActivity, activities);
|
|
4047
|
-
};
|
|
4048
|
-
const updateBookmarkInActivities = (event, activities, isCurrentUser) => {
|
|
4049
|
-
if (!activities) {
|
|
4050
|
-
return { changed: false, activities: [] };
|
|
4051
|
-
}
|
|
4052
|
-
const activityIndex = activities.findIndex((a) => a.id === event.bookmark.activity.id);
|
|
4053
|
-
if (activityIndex === -1) {
|
|
4054
|
-
return { changed: false, activities };
|
|
4055
|
-
}
|
|
4056
|
-
const activity = activities[activityIndex];
|
|
4057
|
-
const updatedActivity = updateBookmarkInActivity(event, activity, isCurrentUser);
|
|
4058
|
-
return updateActivityInActivities(updatedActivity, activities);
|
|
4059
|
-
};
|
|
4060
|
-
|
|
4061
|
-
const isFeedResponse = (follow) => {
|
|
4062
|
-
return 'created_by' in follow;
|
|
4063
|
-
};
|
|
4064
|
-
const handleFollowCreated = (follow, currentState, currentFeedId, connectedUserId) => {
|
|
4065
|
-
// filter non-accepted follows (the way getOrCreate does by default)
|
|
4066
|
-
if (follow.status !== 'accepted') {
|
|
4067
|
-
return { changed: false, data: currentState };
|
|
4068
|
-
}
|
|
4069
|
-
let newState = { ...currentState };
|
|
4070
|
-
// this feed followed someone
|
|
4071
|
-
if (follow.source_feed.fid === currentFeedId) {
|
|
4072
|
-
newState = {
|
|
4073
|
-
...newState,
|
|
4074
|
-
// Update FeedResponse fields, that has the new follower/following count
|
|
4075
|
-
...follow.source_feed,
|
|
4076
|
-
};
|
|
4077
|
-
// Only update if following array already exists
|
|
4078
|
-
if (currentState.following !== undefined) {
|
|
4079
|
-
newState.following = [follow, ...currentState.following];
|
|
4080
|
-
}
|
|
4081
|
-
}
|
|
4082
|
-
else if (
|
|
4083
|
-
// someone followed this feed
|
|
4084
|
-
follow.target_feed.fid === currentFeedId) {
|
|
4085
|
-
const source = follow.source_feed;
|
|
4086
|
-
newState = {
|
|
4087
|
-
...newState,
|
|
4088
|
-
// Update FeedResponse fields, that has the new follower/following count
|
|
4089
|
-
...follow.target_feed,
|
|
4090
|
-
};
|
|
4091
|
-
if (source.created_by.id === connectedUserId) {
|
|
4092
|
-
newState.own_follows = currentState.own_follows
|
|
4093
|
-
? currentState.own_follows.concat(follow)
|
|
4094
|
-
: [follow];
|
|
4095
|
-
}
|
|
4096
|
-
// Only update if followers array already exists
|
|
4097
|
-
if (currentState.followers !== undefined) {
|
|
4098
|
-
newState.followers = [follow, ...currentState.followers];
|
|
4099
|
-
}
|
|
4100
|
-
}
|
|
4101
|
-
return { changed: true, data: newState };
|
|
4102
|
-
};
|
|
4103
|
-
const handleFollowDeleted = (follow, currentState, currentFeedId, connectedUserId) => {
|
|
4104
|
-
let newState = { ...currentState };
|
|
4105
|
-
// this feed unfollowed someone
|
|
4106
|
-
if (follow.source_feed.fid === currentFeedId) {
|
|
4107
|
-
newState = {
|
|
4108
|
-
...newState,
|
|
4109
|
-
// Update FeedResponse fields, that has the new follower/following count
|
|
4110
|
-
...follow.source_feed,
|
|
4111
|
-
};
|
|
4112
|
-
// Only update if following array already exists
|
|
4113
|
-
if (currentState.following !== undefined) {
|
|
4114
|
-
newState.following = currentState.following.filter((followItem) => followItem.target_feed.fid !== follow.target_feed.fid);
|
|
4115
|
-
}
|
|
4116
|
-
}
|
|
4117
|
-
else if (
|
|
4118
|
-
// someone unfollowed this feed
|
|
4119
|
-
follow.target_feed.fid === currentFeedId) {
|
|
4120
|
-
const source = follow.source_feed;
|
|
4121
|
-
newState = {
|
|
4122
|
-
...newState,
|
|
4123
|
-
// Update FeedResponse fields, that has the new follower/following count
|
|
4124
|
-
...follow.target_feed,
|
|
4125
|
-
};
|
|
4126
|
-
if (isFeedResponse(source) &&
|
|
4127
|
-
source.created_by.id === connectedUserId &&
|
|
4128
|
-
currentState.own_follows !== undefined) {
|
|
4129
|
-
newState.own_follows = currentState.own_follows.filter((followItem) => followItem.source_feed.fid !== follow.source_feed.fid);
|
|
4130
|
-
}
|
|
4131
|
-
// Only update if followers array already exists
|
|
4132
|
-
if (currentState.followers !== undefined) {
|
|
4133
|
-
newState.followers = currentState.followers.filter((followItem) => followItem.source_feed.fid !== follow.source_feed.fid);
|
|
4134
|
-
}
|
|
4135
|
-
}
|
|
4136
|
-
return { changed: true, data: newState };
|
|
4137
|
-
};
|
|
4138
|
-
const handleFollowUpdated = (currentState) => {
|
|
4139
|
-
// For now, we'll treat follow updates as no-ops since the current implementation does
|
|
4140
|
-
// This can be enhanced later if needed
|
|
4141
|
-
return { changed: false, data: currentState };
|
|
4142
|
-
};
|
|
4143
|
-
|
|
4144
|
-
const isImageFile = (file) => {
|
|
4145
|
-
// photoshop files begin with 'image/'
|
|
4146
|
-
return file.type.startsWith('image/') && !file.type.endsWith('.photoshop');
|
|
4147
|
-
};
|
|
4148
|
-
const isVideoFile = (file) => {
|
|
4149
|
-
return file.type.startsWith('video/');
|
|
4150
|
-
};
|
|
4151
|
-
const checkHasAnotherPage = (v, cursor) => (typeof v === 'undefined' && typeof cursor === 'undefined') ||
|
|
4152
|
-
typeof cursor === 'string';
|
|
4153
|
-
const isCommentResponse = (entity) => {
|
|
4154
|
-
return typeof entity?.object_id === 'string';
|
|
4155
|
-
};
|
|
4156
|
-
const Constants = {
|
|
4157
|
-
DEFAULT_COMMENT_PAGINATION: 'first',
|
|
4158
|
-
};
|
|
4159
|
-
const uniqueArrayMerge = (existingArray, arrayToMerge, getKey) => {
|
|
4160
|
-
const existing = new Set();
|
|
4161
|
-
existingArray.forEach((value) => {
|
|
4162
|
-
const key = getKey(value);
|
|
4163
|
-
existing.add(key);
|
|
4164
|
-
});
|
|
4165
|
-
const filteredArrayToMerge = arrayToMerge.filter((value) => {
|
|
4166
|
-
const key = getKey(value);
|
|
4167
|
-
return !existing.has(key);
|
|
4168
|
-
});
|
|
4169
|
-
return existingArray.concat(filteredArrayToMerge);
|
|
4170
|
-
};
|
|
4171
|
-
|
|
4172
|
-
const shouldUpdateState = ({ stateUpdateId, stateUpdateQueue, watch, }) => {
|
|
4173
|
-
if (!watch) {
|
|
4174
|
-
return true;
|
|
4175
|
-
}
|
|
4176
|
-
if (watch && stateUpdateQueue.has(stateUpdateId)) {
|
|
4177
|
-
stateUpdateQueue.delete(stateUpdateId);
|
|
4178
|
-
return false;
|
|
4179
|
-
}
|
|
4180
|
-
stateUpdateQueue.add(stateUpdateId);
|
|
4181
|
-
return true;
|
|
4182
|
-
};
|
|
4183
|
-
const getStateUpdateQueueIdForFollow = (follow) => {
|
|
4184
|
-
return `follow${follow.source_feed.fid}-${follow.target_feed.fid}`;
|
|
4185
|
-
};
|
|
4186
|
-
const getStateUpdateQueueIdForUnfollow = (follow) => {
|
|
4187
|
-
return `unfollow${follow.source_feed.fid}-${follow.target_feed.fid}`;
|
|
4188
|
-
};
|
|
3894
|
+
class ModerationClient extends ModerationApi {
|
|
3895
|
+
}
|
|
4189
3896
|
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
'feeds.activity.deleted': (event) => {
|
|
4204
|
-
const currentActivities = this.currentState.activities;
|
|
4205
|
-
if (currentActivities) {
|
|
4206
|
-
const result = removeActivityFromState(event.activity, currentActivities);
|
|
4207
|
-
if (result.changed) {
|
|
4208
|
-
this.state.partialNext({ activities: result.activities });
|
|
4209
|
-
}
|
|
3897
|
+
const isPollUpdatedEvent = (e) => e.type === 'feeds.poll.updated';
|
|
3898
|
+
const isPollClosedEventEvent = (e) => e.type === 'feeds.poll.closed';
|
|
3899
|
+
const isPollVoteCastedEvent = (e) => e.type === 'feeds.poll.vote_casted';
|
|
3900
|
+
const isPollVoteChangedEvent = (e) => e.type === 'feeds.poll.vote_changed';
|
|
3901
|
+
const isPollVoteRemovedEvent = (e) => e.type === 'feeds.poll.vote_removed';
|
|
3902
|
+
const isVoteAnswer = (vote) => !!vote?.answer_text;
|
|
3903
|
+
class StreamPoll {
|
|
3904
|
+
constructor({ client, poll }) {
|
|
3905
|
+
this.getInitialStateFromPollResponse = (poll) => {
|
|
3906
|
+
const { own_votes, id, ...pollResponseForState } = poll;
|
|
3907
|
+
const { ownAnswer, ownVotes } = own_votes?.reduce((acc, voteOrAnswer) => {
|
|
3908
|
+
if (isVoteAnswer(voteOrAnswer)) {
|
|
3909
|
+
acc.ownAnswer = voteOrAnswer;
|
|
4210
3910
|
}
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
const currentActivities = this.currentState.activities;
|
|
4214
|
-
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4215
|
-
const isCurrentUser = Boolean(connectedUser && event.reaction.user.id === connectedUser.id);
|
|
4216
|
-
const result = addReactionToActivities(event, currentActivities, isCurrentUser);
|
|
4217
|
-
if (result.changed) {
|
|
4218
|
-
this.state.partialNext({ activities: result.activities });
|
|
3911
|
+
else {
|
|
3912
|
+
acc.ownVotes.push(voteOrAnswer);
|
|
4219
3913
|
}
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
3914
|
+
return acc;
|
|
3915
|
+
}, { ownVotes: [] }) ?? { ownVotes: [] };
|
|
3916
|
+
return {
|
|
3917
|
+
...pollResponseForState,
|
|
3918
|
+
last_activity_at: new Date(),
|
|
3919
|
+
max_voted_option_ids: getMaxVotedOptionIds(pollResponseForState.vote_counts_by_option),
|
|
3920
|
+
own_answer: ownAnswer,
|
|
3921
|
+
own_votes_by_option_id: getOwnVotesByOptionId(ownVotes),
|
|
3922
|
+
};
|
|
3923
|
+
};
|
|
3924
|
+
this.reinitializeState = (poll) => {
|
|
3925
|
+
this.state.partialNext(this.getInitialStateFromPollResponse(poll));
|
|
3926
|
+
};
|
|
3927
|
+
this.handlePollUpdated = (event) => {
|
|
3928
|
+
if (event.poll?.id && event.poll.id !== this.id)
|
|
3929
|
+
return;
|
|
3930
|
+
if (!isPollUpdatedEvent(event))
|
|
3931
|
+
return;
|
|
3932
|
+
const { id, ...pollData } = event.poll;
|
|
3933
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
3934
|
+
this.state.partialNext({
|
|
3935
|
+
...pollData,
|
|
3936
|
+
last_activity_at: new Date(event.created_at),
|
|
3937
|
+
});
|
|
3938
|
+
};
|
|
3939
|
+
this.handlePollClosed = (event) => {
|
|
3940
|
+
if (event.poll?.id && event.poll.id !== this.id)
|
|
3941
|
+
return;
|
|
3942
|
+
if (!isPollClosedEventEvent(event))
|
|
3943
|
+
return;
|
|
3944
|
+
this.state.partialNext({
|
|
3945
|
+
is_closed: true,
|
|
3946
|
+
last_activity_at: new Date(event.created_at),
|
|
3947
|
+
});
|
|
3948
|
+
};
|
|
3949
|
+
this.handleVoteCasted = (event) => {
|
|
3950
|
+
if (event.poll?.id && event.poll.id !== this.id)
|
|
3951
|
+
return;
|
|
3952
|
+
if (!isPollVoteCastedEvent(event))
|
|
3953
|
+
return;
|
|
3954
|
+
const currentState = this.data;
|
|
3955
|
+
const isOwnVote = event.poll_vote.user_id ===
|
|
3956
|
+
this.client.state.getLatestValue().connected_user?.id;
|
|
3957
|
+
let latestAnswers = [...currentState.latest_answers];
|
|
3958
|
+
let ownAnswer = currentState.own_answer;
|
|
3959
|
+
const ownVotesByOptionId = currentState.own_votes_by_option_id;
|
|
3960
|
+
let maxVotedOptionIds = currentState.max_voted_option_ids;
|
|
3961
|
+
if (isOwnVote) {
|
|
3962
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
3963
|
+
if (isVoteAnswer(event.poll_vote)) {
|
|
3964
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
3965
|
+
ownAnswer = event.poll_vote;
|
|
4228
3966
|
}
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
const currentActivities = this.currentState.activities;
|
|
4233
|
-
if (currentActivities) {
|
|
4234
|
-
const result = removeActivityFromState(event.activity, currentActivities);
|
|
4235
|
-
if (result.changed) {
|
|
4236
|
-
this.state.partialNext({ activities: result.activities });
|
|
4237
|
-
}
|
|
3967
|
+
else if (event.poll_vote.option_id) {
|
|
3968
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
3969
|
+
ownVotesByOptionId[event.poll_vote.option_id] = event.poll_vote;
|
|
4238
3970
|
}
|
|
4239
|
-
}
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
3971
|
+
}
|
|
3972
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
3973
|
+
if (isVoteAnswer(event.poll_vote)) {
|
|
3974
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
3975
|
+
latestAnswers = [event.poll_vote, ...latestAnswers];
|
|
3976
|
+
}
|
|
3977
|
+
else {
|
|
3978
|
+
maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);
|
|
3979
|
+
}
|
|
3980
|
+
const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
|
|
3981
|
+
this.state.partialNext({
|
|
3982
|
+
answers_count,
|
|
3983
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
3984
|
+
latest_votes_by_option,
|
|
3985
|
+
vote_count,
|
|
3986
|
+
vote_counts_by_option,
|
|
3987
|
+
latest_answers: latestAnswers,
|
|
3988
|
+
last_activity_at: new Date(event.created_at),
|
|
3989
|
+
own_answer: ownAnswer,
|
|
3990
|
+
own_votes_by_option_id: ownVotesByOptionId,
|
|
3991
|
+
max_voted_option_ids: maxVotedOptionIds,
|
|
3992
|
+
});
|
|
3993
|
+
};
|
|
3994
|
+
this.handleVoteChanged = (event) => {
|
|
3995
|
+
// this event is triggered only when event.poll.enforce_unique_vote === true
|
|
3996
|
+
if (event.poll?.id && event.poll.id !== this.id)
|
|
3997
|
+
return;
|
|
3998
|
+
if (!isPollVoteChangedEvent(event))
|
|
3999
|
+
return;
|
|
4000
|
+
const currentState = this.data;
|
|
4001
|
+
const isOwnVote = event.poll_vote.user_id ===
|
|
4002
|
+
this.client.state.getLatestValue().connected_user?.id;
|
|
4003
|
+
let latestAnswers = [...currentState.latest_answers];
|
|
4004
|
+
let ownAnswer = currentState.own_answer;
|
|
4005
|
+
let ownVotesByOptionId = currentState.own_votes_by_option_id;
|
|
4006
|
+
let maxVotedOptionIds = currentState.max_voted_option_ids;
|
|
4007
|
+
if (isOwnVote) {
|
|
4008
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
4009
|
+
if (isVoteAnswer(event.poll_vote)) {
|
|
4010
|
+
latestAnswers = [
|
|
4011
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
4012
|
+
event.poll_vote,
|
|
4013
|
+
...latestAnswers.filter((answer) => answer.id !== event.poll_vote.id),
|
|
4014
|
+
];
|
|
4015
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
4016
|
+
ownAnswer = event.poll_vote;
|
|
4248
4017
|
}
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
'feeds.bookmark_folder.deleted': Feed.noop,
|
|
4254
|
-
'feeds.bookmark_folder.updated': Feed.noop,
|
|
4255
|
-
'feeds.comment.added': (event) => {
|
|
4256
|
-
const { comment } = event;
|
|
4257
|
-
const forId = comment.parent_id ?? comment.object_id;
|
|
4258
|
-
this.state.next((currentState) => {
|
|
4259
|
-
const entityState = currentState.comments_by_entity_id[forId];
|
|
4260
|
-
const newComments = entityState?.comments?.concat([]) ?? [];
|
|
4261
|
-
if (entityState?.pagination?.sort === 'last' &&
|
|
4262
|
-
!checkHasAnotherPage(entityState.comments, entityState?.pagination.next)) {
|
|
4263
|
-
newComments.unshift(comment);
|
|
4264
|
-
}
|
|
4265
|
-
else if (entityState?.pagination?.sort === 'first') {
|
|
4266
|
-
newComments.push(comment);
|
|
4018
|
+
else if (event.poll_vote.option_id) {
|
|
4019
|
+
if (event.poll.enforce_unique_vote) {
|
|
4020
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
4021
|
+
ownVotesByOptionId = { [event.poll_vote.option_id]: event.poll_vote };
|
|
4267
4022
|
}
|
|
4268
4023
|
else {
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
},
|
|
4280
|
-
},
|
|
4281
|
-
};
|
|
4282
|
-
});
|
|
4283
|
-
},
|
|
4284
|
-
'feeds.comment.deleted': ({ comment }) => {
|
|
4285
|
-
const forId = comment.parent_id ?? comment.object_id;
|
|
4286
|
-
this.state.next((currentState) => {
|
|
4287
|
-
const newCommentsByEntityId = {
|
|
4288
|
-
...currentState.comments_by_entity_id,
|
|
4289
|
-
[forId]: {
|
|
4290
|
-
...currentState.comments_by_entity_id[forId],
|
|
4291
|
-
},
|
|
4292
|
-
};
|
|
4293
|
-
const index = this.getCommentIndex(comment, currentState);
|
|
4294
|
-
if (newCommentsByEntityId?.[forId]?.comments?.length && index !== -1) {
|
|
4295
|
-
newCommentsByEntityId[forId].comments = [
|
|
4296
|
-
...newCommentsByEntityId[forId].comments,
|
|
4297
|
-
];
|
|
4298
|
-
newCommentsByEntityId[forId]?.comments?.splice(index, 1);
|
|
4299
|
-
}
|
|
4300
|
-
delete newCommentsByEntityId[comment.id];
|
|
4301
|
-
return {
|
|
4302
|
-
...currentState,
|
|
4303
|
-
comments_by_entity_id: newCommentsByEntityId,
|
|
4304
|
-
};
|
|
4305
|
-
});
|
|
4306
|
-
},
|
|
4307
|
-
'feeds.comment.updated': (event) => {
|
|
4308
|
-
const { comment } = event;
|
|
4309
|
-
const forId = comment.parent_id ?? comment.object_id;
|
|
4310
|
-
this.state.next((currentState) => {
|
|
4311
|
-
const entityState = currentState.comments_by_entity_id[forId];
|
|
4312
|
-
if (!entityState?.comments?.length)
|
|
4313
|
-
return currentState;
|
|
4314
|
-
const index = this.getCommentIndex(comment, currentState);
|
|
4315
|
-
if (index === -1)
|
|
4316
|
-
return currentState;
|
|
4317
|
-
const newComments = [...entityState.comments];
|
|
4318
|
-
newComments[index] = comment;
|
|
4319
|
-
return {
|
|
4320
|
-
...currentState,
|
|
4321
|
-
comments_by_entity_id: {
|
|
4322
|
-
...currentState.comments_by_entity_id,
|
|
4323
|
-
[forId]: {
|
|
4324
|
-
...currentState.comments_by_entity_id[forId],
|
|
4325
|
-
comments: newComments,
|
|
4326
|
-
},
|
|
4327
|
-
},
|
|
4328
|
-
};
|
|
4329
|
-
});
|
|
4330
|
-
},
|
|
4331
|
-
'feeds.feed.created': Feed.noop,
|
|
4332
|
-
'feeds.feed.deleted': Feed.noop,
|
|
4333
|
-
'feeds.feed.updated': (event) => {
|
|
4334
|
-
this.state.partialNext({ ...event.feed });
|
|
4335
|
-
},
|
|
4336
|
-
'feeds.feed_group.changed': Feed.noop,
|
|
4337
|
-
'feeds.feed_group.deleted': Feed.noop,
|
|
4338
|
-
'feeds.follow.created': (event) => {
|
|
4339
|
-
this.handleFollowCreated(event.follow);
|
|
4340
|
-
},
|
|
4341
|
-
'feeds.follow.deleted': (event) => {
|
|
4342
|
-
this.handleFollowDeleted(event.follow);
|
|
4343
|
-
},
|
|
4344
|
-
'feeds.follow.updated': (_event) => {
|
|
4345
|
-
handleFollowUpdated(this.currentState);
|
|
4346
|
-
},
|
|
4347
|
-
'feeds.comment.reaction.added': this.handleCommentReactionEvent.bind(this),
|
|
4348
|
-
'feeds.comment.reaction.deleted': this.handleCommentReactionEvent.bind(this),
|
|
4349
|
-
'feeds.comment.reaction.updated': Feed.noop,
|
|
4350
|
-
'feeds.feed_member.added': (event) => {
|
|
4351
|
-
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4352
|
-
this.state.next((currentState) => {
|
|
4353
|
-
let newState;
|
|
4354
|
-
if (typeof currentState.members !== 'undefined') {
|
|
4355
|
-
newState ?? (newState = {
|
|
4356
|
-
...currentState,
|
|
4357
|
-
});
|
|
4358
|
-
newState.members = [event.member, ...currentState.members];
|
|
4359
|
-
}
|
|
4360
|
-
if (connectedUser?.id === event.member.user.id) {
|
|
4361
|
-
newState ?? (newState = {
|
|
4362
|
-
...currentState,
|
|
4363
|
-
});
|
|
4364
|
-
newState.own_membership = event.member;
|
|
4365
|
-
}
|
|
4366
|
-
return newState ?? currentState;
|
|
4367
|
-
});
|
|
4368
|
-
},
|
|
4369
|
-
'feeds.feed_member.removed': (event) => {
|
|
4370
|
-
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4371
|
-
this.state.next((currentState) => {
|
|
4372
|
-
const newState = {
|
|
4373
|
-
...currentState,
|
|
4374
|
-
members: currentState.members?.filter((member) => member.user.id !== event.user?.id),
|
|
4375
|
-
};
|
|
4376
|
-
if (connectedUser?.id === event.member_id) {
|
|
4377
|
-
delete newState.own_membership;
|
|
4378
|
-
}
|
|
4379
|
-
return newState;
|
|
4380
|
-
});
|
|
4381
|
-
},
|
|
4382
|
-
'feeds.feed_member.updated': (event) => {
|
|
4383
|
-
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4384
|
-
this.state.next((currentState) => {
|
|
4385
|
-
const memberIndex = currentState.members?.findIndex((member) => member.user.id === event.member.user.id) ?? -1;
|
|
4386
|
-
let newState;
|
|
4387
|
-
if (memberIndex !== -1) {
|
|
4388
|
-
// if there's an index, there's a member to update
|
|
4389
|
-
const newMembers = [...currentState.members];
|
|
4390
|
-
newMembers[memberIndex] = event.member;
|
|
4391
|
-
newState ?? (newState = {
|
|
4392
|
-
...currentState,
|
|
4393
|
-
});
|
|
4394
|
-
newState.members = newMembers;
|
|
4024
|
+
ownVotesByOptionId = Object.entries(ownVotesByOptionId).reduce((acc, [optionId, vote]) => {
|
|
4025
|
+
if (optionId !== event.poll_vote.option_id &&
|
|
4026
|
+
vote.id === event.poll_vote.id) {
|
|
4027
|
+
return acc;
|
|
4028
|
+
}
|
|
4029
|
+
acc[optionId] = vote;
|
|
4030
|
+
return acc;
|
|
4031
|
+
}, {});
|
|
4032
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
4033
|
+
ownVotesByOptionId[event.poll_vote.option_id] = event.poll_vote;
|
|
4395
4034
|
}
|
|
4396
|
-
if (
|
|
4397
|
-
|
|
4398
|
-
...currentState,
|
|
4399
|
-
});
|
|
4400
|
-
newState.own_membership = event.member;
|
|
4035
|
+
if (ownAnswer?.id === event.poll_vote.id) {
|
|
4036
|
+
ownAnswer = undefined;
|
|
4401
4037
|
}
|
|
4402
|
-
|
|
4403
|
-
});
|
|
4404
|
-
},
|
|
4405
|
-
'feeds.notification_feed.updated': (event) => {
|
|
4406
|
-
console.info('notification feed updated', event);
|
|
4407
|
-
// TODO: handle notification feed updates
|
|
4408
|
-
},
|
|
4409
|
-
// the poll events should be removed from here
|
|
4410
|
-
'feeds.poll.closed': Feed.noop,
|
|
4411
|
-
'feeds.poll.deleted': Feed.noop,
|
|
4412
|
-
'feeds.poll.updated': Feed.noop,
|
|
4413
|
-
'feeds.poll.vote_casted': Feed.noop,
|
|
4414
|
-
'feeds.poll.vote_changed': Feed.noop,
|
|
4415
|
-
'feeds.poll.vote_removed': Feed.noop,
|
|
4416
|
-
'feeds.activity.pinned': Feed.noop,
|
|
4417
|
-
'feeds.activity.unpinned': Feed.noop,
|
|
4418
|
-
'feeds.activity.marked': Feed.noop,
|
|
4419
|
-
'moderation.custom_action': Feed.noop,
|
|
4420
|
-
'moderation.flagged': Feed.noop,
|
|
4421
|
-
'moderation.mark_reviewed': Feed.noop,
|
|
4422
|
-
'health.check': Feed.noop,
|
|
4423
|
-
'app.updated': Feed.noop,
|
|
4424
|
-
'user.banned': Feed.noop,
|
|
4425
|
-
'user.deactivated': Feed.noop,
|
|
4426
|
-
'user.muted': Feed.noop,
|
|
4427
|
-
'user.reactivated': Feed.noop,
|
|
4428
|
-
'user.updated': Feed.noop,
|
|
4429
|
-
};
|
|
4430
|
-
this.eventDispatcher = new EventDispatcher();
|
|
4431
|
-
this.on = this.eventDispatcher.on;
|
|
4432
|
-
this.off = this.eventDispatcher.off;
|
|
4433
|
-
this.state = new StateStore({
|
|
4434
|
-
fid: `${groupId}:${id}`,
|
|
4435
|
-
group_id: groupId,
|
|
4436
|
-
id,
|
|
4437
|
-
...(data ?? {}),
|
|
4438
|
-
is_loading: false,
|
|
4439
|
-
is_loading_activities: false,
|
|
4440
|
-
comments_by_entity_id: {},
|
|
4441
|
-
watch,
|
|
4442
|
-
});
|
|
4443
|
-
this.client = client;
|
|
4444
|
-
}
|
|
4445
|
-
get fid() {
|
|
4446
|
-
return `${this.group}:${this.id}`;
|
|
4447
|
-
}
|
|
4448
|
-
get currentState() {
|
|
4449
|
-
return this.state.getLatestValue();
|
|
4450
|
-
}
|
|
4451
|
-
handleCommentReactionEvent(event) {
|
|
4452
|
-
const { comment, reaction } = event;
|
|
4453
|
-
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4454
|
-
this.state.next((currentState) => {
|
|
4455
|
-
const forId = comment.parent_id ?? comment.object_id;
|
|
4456
|
-
const entityState = currentState.comments_by_entity_id[forId];
|
|
4457
|
-
const commentIndex = this.getCommentIndex(comment, currentState);
|
|
4458
|
-
if (commentIndex === -1)
|
|
4459
|
-
return currentState;
|
|
4460
|
-
const newComments = entityState?.comments?.concat([]) ?? [];
|
|
4461
|
-
const commentCopy = { ...comment };
|
|
4462
|
-
delete commentCopy.own_reactions;
|
|
4463
|
-
const newComment = {
|
|
4464
|
-
...newComments[commentIndex],
|
|
4465
|
-
...commentCopy,
|
|
4466
|
-
// TODO: FIXME this should be handled by the backend
|
|
4467
|
-
latest_reactions: commentCopy.latest_reactions ?? [],
|
|
4468
|
-
reaction_groups: commentCopy.reaction_groups ?? {},
|
|
4469
|
-
};
|
|
4470
|
-
newComments[commentIndex] = newComment;
|
|
4471
|
-
if (reaction.user.id === connectedUser?.id) {
|
|
4472
|
-
if (event.type === 'feeds.comment.reaction.added') {
|
|
4473
|
-
newComment.own_reactions = newComment.own_reactions.concat(reaction) ?? [reaction];
|
|
4474
|
-
}
|
|
4475
|
-
else if (event.type === 'feeds.comment.reaction.deleted') {
|
|
4476
|
-
newComment.own_reactions = newComment.own_reactions.filter((r) => r.type !== reaction.type);
|
|
4038
|
+
maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);
|
|
4477
4039
|
}
|
|
4040
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
4478
4041
|
}
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
});
|
|
4042
|
+
else if (isVoteAnswer(event.poll_vote)) {
|
|
4043
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
4044
|
+
latestAnswers = [event.poll_vote, ...latestAnswers];
|
|
4045
|
+
}
|
|
4046
|
+
else {
|
|
4047
|
+
maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);
|
|
4048
|
+
}
|
|
4049
|
+
const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
|
|
4050
|
+
this.state.partialNext({
|
|
4051
|
+
answers_count,
|
|
4052
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
4053
|
+
latest_votes_by_option,
|
|
4054
|
+
vote_count,
|
|
4055
|
+
vote_counts_by_option,
|
|
4056
|
+
latest_answers: latestAnswers,
|
|
4057
|
+
last_activity_at: new Date(event.created_at),
|
|
4058
|
+
own_answer: ownAnswer,
|
|
4059
|
+
own_votes_by_option_id: ownVotesByOptionId,
|
|
4060
|
+
max_voted_option_ids: maxVotedOptionIds,
|
|
4061
|
+
});
|
|
4062
|
+
};
|
|
4063
|
+
this.handleVoteRemoved = (event) => {
|
|
4064
|
+
if (event.poll?.id && event.poll.id !== this.id)
|
|
4065
|
+
return;
|
|
4066
|
+
if (!isPollVoteRemovedEvent(event))
|
|
4067
|
+
return;
|
|
4068
|
+
const currentState = this.data;
|
|
4069
|
+
const isOwnVote = event.poll_vote.user_id ===
|
|
4070
|
+
this.client.state.getLatestValue().connected_user?.id;
|
|
4071
|
+
let latestAnswers = [...currentState.latest_answers];
|
|
4072
|
+
let ownAnswer = currentState.own_answer;
|
|
4073
|
+
const ownVotesByOptionId = { ...currentState.own_votes_by_option_id };
|
|
4074
|
+
let maxVotedOptionIds = currentState.max_voted_option_ids;
|
|
4075
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
4076
|
+
if (isVoteAnswer(event.poll_vote)) {
|
|
4077
|
+
latestAnswers = latestAnswers.filter((answer) => answer.id !== event.poll_vote.id);
|
|
4078
|
+
if (isOwnVote) {
|
|
4079
|
+
ownAnswer = undefined;
|
|
4518
4080
|
}
|
|
4519
4081
|
}
|
|
4520
4082
|
else {
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
...response.feed,
|
|
4526
|
-
};
|
|
4527
|
-
delete responseCopy.feed;
|
|
4528
|
-
delete responseCopy.metadata;
|
|
4529
|
-
delete responseCopy.duration;
|
|
4530
|
-
this.state.next((currentState) => {
|
|
4531
|
-
const nextState = {
|
|
4532
|
-
...currentState,
|
|
4533
|
-
...responseCopy,
|
|
4534
|
-
};
|
|
4535
|
-
if (!request?.followers_pagination?.limit) {
|
|
4536
|
-
delete nextState.followers;
|
|
4537
|
-
}
|
|
4538
|
-
if (!request?.following_pagination?.limit) {
|
|
4539
|
-
delete nextState.following;
|
|
4540
|
-
}
|
|
4541
|
-
if (response.members.length === 0 && response.feed.member_count > 0) {
|
|
4542
|
-
delete nextState.members;
|
|
4543
|
-
}
|
|
4544
|
-
nextState.last_get_or_create_request_config = request;
|
|
4545
|
-
nextState.watch = request?.watch ? request.watch : currentState.watch;
|
|
4546
|
-
return nextState;
|
|
4547
|
-
});
|
|
4083
|
+
maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);
|
|
4084
|
+
if (isOwnVote && event.poll_vote.option_id) {
|
|
4085
|
+
delete ownVotesByOptionId[event.poll_vote.option_id];
|
|
4086
|
+
}
|
|
4548
4087
|
}
|
|
4549
|
-
|
|
4550
|
-
return response;
|
|
4551
|
-
}
|
|
4552
|
-
finally {
|
|
4088
|
+
const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
|
|
4553
4089
|
this.state.partialNext({
|
|
4554
|
-
|
|
4555
|
-
|
|
4090
|
+
answers_count,
|
|
4091
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
4092
|
+
latest_votes_by_option,
|
|
4093
|
+
vote_count,
|
|
4094
|
+
vote_counts_by_option,
|
|
4095
|
+
latest_answers: latestAnswers,
|
|
4096
|
+
last_activity_at: new Date(event.created_at),
|
|
4097
|
+
own_answer: ownAnswer,
|
|
4098
|
+
own_votes_by_option_id: ownVotesByOptionId,
|
|
4099
|
+
max_voted_option_ids: maxVotedOptionIds,
|
|
4556
4100
|
});
|
|
4557
|
-
}
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
*/
|
|
4562
|
-
handleFollowCreated(follow) {
|
|
4563
|
-
if (!shouldUpdateState({
|
|
4564
|
-
stateUpdateId: getStateUpdateQueueIdForFollow(follow),
|
|
4565
|
-
stateUpdateQueue: this.stateUpdateQueue,
|
|
4566
|
-
watch: this.currentState.watch,
|
|
4567
|
-
})) {
|
|
4568
|
-
return;
|
|
4569
|
-
}
|
|
4570
|
-
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4571
|
-
const result = handleFollowCreated(follow, this.currentState, this.fid, connectedUser?.id);
|
|
4572
|
-
if (result.changed) {
|
|
4573
|
-
this.state.next(result.data);
|
|
4574
|
-
}
|
|
4575
|
-
}
|
|
4576
|
-
/**
|
|
4577
|
-
* @internal
|
|
4578
|
-
*/
|
|
4579
|
-
handleFollowDeleted(follow) {
|
|
4580
|
-
if (!shouldUpdateState({
|
|
4581
|
-
stateUpdateId: getStateUpdateQueueIdForUnfollow(follow),
|
|
4582
|
-
stateUpdateQueue: this.stateUpdateQueue,
|
|
4583
|
-
watch: this.currentState.watch,
|
|
4584
|
-
})) {
|
|
4585
|
-
return;
|
|
4586
|
-
}
|
|
4587
|
-
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4588
|
-
const result = handleFollowDeleted(follow, this.currentState, this.fid, connectedUser?.id);
|
|
4589
|
-
{
|
|
4590
|
-
this.state.next(result.data);
|
|
4591
|
-
}
|
|
4592
|
-
}
|
|
4593
|
-
/**
|
|
4594
|
-
* @internal
|
|
4595
|
-
*/
|
|
4596
|
-
handleWatchStopped() {
|
|
4597
|
-
this.state.partialNext({
|
|
4598
|
-
watch: false,
|
|
4599
|
-
});
|
|
4600
|
-
}
|
|
4601
|
-
/**
|
|
4602
|
-
* @internal
|
|
4603
|
-
*/
|
|
4604
|
-
handleWatchStarted() {
|
|
4605
|
-
this.state.partialNext({
|
|
4606
|
-
watch: true,
|
|
4607
|
-
});
|
|
4608
|
-
}
|
|
4609
|
-
handleBookmarkAdded(event) {
|
|
4610
|
-
const currentActivities = this.currentState.activities;
|
|
4611
|
-
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4612
|
-
const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
|
|
4613
|
-
const result = addBookmarkToActivities(event, currentActivities, isCurrentUser);
|
|
4614
|
-
if (result.changed) {
|
|
4615
|
-
this.state.partialNext({ activities: result.activities });
|
|
4616
|
-
}
|
|
4617
|
-
}
|
|
4618
|
-
handleBookmarkDeleted(event) {
|
|
4619
|
-
const currentActivities = this.currentState.activities;
|
|
4620
|
-
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4621
|
-
const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
|
|
4622
|
-
const result = removeBookmarkFromActivities(event, currentActivities, isCurrentUser);
|
|
4623
|
-
if (result.changed) {
|
|
4624
|
-
this.state.partialNext({ activities: result.activities });
|
|
4625
|
-
}
|
|
4626
|
-
}
|
|
4627
|
-
handleBookmarkUpdated(event) {
|
|
4628
|
-
const currentActivities = this.currentState.activities;
|
|
4629
|
-
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4630
|
-
const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
|
|
4631
|
-
const result = updateBookmarkInActivities(event, currentActivities, isCurrentUser);
|
|
4632
|
-
if (result.changed) {
|
|
4633
|
-
this.state.partialNext({ activities: result.activities });
|
|
4634
|
-
}
|
|
4635
|
-
}
|
|
4636
|
-
/**
|
|
4637
|
-
* Returns index of the provided comment object.
|
|
4638
|
-
*/
|
|
4639
|
-
getCommentIndex(comment, state) {
|
|
4640
|
-
const { comments_by_entity_id = {} } = state ?? this.currentState;
|
|
4641
|
-
const currentComments = comments_by_entity_id[comment.parent_id ?? comment.object_id]?.comments;
|
|
4642
|
-
if (!currentComments?.length) {
|
|
4643
|
-
return -1;
|
|
4644
|
-
}
|
|
4645
|
-
// @ts-expect-error this will just fail if the comment is not object from state
|
|
4646
|
-
let commentIndex = currentComments.indexOf(comment);
|
|
4647
|
-
// fast lookup failed, try slower approach
|
|
4648
|
-
if (commentIndex === -1) {
|
|
4649
|
-
commentIndex = currentComments.findIndex((comment_) => comment_.id === comment.id);
|
|
4650
|
-
}
|
|
4651
|
-
return commentIndex;
|
|
4101
|
+
};
|
|
4102
|
+
this.client = client;
|
|
4103
|
+
this.id = poll.id;
|
|
4104
|
+
this.state = new StateStore(this.getInitialStateFromPollResponse(poll));
|
|
4652
4105
|
}
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
* `entityParentId` should be provided (`CommentResponse.parent_id ?? CommentResponse.object_id`).
|
|
4656
|
-
*/
|
|
4657
|
-
loadCommentsIntoState(data) {
|
|
4658
|
-
// add initial (top level) object for processing
|
|
4659
|
-
const traverseArray = [
|
|
4660
|
-
{
|
|
4661
|
-
entityId: data.entityId,
|
|
4662
|
-
entityParentId: data.entityParentId,
|
|
4663
|
-
comments: data.comments,
|
|
4664
|
-
next: data.next,
|
|
4665
|
-
},
|
|
4666
|
-
];
|
|
4667
|
-
this.state.next((currentState) => {
|
|
4668
|
-
const newCommentsByEntityId = {
|
|
4669
|
-
...currentState.comments_by_entity_id,
|
|
4670
|
-
};
|
|
4671
|
-
while (traverseArray.length) {
|
|
4672
|
-
const item = traverseArray.pop();
|
|
4673
|
-
const entityId = item.entityId;
|
|
4674
|
-
// go over entity comments and generate new objects
|
|
4675
|
-
// for further processing if there are any replies
|
|
4676
|
-
item.comments.forEach((comment) => {
|
|
4677
|
-
if (!comment.replies?.length)
|
|
4678
|
-
return;
|
|
4679
|
-
traverseArray.push({
|
|
4680
|
-
entityId: comment.id,
|
|
4681
|
-
entityParentId: entityId,
|
|
4682
|
-
comments: comment.replies,
|
|
4683
|
-
next: comment.meta?.next_cursor,
|
|
4684
|
-
});
|
|
4685
|
-
});
|
|
4686
|
-
// omit replies & meta from the comments (transform ThreadedCommentResponse to CommentResponse)
|
|
4687
|
-
// this is somehow faster than copying the whole
|
|
4688
|
-
// object and deleting the desired properties
|
|
4689
|
-
const newComments = item.comments.map(({ replies: _r, meta: _m, ...restOfTheCommentResponse }) => restOfTheCommentResponse);
|
|
4690
|
-
newCommentsByEntityId[entityId] = {
|
|
4691
|
-
...newCommentsByEntityId[entityId],
|
|
4692
|
-
entity_parent_id: item.entityParentId,
|
|
4693
|
-
pagination: {
|
|
4694
|
-
...newCommentsByEntityId[entityId]?.pagination,
|
|
4695
|
-
next: item.next,
|
|
4696
|
-
sort: data.sort,
|
|
4697
|
-
},
|
|
4698
|
-
comments: newCommentsByEntityId[entityId]?.comments
|
|
4699
|
-
? newCommentsByEntityId[entityId].comments?.concat(newComments)
|
|
4700
|
-
: newComments,
|
|
4701
|
-
};
|
|
4702
|
-
}
|
|
4703
|
-
return {
|
|
4704
|
-
...currentState,
|
|
4705
|
-
comments_by_entity_id: newCommentsByEntityId,
|
|
4706
|
-
};
|
|
4707
|
-
});
|
|
4106
|
+
get data() {
|
|
4107
|
+
return this.state.getLatestValue();
|
|
4708
4108
|
}
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
...currentState.comments_by_entity_id[entityId],
|
|
4718
|
-
pagination: {
|
|
4719
|
-
...currentState.comments_by_entity_id[entityId]?.pagination,
|
|
4720
|
-
loading_next_page: true,
|
|
4721
|
-
},
|
|
4722
|
-
},
|
|
4723
|
-
},
|
|
4724
|
-
}));
|
|
4725
|
-
const { next, comments } = await base();
|
|
4726
|
-
this.loadCommentsIntoState({
|
|
4727
|
-
entityId,
|
|
4728
|
-
comments,
|
|
4729
|
-
entityParentId,
|
|
4730
|
-
next,
|
|
4731
|
-
sort,
|
|
4732
|
-
});
|
|
4733
|
-
}
|
|
4734
|
-
catch (e) {
|
|
4735
|
-
error = e;
|
|
4736
|
-
}
|
|
4737
|
-
finally {
|
|
4738
|
-
this.state.next((currentState) => ({
|
|
4739
|
-
...currentState,
|
|
4740
|
-
comments_by_entity_id: {
|
|
4741
|
-
...currentState.comments_by_entity_id,
|
|
4742
|
-
[entityId]: {
|
|
4743
|
-
...currentState.comments_by_entity_id[entityId],
|
|
4744
|
-
pagination: {
|
|
4745
|
-
...currentState.comments_by_entity_id[entityId]?.pagination,
|
|
4746
|
-
loading_next_page: false,
|
|
4747
|
-
},
|
|
4748
|
-
},
|
|
4749
|
-
},
|
|
4750
|
-
}));
|
|
4109
|
+
}
|
|
4110
|
+
function getMaxVotedOptionIds(voteCountsByOption) {
|
|
4111
|
+
let maxVotes = 0;
|
|
4112
|
+
let winningOptions = [];
|
|
4113
|
+
for (const [id, count] of Object.entries(voteCountsByOption ?? {})) {
|
|
4114
|
+
if (count > maxVotes) {
|
|
4115
|
+
winningOptions = [id];
|
|
4116
|
+
maxVotes = count;
|
|
4751
4117
|
}
|
|
4752
|
-
if (
|
|
4753
|
-
|
|
4118
|
+
else if (count === maxVotes) {
|
|
4119
|
+
winningOptions.push(id);
|
|
4754
4120
|
}
|
|
4755
4121
|
}
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
return;
|
|
4766
|
-
}
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4122
|
+
return winningOptions;
|
|
4123
|
+
}
|
|
4124
|
+
function getOwnVotesByOptionId(ownVotes) {
|
|
4125
|
+
return !ownVotes
|
|
4126
|
+
? {}
|
|
4127
|
+
: ownVotes.reduce((acc, vote) => {
|
|
4128
|
+
if (isVoteAnswer(vote) || !vote.option_id)
|
|
4129
|
+
return acc;
|
|
4130
|
+
acc[vote.option_id] = vote;
|
|
4131
|
+
return acc;
|
|
4132
|
+
}, {});
|
|
4133
|
+
}
|
|
4134
|
+
|
|
4135
|
+
class FeedApi {
|
|
4136
|
+
constructor(feedsApi, group, id) {
|
|
4137
|
+
this.feedsApi = feedsApi;
|
|
4138
|
+
this.group = group;
|
|
4139
|
+
this.id = id;
|
|
4140
|
+
}
|
|
4141
|
+
delete(request) {
|
|
4142
|
+
return this.feedsApi.deleteFeed({
|
|
4143
|
+
feed_id: this.id,
|
|
4144
|
+
feed_group_id: this.group,
|
|
4145
|
+
...request,
|
|
4777
4146
|
});
|
|
4778
4147
|
}
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
const isLoading = currentPagination?.loading_next_page;
|
|
4785
|
-
const sort = currentSort ?? request?.sort ?? Constants.DEFAULT_COMMENT_PAGINATION;
|
|
4786
|
-
if (isLoading ||
|
|
4787
|
-
!checkHasAnotherPage(currentEntityState?.comments, currentNextCursor)) {
|
|
4788
|
-
return;
|
|
4789
|
-
}
|
|
4790
|
-
await this.loadNextPageComments({
|
|
4791
|
-
entityId: comment.id,
|
|
4792
|
-
base: () => this.client.getCommentReplies({
|
|
4793
|
-
...request,
|
|
4794
|
-
comment_id: comment.id,
|
|
4795
|
-
// use known sort first (prevents broken pagination)
|
|
4796
|
-
sort: currentSort ??
|
|
4797
|
-
request?.sort ??
|
|
4798
|
-
Constants.DEFAULT_COMMENT_PAGINATION,
|
|
4799
|
-
next: currentNextCursor,
|
|
4800
|
-
}),
|
|
4801
|
-
entityParentId: comment.parent_id ?? comment.object_id,
|
|
4802
|
-
sort,
|
|
4148
|
+
getOrCreate(request) {
|
|
4149
|
+
return this.feedsApi.getOrCreateFeed({
|
|
4150
|
+
feed_id: this.id,
|
|
4151
|
+
feed_group_id: this.group,
|
|
4152
|
+
...request,
|
|
4803
4153
|
});
|
|
4804
4154
|
}
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4155
|
+
update(request) {
|
|
4156
|
+
return this.feedsApi.updateFeed({
|
|
4157
|
+
feed_id: this.id,
|
|
4158
|
+
feed_group_id: this.group,
|
|
4159
|
+
...request,
|
|
4160
|
+
});
|
|
4161
|
+
}
|
|
4162
|
+
markActivity(request) {
|
|
4163
|
+
return this.feedsApi.markActivity({
|
|
4164
|
+
feed_id: this.id,
|
|
4165
|
+
feed_group_id: this.group,
|
|
4166
|
+
...request,
|
|
4167
|
+
});
|
|
4168
|
+
}
|
|
4169
|
+
unpinActivity(request) {
|
|
4170
|
+
return this.feedsApi.unpinActivity({
|
|
4171
|
+
feed_id: this.id,
|
|
4172
|
+
feed_group_id: this.group,
|
|
4173
|
+
...request,
|
|
4174
|
+
});
|
|
4175
|
+
}
|
|
4176
|
+
pinActivity(request) {
|
|
4177
|
+
return this.feedsApi.pinActivity({
|
|
4178
|
+
feed_id: this.id,
|
|
4179
|
+
feed_group_id: this.group,
|
|
4180
|
+
...request,
|
|
4181
|
+
});
|
|
4182
|
+
}
|
|
4183
|
+
updateFeedMembers(request) {
|
|
4184
|
+
return this.feedsApi.updateFeedMembers({
|
|
4185
|
+
feed_id: this.id,
|
|
4186
|
+
feed_group_id: this.group,
|
|
4187
|
+
...request,
|
|
4188
|
+
});
|
|
4189
|
+
}
|
|
4190
|
+
acceptFeedMemberInvite(request) {
|
|
4191
|
+
return this.feedsApi.acceptFeedMemberInvite({
|
|
4192
|
+
feed_id: this.id,
|
|
4193
|
+
feed_group_id: this.group,
|
|
4194
|
+
...request,
|
|
4195
|
+
});
|
|
4196
|
+
}
|
|
4197
|
+
queryFeedMembers(request) {
|
|
4198
|
+
return this.feedsApi.queryFeedMembers({
|
|
4199
|
+
feed_id: this.id,
|
|
4200
|
+
feed_group_id: this.group,
|
|
4201
|
+
...request,
|
|
4202
|
+
});
|
|
4203
|
+
}
|
|
4204
|
+
rejectFeedMemberInvite(request) {
|
|
4205
|
+
return this.feedsApi.rejectFeedMemberInvite({
|
|
4206
|
+
feed_id: this.id,
|
|
4207
|
+
feed_group_id: this.group,
|
|
4208
|
+
...request,
|
|
4209
|
+
});
|
|
4210
|
+
}
|
|
4211
|
+
stopWatching(request) {
|
|
4212
|
+
return this.feedsApi.stopWatchingFeed({
|
|
4213
|
+
feed_id: this.id,
|
|
4214
|
+
feed_group_id: this.group,
|
|
4215
|
+
...request,
|
|
4216
|
+
});
|
|
4217
|
+
}
|
|
4218
|
+
}
|
|
4219
|
+
|
|
4220
|
+
const checkHasAnotherPage = (v, cursor) => (typeof v === 'undefined' && typeof cursor === 'undefined') ||
|
|
4221
|
+
typeof cursor === 'string';
|
|
4222
|
+
|
|
4223
|
+
const uniqueArrayMerge = (existingArray, arrayToMerge, getKey) => {
|
|
4224
|
+
const existing = new Set();
|
|
4225
|
+
existingArray.forEach((value) => {
|
|
4226
|
+
const key = getKey(value);
|
|
4227
|
+
existing.add(key);
|
|
4228
|
+
});
|
|
4229
|
+
const filteredArrayToMerge = arrayToMerge.filter((value) => {
|
|
4230
|
+
const key = getKey(value);
|
|
4231
|
+
return !existing.has(key);
|
|
4232
|
+
});
|
|
4233
|
+
return existingArray.concat(filteredArrayToMerge);
|
|
4234
|
+
};
|
|
4235
|
+
|
|
4236
|
+
const Constants = {
|
|
4237
|
+
DEFAULT_COMMENT_PAGINATION: 'first',
|
|
4238
|
+
};
|
|
4239
|
+
|
|
4240
|
+
const isFollowResponse = (data) => {
|
|
4241
|
+
return 'source_feed' in data && 'target_feed' in data;
|
|
4242
|
+
};
|
|
4243
|
+
const isCommentResponse = (entity) => {
|
|
4244
|
+
return typeof entity?.object_id === 'string';
|
|
4245
|
+
};
|
|
4246
|
+
const isImageFile = (file) => {
|
|
4247
|
+
// photoshop files begin with 'image/'
|
|
4248
|
+
return file.type.startsWith('image/') && !file.type.endsWith('.photoshop');
|
|
4249
|
+
};
|
|
4250
|
+
const isVideoFile = (file) => {
|
|
4251
|
+
return file.type.startsWith('video/');
|
|
4252
|
+
};
|
|
4253
|
+
|
|
4254
|
+
const shouldUpdateState = ({ stateUpdateQueueId, stateUpdateQueue, watch, }) => {
|
|
4255
|
+
if (!watch) {
|
|
4256
|
+
return true;
|
|
4257
|
+
}
|
|
4258
|
+
if (watch && stateUpdateQueue.has(stateUpdateQueueId)) {
|
|
4259
|
+
stateUpdateQueue.delete(stateUpdateQueueId);
|
|
4260
|
+
return false;
|
|
4261
|
+
}
|
|
4262
|
+
stateUpdateQueue.add(stateUpdateQueueId);
|
|
4263
|
+
return true;
|
|
4264
|
+
};
|
|
4265
|
+
function getStateUpdateQueueId(data, prefix) {
|
|
4266
|
+
if (isFollowResponse(data)) {
|
|
4267
|
+
const toJoin = [data.source_feed.fid, data.target_feed.fid];
|
|
4268
|
+
if (prefix) {
|
|
4269
|
+
toJoin.unshift(prefix);
|
|
4815
4270
|
}
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
next: newNextCursor,
|
|
4840
|
-
sort,
|
|
4841
|
-
},
|
|
4842
|
-
};
|
|
4843
|
-
});
|
|
4271
|
+
return toJoin.join('-');
|
|
4272
|
+
}
|
|
4273
|
+
// else if (isMemberResponse(data)) {
|
|
4274
|
+
// }
|
|
4275
|
+
throw new Error(`Cannot create state update queueId for data: ${JSON.stringify(data)}`);
|
|
4276
|
+
}
|
|
4277
|
+
|
|
4278
|
+
const updateStateFollowCreated = (follow, currentState, currentFeedId, connectedUserId) => {
|
|
4279
|
+
// filter non-accepted follows (the way getOrCreate does by default)
|
|
4280
|
+
if (follow.status !== 'accepted') {
|
|
4281
|
+
return { changed: false, data: currentState };
|
|
4282
|
+
}
|
|
4283
|
+
let newState = { ...currentState };
|
|
4284
|
+
// this feed followed someone
|
|
4285
|
+
if (follow.source_feed.fid === currentFeedId) {
|
|
4286
|
+
newState = {
|
|
4287
|
+
...newState,
|
|
4288
|
+
// Update FeedResponse fields, that has the new follower/following count
|
|
4289
|
+
...follow.source_feed,
|
|
4290
|
+
};
|
|
4291
|
+
// Only update if following array already exists
|
|
4292
|
+
if (currentState.following !== undefined) {
|
|
4293
|
+
newState.following = [follow, ...currentState.following];
|
|
4844
4294
|
}
|
|
4845
|
-
|
|
4846
|
-
|
|
4295
|
+
}
|
|
4296
|
+
else if (
|
|
4297
|
+
// someone followed this feed
|
|
4298
|
+
follow.target_feed.fid === currentFeedId) {
|
|
4299
|
+
const source = follow.source_feed;
|
|
4300
|
+
newState = {
|
|
4301
|
+
...newState,
|
|
4302
|
+
// Update FeedResponse fields, that has the new follower/following count
|
|
4303
|
+
...follow.target_feed,
|
|
4304
|
+
};
|
|
4305
|
+
if (source.created_by.id === connectedUserId) {
|
|
4306
|
+
newState.own_follows = currentState.own_follows
|
|
4307
|
+
? currentState.own_follows.concat(follow)
|
|
4308
|
+
: [follow];
|
|
4309
|
+
}
|
|
4310
|
+
// Only update if followers array already exists
|
|
4311
|
+
if (currentState.followers !== undefined) {
|
|
4312
|
+
newState.followers = [follow, ...currentState.followers];
|
|
4313
|
+
}
|
|
4314
|
+
}
|
|
4315
|
+
return { changed: true, data: newState };
|
|
4316
|
+
};
|
|
4317
|
+
function handleFollowCreated(eventOrResponse) {
|
|
4318
|
+
const follow = eventOrResponse.follow;
|
|
4319
|
+
if (!shouldUpdateState({
|
|
4320
|
+
stateUpdateQueueId: getStateUpdateQueueId(follow, 'created'),
|
|
4321
|
+
stateUpdateQueue: this.stateUpdateQueue,
|
|
4322
|
+
watch: this.currentState.watch,
|
|
4323
|
+
})) {
|
|
4324
|
+
return;
|
|
4325
|
+
}
|
|
4326
|
+
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4327
|
+
const result = updateStateFollowCreated(follow, this.currentState, this.fid, connectedUser?.id);
|
|
4328
|
+
if (result.changed) {
|
|
4329
|
+
this.state.next(result.data);
|
|
4330
|
+
}
|
|
4331
|
+
}
|
|
4332
|
+
|
|
4333
|
+
const updateStateFollowDeleted = (follow, currentState, currentFeedId, connectedUserId) => {
|
|
4334
|
+
let newState = { ...currentState };
|
|
4335
|
+
// this feed unfollowed someone
|
|
4336
|
+
if (follow.source_feed.fid === currentFeedId) {
|
|
4337
|
+
newState = {
|
|
4338
|
+
...newState,
|
|
4339
|
+
// Update FeedResponse fields, that has the new follower/following count
|
|
4340
|
+
...follow.source_feed,
|
|
4341
|
+
};
|
|
4342
|
+
// Only update if following array already exists
|
|
4343
|
+
if (currentState.following !== undefined) {
|
|
4344
|
+
newState.following = currentState.following.filter((followItem) => followItem.target_feed.fid !== follow.target_feed.fid);
|
|
4847
4345
|
}
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4346
|
+
}
|
|
4347
|
+
else if (
|
|
4348
|
+
// someone unfollowed this feed
|
|
4349
|
+
follow.target_feed.fid === currentFeedId) {
|
|
4350
|
+
const source = follow.source_feed;
|
|
4351
|
+
newState = {
|
|
4352
|
+
...newState,
|
|
4353
|
+
// Update FeedResponse fields, that has the new follower/following count
|
|
4354
|
+
...follow.target_feed,
|
|
4355
|
+
};
|
|
4356
|
+
if (source.created_by.id === connectedUserId &&
|
|
4357
|
+
currentState.own_follows !== undefined) {
|
|
4358
|
+
newState.own_follows = currentState.own_follows.filter((followItem) => followItem.source_feed.fid !== follow.source_feed.fid);
|
|
4858
4359
|
}
|
|
4859
|
-
if
|
|
4860
|
-
|
|
4360
|
+
// Only update if followers array already exists
|
|
4361
|
+
if (currentState.followers !== undefined) {
|
|
4362
|
+
newState.followers = currentState.followers.filter((followItem) => followItem.source_feed.fid !== follow.source_feed.fid);
|
|
4861
4363
|
}
|
|
4862
4364
|
}
|
|
4863
|
-
|
|
4864
|
-
|
|
4365
|
+
return { changed: true, data: newState };
|
|
4366
|
+
};
|
|
4367
|
+
function handleFollowDeleted(eventOrResponse) {
|
|
4368
|
+
const follow = eventOrResponse.follow;
|
|
4369
|
+
if (!shouldUpdateState({
|
|
4370
|
+
stateUpdateQueueId: getStateUpdateQueueId(follow, 'deleted'),
|
|
4371
|
+
stateUpdateQueue: this.stateUpdateQueue,
|
|
4372
|
+
watch: this.currentState.watch,
|
|
4373
|
+
})) {
|
|
4374
|
+
return;
|
|
4865
4375
|
}
|
|
4866
|
-
|
|
4867
|
-
|
|
4376
|
+
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4377
|
+
const result = updateStateFollowDeleted(follow, this.currentState, this.fid, connectedUser?.id);
|
|
4378
|
+
{
|
|
4379
|
+
this.state.next(result.data);
|
|
4868
4380
|
}
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4381
|
+
}
|
|
4382
|
+
|
|
4383
|
+
function handleFollowUpdated(eventOrResponse) {
|
|
4384
|
+
const follow = eventOrResponse.follow;
|
|
4385
|
+
const connectedUserId = this.client.state.getLatestValue().connected_user?.id;
|
|
4386
|
+
const currentFeedId = this.fid;
|
|
4387
|
+
if (!shouldUpdateState({
|
|
4388
|
+
stateUpdateQueueId: getStateUpdateQueueId(follow, 'updated'),
|
|
4389
|
+
stateUpdateQueue: this.stateUpdateQueue,
|
|
4390
|
+
watch: this.currentState.watch,
|
|
4391
|
+
})) {
|
|
4392
|
+
return;
|
|
4393
|
+
}
|
|
4394
|
+
this.state.next((currentState) => {
|
|
4395
|
+
let newState;
|
|
4396
|
+
// this feed followed someone
|
|
4397
|
+
if (follow.source_feed.fid === currentFeedId) {
|
|
4398
|
+
newState ?? (newState = {
|
|
4399
|
+
...currentState,
|
|
4400
|
+
// Update FeedResponse fields, that has the new follower/following count
|
|
4401
|
+
...follow.source_feed,
|
|
4402
|
+
});
|
|
4403
|
+
const index = currentState.following?.findIndex((f) => f.target_feed.fid === follow.target_feed.fid) ?? -1;
|
|
4404
|
+
if (index >= 0) {
|
|
4405
|
+
newState.following = [...newState.following];
|
|
4406
|
+
newState.following[index] = follow;
|
|
4407
|
+
}
|
|
4877
4408
|
}
|
|
4878
|
-
|
|
4879
|
-
|
|
4409
|
+
else if (
|
|
4410
|
+
// someone followed this feed
|
|
4411
|
+
follow.target_feed.fid === currentFeedId) {
|
|
4412
|
+
const source = follow.source_feed;
|
|
4413
|
+
newState ?? (newState = {
|
|
4880
4414
|
...currentState,
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4415
|
+
// Update FeedResponse fields, that has the new follower/following count
|
|
4416
|
+
...follow.target_feed,
|
|
4417
|
+
});
|
|
4418
|
+
if (source.created_by.id === connectedUserId &&
|
|
4419
|
+
currentState.own_follows) {
|
|
4420
|
+
const index = currentState.own_follows.findIndex((f) => f.source_feed.fid === follow.source_feed.fid);
|
|
4421
|
+
if (index >= 0) {
|
|
4422
|
+
newState.own_follows = [...currentState.own_follows];
|
|
4423
|
+
newState.own_follows[index] = follow;
|
|
4424
|
+
}
|
|
4425
|
+
}
|
|
4426
|
+
const index = currentState.followers?.findIndex((f) => f.source_feed.fid === follow.source_feed.fid) ?? -1;
|
|
4427
|
+
if (index >= 0) {
|
|
4428
|
+
newState.followers = [...newState.followers];
|
|
4429
|
+
newState.followers[index] = follow;
|
|
4430
|
+
}
|
|
4431
|
+
}
|
|
4432
|
+
return newState ?? currentState;
|
|
4433
|
+
});
|
|
4434
|
+
}
|
|
4435
|
+
|
|
4436
|
+
function handleCommentAdded(event) {
|
|
4437
|
+
const { comment } = event;
|
|
4438
|
+
const entityId = comment.parent_id ?? comment.object_id;
|
|
4439
|
+
this.state.next((currentState) => {
|
|
4440
|
+
const entityState = currentState.comments_by_entity_id[entityId];
|
|
4441
|
+
if (typeof entityState?.comments === 'undefined') {
|
|
4442
|
+
return currentState;
|
|
4443
|
+
}
|
|
4444
|
+
const newComments = entityState?.comments ? [...entityState.comments] : [];
|
|
4445
|
+
if (entityState.pagination?.sort === 'last') {
|
|
4446
|
+
newComments.unshift(comment);
|
|
4447
|
+
}
|
|
4448
|
+
else {
|
|
4449
|
+
// 'first' and other sort options
|
|
4450
|
+
newComments.push(comment);
|
|
4451
|
+
}
|
|
4452
|
+
return {
|
|
4453
|
+
...currentState,
|
|
4454
|
+
comments_by_entity_id: {
|
|
4455
|
+
...currentState.comments_by_entity_id,
|
|
4456
|
+
[entityId]: {
|
|
4457
|
+
...currentState.comments_by_entity_id[entityId],
|
|
4458
|
+
comments: newComments,
|
|
4884
4459
|
},
|
|
4885
|
-
}
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4460
|
+
},
|
|
4461
|
+
};
|
|
4462
|
+
});
|
|
4463
|
+
}
|
|
4464
|
+
|
|
4465
|
+
function handleCommentDeleted({ comment }) {
|
|
4466
|
+
const entityId = comment.parent_id ?? comment.object_id;
|
|
4467
|
+
this.state.next((currentState) => {
|
|
4468
|
+
const newCommentsByEntityId = {
|
|
4469
|
+
...currentState.comments_by_entity_id,
|
|
4470
|
+
[entityId]: {
|
|
4471
|
+
...currentState.comments_by_entity_id[entityId],
|
|
4472
|
+
},
|
|
4473
|
+
};
|
|
4474
|
+
const index = this.getCommentIndex(comment, currentState);
|
|
4475
|
+
if (newCommentsByEntityId?.[entityId]?.comments?.length && index !== -1) {
|
|
4476
|
+
newCommentsByEntityId[entityId].comments = [
|
|
4477
|
+
...newCommentsByEntityId[entityId].comments,
|
|
4478
|
+
];
|
|
4479
|
+
newCommentsByEntityId[entityId]?.comments?.splice(index, 1);
|
|
4480
|
+
}
|
|
4481
|
+
delete newCommentsByEntityId[comment.id];
|
|
4482
|
+
return {
|
|
4483
|
+
...currentState,
|
|
4484
|
+
comments_by_entity_id: newCommentsByEntityId,
|
|
4485
|
+
};
|
|
4486
|
+
});
|
|
4487
|
+
}
|
|
4488
|
+
|
|
4489
|
+
function handleCommentUpdated(event) {
|
|
4490
|
+
const { comment } = event;
|
|
4491
|
+
const entityId = comment.parent_id ?? comment.object_id;
|
|
4492
|
+
this.state.next((currentState) => {
|
|
4493
|
+
const entityState = currentState.comments_by_entity_id[entityId];
|
|
4494
|
+
if (!entityState?.comments?.length)
|
|
4495
|
+
return currentState;
|
|
4496
|
+
const index = this.getCommentIndex(comment, currentState);
|
|
4497
|
+
if (index === -1)
|
|
4498
|
+
return currentState;
|
|
4499
|
+
const newComments = [...entityState.comments];
|
|
4500
|
+
newComments[index] = comment;
|
|
4501
|
+
return {
|
|
4502
|
+
...currentState,
|
|
4503
|
+
comments_by_entity_id: {
|
|
4504
|
+
...currentState.comments_by_entity_id,
|
|
4505
|
+
[entityId]: {
|
|
4506
|
+
...currentState.comments_by_entity_id[entityId],
|
|
4507
|
+
comments: newComments,
|
|
4508
|
+
},
|
|
4509
|
+
},
|
|
4510
|
+
};
|
|
4511
|
+
});
|
|
4512
|
+
}
|
|
4513
|
+
|
|
4514
|
+
function handleCommentReaction(event) {
|
|
4515
|
+
const { comment, reaction } = event;
|
|
4516
|
+
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4517
|
+
this.state.next((currentState) => {
|
|
4518
|
+
const forId = comment.parent_id ?? comment.object_id;
|
|
4519
|
+
const entityState = currentState.comments_by_entity_id[forId];
|
|
4520
|
+
const commentIndex = this.getCommentIndex(comment, currentState);
|
|
4521
|
+
if (commentIndex === -1)
|
|
4522
|
+
return currentState;
|
|
4523
|
+
const newComments = entityState?.comments?.concat([]) ?? [];
|
|
4524
|
+
const commentCopy = { ...comment };
|
|
4525
|
+
delete commentCopy.own_reactions;
|
|
4526
|
+
const newComment = {
|
|
4527
|
+
...newComments[commentIndex],
|
|
4528
|
+
...commentCopy,
|
|
4529
|
+
// TODO: FIXME this should be handled by the backend
|
|
4530
|
+
latest_reactions: commentCopy.latest_reactions ?? [],
|
|
4531
|
+
reaction_groups: commentCopy.reaction_groups ?? {},
|
|
4532
|
+
};
|
|
4533
|
+
newComments[commentIndex] = newComment;
|
|
4534
|
+
if (reaction.user.id === connectedUser?.id) {
|
|
4535
|
+
if (event.type === 'feeds.comment.reaction.added') {
|
|
4536
|
+
newComment.own_reactions = newComment.own_reactions.concat(reaction) ?? [reaction];
|
|
4537
|
+
}
|
|
4538
|
+
else if (event.type === 'feeds.comment.reaction.deleted') {
|
|
4539
|
+
newComment.own_reactions = newComment.own_reactions.filter((r) => r.type !== reaction.type);
|
|
4540
|
+
}
|
|
4541
|
+
}
|
|
4542
|
+
return {
|
|
4543
|
+
...currentState,
|
|
4544
|
+
comments_by_entity_id: {
|
|
4545
|
+
...currentState.comments_by_entity_id,
|
|
4546
|
+
[forId]: {
|
|
4547
|
+
...entityState,
|
|
4548
|
+
comments: newComments,
|
|
4549
|
+
},
|
|
4550
|
+
},
|
|
4551
|
+
};
|
|
4552
|
+
});
|
|
4553
|
+
}
|
|
4554
|
+
|
|
4555
|
+
function handleFeedMemberAdded(event) {
|
|
4556
|
+
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4557
|
+
this.state.next((currentState) => {
|
|
4558
|
+
let newState;
|
|
4559
|
+
if (typeof currentState.members !== 'undefined') {
|
|
4560
|
+
newState ?? (newState = {
|
|
4561
|
+
...currentState,
|
|
4892
4562
|
});
|
|
4893
|
-
|
|
4563
|
+
newState.members = [event.member, ...currentState.members];
|
|
4564
|
+
}
|
|
4565
|
+
if (connectedUser?.id === event.member.user.id) {
|
|
4566
|
+
newState ?? (newState = {
|
|
4894
4567
|
...currentState,
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
: members,
|
|
4898
|
-
member_pagination: {
|
|
4899
|
-
...currentState.member_pagination,
|
|
4900
|
-
next: newNextCursor,
|
|
4901
|
-
// set sort if not defined yet
|
|
4902
|
-
sort: currentState.member_pagination?.sort ?? request.sort,
|
|
4903
|
-
},
|
|
4904
|
-
}));
|
|
4568
|
+
});
|
|
4569
|
+
newState.own_membership = event.member;
|
|
4905
4570
|
}
|
|
4906
|
-
|
|
4907
|
-
|
|
4571
|
+
return newState ?? currentState;
|
|
4572
|
+
});
|
|
4573
|
+
}
|
|
4574
|
+
|
|
4575
|
+
function handleFeedMemberUpdated(event) {
|
|
4576
|
+
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4577
|
+
this.state.next((currentState) => {
|
|
4578
|
+
const memberIndex = currentState.members?.findIndex((member) => member.user.id === event.member.user.id) ?? -1;
|
|
4579
|
+
let newState;
|
|
4580
|
+
if (memberIndex !== -1) {
|
|
4581
|
+
// if there's an index, there's a member to update
|
|
4582
|
+
const newMembers = [...currentState.members];
|
|
4583
|
+
newMembers[memberIndex] = event.member;
|
|
4584
|
+
newState ?? (newState = {
|
|
4585
|
+
...currentState,
|
|
4586
|
+
});
|
|
4587
|
+
newState.members = newMembers;
|
|
4908
4588
|
}
|
|
4909
|
-
|
|
4910
|
-
|
|
4589
|
+
if (connectedUser?.id === event.member.user.id) {
|
|
4590
|
+
newState ?? (newState = {
|
|
4911
4591
|
...currentState,
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
loading_next_page: false,
|
|
4915
|
-
},
|
|
4916
|
-
}));
|
|
4592
|
+
});
|
|
4593
|
+
newState.own_membership = event.member;
|
|
4917
4594
|
}
|
|
4918
|
-
|
|
4919
|
-
|
|
4595
|
+
return newState ?? currentState;
|
|
4596
|
+
});
|
|
4597
|
+
}
|
|
4598
|
+
|
|
4599
|
+
function handleFeedMemberRemoved(event) {
|
|
4600
|
+
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4601
|
+
this.state.next((currentState) => {
|
|
4602
|
+
const newState = {
|
|
4603
|
+
...currentState,
|
|
4604
|
+
members: currentState.members?.filter((member) => member.user.id !== event.user?.id),
|
|
4605
|
+
};
|
|
4606
|
+
if (connectedUser?.id === event.member_id) {
|
|
4607
|
+
delete newState.own_membership;
|
|
4920
4608
|
}
|
|
4609
|
+
return newState;
|
|
4610
|
+
});
|
|
4611
|
+
}
|
|
4612
|
+
|
|
4613
|
+
const addActivitiesToState = (newActivities, activities, position) => {
|
|
4614
|
+
let result;
|
|
4615
|
+
if (activities === undefined) {
|
|
4616
|
+
activities = [];
|
|
4617
|
+
result = {
|
|
4618
|
+
changed: true,
|
|
4619
|
+
activities,
|
|
4620
|
+
};
|
|
4921
4621
|
}
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
*/
|
|
4927
|
-
async queryFollowers(request) {
|
|
4928
|
-
const filter = {
|
|
4929
|
-
target_feed: this.fid,
|
|
4622
|
+
else {
|
|
4623
|
+
result = {
|
|
4624
|
+
changed: false,
|
|
4625
|
+
activities,
|
|
4930
4626
|
};
|
|
4931
|
-
const response = await this.client.queryFollows({
|
|
4932
|
-
filter,
|
|
4933
|
-
...request,
|
|
4934
|
-
});
|
|
4935
|
-
return response;
|
|
4936
4627
|
}
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
...
|
|
4949
|
-
|
|
4950
|
-
|
|
4628
|
+
const newActivitiesDeduplicated = [];
|
|
4629
|
+
newActivities.forEach((newActivityResponse) => {
|
|
4630
|
+
const index = activities.findIndex((a) => a.id === newActivityResponse.id);
|
|
4631
|
+
if (index === -1) {
|
|
4632
|
+
newActivitiesDeduplicated.push(newActivityResponse);
|
|
4633
|
+
}
|
|
4634
|
+
});
|
|
4635
|
+
if (newActivitiesDeduplicated.length > 0) {
|
|
4636
|
+
// TODO: since feed activities are not necessarily ordered by created_at (personalization) we don't order by created_at
|
|
4637
|
+
// Maybe we can add a flag to the JS client to support order by created_at
|
|
4638
|
+
const updatedActivities = [
|
|
4639
|
+
...(position === 'start' ? newActivitiesDeduplicated : []),
|
|
4640
|
+
...activities,
|
|
4641
|
+
...(position === 'end' ? newActivitiesDeduplicated : []),
|
|
4642
|
+
];
|
|
4643
|
+
result = { changed: true, activities: updatedActivities };
|
|
4644
|
+
}
|
|
4645
|
+
return result;
|
|
4646
|
+
};
|
|
4647
|
+
function handleActivityAdded(event) {
|
|
4648
|
+
const currentActivities = this.currentState.activities;
|
|
4649
|
+
const result = addActivitiesToState([event.activity], currentActivities, 'start');
|
|
4650
|
+
if (result.changed) {
|
|
4651
|
+
this.client.hydratePollCache([event.activity]);
|
|
4652
|
+
this.state.partialNext({ activities: result.activities });
|
|
4653
|
+
}
|
|
4654
|
+
}
|
|
4655
|
+
|
|
4656
|
+
const removeActivityFromState = (activityResponse, activities) => {
|
|
4657
|
+
const index = activities.findIndex((a) => a.id === activityResponse.id);
|
|
4658
|
+
if (index !== -1) {
|
|
4659
|
+
const newActivities = [...activities];
|
|
4660
|
+
newActivities.splice(index, 1);
|
|
4661
|
+
return { changed: true, activities: newActivities };
|
|
4662
|
+
}
|
|
4663
|
+
else {
|
|
4664
|
+
return { changed: false, activities };
|
|
4665
|
+
}
|
|
4666
|
+
};
|
|
4667
|
+
function handleActivityDeleted(event) {
|
|
4668
|
+
const currentActivities = this.currentState.activities;
|
|
4669
|
+
if (currentActivities) {
|
|
4670
|
+
const result = removeActivityFromState(event.activity, currentActivities);
|
|
4671
|
+
if (result.changed) {
|
|
4672
|
+
this.state.partialNext({ activities: result.activities });
|
|
4673
|
+
}
|
|
4674
|
+
}
|
|
4675
|
+
}
|
|
4676
|
+
|
|
4677
|
+
function handleActivityRemovedFromFeed(event) {
|
|
4678
|
+
const currentActivities = this.currentState.activities;
|
|
4679
|
+
if (currentActivities) {
|
|
4680
|
+
const result = removeActivityFromState(event.activity, currentActivities);
|
|
4681
|
+
if (result.changed) {
|
|
4682
|
+
this.state.partialNext({ activities: result.activities });
|
|
4683
|
+
}
|
|
4684
|
+
}
|
|
4685
|
+
}
|
|
4686
|
+
|
|
4687
|
+
const updateActivityInState = (updatedActivityResponse, activities, replaceCompletely = false) => {
|
|
4688
|
+
const index = activities.findIndex((a) => a.id === updatedActivityResponse.id);
|
|
4689
|
+
if (index !== -1) {
|
|
4690
|
+
const newActivities = [...activities];
|
|
4691
|
+
const activity = activities[index];
|
|
4692
|
+
if (replaceCompletely) {
|
|
4693
|
+
newActivities[index] = updatedActivityResponse;
|
|
4694
|
+
}
|
|
4695
|
+
else {
|
|
4696
|
+
newActivities[index] = {
|
|
4697
|
+
...updatedActivityResponse,
|
|
4698
|
+
own_reactions: activity.own_reactions,
|
|
4699
|
+
own_bookmarks: activity.own_bookmarks,
|
|
4700
|
+
latest_reactions: activity.latest_reactions,
|
|
4701
|
+
reaction_groups: activity.reaction_groups,
|
|
4702
|
+
};
|
|
4703
|
+
}
|
|
4704
|
+
return { changed: true, activities: newActivities };
|
|
4705
|
+
}
|
|
4706
|
+
else {
|
|
4707
|
+
return { changed: false, activities };
|
|
4708
|
+
}
|
|
4709
|
+
};
|
|
4710
|
+
function handleActivityUpdated(event) {
|
|
4711
|
+
const currentActivities = this.currentState.activities;
|
|
4712
|
+
if (currentActivities) {
|
|
4713
|
+
const result = updateActivityInState(event.activity, currentActivities);
|
|
4714
|
+
if (result.changed) {
|
|
4715
|
+
this.client.hydratePollCache([event.activity]);
|
|
4716
|
+
this.state.partialNext({ activities: result.activities });
|
|
4717
|
+
}
|
|
4718
|
+
}
|
|
4719
|
+
}
|
|
4720
|
+
|
|
4721
|
+
const addReactionToActivity = (event, activity, isCurrentUser) => {
|
|
4722
|
+
// Update own_reactions if the reaction is from the current user
|
|
4723
|
+
const ownReactions = [...(activity.own_reactions || [])];
|
|
4724
|
+
if (isCurrentUser) {
|
|
4725
|
+
ownReactions.push(event.reaction);
|
|
4726
|
+
}
|
|
4727
|
+
return {
|
|
4728
|
+
...activity,
|
|
4729
|
+
own_reactions: ownReactions,
|
|
4730
|
+
latest_reactions: event.activity.latest_reactions,
|
|
4731
|
+
reaction_groups: event.activity.reaction_groups,
|
|
4732
|
+
changed: true,
|
|
4733
|
+
};
|
|
4734
|
+
};
|
|
4735
|
+
const addReactionToActivities = (event, activities, isCurrentUser) => {
|
|
4736
|
+
if (!activities) {
|
|
4737
|
+
return { changed: false, activities: [] };
|
|
4951
4738
|
}
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
...options,
|
|
4956
|
-
source: this.fid,
|
|
4957
|
-
target: fid,
|
|
4958
|
-
});
|
|
4959
|
-
return response;
|
|
4739
|
+
const activityIndex = activities.findIndex((a) => a.id === event.activity.id);
|
|
4740
|
+
if (activityIndex === -1) {
|
|
4741
|
+
return { changed: false, activities };
|
|
4960
4742
|
}
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4743
|
+
const activity = activities[activityIndex];
|
|
4744
|
+
const updatedActivity = addReactionToActivity(event, activity, isCurrentUser);
|
|
4745
|
+
return updateActivityInState(updatedActivity, activities, true);
|
|
4746
|
+
};
|
|
4747
|
+
function handleActivityReactionAdded(event) {
|
|
4748
|
+
const currentActivities = this.currentState.activities;
|
|
4749
|
+
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4750
|
+
const isCurrentUser = Boolean(connectedUser && event.reaction.user.id === connectedUser.id);
|
|
4751
|
+
const result = addReactionToActivities(event, currentActivities, isCurrentUser);
|
|
4752
|
+
if (result.changed) {
|
|
4753
|
+
this.state.partialNext({ activities: result.activities });
|
|
4968
4754
|
}
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4755
|
+
}
|
|
4756
|
+
|
|
4757
|
+
const removeReactionFromActivity = (event, activity, isCurrentUser) => {
|
|
4758
|
+
// Update own_reactions if the reaction is from the current user
|
|
4759
|
+
const ownReactions = isCurrentUser
|
|
4760
|
+
? (activity.own_reactions || []).filter((r) => !(r.type === event.reaction.type &&
|
|
4761
|
+
r.user.id === event.reaction.user.id))
|
|
4762
|
+
: activity.own_reactions;
|
|
4763
|
+
return {
|
|
4764
|
+
...activity,
|
|
4765
|
+
own_reactions: ownReactions,
|
|
4766
|
+
latest_reactions: event.activity.latest_reactions,
|
|
4767
|
+
reaction_groups: event.activity.reaction_groups,
|
|
4768
|
+
changed: true,
|
|
4769
|
+
};
|
|
4770
|
+
};
|
|
4771
|
+
const removeReactionFromActivities = (event, activities, isCurrentUser) => {
|
|
4772
|
+
if (!activities) {
|
|
4773
|
+
return { changed: false, activities: [] };
|
|
4984
4774
|
}
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
fids: [this.fid],
|
|
4989
|
-
});
|
|
4775
|
+
const activityIndex = activities.findIndex((a) => a.id === event.activity.id);
|
|
4776
|
+
if (activityIndex === -1) {
|
|
4777
|
+
return { changed: false, activities };
|
|
4990
4778
|
}
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
this.
|
|
4779
|
+
const activity = activities[activityIndex];
|
|
4780
|
+
const updatedActivity = removeReactionFromActivity(event, activity, isCurrentUser);
|
|
4781
|
+
return updateActivityInState(updatedActivity, activities, true);
|
|
4782
|
+
};
|
|
4783
|
+
function handleActivityReactionDeleted(event) {
|
|
4784
|
+
const currentActivities = this.currentState.activities;
|
|
4785
|
+
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4786
|
+
const isCurrentUser = Boolean(connectedUser && event.reaction.user.id === connectedUser.id);
|
|
4787
|
+
const result = removeReactionFromActivities(event, currentActivities, isCurrentUser);
|
|
4788
|
+
if (result.changed) {
|
|
4789
|
+
this.state.partialNext({ activities: result.activities });
|
|
5002
4790
|
}
|
|
5003
4791
|
}
|
|
5004
|
-
Feed.noop = () => { };
|
|
5005
4792
|
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
4793
|
+
const addBookmarkToActivity = (event, activity, isCurrentUser) => {
|
|
4794
|
+
// Update own_bookmarks if the bookmark is from the current user
|
|
4795
|
+
const ownBookmarks = [...(activity.own_bookmarks || [])];
|
|
4796
|
+
if (isCurrentUser) {
|
|
4797
|
+
ownBookmarks.push(event.bookmark);
|
|
5009
4798
|
}
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
timeout: request?.timeout,
|
|
5020
|
-
banned_by: request?.banned_by,
|
|
5021
|
-
};
|
|
5022
|
-
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/ban', undefined, undefined, body, 'application/json');
|
|
5023
|
-
decoders.BanResponse?.(response.body);
|
|
5024
|
-
return { ...response.body, metadata: response.metadata };
|
|
4799
|
+
return {
|
|
4800
|
+
...activity,
|
|
4801
|
+
own_bookmarks: ownBookmarks,
|
|
4802
|
+
changed: true,
|
|
4803
|
+
};
|
|
4804
|
+
};
|
|
4805
|
+
const addBookmarkToActivities = (event, activities, isCurrentUser) => {
|
|
4806
|
+
if (!activities) {
|
|
4807
|
+
return { changed: false, activities: [] };
|
|
5025
4808
|
}
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
async: request?.async,
|
|
5030
|
-
team: request?.team,
|
|
5031
|
-
ai_image_config: request?.ai_image_config,
|
|
5032
|
-
ai_text_config: request?.ai_text_config,
|
|
5033
|
-
ai_video_config: request?.ai_video_config,
|
|
5034
|
-
automod_platform_circumvention_config: request?.automod_platform_circumvention_config,
|
|
5035
|
-
automod_semantic_filters_config: request?.automod_semantic_filters_config,
|
|
5036
|
-
automod_toxicity_config: request?.automod_toxicity_config,
|
|
5037
|
-
aws_rekognition_config: request?.aws_rekognition_config,
|
|
5038
|
-
block_list_config: request?.block_list_config,
|
|
5039
|
-
bodyguard_config: request?.bodyguard_config,
|
|
5040
|
-
google_vision_config: request?.google_vision_config,
|
|
5041
|
-
rule_builder_config: request?.rule_builder_config,
|
|
5042
|
-
velocity_filter_config: request?.velocity_filter_config,
|
|
5043
|
-
video_call_rule_config: request?.video_call_rule_config,
|
|
5044
|
-
};
|
|
5045
|
-
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/config', undefined, undefined, body, 'application/json');
|
|
5046
|
-
decoders.UpsertConfigResponse?.(response.body);
|
|
5047
|
-
return { ...response.body, metadata: response.metadata };
|
|
4809
|
+
const activityIndex = activities.findIndex((a) => a.id === event.bookmark.activity.id);
|
|
4810
|
+
if (activityIndex === -1) {
|
|
4811
|
+
return { changed: false, activities };
|
|
5048
4812
|
}
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
4813
|
+
const activity = activities[activityIndex];
|
|
4814
|
+
const updatedActivity = addBookmarkToActivity(event, activity, isCurrentUser);
|
|
4815
|
+
return updateActivityInState(updatedActivity, activities, true);
|
|
4816
|
+
};
|
|
4817
|
+
function handleBookmarkAdded(event) {
|
|
4818
|
+
const currentActivities = this.currentState.activities;
|
|
4819
|
+
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4820
|
+
const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
|
|
4821
|
+
const result = addBookmarkToActivities(event, currentActivities, isCurrentUser);
|
|
4822
|
+
if (result.changed) {
|
|
4823
|
+
this.state.partialNext({ activities: result.activities });
|
|
5059
4824
|
}
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
4825
|
+
}
|
|
4826
|
+
|
|
4827
|
+
// Helper function to check if two bookmarks are the same
|
|
4828
|
+
// A bookmark is identified by activity_id + folder_id + user_id
|
|
4829
|
+
const isSameBookmark = (bookmark1, bookmark2) => {
|
|
4830
|
+
return (bookmark1.user.id === bookmark2.user.id &&
|
|
4831
|
+
bookmark1.activity.id === bookmark2.activity.id &&
|
|
4832
|
+
bookmark1.folder?.id === bookmark2.folder?.id);
|
|
4833
|
+
};
|
|
4834
|
+
const removeBookmarkFromActivities = (event, activities, isCurrentUser) => {
|
|
4835
|
+
if (!activities) {
|
|
4836
|
+
return { changed: false, activities: [] };
|
|
5070
4837
|
}
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
next: request?.next,
|
|
5075
|
-
prev: request?.prev,
|
|
5076
|
-
sort: request?.sort,
|
|
5077
|
-
filter: request?.filter,
|
|
5078
|
-
};
|
|
5079
|
-
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/configs', undefined, undefined, body, 'application/json');
|
|
5080
|
-
decoders.QueryModerationConfigsResponse?.(response.body);
|
|
5081
|
-
return { ...response.body, metadata: response.metadata };
|
|
4838
|
+
const activityIndex = activities.findIndex((a) => a.id === event.bookmark.activity.id);
|
|
4839
|
+
if (activityIndex === -1) {
|
|
4840
|
+
return { changed: false, activities };
|
|
5082
4841
|
}
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
4842
|
+
const activity = activities[activityIndex];
|
|
4843
|
+
const updatedActivity = removeBookmarkFromActivity(event, activity, isCurrentUser);
|
|
4844
|
+
return updateActivityInState(updatedActivity, activities, true);
|
|
4845
|
+
};
|
|
4846
|
+
const removeBookmarkFromActivity = (event, activity, isCurrentUser) => {
|
|
4847
|
+
// Update own_bookmarks if the bookmark is from the current user
|
|
4848
|
+
const ownBookmarks = isCurrentUser
|
|
4849
|
+
? (activity.own_bookmarks || []).filter((bookmark) => !isSameBookmark(bookmark, event.bookmark))
|
|
4850
|
+
: activity.own_bookmarks;
|
|
4851
|
+
return {
|
|
4852
|
+
...activity,
|
|
4853
|
+
own_bookmarks: ownBookmarks,
|
|
4854
|
+
changed: true,
|
|
4855
|
+
};
|
|
4856
|
+
};
|
|
4857
|
+
function handleBookmarkDeleted(event) {
|
|
4858
|
+
const currentActivities = this.currentState.activities;
|
|
4859
|
+
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4860
|
+
const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
|
|
4861
|
+
const result = removeBookmarkFromActivities(event, currentActivities, isCurrentUser);
|
|
4862
|
+
if (result.changed) {
|
|
4863
|
+
this.state.partialNext({ activities: result.activities });
|
|
5095
4864
|
}
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
4865
|
+
}
|
|
4866
|
+
|
|
4867
|
+
const updateBookmarkInActivity = (event, activity, isCurrentUser) => {
|
|
4868
|
+
// Update own_bookmarks if the bookmark is from the current user
|
|
4869
|
+
let ownBookmarks = activity.own_bookmarks || [];
|
|
4870
|
+
if (isCurrentUser) {
|
|
4871
|
+
const bookmarkIndex = ownBookmarks.findIndex((bookmark) => isSameBookmark(bookmark, event.bookmark));
|
|
4872
|
+
if (bookmarkIndex !== -1) {
|
|
4873
|
+
ownBookmarks = [...ownBookmarks];
|
|
4874
|
+
ownBookmarks[bookmarkIndex] = event.bookmark;
|
|
4875
|
+
}
|
|
4876
|
+
}
|
|
4877
|
+
return {
|
|
4878
|
+
...activity,
|
|
4879
|
+
own_bookmarks: ownBookmarks,
|
|
4880
|
+
changed: true,
|
|
4881
|
+
};
|
|
4882
|
+
};
|
|
4883
|
+
const updateBookmarkInActivities = (event, activities, isCurrentUser) => {
|
|
4884
|
+
if (!activities) {
|
|
4885
|
+
return { changed: false, activities: [] };
|
|
5104
4886
|
}
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
lock_count: request?.lock_count,
|
|
5109
|
-
lock_duration: request?.lock_duration,
|
|
5110
|
-
lock_items: request?.lock_items,
|
|
5111
|
-
next: request?.next,
|
|
5112
|
-
prev: request?.prev,
|
|
5113
|
-
stats_only: request?.stats_only,
|
|
5114
|
-
sort: request?.sort,
|
|
5115
|
-
filter: request?.filter,
|
|
5116
|
-
};
|
|
5117
|
-
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/review_queue', undefined, undefined, body, 'application/json');
|
|
5118
|
-
decoders.QueryReviewQueueResponse?.(response.body);
|
|
5119
|
-
return { ...response.body, metadata: response.metadata };
|
|
4887
|
+
const activityIndex = activities.findIndex((a) => a.id === event.bookmark.activity.id);
|
|
4888
|
+
if (activityIndex === -1) {
|
|
4889
|
+
return { changed: false, activities };
|
|
5120
4890
|
}
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
unban: request?.unban,
|
|
5133
|
-
};
|
|
5134
|
-
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/submit_action', undefined, undefined, body, 'application/json');
|
|
5135
|
-
decoders.SubmitActionResponse?.(response.body);
|
|
5136
|
-
return { ...response.body, metadata: response.metadata };
|
|
4891
|
+
const activity = activities[activityIndex];
|
|
4892
|
+
const updatedActivity = updateBookmarkInActivity(event, activity, isCurrentUser);
|
|
4893
|
+
return updateActivityInState(updatedActivity, activities, true);
|
|
4894
|
+
};
|
|
4895
|
+
function handleBookmarkUpdated(event) {
|
|
4896
|
+
const currentActivities = this.currentState.activities;
|
|
4897
|
+
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4898
|
+
const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
|
|
4899
|
+
const result = updateBookmarkInActivities(event, currentActivities, isCurrentUser);
|
|
4900
|
+
if (result.changed) {
|
|
4901
|
+
this.state.partialNext({ activities: result.activities });
|
|
5137
4902
|
}
|
|
5138
4903
|
}
|
|
5139
4904
|
|
|
5140
|
-
|
|
4905
|
+
function handleFeedUpdated(event) {
|
|
4906
|
+
this.state.partialNext({ ...event.feed });
|
|
5141
4907
|
}
|
|
5142
4908
|
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
this.
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
let latestAnswers = [...currentState.latest_answers];
|
|
5204
|
-
let ownAnswer = currentState.own_answer;
|
|
5205
|
-
const ownVotesByOptionId = currentState.own_votes_by_option_id;
|
|
5206
|
-
let maxVotedOptionIds = currentState.max_voted_option_ids;
|
|
5207
|
-
if (isOwnVote) {
|
|
5208
|
-
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
5209
|
-
if (isVoteAnswer(event.poll_vote)) {
|
|
5210
|
-
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
5211
|
-
ownAnswer = event.poll_vote;
|
|
5212
|
-
}
|
|
5213
|
-
else if (event.poll_vote.option_id) {
|
|
5214
|
-
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
5215
|
-
ownVotesByOptionId[event.poll_vote.option_id] = event.poll_vote;
|
|
5216
|
-
}
|
|
5217
|
-
}
|
|
5218
|
-
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
5219
|
-
if (isVoteAnswer(event.poll_vote)) {
|
|
5220
|
-
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
5221
|
-
latestAnswers = [event.poll_vote, ...latestAnswers];
|
|
5222
|
-
}
|
|
5223
|
-
else {
|
|
5224
|
-
maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);
|
|
5225
|
-
}
|
|
5226
|
-
const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
|
|
5227
|
-
this.state.partialNext({
|
|
5228
|
-
answers_count,
|
|
5229
|
-
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
5230
|
-
latest_votes_by_option,
|
|
5231
|
-
vote_count,
|
|
5232
|
-
vote_counts_by_option,
|
|
5233
|
-
latest_answers: latestAnswers,
|
|
5234
|
-
last_activity_at: new Date(event.created_at),
|
|
5235
|
-
own_answer: ownAnswer,
|
|
5236
|
-
own_votes_by_option_id: ownVotesByOptionId,
|
|
5237
|
-
max_voted_option_ids: maxVotedOptionIds,
|
|
5238
|
-
});
|
|
4909
|
+
function handleNotificationFeedUpdated(event) {
|
|
4910
|
+
console.info('notification feed updated', event);
|
|
4911
|
+
// TODO: handle notification feed updates
|
|
4912
|
+
}
|
|
4913
|
+
|
|
4914
|
+
class Feed extends FeedApi {
|
|
4915
|
+
constructor(client, groupId, id, data, watch = false) {
|
|
4916
|
+
super(client, groupId, id);
|
|
4917
|
+
this.stateUpdateQueue = new Set();
|
|
4918
|
+
this.eventHandlers = {
|
|
4919
|
+
'feeds.activity.added': handleActivityAdded.bind(this),
|
|
4920
|
+
'feeds.activity.deleted': handleActivityDeleted.bind(this),
|
|
4921
|
+
'feeds.activity.reaction.added': handleActivityReactionAdded.bind(this),
|
|
4922
|
+
'feeds.activity.reaction.deleted': handleActivityReactionDeleted.bind(this),
|
|
4923
|
+
'feeds.activity.reaction.updated': Feed.noop,
|
|
4924
|
+
'feeds.activity.removed_from_feed': handleActivityRemovedFromFeed.bind(this),
|
|
4925
|
+
'feeds.activity.updated': handleActivityUpdated.bind(this),
|
|
4926
|
+
'feeds.bookmark.added': handleBookmarkAdded.bind(this),
|
|
4927
|
+
'feeds.bookmark.deleted': handleBookmarkDeleted.bind(this),
|
|
4928
|
+
'feeds.bookmark.updated': handleBookmarkUpdated.bind(this),
|
|
4929
|
+
'feeds.bookmark_folder.deleted': Feed.noop,
|
|
4930
|
+
'feeds.bookmark_folder.updated': Feed.noop,
|
|
4931
|
+
'feeds.comment.added': handleCommentAdded.bind(this),
|
|
4932
|
+
'feeds.comment.deleted': handleCommentDeleted.bind(this),
|
|
4933
|
+
'feeds.comment.updated': handleCommentUpdated.bind(this),
|
|
4934
|
+
'feeds.feed.created': Feed.noop,
|
|
4935
|
+
'feeds.feed.deleted': Feed.noop,
|
|
4936
|
+
'feeds.feed.updated': handleFeedUpdated.bind(this),
|
|
4937
|
+
'feeds.feed_group.changed': Feed.noop,
|
|
4938
|
+
'feeds.feed_group.deleted': Feed.noop,
|
|
4939
|
+
'feeds.follow.created': handleFollowCreated.bind(this),
|
|
4940
|
+
'feeds.follow.deleted': handleFollowDeleted.bind(this),
|
|
4941
|
+
'feeds.follow.updated': handleFollowUpdated.bind(this),
|
|
4942
|
+
'feeds.comment.reaction.added': handleCommentReaction.bind(this),
|
|
4943
|
+
'feeds.comment.reaction.deleted': handleCommentReaction.bind(this),
|
|
4944
|
+
'feeds.comment.reaction.updated': Feed.noop,
|
|
4945
|
+
'feeds.feed_member.added': handleFeedMemberAdded.bind(this),
|
|
4946
|
+
'feeds.feed_member.removed': handleFeedMemberRemoved.bind(this),
|
|
4947
|
+
'feeds.feed_member.updated': handleFeedMemberUpdated.bind(this),
|
|
4948
|
+
'feeds.notification_feed.updated': handleNotificationFeedUpdated.bind(this),
|
|
4949
|
+
// the poll events should be removed from here
|
|
4950
|
+
'feeds.poll.closed': Feed.noop,
|
|
4951
|
+
'feeds.poll.deleted': Feed.noop,
|
|
4952
|
+
'feeds.poll.updated': Feed.noop,
|
|
4953
|
+
'feeds.poll.vote_casted': Feed.noop,
|
|
4954
|
+
'feeds.poll.vote_changed': Feed.noop,
|
|
4955
|
+
'feeds.poll.vote_removed': Feed.noop,
|
|
4956
|
+
'feeds.activity.pinned': Feed.noop,
|
|
4957
|
+
'feeds.activity.unpinned': Feed.noop,
|
|
4958
|
+
'feeds.activity.marked': Feed.noop,
|
|
4959
|
+
'moderation.custom_action': Feed.noop,
|
|
4960
|
+
'moderation.flagged': Feed.noop,
|
|
4961
|
+
'moderation.mark_reviewed': Feed.noop,
|
|
4962
|
+
'health.check': Feed.noop,
|
|
4963
|
+
'app.updated': Feed.noop,
|
|
4964
|
+
'user.banned': Feed.noop,
|
|
4965
|
+
'user.deactivated': Feed.noop,
|
|
4966
|
+
'user.muted': Feed.noop,
|
|
4967
|
+
'user.reactivated': Feed.noop,
|
|
4968
|
+
'user.updated': Feed.noop,
|
|
5239
4969
|
};
|
|
5240
|
-
this.
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
|
|
5268
|
-
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
|
|
5275
|
-
|
|
5276
|
-
|
|
5277
|
-
|
|
5278
|
-
|
|
5279
|
-
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
|
|
5283
|
-
|
|
5284
|
-
|
|
4970
|
+
this.eventDispatcher = new EventDispatcher();
|
|
4971
|
+
this.on = this.eventDispatcher.on;
|
|
4972
|
+
this.off = this.eventDispatcher.off;
|
|
4973
|
+
this.state = new StateStore({
|
|
4974
|
+
fid: `${groupId}:${id}`,
|
|
4975
|
+
group_id: groupId,
|
|
4976
|
+
id,
|
|
4977
|
+
...(data ?? {}),
|
|
4978
|
+
is_loading: false,
|
|
4979
|
+
is_loading_activities: false,
|
|
4980
|
+
comments_by_entity_id: {},
|
|
4981
|
+
watch,
|
|
4982
|
+
});
|
|
4983
|
+
this.client = client;
|
|
4984
|
+
}
|
|
4985
|
+
get fid() {
|
|
4986
|
+
return `${this.group}:${this.id}`;
|
|
4987
|
+
}
|
|
4988
|
+
get currentState() {
|
|
4989
|
+
return this.state.getLatestValue();
|
|
4990
|
+
}
|
|
4991
|
+
async synchronize() {
|
|
4992
|
+
const { last_get_or_create_request_config } = this.state.getLatestValue();
|
|
4993
|
+
if (last_get_or_create_request_config?.watch) {
|
|
4994
|
+
await this.getOrCreate(last_get_or_create_request_config);
|
|
4995
|
+
}
|
|
4996
|
+
}
|
|
4997
|
+
async getOrCreate(request) {
|
|
4998
|
+
if (this.currentState.is_loading_activities) {
|
|
4999
|
+
throw new Error('Only one getOrCreate call is allowed at a time');
|
|
5000
|
+
}
|
|
5001
|
+
this.state.partialNext({
|
|
5002
|
+
is_loading: !request?.next,
|
|
5003
|
+
is_loading_activities: true,
|
|
5004
|
+
});
|
|
5005
|
+
// TODO: pull comments/comment_pagination from activities and comment_sort from request
|
|
5006
|
+
// and pre-populate comments_by_entity_id (once comment_sort and comment_limit are supported)
|
|
5007
|
+
try {
|
|
5008
|
+
const response = await super.getOrCreate(request);
|
|
5009
|
+
if (request?.next) {
|
|
5010
|
+
const { activities: currentActivities = [] } = this.currentState;
|
|
5011
|
+
const result = addActivitiesToState(response.activities, currentActivities, 'end');
|
|
5012
|
+
if (result.changed) {
|
|
5013
|
+
this.state.partialNext({
|
|
5014
|
+
activities: result.activities,
|
|
5015
|
+
next: response.next,
|
|
5016
|
+
prev: response.prev,
|
|
5017
|
+
});
|
|
5285
5018
|
}
|
|
5286
|
-
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
5287
|
-
}
|
|
5288
|
-
else if (isVoteAnswer(event.poll_vote)) {
|
|
5289
|
-
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
5290
|
-
latestAnswers = [event.poll_vote, ...latestAnswers];
|
|
5291
5019
|
}
|
|
5292
5020
|
else {
|
|
5293
|
-
|
|
5021
|
+
// Empty queue when reinitializing the state
|
|
5022
|
+
this.stateUpdateQueue.clear();
|
|
5023
|
+
const responseCopy = {
|
|
5024
|
+
...response,
|
|
5025
|
+
...response.feed,
|
|
5026
|
+
};
|
|
5027
|
+
delete responseCopy.feed;
|
|
5028
|
+
delete responseCopy.metadata;
|
|
5029
|
+
delete responseCopy.duration;
|
|
5030
|
+
// TODO: lazy-load comments from activities when comment_sort and comment_pagination are supported
|
|
5031
|
+
this.state.next((currentState) => {
|
|
5032
|
+
const nextState = {
|
|
5033
|
+
...currentState,
|
|
5034
|
+
...responseCopy,
|
|
5035
|
+
};
|
|
5036
|
+
if (!request?.followers_pagination?.limit) {
|
|
5037
|
+
delete nextState.followers;
|
|
5038
|
+
}
|
|
5039
|
+
if (!request?.following_pagination?.limit) {
|
|
5040
|
+
delete nextState.following;
|
|
5041
|
+
}
|
|
5042
|
+
if (response.members.length === 0 && response.feed.member_count > 0) {
|
|
5043
|
+
delete nextState.members;
|
|
5044
|
+
}
|
|
5045
|
+
nextState.last_get_or_create_request_config = request;
|
|
5046
|
+
nextState.watch = request?.watch ? request.watch : currentState.watch;
|
|
5047
|
+
return nextState;
|
|
5048
|
+
});
|
|
5294
5049
|
}
|
|
5295
|
-
|
|
5050
|
+
this.client.hydratePollCache(response.activities);
|
|
5051
|
+
return response;
|
|
5052
|
+
}
|
|
5053
|
+
finally {
|
|
5296
5054
|
this.state.partialNext({
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5055
|
+
is_loading: false,
|
|
5056
|
+
is_loading_activities: false,
|
|
5057
|
+
});
|
|
5058
|
+
}
|
|
5059
|
+
}
|
|
5060
|
+
/**
|
|
5061
|
+
* @internal
|
|
5062
|
+
*/
|
|
5063
|
+
handleWatchStopped() {
|
|
5064
|
+
this.state.partialNext({
|
|
5065
|
+
watch: false,
|
|
5066
|
+
});
|
|
5067
|
+
}
|
|
5068
|
+
/**
|
|
5069
|
+
* @internal
|
|
5070
|
+
*/
|
|
5071
|
+
handleWatchStarted() {
|
|
5072
|
+
this.state.partialNext({
|
|
5073
|
+
watch: true,
|
|
5074
|
+
});
|
|
5075
|
+
}
|
|
5076
|
+
/**
|
|
5077
|
+
* Returns index of the provided comment object.
|
|
5078
|
+
*/
|
|
5079
|
+
getCommentIndex(comment, state) {
|
|
5080
|
+
const { comments_by_entity_id = {} } = state ?? this.currentState;
|
|
5081
|
+
const currentComments = comments_by_entity_id[comment.parent_id ?? comment.object_id]?.comments;
|
|
5082
|
+
if (!currentComments?.length) {
|
|
5083
|
+
return -1;
|
|
5084
|
+
}
|
|
5085
|
+
// @ts-expect-error this will just fail if the comment is not object from state
|
|
5086
|
+
let commentIndex = currentComments.indexOf(comment);
|
|
5087
|
+
// fast lookup failed, try slower approach
|
|
5088
|
+
if (commentIndex === -1) {
|
|
5089
|
+
commentIndex = currentComments.findIndex((comment_) => comment_.id === comment.id);
|
|
5090
|
+
}
|
|
5091
|
+
return commentIndex;
|
|
5092
|
+
}
|
|
5093
|
+
/**
|
|
5094
|
+
* Load child comments of entity (activity or comment) into the state, if the target entity is comment,
|
|
5095
|
+
* `entityParentId` should be provided (`CommentResponse.parent_id ?? CommentResponse.object_id`).
|
|
5096
|
+
*/
|
|
5097
|
+
loadCommentsIntoState(data) {
|
|
5098
|
+
// add initial (top level) object for processing
|
|
5099
|
+
const traverseArray = [
|
|
5100
|
+
{
|
|
5101
|
+
entityId: data.entityId,
|
|
5102
|
+
entityParentId: data.entityParentId,
|
|
5103
|
+
comments: data.comments,
|
|
5104
|
+
next: data.next,
|
|
5105
|
+
},
|
|
5106
|
+
];
|
|
5107
|
+
this.state.next((currentState) => {
|
|
5108
|
+
const newCommentsByEntityId = {
|
|
5109
|
+
...currentState.comments_by_entity_id,
|
|
5110
|
+
};
|
|
5111
|
+
while (traverseArray.length) {
|
|
5112
|
+
const item = traverseArray.pop();
|
|
5113
|
+
const entityId = item.entityId;
|
|
5114
|
+
// go over entity comments and generate new objects
|
|
5115
|
+
// for further processing if there are any replies
|
|
5116
|
+
item.comments.forEach((comment) => {
|
|
5117
|
+
if (!comment.replies?.length)
|
|
5118
|
+
return;
|
|
5119
|
+
traverseArray.push({
|
|
5120
|
+
entityId: comment.id,
|
|
5121
|
+
entityParentId: entityId,
|
|
5122
|
+
comments: comment.replies,
|
|
5123
|
+
next: comment.meta?.next_cursor,
|
|
5124
|
+
});
|
|
5125
|
+
});
|
|
5126
|
+
// omit replies & meta from the comments (transform ThreadedCommentResponse to CommentResponse)
|
|
5127
|
+
// this is somehow faster than copying the whole
|
|
5128
|
+
// object and deleting the desired properties
|
|
5129
|
+
const newComments = item.comments.map(({ replies: _r, meta: _m, ...restOfTheCommentResponse }) => restOfTheCommentResponse);
|
|
5130
|
+
const existingComments = newCommentsByEntityId[entityId]?.comments;
|
|
5131
|
+
newCommentsByEntityId[entityId] = {
|
|
5132
|
+
...newCommentsByEntityId[entityId],
|
|
5133
|
+
entity_parent_id: item.entityParentId,
|
|
5134
|
+
pagination: {
|
|
5135
|
+
...newCommentsByEntityId[entityId]?.pagination,
|
|
5136
|
+
next: item.next,
|
|
5137
|
+
sort: data.sort,
|
|
5138
|
+
},
|
|
5139
|
+
comments: existingComments
|
|
5140
|
+
? uniqueArrayMerge(existingComments, newComments, (comment) => comment.id)
|
|
5141
|
+
: newComments,
|
|
5142
|
+
};
|
|
5143
|
+
}
|
|
5144
|
+
return {
|
|
5145
|
+
...currentState,
|
|
5146
|
+
comments_by_entity_id: newCommentsByEntityId,
|
|
5147
|
+
};
|
|
5148
|
+
});
|
|
5149
|
+
}
|
|
5150
|
+
async loadNextPageComments({ entityId, base, sort, entityParentId, }) {
|
|
5151
|
+
let error;
|
|
5152
|
+
try {
|
|
5153
|
+
this.state.next((currentState) => ({
|
|
5154
|
+
...currentState,
|
|
5155
|
+
comments_by_entity_id: {
|
|
5156
|
+
...currentState.comments_by_entity_id,
|
|
5157
|
+
[entityId]: {
|
|
5158
|
+
...currentState.comments_by_entity_id[entityId],
|
|
5159
|
+
pagination: {
|
|
5160
|
+
...currentState.comments_by_entity_id[entityId]?.pagination,
|
|
5161
|
+
loading_next_page: true,
|
|
5162
|
+
},
|
|
5163
|
+
},
|
|
5164
|
+
},
|
|
5165
|
+
}));
|
|
5166
|
+
const { next, comments } = await base();
|
|
5167
|
+
this.loadCommentsIntoState({
|
|
5168
|
+
entityId,
|
|
5169
|
+
comments,
|
|
5170
|
+
entityParentId,
|
|
5171
|
+
next,
|
|
5172
|
+
sort,
|
|
5173
|
+
});
|
|
5174
|
+
}
|
|
5175
|
+
catch (e) {
|
|
5176
|
+
error = e;
|
|
5177
|
+
}
|
|
5178
|
+
finally {
|
|
5179
|
+
this.state.next((currentState) => ({
|
|
5180
|
+
...currentState,
|
|
5181
|
+
comments_by_entity_id: {
|
|
5182
|
+
...currentState.comments_by_entity_id,
|
|
5183
|
+
[entityId]: {
|
|
5184
|
+
...currentState.comments_by_entity_id[entityId],
|
|
5185
|
+
pagination: {
|
|
5186
|
+
...currentState.comments_by_entity_id[entityId]?.pagination,
|
|
5187
|
+
loading_next_page: false,
|
|
5188
|
+
},
|
|
5189
|
+
},
|
|
5190
|
+
},
|
|
5191
|
+
}));
|
|
5192
|
+
}
|
|
5193
|
+
if (error) {
|
|
5194
|
+
throw error;
|
|
5195
|
+
}
|
|
5196
|
+
}
|
|
5197
|
+
async loadNextPageActivityComments(activity, request) {
|
|
5198
|
+
const currentEntityState = this.currentState.comments_by_entity_id[activity.id];
|
|
5199
|
+
const currentPagination = currentEntityState?.pagination;
|
|
5200
|
+
const currentNextCursor = currentPagination?.next;
|
|
5201
|
+
const currentSort = currentPagination?.sort;
|
|
5202
|
+
const isLoading = currentPagination?.loading_next_page;
|
|
5203
|
+
const sort = currentSort ?? request?.sort ?? Constants.DEFAULT_COMMENT_PAGINATION;
|
|
5204
|
+
if (isLoading ||
|
|
5205
|
+
!checkHasAnotherPage(currentEntityState?.comments, currentNextCursor)) {
|
|
5206
|
+
return;
|
|
5207
|
+
}
|
|
5208
|
+
await this.loadNextPageComments({
|
|
5209
|
+
entityId: activity.id,
|
|
5210
|
+
base: () => this.client.getComments({
|
|
5211
|
+
...request,
|
|
5212
|
+
sort,
|
|
5213
|
+
object_id: activity.id,
|
|
5214
|
+
object_type: 'activity',
|
|
5215
|
+
next: currentNextCursor,
|
|
5216
|
+
}),
|
|
5217
|
+
sort,
|
|
5218
|
+
});
|
|
5219
|
+
}
|
|
5220
|
+
async loadNextPageCommentReplies(comment, request) {
|
|
5221
|
+
const currentEntityState = this.currentState.comments_by_entity_id[comment.id];
|
|
5222
|
+
const currentPagination = currentEntityState?.pagination;
|
|
5223
|
+
const currentNextCursor = currentPagination?.next;
|
|
5224
|
+
const currentSort = currentPagination?.sort;
|
|
5225
|
+
const isLoading = currentPagination?.loading_next_page;
|
|
5226
|
+
const sort = currentSort ?? request?.sort ?? Constants.DEFAULT_COMMENT_PAGINATION;
|
|
5227
|
+
if (isLoading ||
|
|
5228
|
+
!checkHasAnotherPage(currentEntityState?.comments, currentNextCursor)) {
|
|
5229
|
+
return;
|
|
5230
|
+
}
|
|
5231
|
+
await this.loadNextPageComments({
|
|
5232
|
+
entityId: comment.id,
|
|
5233
|
+
base: () => this.client.getCommentReplies({
|
|
5234
|
+
...request,
|
|
5235
|
+
comment_id: comment.id,
|
|
5236
|
+
// use known sort first (prevents broken pagination)
|
|
5237
|
+
sort,
|
|
5238
|
+
next: currentNextCursor,
|
|
5239
|
+
}),
|
|
5240
|
+
entityParentId: comment.parent_id ?? comment.object_id,
|
|
5241
|
+
sort,
|
|
5242
|
+
});
|
|
5243
|
+
}
|
|
5244
|
+
async loadNextPageFollows(type, request) {
|
|
5245
|
+
const paginationKey = `${type}_pagination`;
|
|
5246
|
+
const method = `query${capitalize(type)}`;
|
|
5247
|
+
const currentFollows = this.currentState[type];
|
|
5248
|
+
const currentNextCursor = this.currentState[paginationKey]?.next;
|
|
5249
|
+
const isLoading = this.currentState[paginationKey]?.loading_next_page;
|
|
5250
|
+
const sort = this.currentState[paginationKey]?.sort ?? request.sort;
|
|
5251
|
+
let error;
|
|
5252
|
+
if (isLoading || !checkHasAnotherPage(currentFollows, currentNextCursor)) {
|
|
5253
|
+
return;
|
|
5254
|
+
}
|
|
5255
|
+
try {
|
|
5256
|
+
this.state.next((currentState) => {
|
|
5257
|
+
return {
|
|
5258
|
+
...currentState,
|
|
5259
|
+
[paginationKey]: {
|
|
5260
|
+
...currentState[paginationKey],
|
|
5261
|
+
loading_next_page: true,
|
|
5262
|
+
},
|
|
5263
|
+
};
|
|
5307
5264
|
});
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5265
|
+
const { next: newNextCursor, follows } = await this[method]({
|
|
5266
|
+
...request,
|
|
5267
|
+
next: currentNextCursor,
|
|
5268
|
+
sort,
|
|
5269
|
+
});
|
|
5270
|
+
this.state.next((currentState) => {
|
|
5271
|
+
return {
|
|
5272
|
+
...currentState,
|
|
5273
|
+
[type]: currentState[type] === undefined
|
|
5274
|
+
? follows
|
|
5275
|
+
: uniqueArrayMerge(currentState[type], follows, (follow) => `${follow.source_feed.fid}-${follow.target_feed.fid}`),
|
|
5276
|
+
[paginationKey]: {
|
|
5277
|
+
...currentState[paginationKey],
|
|
5278
|
+
next: newNextCursor,
|
|
5279
|
+
sort,
|
|
5280
|
+
},
|
|
5281
|
+
};
|
|
5282
|
+
});
|
|
5283
|
+
}
|
|
5284
|
+
catch (e) {
|
|
5285
|
+
error = e;
|
|
5286
|
+
}
|
|
5287
|
+
finally {
|
|
5288
|
+
this.state.next((currentState) => {
|
|
5289
|
+
return {
|
|
5290
|
+
...currentState,
|
|
5291
|
+
[paginationKey]: {
|
|
5292
|
+
...currentState[paginationKey],
|
|
5293
|
+
loading_next_page: false,
|
|
5294
|
+
},
|
|
5295
|
+
};
|
|
5296
|
+
});
|
|
5297
|
+
}
|
|
5298
|
+
if (error) {
|
|
5299
|
+
throw error;
|
|
5300
|
+
}
|
|
5301
|
+
}
|
|
5302
|
+
async loadNextPageFollowers(request) {
|
|
5303
|
+
await this.loadNextPageFollows('followers', request);
|
|
5304
|
+
}
|
|
5305
|
+
async loadNextPageFollowing(request) {
|
|
5306
|
+
await this.loadNextPageFollows('following', request);
|
|
5307
|
+
}
|
|
5308
|
+
async loadNextPageMembers(request) {
|
|
5309
|
+
const currentMembers = this.currentState.members;
|
|
5310
|
+
const currentNextCursor = this.currentState.member_pagination?.next;
|
|
5311
|
+
const isLoading = this.currentState.member_pagination?.loading_next_page;
|
|
5312
|
+
const sort = this.currentState.member_pagination?.sort ?? request.sort;
|
|
5313
|
+
let error;
|
|
5314
|
+
if (isLoading || !checkHasAnotherPage(currentMembers, currentNextCursor)) {
|
|
5315
|
+
return;
|
|
5316
|
+
}
|
|
5317
|
+
try {
|
|
5318
|
+
this.state.next((currentState) => ({
|
|
5319
|
+
...currentState,
|
|
5320
|
+
member_pagination: {
|
|
5321
|
+
...currentState.member_pagination,
|
|
5322
|
+
loading_next_page: true,
|
|
5323
|
+
},
|
|
5324
|
+
}));
|
|
5325
|
+
const { next: newNextCursor, members } = await this.client.queryFeedMembers({
|
|
5326
|
+
...request,
|
|
5327
|
+
sort,
|
|
5328
|
+
feed_id: this.id,
|
|
5329
|
+
feed_group_id: this.group,
|
|
5330
|
+
next: currentNextCursor,
|
|
5346
5331
|
});
|
|
5332
|
+
this.state.next((currentState) => ({
|
|
5333
|
+
...currentState,
|
|
5334
|
+
members: currentState.members
|
|
5335
|
+
? uniqueArrayMerge(currentState.members, members, ({ user }) => user.id)
|
|
5336
|
+
: members,
|
|
5337
|
+
member_pagination: {
|
|
5338
|
+
...currentState.member_pagination,
|
|
5339
|
+
next: newNextCursor,
|
|
5340
|
+
// set sort if not defined yet
|
|
5341
|
+
sort: currentState.member_pagination?.sort ?? request.sort,
|
|
5342
|
+
},
|
|
5343
|
+
}));
|
|
5344
|
+
}
|
|
5345
|
+
catch (e) {
|
|
5346
|
+
error = e;
|
|
5347
|
+
}
|
|
5348
|
+
finally {
|
|
5349
|
+
this.state.next((currentState) => ({
|
|
5350
|
+
...currentState,
|
|
5351
|
+
member_pagination: {
|
|
5352
|
+
...currentState.member_pagination,
|
|
5353
|
+
loading_next_page: false,
|
|
5354
|
+
},
|
|
5355
|
+
}));
|
|
5356
|
+
}
|
|
5357
|
+
if (error) {
|
|
5358
|
+
throw error;
|
|
5359
|
+
}
|
|
5360
|
+
}
|
|
5361
|
+
/**
|
|
5362
|
+
* Method which queries followers of this feed (feeds which target this feed).
|
|
5363
|
+
*
|
|
5364
|
+
* _Note: Useful only for feeds with `groupId` of `user` value._
|
|
5365
|
+
*/
|
|
5366
|
+
async queryFollowers(request) {
|
|
5367
|
+
const filter = {
|
|
5368
|
+
target_feed: this.fid,
|
|
5347
5369
|
};
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5370
|
+
const response = await this.client.queryFollows({
|
|
5371
|
+
filter,
|
|
5372
|
+
...request,
|
|
5373
|
+
});
|
|
5374
|
+
return response;
|
|
5351
5375
|
}
|
|
5352
|
-
|
|
5353
|
-
|
|
5376
|
+
/**
|
|
5377
|
+
* Method which queries following of this feed (target feeds of this feed).
|
|
5378
|
+
*
|
|
5379
|
+
* _Note: Useful only for feeds with `groupId` of `timeline` value._
|
|
5380
|
+
*/
|
|
5381
|
+
async queryFollowing(request) {
|
|
5382
|
+
const filter = {
|
|
5383
|
+
source_feed: this.fid,
|
|
5384
|
+
};
|
|
5385
|
+
const response = await this.client.queryFollows({
|
|
5386
|
+
filter,
|
|
5387
|
+
...request,
|
|
5388
|
+
});
|
|
5389
|
+
return response;
|
|
5354
5390
|
}
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5391
|
+
async follow(feedOrFid, options) {
|
|
5392
|
+
const fid = typeof feedOrFid === 'string' ? feedOrFid : feedOrFid.fid;
|
|
5393
|
+
const response = await this.client.follow({
|
|
5394
|
+
...options,
|
|
5395
|
+
source: this.fid,
|
|
5396
|
+
target: fid,
|
|
5397
|
+
});
|
|
5398
|
+
return response;
|
|
5399
|
+
}
|
|
5400
|
+
async unfollow(feedOrFid) {
|
|
5401
|
+
const fid = typeof feedOrFid === 'string' ? feedOrFid : feedOrFid.fid;
|
|
5402
|
+
const response = await this.client.unfollow({
|
|
5403
|
+
source: this.fid,
|
|
5404
|
+
target: fid,
|
|
5405
|
+
});
|
|
5406
|
+
return response;
|
|
5407
|
+
}
|
|
5408
|
+
async getNextPage() {
|
|
5409
|
+
const currentState = this.currentState;
|
|
5410
|
+
return await this.getOrCreate({
|
|
5411
|
+
member_pagination: {
|
|
5412
|
+
limit: 0,
|
|
5413
|
+
},
|
|
5414
|
+
followers_pagination: {
|
|
5415
|
+
limit: 0,
|
|
5416
|
+
},
|
|
5417
|
+
following_pagination: {
|
|
5418
|
+
limit: 0,
|
|
5419
|
+
},
|
|
5420
|
+
next: currentState.next,
|
|
5421
|
+
limit: currentState.last_get_or_create_request_config?.limit ?? 20,
|
|
5422
|
+
});
|
|
5423
|
+
}
|
|
5424
|
+
addActivity(request) {
|
|
5425
|
+
return this.feedsApi.addActivity({
|
|
5426
|
+
...request,
|
|
5427
|
+
fids: [this.fid],
|
|
5428
|
+
});
|
|
5429
|
+
}
|
|
5430
|
+
handleWSEvent(event) {
|
|
5431
|
+
const eventHandler = this.eventHandlers[event.type];
|
|
5432
|
+
// no need to run noop function
|
|
5433
|
+
if (eventHandler !== Feed.noop) {
|
|
5434
|
+
// @ts-expect-error intersection of handler arguments results to never
|
|
5435
|
+
eventHandler?.(event);
|
|
5363
5436
|
}
|
|
5364
|
-
|
|
5365
|
-
|
|
5437
|
+
if (typeof eventHandler === 'undefined') {
|
|
5438
|
+
console.warn(`Received unknown event type: ${event.type}`, event);
|
|
5366
5439
|
}
|
|
5440
|
+
this.eventDispatcher.dispatch(event);
|
|
5367
5441
|
}
|
|
5368
|
-
return winningOptions;
|
|
5369
|
-
}
|
|
5370
|
-
function getOwnVotesByOptionId(ownVotes) {
|
|
5371
|
-
return !ownVotes
|
|
5372
|
-
? {}
|
|
5373
|
-
: ownVotes.reduce((acc, vote) => {
|
|
5374
|
-
if (isVoteAnswer(vote) || !vote.option_id)
|
|
5375
|
-
return acc;
|
|
5376
|
-
acc[vote.option_id] = vote;
|
|
5377
|
-
return acc;
|
|
5378
|
-
}, {});
|
|
5379
5442
|
}
|
|
5443
|
+
Feed.noop = () => { };
|
|
5380
5444
|
|
|
5381
5445
|
class FeedsClient extends FeedsApi {
|
|
5382
5446
|
constructor(apiKey, options) {
|
|
@@ -5636,13 +5700,23 @@ class FeedsClient extends FeedsApi {
|
|
|
5636
5700
|
duration: response.duration,
|
|
5637
5701
|
};
|
|
5638
5702
|
}
|
|
5703
|
+
async updateFollow(request) {
|
|
5704
|
+
const response = await super.updateFollow(request);
|
|
5705
|
+
[response.follow.source_feed.fid, response.follow.target_feed.fid].forEach((fid) => {
|
|
5706
|
+
const feed = this.activeFeeds[fid];
|
|
5707
|
+
if (feed) {
|
|
5708
|
+
handleFollowUpdated.bind(feed)(response);
|
|
5709
|
+
}
|
|
5710
|
+
});
|
|
5711
|
+
return response;
|
|
5712
|
+
}
|
|
5639
5713
|
// For follow API endpoints we update the state after HTTP response to allow queryFeeds with watch: false
|
|
5640
5714
|
async follow(request) {
|
|
5641
5715
|
const response = await super.follow(request);
|
|
5642
5716
|
[response.follow.source_feed.fid, response.follow.target_feed.fid].forEach((fid) => {
|
|
5643
5717
|
const feed = this.activeFeeds[fid];
|
|
5644
5718
|
if (feed) {
|
|
5645
|
-
|
|
5719
|
+
handleFollowCreated.bind(feed)(response);
|
|
5646
5720
|
}
|
|
5647
5721
|
});
|
|
5648
5722
|
return response;
|
|
@@ -5652,7 +5726,7 @@ class FeedsClient extends FeedsApi {
|
|
|
5652
5726
|
response.follows.forEach((follow) => {
|
|
5653
5727
|
const feed = this.activeFeeds[follow.source_feed.fid];
|
|
5654
5728
|
if (feed) {
|
|
5655
|
-
|
|
5729
|
+
handleFollowCreated.bind(feed)({ follow });
|
|
5656
5730
|
}
|
|
5657
5731
|
});
|
|
5658
5732
|
return response;
|
|
@@ -5662,10 +5736,7 @@ class FeedsClient extends FeedsApi {
|
|
|
5662
5736
|
[request.source, request.target].forEach((fid) => {
|
|
5663
5737
|
const feed = this.activeFeeds[fid];
|
|
5664
5738
|
if (feed) {
|
|
5665
|
-
|
|
5666
|
-
source_feed: { fid: request.source },
|
|
5667
|
-
target_feed: { fid: request.target },
|
|
5668
|
-
});
|
|
5739
|
+
handleFollowDeleted.bind(feed)(response);
|
|
5669
5740
|
}
|
|
5670
5741
|
});
|
|
5671
5742
|
return response;
|
|
@@ -6110,10 +6181,13 @@ exports.StreamApiError = StreamApiError;
|
|
|
6110
6181
|
exports.StreamPoll = StreamPoll;
|
|
6111
6182
|
exports.UserSearchSource = UserSearchSource;
|
|
6112
6183
|
exports.checkHasAnotherPage = checkHasAnotherPage;
|
|
6184
|
+
exports.getStateUpdateQueueId = getStateUpdateQueueId;
|
|
6113
6185
|
exports.isCommentResponse = isCommentResponse;
|
|
6186
|
+
exports.isFollowResponse = isFollowResponse;
|
|
6114
6187
|
exports.isImageFile = isImageFile;
|
|
6115
6188
|
exports.isPatch = isPatch;
|
|
6116
6189
|
exports.isVideoFile = isVideoFile;
|
|
6117
6190
|
exports.isVoteAnswer = isVoteAnswer;
|
|
6191
|
+
exports.shouldUpdateState = shouldUpdateState;
|
|
6118
6192
|
exports.uniqueArrayMerge = uniqueArrayMerge;
|
|
6119
6193
|
//# sourceMappingURL=index.browser.cjs.map
|