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