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