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