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