@stream-io/feeds-client 0.1.7 → 0.1.9
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/util/index.ts +1 -0
- package/CHANGELOG.md +20 -0
- package/dist/@react-bindings/hooks/util/index.d.ts +1 -0
- package/dist/@react-bindings/hooks/util/useBookmarkActions.d.ts +13 -0
- package/dist/@react-bindings/hooks/util/useReactionActions.d.ts +1 -1
- package/dist/index-react-bindings.browser.cjs +363 -141
- package/dist/index-react-bindings.browser.cjs.map +1 -1
- package/dist/index-react-bindings.browser.js +363 -142
- package/dist/index-react-bindings.browser.js.map +1 -1
- package/dist/index-react-bindings.node.cjs +363 -141
- package/dist/index-react-bindings.node.cjs.map +1 -1
- package/dist/index-react-bindings.node.js +363 -142
- package/dist/index-react-bindings.node.js.map +1 -1
- package/dist/index.browser.cjs +337 -140
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.js +337 -141
- package/dist/index.browser.js.map +1 -1
- package/dist/index.node.cjs +337 -140
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.js +337 -141
- package/dist/index.node.js.map +1 -1
- package/dist/src/Feed.d.ts +42 -11
- package/dist/src/FeedsClient.d.ts +10 -3
- package/dist/src/common/real-time/StableWSConnection.d.ts +3 -3
- package/dist/src/gen/models/index.d.ts +25 -2
- package/dist/src/gen-imports.d.ts +1 -1
- package/dist/src/state-updates/follow-utils.d.ts +19 -0
- package/dist/src/state-updates/state-update-queue.d.ts +15 -0
- package/dist/src/utils.d.ts +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/Feed.ts +230 -192
- package/src/FeedsClient.ts +75 -3
- package/src/gen/feeds/FeedsApi.ts +0 -1
- package/src/gen/model-decoders/decoders.ts +16 -0
- package/src/gen/model-decoders/event-decoder-mapping.ts +3 -0
- package/src/gen/models/index.ts +42 -4
- package/src/gen-imports.ts +1 -1
- package/src/state-updates/activity-reaction-utils.test.ts +1 -0
- package/src/state-updates/activity-utils.test.ts +1 -0
- package/src/state-updates/follow-utils.test.ts +552 -0
- package/src/state-updates/follow-utils.ts +126 -0
- package/src/state-updates/state-update-queue.test.ts +53 -0
- package/src/state-updates/state-update-queue.ts +35 -0
- package/src/utils.test.ts +175 -0
- package/src/utils.ts +20 -0
package/dist/index.browser.cjs
CHANGED
|
@@ -874,6 +874,18 @@ decoders.MuteResponse = (input) => {
|
|
|
874
874
|
};
|
|
875
875
|
return decode(typeMappings, input);
|
|
876
876
|
};
|
|
877
|
+
decoders.NotificationFeedUpdatedEvent = (input) => {
|
|
878
|
+
const typeMappings = {
|
|
879
|
+
created_at: { type: 'DatetimeType', isSingle: true },
|
|
880
|
+
received_at: { type: 'DatetimeType', isSingle: true },
|
|
881
|
+
aggregated_activities: {
|
|
882
|
+
type: 'AggregatedActivityResponse',
|
|
883
|
+
isSingle: false,
|
|
884
|
+
},
|
|
885
|
+
notification_status: { type: 'NotificationStatusResponse', isSingle: true },
|
|
886
|
+
};
|
|
887
|
+
return decode(typeMappings, input);
|
|
888
|
+
};
|
|
877
889
|
decoders.NotificationStatusResponse = (input) => {
|
|
878
890
|
const typeMappings = {
|
|
879
891
|
last_seen_at: { type: 'DatetimeType', isSingle: true },
|
|
@@ -2349,7 +2361,6 @@ class FeedsApi {
|
|
|
2349
2361
|
}
|
|
2350
2362
|
async updateLiveLocation(request) {
|
|
2351
2363
|
const body = {
|
|
2352
|
-
created_by_device_id: request?.created_by_device_id,
|
|
2353
2364
|
message_id: request?.message_id,
|
|
2354
2365
|
end_at: request?.end_at,
|
|
2355
2366
|
latitude: request?.latitude,
|
|
@@ -3714,6 +3725,7 @@ const eventDecoderMapping = {
|
|
|
3714
3725
|
'feeds.follow.created': (data) => decoders.FollowCreatedEvent(data),
|
|
3715
3726
|
'feeds.follow.deleted': (data) => decoders.FollowDeletedEvent(data),
|
|
3716
3727
|
'feeds.follow.updated': (data) => decoders.FollowUpdatedEvent(data),
|
|
3728
|
+
'feeds.notification_feed.updated': (data) => decoders.NotificationFeedUpdatedEvent(data),
|
|
3717
3729
|
'feeds.poll.closed': (data) => decoders.PollClosedFeedEvent(data),
|
|
3718
3730
|
'feeds.poll.deleted': (data) => decoders.PollDeletedFeedEvent(data),
|
|
3719
3731
|
'feeds.poll.updated': (data) => decoders.PollUpdatedFeedEvent(data),
|
|
@@ -4046,6 +4058,89 @@ const updateBookmarkInActivities = (event, activities, isCurrentUser) => {
|
|
|
4046
4058
|
return updateActivityInActivities(updatedActivity, activities);
|
|
4047
4059
|
};
|
|
4048
4060
|
|
|
4061
|
+
const isFeedResponse = (follow) => {
|
|
4062
|
+
return 'created_by' in follow;
|
|
4063
|
+
};
|
|
4064
|
+
const handleFollowCreated = (follow, currentState, currentFeedId, connectedUserId) => {
|
|
4065
|
+
// filter non-accepted follows (the way getOrCreate does by default)
|
|
4066
|
+
if (follow.status !== 'accepted') {
|
|
4067
|
+
return { changed: false, data: currentState };
|
|
4068
|
+
}
|
|
4069
|
+
let newState = { ...currentState };
|
|
4070
|
+
// this feed followed someone
|
|
4071
|
+
if (follow.source_feed.fid === currentFeedId) {
|
|
4072
|
+
newState = {
|
|
4073
|
+
...newState,
|
|
4074
|
+
// Update FeedResponse fields, that has the new follower/following count
|
|
4075
|
+
...follow.source_feed,
|
|
4076
|
+
};
|
|
4077
|
+
// Only update if following array already exists
|
|
4078
|
+
if (currentState.following !== undefined) {
|
|
4079
|
+
newState.following = [follow, ...currentState.following];
|
|
4080
|
+
}
|
|
4081
|
+
}
|
|
4082
|
+
else if (
|
|
4083
|
+
// someone followed this feed
|
|
4084
|
+
follow.target_feed.fid === currentFeedId) {
|
|
4085
|
+
const source = follow.source_feed;
|
|
4086
|
+
newState = {
|
|
4087
|
+
...newState,
|
|
4088
|
+
// Update FeedResponse fields, that has the new follower/following count
|
|
4089
|
+
...follow.target_feed,
|
|
4090
|
+
};
|
|
4091
|
+
if (source.created_by.id === connectedUserId) {
|
|
4092
|
+
newState.own_follows = currentState.own_follows
|
|
4093
|
+
? currentState.own_follows.concat(follow)
|
|
4094
|
+
: [follow];
|
|
4095
|
+
}
|
|
4096
|
+
// Only update if followers array already exists
|
|
4097
|
+
if (currentState.followers !== undefined) {
|
|
4098
|
+
newState.followers = [follow, ...currentState.followers];
|
|
4099
|
+
}
|
|
4100
|
+
}
|
|
4101
|
+
return { changed: true, data: newState };
|
|
4102
|
+
};
|
|
4103
|
+
const handleFollowDeleted = (follow, currentState, currentFeedId, connectedUserId) => {
|
|
4104
|
+
let newState = { ...currentState };
|
|
4105
|
+
// this feed unfollowed someone
|
|
4106
|
+
if (follow.source_feed.fid === currentFeedId) {
|
|
4107
|
+
newState = {
|
|
4108
|
+
...newState,
|
|
4109
|
+
// Update FeedResponse fields, that has the new follower/following count
|
|
4110
|
+
...follow.source_feed,
|
|
4111
|
+
};
|
|
4112
|
+
// Only update if following array already exists
|
|
4113
|
+
if (currentState.following !== undefined) {
|
|
4114
|
+
newState.following = currentState.following.filter((followItem) => followItem.target_feed.fid !== follow.target_feed.fid);
|
|
4115
|
+
}
|
|
4116
|
+
}
|
|
4117
|
+
else if (
|
|
4118
|
+
// someone unfollowed this feed
|
|
4119
|
+
follow.target_feed.fid === currentFeedId) {
|
|
4120
|
+
const source = follow.source_feed;
|
|
4121
|
+
newState = {
|
|
4122
|
+
...newState,
|
|
4123
|
+
// Update FeedResponse fields, that has the new follower/following count
|
|
4124
|
+
...follow.target_feed,
|
|
4125
|
+
};
|
|
4126
|
+
if (isFeedResponse(source) &&
|
|
4127
|
+
source.created_by.id === connectedUserId &&
|
|
4128
|
+
currentState.own_follows !== undefined) {
|
|
4129
|
+
newState.own_follows = currentState.own_follows.filter((followItem) => followItem.source_feed.fid !== follow.source_feed.fid);
|
|
4130
|
+
}
|
|
4131
|
+
// Only update if followers array already exists
|
|
4132
|
+
if (currentState.followers !== undefined) {
|
|
4133
|
+
newState.followers = currentState.followers.filter((followItem) => followItem.source_feed.fid !== follow.source_feed.fid);
|
|
4134
|
+
}
|
|
4135
|
+
}
|
|
4136
|
+
return { changed: true, data: newState };
|
|
4137
|
+
};
|
|
4138
|
+
const handleFollowUpdated = (currentState) => {
|
|
4139
|
+
// For now, we'll treat follow updates as no-ops since the current implementation does
|
|
4140
|
+
// This can be enhanced later if needed
|
|
4141
|
+
return { changed: false, data: currentState };
|
|
4142
|
+
};
|
|
4143
|
+
|
|
4049
4144
|
const isImageFile = (file) => {
|
|
4050
4145
|
// photoshop files begin with 'image/'
|
|
4051
4146
|
return file.type.startsWith('image/') && !file.type.endsWith('.photoshop');
|
|
@@ -4061,11 +4156,41 @@ const isCommentResponse = (entity) => {
|
|
|
4061
4156
|
const Constants = {
|
|
4062
4157
|
DEFAULT_COMMENT_PAGINATION: 'first',
|
|
4063
4158
|
};
|
|
4159
|
+
const uniqueArrayMerge = (existingArray, arrayToMerge, getKey) => {
|
|
4160
|
+
const existing = new Set();
|
|
4161
|
+
existingArray.forEach((value) => {
|
|
4162
|
+
const key = getKey(value);
|
|
4163
|
+
existing.add(key);
|
|
4164
|
+
});
|
|
4165
|
+
const filteredArrayToMerge = arrayToMerge.filter((value) => {
|
|
4166
|
+
const key = getKey(value);
|
|
4167
|
+
return !existing.has(key);
|
|
4168
|
+
});
|
|
4169
|
+
return existingArray.concat(filteredArrayToMerge);
|
|
4170
|
+
};
|
|
4171
|
+
|
|
4172
|
+
const shouldUpdateState = ({ stateUpdateId, stateUpdateQueue, watch, }) => {
|
|
4173
|
+
if (!watch) {
|
|
4174
|
+
return true;
|
|
4175
|
+
}
|
|
4176
|
+
if (watch && stateUpdateQueue.has(stateUpdateId)) {
|
|
4177
|
+
stateUpdateQueue.delete(stateUpdateId);
|
|
4178
|
+
return false;
|
|
4179
|
+
}
|
|
4180
|
+
stateUpdateQueue.add(stateUpdateId);
|
|
4181
|
+
return true;
|
|
4182
|
+
};
|
|
4183
|
+
const getStateUpdateQueueIdForFollow = (follow) => {
|
|
4184
|
+
return `follow${follow.source_feed.fid}-${follow.target_feed.fid}`;
|
|
4185
|
+
};
|
|
4186
|
+
const getStateUpdateQueueIdForUnfollow = (follow) => {
|
|
4187
|
+
return `unfollow${follow.source_feed.fid}-${follow.target_feed.fid}`;
|
|
4188
|
+
};
|
|
4064
4189
|
|
|
4065
4190
|
class Feed extends FeedApi {
|
|
4066
|
-
constructor(client, groupId, id, data) {
|
|
4067
|
-
// Need this ugly cast because fileUpload endpoints :(
|
|
4191
|
+
constructor(client, groupId, id, data, watch = false) {
|
|
4068
4192
|
super(client, groupId, id);
|
|
4193
|
+
this.stateUpdateQueue = new Set();
|
|
4069
4194
|
this.eventHandlers = {
|
|
4070
4195
|
'feeds.activity.added': (event) => {
|
|
4071
4196
|
const currentActivities = this.currentState.activities;
|
|
@@ -4211,74 +4336,14 @@ class Feed extends FeedApi {
|
|
|
4211
4336
|
'feeds.feed_group.changed': Feed.noop,
|
|
4212
4337
|
'feeds.feed_group.deleted': Feed.noop,
|
|
4213
4338
|
'feeds.follow.created': (event) => {
|
|
4214
|
-
|
|
4215
|
-
if (event.follow.status !== 'accepted')
|
|
4216
|
-
return;
|
|
4217
|
-
// this feed followed someone
|
|
4218
|
-
if (event.follow.source_feed.fid === this.fid) {
|
|
4219
|
-
this.state.next((currentState) => {
|
|
4220
|
-
const newState = {
|
|
4221
|
-
...currentState,
|
|
4222
|
-
...event.follow.source_feed,
|
|
4223
|
-
};
|
|
4224
|
-
if (!checkHasAnotherPage(currentState.following, currentState.following_pagination?.next)) {
|
|
4225
|
-
// TODO: respect sort
|
|
4226
|
-
newState.following = currentState.following
|
|
4227
|
-
? currentState.following.concat(event.follow)
|
|
4228
|
-
: [event.follow];
|
|
4229
|
-
}
|
|
4230
|
-
return newState;
|
|
4231
|
-
});
|
|
4232
|
-
}
|
|
4233
|
-
else if (
|
|
4234
|
-
// someone followed this feed
|
|
4235
|
-
event.follow.target_feed.fid === this.fid) {
|
|
4236
|
-
const source = event.follow.source_feed;
|
|
4237
|
-
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4238
|
-
this.state.next((currentState) => {
|
|
4239
|
-
const newState = { ...currentState, ...event.follow.target_feed };
|
|
4240
|
-
if (source.created_by.id === connectedUser?.id) {
|
|
4241
|
-
newState.own_follows = currentState.own_follows
|
|
4242
|
-
? currentState.own_follows.concat(event.follow)
|
|
4243
|
-
: [event.follow];
|
|
4244
|
-
}
|
|
4245
|
-
if (!checkHasAnotherPage(currentState.followers, currentState.followers_pagination?.next)) {
|
|
4246
|
-
// TODO: respect sort
|
|
4247
|
-
newState.followers = currentState.followers
|
|
4248
|
-
? currentState.followers.concat(event.follow)
|
|
4249
|
-
: [event.follow];
|
|
4250
|
-
}
|
|
4251
|
-
return newState;
|
|
4252
|
-
});
|
|
4253
|
-
}
|
|
4339
|
+
this.handleFollowCreated(event.follow);
|
|
4254
4340
|
},
|
|
4255
4341
|
'feeds.follow.deleted': (event) => {
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
...currentState,
|
|
4261
|
-
...event.follow.source_feed,
|
|
4262
|
-
following: currentState.following?.filter((follow) => follow.target_feed.fid !== event.follow.target_feed.fid),
|
|
4263
|
-
};
|
|
4264
|
-
});
|
|
4265
|
-
}
|
|
4266
|
-
else if (
|
|
4267
|
-
// someone unfollowed this feed
|
|
4268
|
-
event.follow.target_feed.fid === this.fid) {
|
|
4269
|
-
const source = event.follow.source_feed;
|
|
4270
|
-
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4271
|
-
this.state.next((currentState) => {
|
|
4272
|
-
const newState = { ...currentState, ...event.follow.target_feed };
|
|
4273
|
-
if (source.created_by.id === connectedUser?.id) {
|
|
4274
|
-
newState.own_follows = currentState.own_follows?.filter((follow) => follow.source_feed.fid !== event.follow.source_feed.fid);
|
|
4275
|
-
}
|
|
4276
|
-
newState.followers = currentState.followers?.filter((follow) => follow.source_feed.fid !== event.follow.source_feed.fid);
|
|
4277
|
-
return newState;
|
|
4278
|
-
});
|
|
4279
|
-
}
|
|
4342
|
+
this.handleFollowDeleted(event.follow);
|
|
4343
|
+
},
|
|
4344
|
+
'feeds.follow.updated': (_event) => {
|
|
4345
|
+
handleFollowUpdated(this.currentState);
|
|
4280
4346
|
},
|
|
4281
|
-
'feeds.follow.updated': Feed.noop,
|
|
4282
4347
|
'feeds.comment.reaction.added': this.handleCommentReactionEvent.bind(this),
|
|
4283
4348
|
'feeds.comment.reaction.deleted': this.handleCommentReactionEvent.bind(this),
|
|
4284
4349
|
'feeds.comment.reaction.updated': Feed.noop,
|
|
@@ -4286,13 +4351,11 @@ class Feed extends FeedApi {
|
|
|
4286
4351
|
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4287
4352
|
this.state.next((currentState) => {
|
|
4288
4353
|
let newState;
|
|
4289
|
-
if (
|
|
4354
|
+
if (typeof currentState.members !== 'undefined') {
|
|
4290
4355
|
newState ?? (newState = {
|
|
4291
4356
|
...currentState,
|
|
4292
4357
|
});
|
|
4293
|
-
newState.members =
|
|
4294
|
-
event.member,
|
|
4295
|
-
];
|
|
4358
|
+
newState.members = [event.member, ...currentState.members];
|
|
4296
4359
|
}
|
|
4297
4360
|
if (connectedUser?.id === event.member.user.id) {
|
|
4298
4361
|
newState ?? (newState = {
|
|
@@ -4339,6 +4402,10 @@ class Feed extends FeedApi {
|
|
|
4339
4402
|
return newState ?? currentState;
|
|
4340
4403
|
});
|
|
4341
4404
|
},
|
|
4405
|
+
'feeds.notification_feed.updated': (event) => {
|
|
4406
|
+
console.info('notification feed updated', event);
|
|
4407
|
+
// TODO: handle notification feed updates
|
|
4408
|
+
},
|
|
4342
4409
|
// the poll events should be removed from here
|
|
4343
4410
|
'feeds.poll.closed': Feed.noop,
|
|
4344
4411
|
'feeds.poll.deleted': Feed.noop,
|
|
@@ -4371,6 +4438,7 @@ class Feed extends FeedApi {
|
|
|
4371
4438
|
is_loading: false,
|
|
4372
4439
|
is_loading_activities: false,
|
|
4373
4440
|
comments_by_entity_id: {},
|
|
4441
|
+
watch,
|
|
4374
4442
|
});
|
|
4375
4443
|
this.client = client;
|
|
4376
4444
|
}
|
|
@@ -4450,6 +4518,8 @@ class Feed extends FeedApi {
|
|
|
4450
4518
|
}
|
|
4451
4519
|
}
|
|
4452
4520
|
else {
|
|
4521
|
+
// Empty queue when reinitializing the state
|
|
4522
|
+
this.stateUpdateQueue.clear();
|
|
4453
4523
|
const responseCopy = {
|
|
4454
4524
|
...response,
|
|
4455
4525
|
...response.feed,
|
|
@@ -4468,7 +4538,11 @@ class Feed extends FeedApi {
|
|
|
4468
4538
|
if (!request?.following_pagination?.limit) {
|
|
4469
4539
|
delete nextState.following;
|
|
4470
4540
|
}
|
|
4541
|
+
if (response.members.length === 0 && response.feed.member_count > 0) {
|
|
4542
|
+
delete nextState.members;
|
|
4543
|
+
}
|
|
4471
4544
|
nextState.last_get_or_create_request_config = request;
|
|
4545
|
+
nextState.watch = request?.watch ? request.watch : currentState.watch;
|
|
4472
4546
|
return nextState;
|
|
4473
4547
|
});
|
|
4474
4548
|
}
|
|
@@ -4482,6 +4556,56 @@ class Feed extends FeedApi {
|
|
|
4482
4556
|
});
|
|
4483
4557
|
}
|
|
4484
4558
|
}
|
|
4559
|
+
/**
|
|
4560
|
+
* @internal
|
|
4561
|
+
*/
|
|
4562
|
+
handleFollowCreated(follow) {
|
|
4563
|
+
if (!shouldUpdateState({
|
|
4564
|
+
stateUpdateId: getStateUpdateQueueIdForFollow(follow),
|
|
4565
|
+
stateUpdateQueue: this.stateUpdateQueue,
|
|
4566
|
+
watch: this.currentState.watch,
|
|
4567
|
+
})) {
|
|
4568
|
+
return;
|
|
4569
|
+
}
|
|
4570
|
+
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4571
|
+
const result = handleFollowCreated(follow, this.currentState, this.fid, connectedUser?.id);
|
|
4572
|
+
if (result.changed) {
|
|
4573
|
+
this.state.next(result.data);
|
|
4574
|
+
}
|
|
4575
|
+
}
|
|
4576
|
+
/**
|
|
4577
|
+
* @internal
|
|
4578
|
+
*/
|
|
4579
|
+
handleFollowDeleted(follow) {
|
|
4580
|
+
if (!shouldUpdateState({
|
|
4581
|
+
stateUpdateId: getStateUpdateQueueIdForUnfollow(follow),
|
|
4582
|
+
stateUpdateQueue: this.stateUpdateQueue,
|
|
4583
|
+
watch: this.currentState.watch,
|
|
4584
|
+
})) {
|
|
4585
|
+
return;
|
|
4586
|
+
}
|
|
4587
|
+
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4588
|
+
const result = handleFollowDeleted(follow, this.currentState, this.fid, connectedUser?.id);
|
|
4589
|
+
{
|
|
4590
|
+
this.state.next(result.data);
|
|
4591
|
+
}
|
|
4592
|
+
}
|
|
4593
|
+
/**
|
|
4594
|
+
* @internal
|
|
4595
|
+
*/
|
|
4596
|
+
handleWatchStopped() {
|
|
4597
|
+
this.state.partialNext({
|
|
4598
|
+
watch: false,
|
|
4599
|
+
});
|
|
4600
|
+
}
|
|
4601
|
+
/**
|
|
4602
|
+
* @internal
|
|
4603
|
+
*/
|
|
4604
|
+
handleWatchStarted() {
|
|
4605
|
+
this.state.partialNext({
|
|
4606
|
+
watch: true,
|
|
4607
|
+
});
|
|
4608
|
+
}
|
|
4485
4609
|
handleBookmarkAdded(event) {
|
|
4486
4610
|
const currentActivities = this.currentState.activities;
|
|
4487
4611
|
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
@@ -4526,70 +4650,85 @@ class Feed extends FeedApi {
|
|
|
4526
4650
|
}
|
|
4527
4651
|
return commentIndex;
|
|
4528
4652
|
}
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4653
|
+
/**
|
|
4654
|
+
* Load child comments of entity (activity or comment) into the state, if the target entity is comment,
|
|
4655
|
+
* `entityParentId` should be provided (`CommentResponse.parent_id ?? CommentResponse.object_id`).
|
|
4656
|
+
*/
|
|
4657
|
+
loadCommentsIntoState(data) {
|
|
4658
|
+
// add initial (top level) object for processing
|
|
4659
|
+
const traverseArray = [
|
|
4660
|
+
{
|
|
4661
|
+
entityId: data.entityId,
|
|
4662
|
+
entityParentId: data.entityParentId,
|
|
4663
|
+
comments: data.comments,
|
|
4664
|
+
next: data.next,
|
|
4665
|
+
},
|
|
4666
|
+
];
|
|
4542
4667
|
this.state.next((currentState) => {
|
|
4543
|
-
const
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4668
|
+
const newCommentsByEntityId = {
|
|
4669
|
+
...currentState.comments_by_entity_id,
|
|
4670
|
+
};
|
|
4671
|
+
while (traverseArray.length) {
|
|
4672
|
+
const item = traverseArray.pop();
|
|
4673
|
+
const entityId = item.entityId;
|
|
4674
|
+
// go over entity comments and generate new objects
|
|
4675
|
+
// for further processing if there are any replies
|
|
4676
|
+
item.comments.forEach((comment) => {
|
|
4677
|
+
if (!comment.replies?.length)
|
|
4678
|
+
return;
|
|
4679
|
+
traverseArray.push({
|
|
4680
|
+
entityId: comment.id,
|
|
4681
|
+
entityParentId: entityId,
|
|
4682
|
+
comments: comment.replies,
|
|
4683
|
+
next: comment.meta?.next_cursor,
|
|
4684
|
+
});
|
|
4685
|
+
});
|
|
4686
|
+
// omit replies & meta from the comments (transform ThreadedCommentResponse to CommentResponse)
|
|
4687
|
+
// this is somehow faster than copying the whole
|
|
4688
|
+
// object and deleting the desired properties
|
|
4689
|
+
const newComments = item.comments.map(({ replies: _r, meta: _m, ...restOfTheCommentResponse }) => restOfTheCommentResponse);
|
|
4690
|
+
newCommentsByEntityId[entityId] = {
|
|
4691
|
+
...newCommentsByEntityId[entityId],
|
|
4692
|
+
entity_parent_id: item.entityParentId,
|
|
4693
|
+
pagination: {
|
|
4694
|
+
...newCommentsByEntityId[entityId]?.pagination,
|
|
4695
|
+
next: item.next,
|
|
4696
|
+
sort: data.sort,
|
|
4697
|
+
},
|
|
4698
|
+
comments: newCommentsByEntityId[entityId]?.comments
|
|
4699
|
+
? newCommentsByEntityId[entityId].comments?.concat(newComments)
|
|
4700
|
+
: newComments,
|
|
4701
|
+
};
|
|
4702
|
+
}
|
|
4548
4703
|
return {
|
|
4549
4704
|
...currentState,
|
|
4550
|
-
|
|
4705
|
+
comments_by_entity_id: newCommentsByEntityId,
|
|
4551
4706
|
};
|
|
4552
4707
|
});
|
|
4553
4708
|
}
|
|
4554
|
-
async loadNextPageComments({
|
|
4709
|
+
async loadNextPageComments({ entityId, base, sort, entityParentId, }) {
|
|
4555
4710
|
let error;
|
|
4556
4711
|
try {
|
|
4557
4712
|
this.state.next((currentState) => ({
|
|
4558
4713
|
...currentState,
|
|
4559
4714
|
comments_by_entity_id: {
|
|
4560
4715
|
...currentState.comments_by_entity_id,
|
|
4561
|
-
[
|
|
4562
|
-
...currentState.comments_by_entity_id[
|
|
4716
|
+
[entityId]: {
|
|
4717
|
+
...currentState.comments_by_entity_id[entityId],
|
|
4563
4718
|
pagination: {
|
|
4564
|
-
...currentState.comments_by_entity_id[
|
|
4719
|
+
...currentState.comments_by_entity_id[entityId]?.pagination,
|
|
4565
4720
|
loading_next_page: true,
|
|
4566
4721
|
},
|
|
4567
4722
|
},
|
|
4568
4723
|
},
|
|
4569
4724
|
}));
|
|
4570
|
-
const { next
|
|
4571
|
-
this.
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
newPagination.sort = sort;
|
|
4578
|
-
}
|
|
4579
|
-
return {
|
|
4580
|
-
...currentState,
|
|
4581
|
-
comments_by_entity_id: {
|
|
4582
|
-
...currentState.comments_by_entity_id,
|
|
4583
|
-
[forId]: {
|
|
4584
|
-
...currentState.comments_by_entity_id[forId],
|
|
4585
|
-
parent_id: parentId,
|
|
4586
|
-
pagination: newPagination,
|
|
4587
|
-
comments: currentState.comments_by_entity_id[forId]?.comments
|
|
4588
|
-
? currentState.comments_by_entity_id[forId].comments?.concat(comments)
|
|
4589
|
-
: comments,
|
|
4590
|
-
},
|
|
4591
|
-
},
|
|
4592
|
-
};
|
|
4725
|
+
const { next, comments } = await base();
|
|
4726
|
+
this.loadCommentsIntoState({
|
|
4727
|
+
entityId,
|
|
4728
|
+
comments,
|
|
4729
|
+
entityParentId,
|
|
4730
|
+
next,
|
|
4731
|
+
sort,
|
|
4593
4732
|
});
|
|
4594
4733
|
}
|
|
4595
4734
|
catch (e) {
|
|
@@ -4600,10 +4739,10 @@ class Feed extends FeedApi {
|
|
|
4600
4739
|
...currentState,
|
|
4601
4740
|
comments_by_entity_id: {
|
|
4602
4741
|
...currentState.comments_by_entity_id,
|
|
4603
|
-
[
|
|
4604
|
-
...currentState.comments_by_entity_id[
|
|
4742
|
+
[entityId]: {
|
|
4743
|
+
...currentState.comments_by_entity_id[entityId],
|
|
4605
4744
|
pagination: {
|
|
4606
|
-
...currentState.comments_by_entity_id[
|
|
4745
|
+
...currentState.comments_by_entity_id[entityId]?.pagination,
|
|
4607
4746
|
loading_next_page: false,
|
|
4608
4747
|
},
|
|
4609
4748
|
},
|
|
@@ -4626,7 +4765,7 @@ class Feed extends FeedApi {
|
|
|
4626
4765
|
return;
|
|
4627
4766
|
}
|
|
4628
4767
|
await this.loadNextPageComments({
|
|
4629
|
-
|
|
4768
|
+
entityId: activity.id,
|
|
4630
4769
|
base: () => this.client.getComments({
|
|
4631
4770
|
...request,
|
|
4632
4771
|
sort,
|
|
@@ -4649,7 +4788,7 @@ class Feed extends FeedApi {
|
|
|
4649
4788
|
return;
|
|
4650
4789
|
}
|
|
4651
4790
|
await this.loadNextPageComments({
|
|
4652
|
-
|
|
4791
|
+
entityId: comment.id,
|
|
4653
4792
|
base: () => this.client.getCommentReplies({
|
|
4654
4793
|
...request,
|
|
4655
4794
|
comment_id: comment.id,
|
|
@@ -4659,7 +4798,7 @@ class Feed extends FeedApi {
|
|
|
4659
4798
|
Constants.DEFAULT_COMMENT_PAGINATION,
|
|
4660
4799
|
next: currentNextCursor,
|
|
4661
4800
|
}),
|
|
4662
|
-
|
|
4801
|
+
entityParentId: comment.parent_id ?? comment.object_id,
|
|
4663
4802
|
sort,
|
|
4664
4803
|
});
|
|
4665
4804
|
}
|
|
@@ -4689,17 +4828,19 @@ class Feed extends FeedApi {
|
|
|
4689
4828
|
next: currentNextCursor,
|
|
4690
4829
|
sort,
|
|
4691
4830
|
});
|
|
4692
|
-
this.state.next((currentState) =>
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4831
|
+
this.state.next((currentState) => {
|
|
4832
|
+
return {
|
|
4833
|
+
...currentState,
|
|
4834
|
+
[type]: currentState[type] === undefined
|
|
4835
|
+
? follows
|
|
4836
|
+
: uniqueArrayMerge(currentState[type], follows, (follow) => `${follow.source_feed.fid}-${follow.target_feed.fid}`),
|
|
4837
|
+
[paginationKey]: {
|
|
4838
|
+
...currentState[paginationKey],
|
|
4839
|
+
next: newNextCursor,
|
|
4840
|
+
sort,
|
|
4841
|
+
},
|
|
4842
|
+
};
|
|
4843
|
+
});
|
|
4703
4844
|
}
|
|
4704
4845
|
catch (e) {
|
|
4705
4846
|
error = e;
|
|
@@ -4752,7 +4893,7 @@ class Feed extends FeedApi {
|
|
|
4752
4893
|
this.state.next((currentState) => ({
|
|
4753
4894
|
...currentState,
|
|
4754
4895
|
members: currentState.members
|
|
4755
|
-
? currentState.members
|
|
4896
|
+
? uniqueArrayMerge(currentState.members, members, ({ user }) => user.id)
|
|
4756
4897
|
: members,
|
|
4757
4898
|
member_pagination: {
|
|
4758
4899
|
...currentState.member_pagination,
|
|
@@ -5339,13 +5480,17 @@ class FeedsClient extends FeedsApi {
|
|
|
5339
5480
|
};
|
|
5340
5481
|
this.eventDispatcher.dispatch(networkEvent);
|
|
5341
5482
|
};
|
|
5342
|
-
this.getOrCreateActiveFeed = (group, id, data) => {
|
|
5483
|
+
this.getOrCreateActiveFeed = (group, id, data, watch) => {
|
|
5343
5484
|
const fid = `${group}:${id}`;
|
|
5344
5485
|
if (this.activeFeeds[fid]) {
|
|
5345
|
-
|
|
5486
|
+
const feed = this.activeFeeds[fid];
|
|
5487
|
+
if (watch && !feed.currentState.watch) {
|
|
5488
|
+
feed.handleWatchStarted();
|
|
5489
|
+
}
|
|
5490
|
+
return feed;
|
|
5346
5491
|
}
|
|
5347
5492
|
else {
|
|
5348
|
-
const feed = new Feed(this, group, id, data);
|
|
5493
|
+
const feed = new Feed(this, group, id, data, watch);
|
|
5349
5494
|
this.activeFeeds[fid] = feed;
|
|
5350
5495
|
return feed;
|
|
5351
5496
|
}
|
|
@@ -5374,6 +5519,11 @@ class FeedsClient extends FeedsApi {
|
|
|
5374
5519
|
}
|
|
5375
5520
|
}
|
|
5376
5521
|
}
|
|
5522
|
+
else {
|
|
5523
|
+
for (const activeFeed of Object.values(this.activeFeeds)) {
|
|
5524
|
+
activeFeed.handleWatchStopped();
|
|
5525
|
+
}
|
|
5526
|
+
}
|
|
5377
5527
|
break;
|
|
5378
5528
|
}
|
|
5379
5529
|
case 'feeds.feed.created': {
|
|
@@ -5477,7 +5627,7 @@ class FeedsClient extends FeedsApi {
|
|
|
5477
5627
|
}
|
|
5478
5628
|
async queryFeeds(request) {
|
|
5479
5629
|
const response = await this.feedsQueryFeeds(request);
|
|
5480
|
-
const feeds = response.feeds.map((f) => this.getOrCreateActiveFeed(f.group_id, f.id, f));
|
|
5630
|
+
const feeds = response.feeds.map((f) => this.getOrCreateActiveFeed(f.group_id, f.id, f, request?.watch));
|
|
5481
5631
|
return {
|
|
5482
5632
|
feeds,
|
|
5483
5633
|
next: response.next,
|
|
@@ -5486,6 +5636,52 @@ class FeedsClient extends FeedsApi {
|
|
|
5486
5636
|
duration: response.duration,
|
|
5487
5637
|
};
|
|
5488
5638
|
}
|
|
5639
|
+
// For follow API endpoints we update the state after HTTP response to allow queryFeeds with watch: false
|
|
5640
|
+
async follow(request) {
|
|
5641
|
+
const response = await super.follow(request);
|
|
5642
|
+
[response.follow.source_feed.fid, response.follow.target_feed.fid].forEach((fid) => {
|
|
5643
|
+
const feed = this.activeFeeds[fid];
|
|
5644
|
+
if (feed) {
|
|
5645
|
+
feed.handleFollowCreated(response.follow);
|
|
5646
|
+
}
|
|
5647
|
+
});
|
|
5648
|
+
return response;
|
|
5649
|
+
}
|
|
5650
|
+
async followBatch(request) {
|
|
5651
|
+
const response = await super.followBatch(request);
|
|
5652
|
+
response.follows.forEach((follow) => {
|
|
5653
|
+
const feed = this.activeFeeds[follow.source_feed.fid];
|
|
5654
|
+
if (feed) {
|
|
5655
|
+
feed.handleFollowCreated(follow);
|
|
5656
|
+
}
|
|
5657
|
+
});
|
|
5658
|
+
return response;
|
|
5659
|
+
}
|
|
5660
|
+
async unfollow(request) {
|
|
5661
|
+
const response = await super.unfollow(request);
|
|
5662
|
+
[request.source, request.target].forEach((fid) => {
|
|
5663
|
+
const feed = this.activeFeeds[fid];
|
|
5664
|
+
if (feed) {
|
|
5665
|
+
feed.handleFollowDeleted({
|
|
5666
|
+
source_feed: { fid: request.source },
|
|
5667
|
+
target_feed: { fid: request.target },
|
|
5668
|
+
});
|
|
5669
|
+
}
|
|
5670
|
+
});
|
|
5671
|
+
return response;
|
|
5672
|
+
}
|
|
5673
|
+
async stopWatchingFeed(request) {
|
|
5674
|
+
const connectionId = await this.connectionIdManager.getConnectionId();
|
|
5675
|
+
const response = await super.stopWatchingFeed({
|
|
5676
|
+
...request,
|
|
5677
|
+
connection_id: connectionId,
|
|
5678
|
+
});
|
|
5679
|
+
const feed = this.activeFeeds[`${request.feed_group_id}:${request.feed_id}`];
|
|
5680
|
+
if (feed) {
|
|
5681
|
+
feed.handleWatchStopped();
|
|
5682
|
+
}
|
|
5683
|
+
return response;
|
|
5684
|
+
}
|
|
5489
5685
|
findActiveFeedByActivityId(activityId) {
|
|
5490
5686
|
return Object.values(this.activeFeeds).filter((feed) => feed.currentState.activities?.some((activity) => activity.id === activityId));
|
|
5491
5687
|
}
|
|
@@ -6018,4 +6214,5 @@ exports.isImageFile = isImageFile;
|
|
|
6018
6214
|
exports.isPatch = isPatch;
|
|
6019
6215
|
exports.isVideoFile = isVideoFile;
|
|
6020
6216
|
exports.isVoteAnswer = isVoteAnswer;
|
|
6217
|
+
exports.uniqueArrayMerge = uniqueArrayMerge;
|
|
6021
6218
|
//# sourceMappingURL=index.browser.cjs.map
|