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