@stream-io/feeds-client 0.1.4 → 0.1.5
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/client-state-hooks/index.ts +2 -0
- package/@react-bindings/hooks/feed-state-hooks/index.ts +5 -0
- package/@react-bindings/hooks/internal/index.ts +1 -0
- package/@react-bindings/hooks/util/index.ts +1 -0
- package/@react-bindings/index.ts +6 -3
- package/CHANGELOG.md +16 -0
- package/dist/@react-bindings/contexts/StreamFeedContext.d.ts +12 -0
- package/dist/@react-bindings/hooks/client-state-hooks/index.d.ts +2 -0
- package/dist/@react-bindings/hooks/client-state-hooks/useClientConnectedUser.d.ts +4 -0
- package/dist/@react-bindings/hooks/client-state-hooks/useWsConnectionState.d.ts +6 -0
- package/dist/@react-bindings/hooks/feed-state-hooks/index.d.ts +5 -0
- package/dist/@react-bindings/hooks/feed-state-hooks/useComments.d.ts +19 -0
- package/dist/@react-bindings/hooks/feed-state-hooks/useFeedActivities.d.ts +11 -0
- package/dist/@react-bindings/hooks/feed-state-hooks/useFollowers.d.ts +16 -0
- package/dist/@react-bindings/hooks/feed-state-hooks/useFollowing.d.ts +16 -0
- package/dist/@react-bindings/hooks/{useOwnCapabilities.d.ts → feed-state-hooks/useOwnCapabilities.d.ts} +2 -2
- package/dist/@react-bindings/hooks/internal/index.d.ts +1 -0
- package/dist/@react-bindings/hooks/internal/useStableCallback.d.ts +25 -0
- package/dist/@react-bindings/hooks/util/index.d.ts +1 -0
- package/dist/@react-bindings/hooks/util/useReactionActions.d.ts +17 -0
- package/dist/@react-bindings/index.d.ts +5 -3
- package/dist/@react-bindings/wrappers/StreamFeed.d.ts +12 -0
- package/dist/index-react-bindings.browser.cjs +451 -183
- package/dist/index-react-bindings.browser.cjs.map +1 -1
- package/dist/index-react-bindings.browser.js +446 -185
- package/dist/index-react-bindings.browser.js.map +1 -1
- package/dist/index-react-bindings.node.cjs +451 -183
- package/dist/index-react-bindings.node.cjs.map +1 -1
- package/dist/index-react-bindings.node.js +446 -185
- package/dist/index-react-bindings.node.js.map +1 -1
- package/dist/index.browser.cjs +167 -72
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.js +164 -73
- package/dist/index.browser.js.map +1 -1
- package/dist/index.node.cjs +167 -72
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.js +164 -73
- package/dist/index.node.js.map +1 -1
- package/dist/src/Feed.d.ts +7 -3
- package/dist/src/FeedsClient.d.ts +4 -3
- package/dist/src/types.d.ts +7 -0
- package/dist/src/utils.d.ts +9 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -1
- package/src/Feed.ts +200 -89
- package/src/FeedsClient.ts +8 -3
- package/src/common/real-time/StableWSConnection.ts +4 -1
- package/src/types.ts +12 -1
- package/src/utils.ts +25 -1
- package/dist/@react-bindings/hooks/clientStateHooks.d.ts +0 -10
- package/dist/@react-bindings/hooks/useComments.d.ts +0 -12
|
@@ -275,122 +275,6 @@ function useStateStore(store, selector) {
|
|
|
275
275
|
return state;
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
-
const useComments = (feed,
|
|
279
|
-
/**
|
|
280
|
-
* The parent (activity or comment) for which to fetch comments.
|
|
281
|
-
*/
|
|
282
|
-
parent) => {
|
|
283
|
-
const selector = react.useCallback((state) => ({
|
|
284
|
-
comments: state.comments_by_entity_id?.[parent.id]?.comments ?? [],
|
|
285
|
-
comment_pagination: state.comments_by_entity_id?.[parent.id]?.pagination,
|
|
286
|
-
}), [parent.id]);
|
|
287
|
-
return useStateStore(feed.state, selector);
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
const FeedOwnCapability = {
|
|
291
|
-
ADD_ACTIVITY: 'add-activity',
|
|
292
|
-
ADD_ACTIVITY_REACTION: 'add-activity-reaction',
|
|
293
|
-
ADD_COMMENT: 'add-comment',
|
|
294
|
-
ADD_COMMENT_REACTION: 'add-comment-reaction',
|
|
295
|
-
BOOKMARK_ACTIVITY: 'bookmark-activity',
|
|
296
|
-
CREATE_FEED: 'create-feed',
|
|
297
|
-
DELETE_BOOKMARK: 'delete-bookmark',
|
|
298
|
-
DELETE_COMMENT: 'delete-comment',
|
|
299
|
-
DELETE_FEED: 'delete-feed',
|
|
300
|
-
EDIT_BOOKMARK: 'edit-bookmark',
|
|
301
|
-
FOLLOW: 'follow',
|
|
302
|
-
INVITE_FEED: 'invite-feed',
|
|
303
|
-
JOIN_FEED: 'join-feed',
|
|
304
|
-
LEAVE_FEED: 'leave-feed',
|
|
305
|
-
MANAGE_FEED_GROUP: 'manage-feed-group',
|
|
306
|
-
MARK_ACTIVITY: 'mark-activity',
|
|
307
|
-
PIN_ACTIVITY: 'pin-activity',
|
|
308
|
-
QUERY_FEED_MEMBERS: 'query-feed-members',
|
|
309
|
-
QUERY_FOLLOWS: 'query-follows',
|
|
310
|
-
READ_ACTIVITIES: 'read-activities',
|
|
311
|
-
READ_FEED: 'read-feed',
|
|
312
|
-
REMOVE_ACTIVITY: 'remove-activity',
|
|
313
|
-
REMOVE_ACTIVITY_REACTION: 'remove-activity-reaction',
|
|
314
|
-
REMOVE_COMMENT_REACTION: 'remove-comment-reaction',
|
|
315
|
-
UNFOLLOW: 'unfollow',
|
|
316
|
-
UPDATE_ACTIVITY: 'update-activity',
|
|
317
|
-
UPDATE_COMMENT: 'update-comment',
|
|
318
|
-
UPDATE_FEED: 'update-feed',
|
|
319
|
-
UPDATE_FEED_FOLLOWERS: 'update-feed-followers',
|
|
320
|
-
UPDATE_FEED_MEMBERS: 'update-feed-members',
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
const stableEmptyArray = [];
|
|
324
|
-
const selector = (currentState) => ({
|
|
325
|
-
oc: currentState.own_capabilities ?? stableEmptyArray,
|
|
326
|
-
});
|
|
327
|
-
const useOwnCapabilities = (feed) => {
|
|
328
|
-
const { oc = stableEmptyArray } = useStateStore(feed?.state, selector) ?? {};
|
|
329
|
-
return react.useMemo(() => ({
|
|
330
|
-
canAddActivity: oc.indexOf(FeedOwnCapability.ADD_ACTIVITY) > -1,
|
|
331
|
-
canAddActivityReaction: oc.indexOf(FeedOwnCapability.ADD_ACTIVITY_REACTION) > -1,
|
|
332
|
-
canAddComment: oc.indexOf(FeedOwnCapability.ADD_COMMENT) > -1,
|
|
333
|
-
canAddCommentReaction: oc.indexOf(FeedOwnCapability.ADD_COMMENT_REACTION) > -1,
|
|
334
|
-
canBookmarkActivity: oc.indexOf(FeedOwnCapability.BOOKMARK_ACTIVITY) > -1,
|
|
335
|
-
canCreateFeed: oc.indexOf(FeedOwnCapability.CREATE_FEED) > -1,
|
|
336
|
-
canDeleteBookmark: oc.indexOf(FeedOwnCapability.DELETE_BOOKMARK) > -1,
|
|
337
|
-
canDeleteComment: oc.indexOf(FeedOwnCapability.DELETE_COMMENT) > -1,
|
|
338
|
-
canDeleteFeed: oc.indexOf(FeedOwnCapability.DELETE_FEED) > -1,
|
|
339
|
-
canEditBookmark: oc.indexOf(FeedOwnCapability.EDIT_BOOKMARK) > -1,
|
|
340
|
-
canFollow: oc.indexOf(FeedOwnCapability.FOLLOW) > -1,
|
|
341
|
-
canRemoveActivity: oc.indexOf(FeedOwnCapability.REMOVE_ACTIVITY) > -1,
|
|
342
|
-
canRemoveActivityReaction: oc.indexOf(FeedOwnCapability.REMOVE_ACTIVITY_REACTION) > -1,
|
|
343
|
-
canRemoveCommentReaction: oc.indexOf(FeedOwnCapability.REMOVE_COMMENT_REACTION) > -1,
|
|
344
|
-
canUnfollow: oc.indexOf(FeedOwnCapability.UNFOLLOW) > -1,
|
|
345
|
-
canUpdateFeed: oc.indexOf(FeedOwnCapability.UPDATE_FEED) > -1,
|
|
346
|
-
canInviteFeed: oc.indexOf(FeedOwnCapability.INVITE_FEED) > -1,
|
|
347
|
-
canJoinFeed: oc.indexOf(FeedOwnCapability.JOIN_FEED) > -1,
|
|
348
|
-
canLeaveFeed: oc.indexOf(FeedOwnCapability.LEAVE_FEED) > -1,
|
|
349
|
-
canManageFeedGroup: oc.indexOf(FeedOwnCapability.MANAGE_FEED_GROUP) > -1,
|
|
350
|
-
canMarkActivity: oc.indexOf(FeedOwnCapability.MARK_ACTIVITY) > -1,
|
|
351
|
-
canPinActivity: oc.indexOf(FeedOwnCapability.PIN_ACTIVITY) > -1,
|
|
352
|
-
canQueryFeedMembers: oc.indexOf(FeedOwnCapability.QUERY_FEED_MEMBERS) > -1,
|
|
353
|
-
canQueryFollows: oc.indexOf(FeedOwnCapability.QUERY_FOLLOWS) > -1,
|
|
354
|
-
canReadActivities: oc.indexOf(FeedOwnCapability.READ_ACTIVITIES) > -1,
|
|
355
|
-
canReadFeed: oc.indexOf(FeedOwnCapability.READ_FEED) > -1,
|
|
356
|
-
canUpdateActivity: oc.indexOf(FeedOwnCapability.UPDATE_ACTIVITY) > -1,
|
|
357
|
-
canUpdateComment: oc.indexOf(FeedOwnCapability.UPDATE_COMMENT) > -1,
|
|
358
|
-
canUpdateFeedFollowers: oc.indexOf(FeedOwnCapability.UPDATE_FEED_FOLLOWERS) > -1,
|
|
359
|
-
canUpdateFeedMembers: oc.indexOf(FeedOwnCapability.UPDATE_FEED_MEMBERS) > -1,
|
|
360
|
-
}), [oc]);
|
|
361
|
-
};
|
|
362
|
-
|
|
363
|
-
const StreamFeedsContext = react.createContext(undefined);
|
|
364
|
-
/**
|
|
365
|
-
* Hook to access the nearest FeedsClient instance.
|
|
366
|
-
*/
|
|
367
|
-
const useFeedsClient = () => {
|
|
368
|
-
return react.useContext(StreamFeedsContext);
|
|
369
|
-
};
|
|
370
|
-
|
|
371
|
-
/**
|
|
372
|
-
* A React hook that returns the currently connected user on a `FeedsClient` instance and null otherwise.
|
|
373
|
-
*/
|
|
374
|
-
const useClientConnectedUser = () => {
|
|
375
|
-
const client = useFeedsClient();
|
|
376
|
-
const { user } = useStateStore(client?.state, clientConnectedUserSelector) ?? {};
|
|
377
|
-
return user;
|
|
378
|
-
};
|
|
379
|
-
/**
|
|
380
|
-
* A React hook that returns the websocket connection state of `FeedsClient`.
|
|
381
|
-
*/
|
|
382
|
-
const useWsConnectionState = () => {
|
|
383
|
-
const client = useFeedsClient();
|
|
384
|
-
const { isHealthy } = useStateStore(client?.state, wsConnectionStateSelector) ?? {};
|
|
385
|
-
return { isHealthy };
|
|
386
|
-
};
|
|
387
|
-
const clientConnectedUserSelector = (nextState) => ({
|
|
388
|
-
user: nextState.connectedUser,
|
|
389
|
-
});
|
|
390
|
-
const wsConnectionStateSelector = (nextState) => ({
|
|
391
|
-
isHealthy: nextState.isWsConnectionHealthy,
|
|
392
|
-
});
|
|
393
|
-
|
|
394
278
|
const decoders = {};
|
|
395
279
|
const decodeDatetimeType = (input) => typeof input === 'number'
|
|
396
280
|
? new Date(Math.floor(input / 1000000))
|
|
@@ -2835,6 +2719,13 @@ function removeConnectionEventListeners(cb) {
|
|
|
2835
2719
|
window.removeEventListener('online', cb);
|
|
2836
2720
|
}
|
|
2837
2721
|
}
|
|
2722
|
+
const streamDevToken = (userId) => {
|
|
2723
|
+
return [
|
|
2724
|
+
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9', // {"alg": "HS256", "typ": "JWT"}
|
|
2725
|
+
window.btoa(JSON.stringify({ user_id: userId })),
|
|
2726
|
+
'devtoken', // hardcoded signature
|
|
2727
|
+
].join('.');
|
|
2728
|
+
};
|
|
2838
2729
|
const capitalize = (s) => {
|
|
2839
2730
|
return `${s.charAt(0).toLocaleUpperCase()}${s.slice(1)}`;
|
|
2840
2731
|
};
|
|
@@ -3105,7 +2996,10 @@ class StableWSConnection {
|
|
|
3105
2996
|
this.onmessage = (wsID, event) => {
|
|
3106
2997
|
if (this.wsID !== wsID)
|
|
3107
2998
|
return;
|
|
3108
|
-
this._log('onmessage() - onmessage callback', {
|
|
2999
|
+
this._log('onmessage() - onmessage callback', {
|
|
3000
|
+
event: { ...event, data: JSON.parse(event.data) },
|
|
3001
|
+
wsID,
|
|
3002
|
+
});
|
|
3109
3003
|
let data = typeof event.data === 'string' ? JSON.parse(event.data) : null;
|
|
3110
3004
|
this.decoders.forEach((decode) => {
|
|
3111
3005
|
data = decode(data);
|
|
@@ -4120,8 +4014,15 @@ const updateBookmarkInActivities = (event, activities, isCurrentUser) => {
|
|
|
4120
4014
|
return updateActivityInActivities(updatedActivity, activities);
|
|
4121
4015
|
};
|
|
4122
4016
|
|
|
4123
|
-
const
|
|
4124
|
-
|
|
4017
|
+
const checkHasAnotherPage = (v, cursor) => (typeof v === 'undefined' && typeof cursor === 'undefined') ||
|
|
4018
|
+
typeof cursor === 'string';
|
|
4019
|
+
const isCommentResponse = (entity) => {
|
|
4020
|
+
return typeof entity?.object_id === 'string';
|
|
4021
|
+
};
|
|
4022
|
+
const Constants = {
|
|
4023
|
+
DEFAULT_COMMENT_PAGINATION: 'first',
|
|
4024
|
+
};
|
|
4025
|
+
|
|
4125
4026
|
class Feed extends FeedApi {
|
|
4126
4027
|
constructor(client, groupId, id, data) {
|
|
4127
4028
|
// Need this ugly cast because fileUpload endpoints :(
|
|
@@ -4194,7 +4095,7 @@ class Feed extends FeedApi {
|
|
|
4194
4095
|
const entityState = currentState.comments_by_entity_id[forId];
|
|
4195
4096
|
const newComments = entityState?.comments?.concat([]) ?? [];
|
|
4196
4097
|
if (entityState?.pagination?.sort === 'last' &&
|
|
4197
|
-
entityState?.pagination.next
|
|
4098
|
+
!checkHasAnotherPage(entityState.comments, entityState?.pagination.next)) {
|
|
4198
4099
|
newComments.unshift(comment);
|
|
4199
4100
|
}
|
|
4200
4101
|
else if (entityState?.pagination?.sort === 'first') {
|
|
@@ -4281,7 +4182,7 @@ class Feed extends FeedApi {
|
|
|
4281
4182
|
...currentState,
|
|
4282
4183
|
...event.follow.source_feed,
|
|
4283
4184
|
};
|
|
4284
|
-
if (currentState.following_pagination?.next
|
|
4185
|
+
if (!checkHasAnotherPage(currentState.following, currentState.following_pagination?.next)) {
|
|
4285
4186
|
// TODO: respect sort
|
|
4286
4187
|
newState.following = currentState.following
|
|
4287
4188
|
? currentState.following.concat(event.follow)
|
|
@@ -4302,7 +4203,7 @@ class Feed extends FeedApi {
|
|
|
4302
4203
|
? currentState.own_follows.concat(event.follow)
|
|
4303
4204
|
: [event.follow];
|
|
4304
4205
|
}
|
|
4305
|
-
if (currentState.followers_pagination?.next
|
|
4206
|
+
if (!checkHasAnotherPage(currentState.followers, currentState.followers_pagination?.next)) {
|
|
4306
4207
|
// TODO: respect sort
|
|
4307
4208
|
newState.followers = currentState.followers
|
|
4308
4209
|
? currentState.followers.concat(event.follow)
|
|
@@ -4343,40 +4244,60 @@ class Feed extends FeedApi {
|
|
|
4343
4244
|
'feeds.comment.reaction.deleted': this.handleCommentReactionEvent.bind(this),
|
|
4344
4245
|
'feeds.comment.reaction.updated': Feed.noop,
|
|
4345
4246
|
'feeds.feed_member.added': (event) => {
|
|
4346
|
-
const {
|
|
4347
|
-
// do not add a member if the pagination has reached the end of the list
|
|
4348
|
-
if (this.currentState.member_pagination?.next !== END_OF_LIST)
|
|
4349
|
-
return;
|
|
4247
|
+
const { connectedUser } = this.client.state.getLatestValue();
|
|
4350
4248
|
this.state.next((currentState) => {
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4249
|
+
let newState;
|
|
4250
|
+
if (!checkHasAnotherPage(currentState.members, currentState.member_pagination?.next)) {
|
|
4251
|
+
newState ?? (newState = {
|
|
4252
|
+
...currentState,
|
|
4253
|
+
});
|
|
4254
|
+
newState.members = newState.members?.concat(event.member) ?? [
|
|
4255
|
+
event.member,
|
|
4256
|
+
];
|
|
4257
|
+
}
|
|
4258
|
+
if (connectedUser?.id === event.member.user.id) {
|
|
4259
|
+
newState ?? (newState = {
|
|
4260
|
+
...currentState,
|
|
4261
|
+
});
|
|
4262
|
+
newState.own_membership = event.member;
|
|
4263
|
+
}
|
|
4264
|
+
return newState ?? currentState;
|
|
4358
4265
|
});
|
|
4359
4266
|
},
|
|
4360
4267
|
'feeds.feed_member.removed': (event) => {
|
|
4268
|
+
const { connectedUser } = this.client.state.getLatestValue();
|
|
4361
4269
|
this.state.next((currentState) => {
|
|
4362
|
-
|
|
4270
|
+
const newState = {
|
|
4363
4271
|
...currentState,
|
|
4364
4272
|
members: currentState.members?.filter((member) => member.user.id !== event.user?.id),
|
|
4365
4273
|
};
|
|
4274
|
+
if (connectedUser?.id === event.member_id) {
|
|
4275
|
+
delete newState.own_membership;
|
|
4276
|
+
}
|
|
4277
|
+
return newState;
|
|
4366
4278
|
});
|
|
4367
4279
|
},
|
|
4368
4280
|
'feeds.feed_member.updated': (event) => {
|
|
4281
|
+
const { connectedUser } = this.client.state.getLatestValue();
|
|
4369
4282
|
this.state.next((currentState) => {
|
|
4370
4283
|
const memberIndex = currentState.members?.findIndex((member) => member.user.id === event.member.user.id) ?? -1;
|
|
4284
|
+
let newState;
|
|
4371
4285
|
if (memberIndex !== -1) {
|
|
4286
|
+
// if there's an index, there's a member to update
|
|
4372
4287
|
const newMembers = [...currentState.members];
|
|
4373
4288
|
newMembers[memberIndex] = event.member;
|
|
4374
|
-
|
|
4289
|
+
newState ?? (newState = {
|
|
4375
4290
|
...currentState,
|
|
4376
|
-
|
|
4377
|
-
|
|
4291
|
+
});
|
|
4292
|
+
newState.members = newMembers;
|
|
4293
|
+
}
|
|
4294
|
+
if (connectedUser?.id === event.member.user.id) {
|
|
4295
|
+
newState ?? (newState = {
|
|
4296
|
+
...currentState,
|
|
4297
|
+
});
|
|
4298
|
+
newState.own_membership = event.member;
|
|
4378
4299
|
}
|
|
4379
|
-
return currentState;
|
|
4300
|
+
return newState ?? currentState;
|
|
4380
4301
|
});
|
|
4381
4302
|
},
|
|
4382
4303
|
// the poll events should be removed from here
|
|
@@ -4502,29 +4423,6 @@ class Feed extends FeedApi {
|
|
|
4502
4423
|
...currentState,
|
|
4503
4424
|
...responseCopy,
|
|
4504
4425
|
};
|
|
4505
|
-
// if there is no next cursor, set it to END_OF_LIST
|
|
4506
|
-
// request has to have a limit set for this to work
|
|
4507
|
-
if ((request?.followers_pagination?.limit ?? 0) > 0 &&
|
|
4508
|
-
typeof nextState.followers_pagination?.next === 'undefined') {
|
|
4509
|
-
nextState.followers_pagination = {
|
|
4510
|
-
...nextState.followers_pagination,
|
|
4511
|
-
next: END_OF_LIST,
|
|
4512
|
-
};
|
|
4513
|
-
}
|
|
4514
|
-
if ((request?.following_pagination?.limit ?? 0) > 0 &&
|
|
4515
|
-
typeof nextState.following_pagination?.next === 'undefined') {
|
|
4516
|
-
nextState.following_pagination = {
|
|
4517
|
-
...nextState.following_pagination,
|
|
4518
|
-
next: END_OF_LIST,
|
|
4519
|
-
};
|
|
4520
|
-
}
|
|
4521
|
-
if ((request?.member_pagination?.limit ?? 0) > 0 &&
|
|
4522
|
-
typeof nextState.member_pagination?.next === 'undefined') {
|
|
4523
|
-
nextState.member_pagination = {
|
|
4524
|
-
...nextState.member_pagination,
|
|
4525
|
-
next: END_OF_LIST,
|
|
4526
|
-
};
|
|
4527
|
-
}
|
|
4528
4426
|
if (!request?.followers_pagination?.limit) {
|
|
4529
4427
|
delete nextState.followers;
|
|
4530
4428
|
}
|
|
@@ -4615,6 +4513,7 @@ class Feed extends FeedApi {
|
|
|
4615
4513
|
});
|
|
4616
4514
|
}
|
|
4617
4515
|
async loadNextPageComments({ forId, base, sort, parentId, }) {
|
|
4516
|
+
let error;
|
|
4618
4517
|
try {
|
|
4619
4518
|
this.state.next((currentState) => ({
|
|
4620
4519
|
...currentState,
|
|
@@ -4629,7 +4528,7 @@ class Feed extends FeedApi {
|
|
|
4629
4528
|
},
|
|
4630
4529
|
},
|
|
4631
4530
|
}));
|
|
4632
|
-
const { next: newNextCursor
|
|
4531
|
+
const { next: newNextCursor, comments } = await base();
|
|
4633
4532
|
this.state.next((currentState) => {
|
|
4634
4533
|
const newPagination = {
|
|
4635
4534
|
...currentState.comments_by_entity_id[forId]?.pagination,
|
|
@@ -4654,9 +4553,8 @@ class Feed extends FeedApi {
|
|
|
4654
4553
|
};
|
|
4655
4554
|
});
|
|
4656
4555
|
}
|
|
4657
|
-
catch (
|
|
4658
|
-
|
|
4659
|
-
// TODO: figure out how to handle errorss
|
|
4556
|
+
catch (e) {
|
|
4557
|
+
error = e;
|
|
4660
4558
|
}
|
|
4661
4559
|
finally {
|
|
4662
4560
|
this.state.next((currentState) => ({
|
|
@@ -4673,15 +4571,21 @@ class Feed extends FeedApi {
|
|
|
4673
4571
|
},
|
|
4674
4572
|
}));
|
|
4675
4573
|
}
|
|
4574
|
+
if (error) {
|
|
4575
|
+
throw error;
|
|
4576
|
+
}
|
|
4676
4577
|
}
|
|
4677
4578
|
async loadNextPageActivityComments(activity, request) {
|
|
4678
|
-
const
|
|
4679
|
-
const
|
|
4680
|
-
const
|
|
4681
|
-
const
|
|
4682
|
-
const
|
|
4683
|
-
|
|
4579
|
+
const currentEntityState = this.currentState.comments_by_entity_id[activity.id];
|
|
4580
|
+
const currentPagination = currentEntityState?.pagination;
|
|
4581
|
+
const currentNextCursor = currentPagination?.next;
|
|
4582
|
+
const currentSort = currentPagination?.sort;
|
|
4583
|
+
const isLoading = currentPagination?.loading_next_page;
|
|
4584
|
+
const sort = currentSort ?? request?.sort ?? Constants.DEFAULT_COMMENT_PAGINATION;
|
|
4585
|
+
if (isLoading ||
|
|
4586
|
+
!checkHasAnotherPage(currentEntityState?.comments, currentNextCursor)) {
|
|
4684
4587
|
return;
|
|
4588
|
+
}
|
|
4685
4589
|
await this.loadNextPageComments({
|
|
4686
4590
|
forId: activity.id,
|
|
4687
4591
|
base: () => this.client.getComments({
|
|
@@ -4695,20 +4599,25 @@ class Feed extends FeedApi {
|
|
|
4695
4599
|
});
|
|
4696
4600
|
}
|
|
4697
4601
|
async loadNextPageCommentReplies(comment, request) {
|
|
4698
|
-
const
|
|
4699
|
-
const
|
|
4700
|
-
const
|
|
4701
|
-
const
|
|
4702
|
-
const
|
|
4703
|
-
|
|
4602
|
+
const currentEntityState = this.currentState.comments_by_entity_id[comment.id];
|
|
4603
|
+
const currentPagination = currentEntityState?.pagination;
|
|
4604
|
+
const currentNextCursor = currentPagination?.next;
|
|
4605
|
+
const currentSort = currentPagination?.sort;
|
|
4606
|
+
const isLoading = currentPagination?.loading_next_page;
|
|
4607
|
+
const sort = currentSort ?? request?.sort ?? Constants.DEFAULT_COMMENT_PAGINATION;
|
|
4608
|
+
if (isLoading ||
|
|
4609
|
+
!checkHasAnotherPage(currentEntityState?.comments, currentNextCursor)) {
|
|
4704
4610
|
return;
|
|
4611
|
+
}
|
|
4705
4612
|
await this.loadNextPageComments({
|
|
4706
4613
|
forId: comment.id,
|
|
4707
4614
|
base: () => this.client.getCommentReplies({
|
|
4708
4615
|
...request,
|
|
4709
4616
|
comment_id: comment.id,
|
|
4710
4617
|
// use known sort first (prevents broken pagination)
|
|
4711
|
-
sort: currentSort ??
|
|
4618
|
+
sort: currentSort ??
|
|
4619
|
+
request?.sort ??
|
|
4620
|
+
Constants.DEFAULT_COMMENT_PAGINATION,
|
|
4712
4621
|
next: currentNextCursor,
|
|
4713
4622
|
}),
|
|
4714
4623
|
parentId: comment.parent_id ?? comment.object_id,
|
|
@@ -4718,10 +4627,14 @@ class Feed extends FeedApi {
|
|
|
4718
4627
|
async loadNextPageFollows(type, request) {
|
|
4719
4628
|
const paginationKey = `${type}_pagination`;
|
|
4720
4629
|
const method = `query${capitalize(type)}`;
|
|
4630
|
+
const currentFollows = this.currentState[type];
|
|
4721
4631
|
const currentNextCursor = this.currentState[paginationKey]?.next;
|
|
4722
4632
|
const isLoading = this.currentState[paginationKey]?.loading_next_page;
|
|
4723
|
-
|
|
4633
|
+
const sort = this.currentState[paginationKey]?.sort ?? request.sort;
|
|
4634
|
+
let error;
|
|
4635
|
+
if (isLoading || !checkHasAnotherPage(currentFollows, currentNextCursor)) {
|
|
4724
4636
|
return;
|
|
4637
|
+
}
|
|
4725
4638
|
try {
|
|
4726
4639
|
this.state.next((currentState) => {
|
|
4727
4640
|
return {
|
|
@@ -4732,9 +4645,10 @@ class Feed extends FeedApi {
|
|
|
4732
4645
|
},
|
|
4733
4646
|
};
|
|
4734
4647
|
});
|
|
4735
|
-
const { next: newNextCursor
|
|
4648
|
+
const { next: newNextCursor, follows } = await this[method]({
|
|
4736
4649
|
...request,
|
|
4737
4650
|
next: currentNextCursor,
|
|
4651
|
+
sort,
|
|
4738
4652
|
});
|
|
4739
4653
|
this.state.next((currentState) => ({
|
|
4740
4654
|
...currentState,
|
|
@@ -4744,12 +4658,12 @@ class Feed extends FeedApi {
|
|
|
4744
4658
|
[paginationKey]: {
|
|
4745
4659
|
...currentState[paginationKey],
|
|
4746
4660
|
next: newNextCursor,
|
|
4661
|
+
sort,
|
|
4747
4662
|
},
|
|
4748
4663
|
}));
|
|
4749
4664
|
}
|
|
4750
|
-
catch (
|
|
4751
|
-
|
|
4752
|
-
// TODO: figure out how to handle errorss
|
|
4665
|
+
catch (e) {
|
|
4666
|
+
error = e;
|
|
4753
4667
|
}
|
|
4754
4668
|
finally {
|
|
4755
4669
|
this.state.next((currentState) => {
|
|
@@ -4762,6 +4676,9 @@ class Feed extends FeedApi {
|
|
|
4762
4676
|
};
|
|
4763
4677
|
});
|
|
4764
4678
|
}
|
|
4679
|
+
if (error) {
|
|
4680
|
+
throw error;
|
|
4681
|
+
}
|
|
4765
4682
|
}
|
|
4766
4683
|
async loadNextPageFollowers(request) {
|
|
4767
4684
|
await this.loadNextPageFollows('followers', request);
|
|
@@ -4769,6 +4686,59 @@ class Feed extends FeedApi {
|
|
|
4769
4686
|
async loadNextPageFollowing(request) {
|
|
4770
4687
|
await this.loadNextPageFollows('following', request);
|
|
4771
4688
|
}
|
|
4689
|
+
async loadNextPageMembers(request) {
|
|
4690
|
+
const currentMembers = this.currentState.members;
|
|
4691
|
+
const currentNextCursor = this.currentState.member_pagination?.next;
|
|
4692
|
+
const isLoading = this.currentState.member_pagination?.loading_next_page;
|
|
4693
|
+
const sort = this.currentState.member_pagination?.sort ?? request.sort;
|
|
4694
|
+
let error;
|
|
4695
|
+
if (isLoading || !checkHasAnotherPage(currentMembers, currentNextCursor)) {
|
|
4696
|
+
return;
|
|
4697
|
+
}
|
|
4698
|
+
try {
|
|
4699
|
+
this.state.next((currentState) => ({
|
|
4700
|
+
...currentState,
|
|
4701
|
+
member_pagination: {
|
|
4702
|
+
...currentState.member_pagination,
|
|
4703
|
+
loading_next_page: true,
|
|
4704
|
+
},
|
|
4705
|
+
}));
|
|
4706
|
+
const { next: newNextCursor, members } = await this.client.queryFeedMembers({
|
|
4707
|
+
...request,
|
|
4708
|
+
sort,
|
|
4709
|
+
feed_id: this.id,
|
|
4710
|
+
feed_group_id: this.group,
|
|
4711
|
+
next: currentNextCursor,
|
|
4712
|
+
});
|
|
4713
|
+
this.state.next((currentState) => ({
|
|
4714
|
+
...currentState,
|
|
4715
|
+
members: currentState.members
|
|
4716
|
+
? currentState.members.concat(members)
|
|
4717
|
+
: members,
|
|
4718
|
+
member_pagination: {
|
|
4719
|
+
...currentState.member_pagination,
|
|
4720
|
+
next: newNextCursor,
|
|
4721
|
+
// set sort if not defined yet
|
|
4722
|
+
sort: currentState.member_pagination?.sort ?? request.sort,
|
|
4723
|
+
},
|
|
4724
|
+
}));
|
|
4725
|
+
}
|
|
4726
|
+
catch (e) {
|
|
4727
|
+
error = e;
|
|
4728
|
+
}
|
|
4729
|
+
finally {
|
|
4730
|
+
this.state.next((currentState) => ({
|
|
4731
|
+
...currentState,
|
|
4732
|
+
member_pagination: {
|
|
4733
|
+
...currentState.member_pagination,
|
|
4734
|
+
loading_next_page: false,
|
|
4735
|
+
},
|
|
4736
|
+
}));
|
|
4737
|
+
}
|
|
4738
|
+
if (error) {
|
|
4739
|
+
throw error;
|
|
4740
|
+
}
|
|
4741
|
+
}
|
|
4772
4742
|
/**
|
|
4773
4743
|
* Method which queries followers of this feed (feeds which target this feed).
|
|
4774
4744
|
*
|
|
@@ -5259,6 +5229,9 @@ class FeedsClient extends FeedsApi {
|
|
|
5259
5229
|
throw err;
|
|
5260
5230
|
}
|
|
5261
5231
|
};
|
|
5232
|
+
this.devToken = (userId) => {
|
|
5233
|
+
return streamDevToken(userId);
|
|
5234
|
+
};
|
|
5262
5235
|
this.closePoll = async (request) => {
|
|
5263
5236
|
return await this.updatePollPartial({
|
|
5264
5237
|
poll_id: request.poll_id,
|
|
@@ -5517,18 +5490,313 @@ const useCreateFeedsClient = ({ apiKey, tokenOrProvider, userData, options, }) =
|
|
|
5517
5490
|
return client;
|
|
5518
5491
|
};
|
|
5519
5492
|
|
|
5493
|
+
const StreamFeedsContext = react.createContext(undefined);
|
|
5494
|
+
/**
|
|
5495
|
+
* Hook to access the nearest FeedsClient instance.
|
|
5496
|
+
*/
|
|
5497
|
+
const useFeedsClient = () => {
|
|
5498
|
+
return react.useContext(StreamFeedsContext);
|
|
5499
|
+
};
|
|
5500
|
+
|
|
5501
|
+
/**
|
|
5502
|
+
* A React hook that returns the currently connected user on a `FeedsClient` instance and null otherwise.
|
|
5503
|
+
*/
|
|
5504
|
+
const useClientConnectedUser = () => {
|
|
5505
|
+
const client = useFeedsClient();
|
|
5506
|
+
const { user } = useStateStore(client?.state, selector$5) ?? {};
|
|
5507
|
+
return user;
|
|
5508
|
+
};
|
|
5509
|
+
const selector$5 = (nextState) => ({
|
|
5510
|
+
user: nextState.connectedUser,
|
|
5511
|
+
});
|
|
5512
|
+
|
|
5513
|
+
/**
|
|
5514
|
+
* A React hook that returns the websocket connection state of `FeedsClient`.
|
|
5515
|
+
*/
|
|
5516
|
+
const useWsConnectionState = () => {
|
|
5517
|
+
const client = useFeedsClient();
|
|
5518
|
+
const { isHealthy } = useStateStore(client?.state, selector$4) ?? {};
|
|
5519
|
+
return { isHealthy };
|
|
5520
|
+
};
|
|
5521
|
+
const selector$4 = (nextState) => ({
|
|
5522
|
+
isHealthy: nextState.isWsConnectionHealthy,
|
|
5523
|
+
});
|
|
5524
|
+
|
|
5525
|
+
const StreamFeedContext = react.createContext(undefined);
|
|
5526
|
+
/**
|
|
5527
|
+
* Hook to access the nearest Feed instance.
|
|
5528
|
+
*/
|
|
5529
|
+
const useFeedContext = () => {
|
|
5530
|
+
return react.useContext(StreamFeedContext);
|
|
5531
|
+
};
|
|
5532
|
+
|
|
5533
|
+
/**
|
|
5534
|
+
* A utility hook implementing a stable callback. It takes in an unstable method that
|
|
5535
|
+
* is supposed to be invoked somewhere deeper in the DOM tree without making it
|
|
5536
|
+
* change its reference every time the parent component rerenders. It will also return
|
|
5537
|
+
* the value of the callback if it does return one.
|
|
5538
|
+
* A common use-case would be having a function whose invocation depends on state
|
|
5539
|
+
* somewhere high up in the DOM tree and wanting to use the same function deeper
|
|
5540
|
+
* down, for example in a leaf node and simply using useCallback results in
|
|
5541
|
+
* cascading dependency hell. If we wrap it in useStableCallback, we would be able
|
|
5542
|
+
* to:
|
|
5543
|
+
* - Use the same function as a dependency of another hook (since it is stable)
|
|
5544
|
+
* - Still invoke it and get the latest state
|
|
5545
|
+
*
|
|
5546
|
+
* **Caveats:**
|
|
5547
|
+
* - Never wrap a function that is supposed to return a React.ReactElement in
|
|
5548
|
+
* useStableCallback, since React will not know that the DOM needs to be updated
|
|
5549
|
+
* whenever the callback value changes (for example, renderItem from FlatList must
|
|
5550
|
+
* never be wrapped in this hook)
|
|
5551
|
+
* - Always prefer using a standard useCallback/stable function wherever possible
|
|
5552
|
+
* (the purpose of useStableCallback is to bridge the gap between top level contexts
|
|
5553
|
+
* and cascading rereders in downstream components - **not** as an escape hatch)
|
|
5554
|
+
* @param callback - the callback we want to stabilize
|
|
5555
|
+
*/
|
|
5556
|
+
const useStableCallback = (callback) => {
|
|
5557
|
+
const ref = react.useRef(callback);
|
|
5558
|
+
ref.current = callback;
|
|
5559
|
+
return react.useCallback((...args) => {
|
|
5560
|
+
return ref.current(...args);
|
|
5561
|
+
}, []);
|
|
5562
|
+
};
|
|
5563
|
+
|
|
5564
|
+
/**
|
|
5565
|
+
* A React hook that returns a reactive object containing the current activities,
|
|
5566
|
+
* loading state and whether there is a next page to paginate to or not.
|
|
5567
|
+
*/
|
|
5568
|
+
const useFeedActivities = (feedFromProps) => {
|
|
5569
|
+
const feedFromContext = useFeedContext();
|
|
5570
|
+
const feed = feedFromProps ?? feedFromContext;
|
|
5571
|
+
const data = useStateStore(feed?.state, selector$3);
|
|
5572
|
+
const loadNextPage = useStableCallback(async () => {
|
|
5573
|
+
if (!feed || !data?.hasNextPage || data?.isLoading) {
|
|
5574
|
+
return;
|
|
5575
|
+
}
|
|
5576
|
+
await feed.getNextPage();
|
|
5577
|
+
});
|
|
5578
|
+
return react.useMemo(() => ({ ...data, loadNextPage }), [data, loadNextPage]);
|
|
5579
|
+
};
|
|
5580
|
+
const selector$3 = (nextState) => ({
|
|
5581
|
+
isLoading: nextState.is_loading_activities,
|
|
5582
|
+
hasNextPage: typeof nextState.next !== 'undefined',
|
|
5583
|
+
activities: nextState.activities ?? [],
|
|
5584
|
+
});
|
|
5585
|
+
|
|
5586
|
+
function useComments({ feed: feedFromProps, parent, }) {
|
|
5587
|
+
const feedFromContext = useFeedContext();
|
|
5588
|
+
const feed = feedFromProps ?? feedFromContext;
|
|
5589
|
+
const selector = react.useCallback((state) => ({
|
|
5590
|
+
comments: state.comments_by_entity_id?.[parent.id]?.comments,
|
|
5591
|
+
comments_pagination: state.comments_by_entity_id?.[parent.id]?.pagination,
|
|
5592
|
+
}), [parent.id]);
|
|
5593
|
+
const data = useStateStore(feed?.state, selector);
|
|
5594
|
+
const loadNextPage = react.useMemo(() => {
|
|
5595
|
+
if (!feed)
|
|
5596
|
+
return undefined;
|
|
5597
|
+
return (request) => {
|
|
5598
|
+
if (isCommentResponse(parent)) {
|
|
5599
|
+
return feed.loadNextPageCommentReplies(parent, request);
|
|
5600
|
+
}
|
|
5601
|
+
else {
|
|
5602
|
+
return feed.loadNextPageActivityComments(parent, request);
|
|
5603
|
+
}
|
|
5604
|
+
};
|
|
5605
|
+
}, [feed, parent]);
|
|
5606
|
+
return react.useMemo(() => {
|
|
5607
|
+
if (!data) {
|
|
5608
|
+
return undefined;
|
|
5609
|
+
}
|
|
5610
|
+
return {
|
|
5611
|
+
...data,
|
|
5612
|
+
hasNextPage: checkHasAnotherPage(data.comments, data.comments_pagination?.next),
|
|
5613
|
+
isLoadingNextPage: data?.comments_pagination?.loading_next_page ?? false,
|
|
5614
|
+
loadNextPage,
|
|
5615
|
+
};
|
|
5616
|
+
}, [data, loadNextPage]);
|
|
5617
|
+
}
|
|
5618
|
+
|
|
5619
|
+
const FeedOwnCapability = {
|
|
5620
|
+
ADD_ACTIVITY: 'add-activity',
|
|
5621
|
+
ADD_ACTIVITY_REACTION: 'add-activity-reaction',
|
|
5622
|
+
ADD_COMMENT: 'add-comment',
|
|
5623
|
+
ADD_COMMENT_REACTION: 'add-comment-reaction',
|
|
5624
|
+
BOOKMARK_ACTIVITY: 'bookmark-activity',
|
|
5625
|
+
CREATE_FEED: 'create-feed',
|
|
5626
|
+
DELETE_BOOKMARK: 'delete-bookmark',
|
|
5627
|
+
DELETE_COMMENT: 'delete-comment',
|
|
5628
|
+
DELETE_FEED: 'delete-feed',
|
|
5629
|
+
EDIT_BOOKMARK: 'edit-bookmark',
|
|
5630
|
+
FOLLOW: 'follow',
|
|
5631
|
+
INVITE_FEED: 'invite-feed',
|
|
5632
|
+
JOIN_FEED: 'join-feed',
|
|
5633
|
+
LEAVE_FEED: 'leave-feed',
|
|
5634
|
+
MANAGE_FEED_GROUP: 'manage-feed-group',
|
|
5635
|
+
MARK_ACTIVITY: 'mark-activity',
|
|
5636
|
+
PIN_ACTIVITY: 'pin-activity',
|
|
5637
|
+
QUERY_FEED_MEMBERS: 'query-feed-members',
|
|
5638
|
+
QUERY_FOLLOWS: 'query-follows',
|
|
5639
|
+
READ_ACTIVITIES: 'read-activities',
|
|
5640
|
+
READ_FEED: 'read-feed',
|
|
5641
|
+
REMOVE_ACTIVITY: 'remove-activity',
|
|
5642
|
+
REMOVE_ACTIVITY_REACTION: 'remove-activity-reaction',
|
|
5643
|
+
REMOVE_COMMENT_REACTION: 'remove-comment-reaction',
|
|
5644
|
+
UNFOLLOW: 'unfollow',
|
|
5645
|
+
UPDATE_ACTIVITY: 'update-activity',
|
|
5646
|
+
UPDATE_COMMENT: 'update-comment',
|
|
5647
|
+
UPDATE_FEED: 'update-feed',
|
|
5648
|
+
UPDATE_FEED_FOLLOWERS: 'update-feed-followers',
|
|
5649
|
+
UPDATE_FEED_MEMBERS: 'update-feed-members',
|
|
5650
|
+
};
|
|
5651
|
+
|
|
5652
|
+
const stableEmptyArray = [];
|
|
5653
|
+
const selector$2 = (currentState) => ({
|
|
5654
|
+
oc: currentState.own_capabilities ?? stableEmptyArray,
|
|
5655
|
+
});
|
|
5656
|
+
const useOwnCapabilities = (feedFromProps) => {
|
|
5657
|
+
const feedFromContext = useFeedContext();
|
|
5658
|
+
const feed = feedFromProps ?? feedFromContext;
|
|
5659
|
+
const { oc = stableEmptyArray } = useStateStore(feed?.state, selector$2) ?? {};
|
|
5660
|
+
return react.useMemo(() => ({
|
|
5661
|
+
canAddActivity: oc.indexOf(FeedOwnCapability.ADD_ACTIVITY) > -1,
|
|
5662
|
+
canAddActivityReaction: oc.indexOf(FeedOwnCapability.ADD_ACTIVITY_REACTION) > -1,
|
|
5663
|
+
canAddComment: oc.indexOf(FeedOwnCapability.ADD_COMMENT) > -1,
|
|
5664
|
+
canAddCommentReaction: oc.indexOf(FeedOwnCapability.ADD_COMMENT_REACTION) > -1,
|
|
5665
|
+
canBookmarkActivity: oc.indexOf(FeedOwnCapability.BOOKMARK_ACTIVITY) > -1,
|
|
5666
|
+
canCreateFeed: oc.indexOf(FeedOwnCapability.CREATE_FEED) > -1,
|
|
5667
|
+
canDeleteBookmark: oc.indexOf(FeedOwnCapability.DELETE_BOOKMARK) > -1,
|
|
5668
|
+
canDeleteComment: oc.indexOf(FeedOwnCapability.DELETE_COMMENT) > -1,
|
|
5669
|
+
canDeleteFeed: oc.indexOf(FeedOwnCapability.DELETE_FEED) > -1,
|
|
5670
|
+
canEditBookmark: oc.indexOf(FeedOwnCapability.EDIT_BOOKMARK) > -1,
|
|
5671
|
+
canFollow: oc.indexOf(FeedOwnCapability.FOLLOW) > -1,
|
|
5672
|
+
canRemoveActivity: oc.indexOf(FeedOwnCapability.REMOVE_ACTIVITY) > -1,
|
|
5673
|
+
canRemoveActivityReaction: oc.indexOf(FeedOwnCapability.REMOVE_ACTIVITY_REACTION) > -1,
|
|
5674
|
+
canRemoveCommentReaction: oc.indexOf(FeedOwnCapability.REMOVE_COMMENT_REACTION) > -1,
|
|
5675
|
+
canUnfollow: oc.indexOf(FeedOwnCapability.UNFOLLOW) > -1,
|
|
5676
|
+
canUpdateFeed: oc.indexOf(FeedOwnCapability.UPDATE_FEED) > -1,
|
|
5677
|
+
canInviteFeed: oc.indexOf(FeedOwnCapability.INVITE_FEED) > -1,
|
|
5678
|
+
canJoinFeed: oc.indexOf(FeedOwnCapability.JOIN_FEED) > -1,
|
|
5679
|
+
canLeaveFeed: oc.indexOf(FeedOwnCapability.LEAVE_FEED) > -1,
|
|
5680
|
+
canManageFeedGroup: oc.indexOf(FeedOwnCapability.MANAGE_FEED_GROUP) > -1,
|
|
5681
|
+
canMarkActivity: oc.indexOf(FeedOwnCapability.MARK_ACTIVITY) > -1,
|
|
5682
|
+
canPinActivity: oc.indexOf(FeedOwnCapability.PIN_ACTIVITY) > -1,
|
|
5683
|
+
canQueryFeedMembers: oc.indexOf(FeedOwnCapability.QUERY_FEED_MEMBERS) > -1,
|
|
5684
|
+
canQueryFollows: oc.indexOf(FeedOwnCapability.QUERY_FOLLOWS) > -1,
|
|
5685
|
+
canReadActivities: oc.indexOf(FeedOwnCapability.READ_ACTIVITIES) > -1,
|
|
5686
|
+
canReadFeed: oc.indexOf(FeedOwnCapability.READ_FEED) > -1,
|
|
5687
|
+
canUpdateActivity: oc.indexOf(FeedOwnCapability.UPDATE_ACTIVITY) > -1,
|
|
5688
|
+
canUpdateComment: oc.indexOf(FeedOwnCapability.UPDATE_COMMENT) > -1,
|
|
5689
|
+
canUpdateFeedFollowers: oc.indexOf(FeedOwnCapability.UPDATE_FEED_FOLLOWERS) > -1,
|
|
5690
|
+
canUpdateFeedMembers: oc.indexOf(FeedOwnCapability.UPDATE_FEED_MEMBERS) > -1,
|
|
5691
|
+
}), [oc]);
|
|
5692
|
+
};
|
|
5693
|
+
|
|
5694
|
+
const selector$1 = ({ follower_count, followers, followers_pagination, }) => ({
|
|
5695
|
+
follower_count,
|
|
5696
|
+
followers,
|
|
5697
|
+
followers_pagination,
|
|
5698
|
+
});
|
|
5699
|
+
function useFollowers(feedFromProps) {
|
|
5700
|
+
const feedFromContext = useFeedContext();
|
|
5701
|
+
const feed = feedFromProps ?? feedFromContext;
|
|
5702
|
+
const data = useStateStore(feed?.state, selector$1);
|
|
5703
|
+
const loadNextPage = react.useCallback((...options) => feed?.loadNextPageFollowers(...options), [feed]);
|
|
5704
|
+
return react.useMemo(() => {
|
|
5705
|
+
if (!data) {
|
|
5706
|
+
return undefined;
|
|
5707
|
+
}
|
|
5708
|
+
return {
|
|
5709
|
+
...data,
|
|
5710
|
+
isLoadingNextPage: data.followers_pagination?.loading_next_page ?? false,
|
|
5711
|
+
hasNextPage: checkHasAnotherPage(data.followers, data.followers_pagination?.next),
|
|
5712
|
+
loadNextPage,
|
|
5713
|
+
};
|
|
5714
|
+
}, [data, loadNextPage]);
|
|
5715
|
+
}
|
|
5716
|
+
|
|
5717
|
+
const selector = ({ following_count, following, following_pagination, }) => ({
|
|
5718
|
+
following_count,
|
|
5719
|
+
following,
|
|
5720
|
+
following_pagination,
|
|
5721
|
+
});
|
|
5722
|
+
function useFollowing(feedFromProps) {
|
|
5723
|
+
const feedFromContext = useFeedContext();
|
|
5724
|
+
const feed = feedFromProps ?? feedFromContext;
|
|
5725
|
+
const data = useStateStore(feed?.state, selector);
|
|
5726
|
+
const loadNextPage = react.useCallback((...options) => feed?.loadNextPageFollowing(...options), [feed]);
|
|
5727
|
+
return react.useMemo(() => {
|
|
5728
|
+
if (!data) {
|
|
5729
|
+
return undefined;
|
|
5730
|
+
}
|
|
5731
|
+
return {
|
|
5732
|
+
...data,
|
|
5733
|
+
isLoadingNextPage: data.following_pagination?.loading_next_page ?? false,
|
|
5734
|
+
hasNextPage: checkHasAnotherPage(data.following, data.following_pagination?.next),
|
|
5735
|
+
loadNextPage,
|
|
5736
|
+
};
|
|
5737
|
+
}, [data, loadNextPage]);
|
|
5738
|
+
}
|
|
5739
|
+
|
|
5740
|
+
/**
|
|
5741
|
+
* A utility hook that takes in an entity and a reaction type, and creates reaction actions
|
|
5742
|
+
* that can then be used on the UI. The entity can be either an ActivityResponse or a CommentResponse
|
|
5743
|
+
* as the hook determines internally which APIs it is supposed to use, while taking the
|
|
5744
|
+
* correct ownCapabilities into account.
|
|
5745
|
+
* @param entity - The entity to which we want to add a reaction, can be either ActivityResponse or CommentResponse.
|
|
5746
|
+
* @param type - The type of reaction we want to add or remove.
|
|
5747
|
+
*/
|
|
5748
|
+
const useReactionActions = ({ entity, type, }) => {
|
|
5749
|
+
const client = useFeedsClient();
|
|
5750
|
+
const isComment = isCommentResponse(entity);
|
|
5751
|
+
const hasOwnReaction = react.useMemo(() => !!entity.own_reactions?.find((r) => r.type === type), [entity.own_reactions, type]);
|
|
5752
|
+
const addReaction = useStableCallback(async () => {
|
|
5753
|
+
await (isComment
|
|
5754
|
+
? client?.addCommentReaction({ comment_id: entity.id, type })
|
|
5755
|
+
: client?.addReaction({ activity_id: entity.id, type }));
|
|
5756
|
+
});
|
|
5757
|
+
const removeReaction = useStableCallback(async () => {
|
|
5758
|
+
await (isComment
|
|
5759
|
+
? client?.deleteCommentReaction({ comment_id: entity.id, type })
|
|
5760
|
+
: client?.deleteActivityReaction({
|
|
5761
|
+
activity_id: entity.id,
|
|
5762
|
+
type,
|
|
5763
|
+
}));
|
|
5764
|
+
});
|
|
5765
|
+
const toggleReaction = useStableCallback(async () => {
|
|
5766
|
+
if (hasOwnReaction) {
|
|
5767
|
+
await removeReaction();
|
|
5768
|
+
}
|
|
5769
|
+
else {
|
|
5770
|
+
await addReaction();
|
|
5771
|
+
}
|
|
5772
|
+
});
|
|
5773
|
+
return react.useMemo(() => ({ addReaction, removeReaction, toggleReaction }), [addReaction, removeReaction, toggleReaction]);
|
|
5774
|
+
};
|
|
5775
|
+
|
|
5520
5776
|
const StreamFeeds = ({ client, children }) => {
|
|
5521
5777
|
return (jsxRuntime.jsx(StreamFeedsContext.Provider, { value: client, children: children }));
|
|
5522
5778
|
};
|
|
5523
5779
|
StreamFeeds.displayName = 'StreamFeeds';
|
|
5524
5780
|
|
|
5781
|
+
const StreamFeed = ({ feed, children }) => {
|
|
5782
|
+
return (jsxRuntime.jsx(StreamFeedContext.Provider, { value: feed, children: children }));
|
|
5783
|
+
};
|
|
5784
|
+
StreamFeed.displayName = 'StreamFeed';
|
|
5785
|
+
|
|
5786
|
+
exports.StreamFeed = StreamFeed;
|
|
5787
|
+
exports.StreamFeedContext = StreamFeedContext;
|
|
5525
5788
|
exports.StreamFeeds = StreamFeeds;
|
|
5526
5789
|
exports.StreamFeedsContext = StreamFeedsContext;
|
|
5527
5790
|
exports.useClientConnectedUser = useClientConnectedUser;
|
|
5528
5791
|
exports.useComments = useComments;
|
|
5529
5792
|
exports.useCreateFeedsClient = useCreateFeedsClient;
|
|
5793
|
+
exports.useFeedActivities = useFeedActivities;
|
|
5794
|
+
exports.useFeedContext = useFeedContext;
|
|
5530
5795
|
exports.useFeedsClient = useFeedsClient;
|
|
5796
|
+
exports.useFollowers = useFollowers;
|
|
5797
|
+
exports.useFollowing = useFollowing;
|
|
5531
5798
|
exports.useOwnCapabilities = useOwnCapabilities;
|
|
5799
|
+
exports.useReactionActions = useReactionActions;
|
|
5532
5800
|
exports.useStateStore = useStateStore;
|
|
5533
5801
|
exports.useWsConnectionState = useWsConnectionState;
|
|
5534
5802
|
//# sourceMappingURL=index-react-bindings.browser.cjs.map
|