@stream-io/feeds-client 0.1.4 → 0.1.6
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 +7 -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 +31 -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 +7 -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/useFeedMetadata.d.ts +12 -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/feed-state-hooks/useOwnCapabilities.d.ts +33 -0
- package/dist/@react-bindings/hooks/feed-state-hooks/useOwnFollows.d.ts +8 -0
- 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 +521 -210
- package/dist/index-react-bindings.browser.cjs.map +1 -1
- package/dist/index-react-bindings.browser.js +514 -212
- package/dist/index-react-bindings.browser.js.map +1 -1
- package/dist/index-react-bindings.node.cjs +521 -210
- package/dist/index-react-bindings.node.cjs.map +1 -1
- package/dist/index-react-bindings.node.js +514 -212
- package/dist/index-react-bindings.node.js.map +1 -1
- package/dist/index.browser.cjs +212 -106
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.js +209 -107
- package/dist/index.browser.js.map +1 -1
- package/dist/index.node.cjs +212 -106
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.js +209 -107
- package/dist/index.node.js.map +1 -1
- package/dist/src/Feed.d.ts +7 -3
- package/dist/src/FeedsClient.d.ts +6 -5
- 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 +6 -2
- package/src/Feed.ts +214 -97
- package/src/FeedsClient.ts +22 -12
- package/src/common/ActivitySearchSource.ts +5 -5
- package/src/common/ApiClient.ts +1 -1
- package/src/common/FeedSearchSource.ts +1 -1
- package/src/common/Poll.ts +35 -10
- package/src/common/TokenManager.ts +2 -3
- package/src/common/UserSearchSource.ts +1 -1
- package/src/common/real-time/StableWSConnection.ts +4 -1
- package/src/state-updates/bookmark-utils.test.ts +134 -8
- package/src/state-updates/bookmark-utils.ts +17 -7
- 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
- package/dist/@react-bindings/hooks/useOwnCapabilities.d.ts +0 -33
|
@@ -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
|
};
|
|
@@ -2892,7 +2783,7 @@ class TokenManager {
|
|
|
2892
2783
|
}
|
|
2893
2784
|
catch (e) {
|
|
2894
2785
|
const numberOfFailures = ++previousFailuresCount;
|
|
2895
|
-
await sleep(
|
|
2786
|
+
await sleep(1000);
|
|
2896
2787
|
if (numberOfFailures === 3) {
|
|
2897
2788
|
this.loadTokenPromise = null;
|
|
2898
2789
|
return reject(new Error(`Stream error: tried to get token ${numberOfFailures} times, but it failed with ${e}. Check your token provider`, { cause: e }));
|
|
@@ -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);
|
|
@@ -3737,7 +3631,7 @@ class ApiClient {
|
|
|
3737
3631
|
rate_limit: getRateLimitFromResponseHeader(response_headers),
|
|
3738
3632
|
};
|
|
3739
3633
|
};
|
|
3740
|
-
this.baseUrl = options?.base_url ?? 'https://
|
|
3634
|
+
this.baseUrl = options?.base_url ?? 'https://feeds.stream-io-api.com';
|
|
3741
3635
|
this.timeout = options?.timeout ?? 3000;
|
|
3742
3636
|
this.axiosInstance = axios.create({
|
|
3743
3637
|
baseURL: this.baseUrl,
|
|
@@ -4031,6 +3925,13 @@ const removeReactionFromActivities = (event, activities, isCurrentUser) => {
|
|
|
4031
3925
|
return updateActivityInActivities$1(updatedActivity, activities);
|
|
4032
3926
|
};
|
|
4033
3927
|
|
|
3928
|
+
// Helper function to check if two bookmarks are the same
|
|
3929
|
+
// A bookmark is identified by activity_id + folder_id + user_id
|
|
3930
|
+
const isSameBookmark = (bookmark1, bookmark2) => {
|
|
3931
|
+
return (bookmark1.user.id === bookmark2.user.id &&
|
|
3932
|
+
bookmark1.activity.id === bookmark2.activity.id &&
|
|
3933
|
+
bookmark1.folder?.id === bookmark2.folder?.id);
|
|
3934
|
+
};
|
|
4034
3935
|
const updateActivityInActivities = (updatedActivity, activities) => {
|
|
4035
3936
|
const index = activities.findIndex((a) => a.id === updatedActivity.id);
|
|
4036
3937
|
if (index !== -1) {
|
|
@@ -4057,8 +3958,7 @@ const addBookmarkToActivity = (event, activity, isCurrentUser) => {
|
|
|
4057
3958
|
const removeBookmarkFromActivity = (event, activity, isCurrentUser) => {
|
|
4058
3959
|
// Update own_bookmarks if the bookmark is from the current user
|
|
4059
3960
|
const ownBookmarks = isCurrentUser
|
|
4060
|
-
? (activity.own_bookmarks || []).filter((bookmark) => bookmark
|
|
4061
|
-
bookmark.activity.id !== event.bookmark.activity.id)
|
|
3961
|
+
? (activity.own_bookmarks || []).filter((bookmark) => !isSameBookmark(bookmark, event.bookmark))
|
|
4062
3962
|
: activity.own_bookmarks;
|
|
4063
3963
|
return {
|
|
4064
3964
|
...activity,
|
|
@@ -4070,8 +3970,7 @@ const updateBookmarkInActivity = (event, activity, isCurrentUser) => {
|
|
|
4070
3970
|
// Update own_bookmarks if the bookmark is from the current user
|
|
4071
3971
|
let ownBookmarks = activity.own_bookmarks || [];
|
|
4072
3972
|
if (isCurrentUser) {
|
|
4073
|
-
const bookmarkIndex = ownBookmarks.findIndex((bookmark) => bookmark
|
|
4074
|
-
bookmark.activity.id === event.bookmark.activity.id);
|
|
3973
|
+
const bookmarkIndex = ownBookmarks.findIndex((bookmark) => isSameBookmark(bookmark, event.bookmark));
|
|
4075
3974
|
if (bookmarkIndex !== -1) {
|
|
4076
3975
|
ownBookmarks = [...ownBookmarks];
|
|
4077
3976
|
ownBookmarks[bookmarkIndex] = event.bookmark;
|
|
@@ -4120,8 +4019,15 @@ const updateBookmarkInActivities = (event, activities, isCurrentUser) => {
|
|
|
4120
4019
|
return updateActivityInActivities(updatedActivity, activities);
|
|
4121
4020
|
};
|
|
4122
4021
|
|
|
4123
|
-
const
|
|
4124
|
-
|
|
4022
|
+
const checkHasAnotherPage = (v, cursor) => (typeof v === 'undefined' && typeof cursor === 'undefined') ||
|
|
4023
|
+
typeof cursor === 'string';
|
|
4024
|
+
const isCommentResponse = (entity) => {
|
|
4025
|
+
return typeof entity?.object_id === 'string';
|
|
4026
|
+
};
|
|
4027
|
+
const Constants = {
|
|
4028
|
+
DEFAULT_COMMENT_PAGINATION: 'first',
|
|
4029
|
+
};
|
|
4030
|
+
|
|
4125
4031
|
class Feed extends FeedApi {
|
|
4126
4032
|
constructor(client, groupId, id, data) {
|
|
4127
4033
|
// Need this ugly cast because fileUpload endpoints :(
|
|
@@ -4146,7 +4052,7 @@ class Feed extends FeedApi {
|
|
|
4146
4052
|
},
|
|
4147
4053
|
'feeds.activity.reaction.added': (event) => {
|
|
4148
4054
|
const currentActivities = this.currentState.activities;
|
|
4149
|
-
const connectedUser = this.client.state.getLatestValue().
|
|
4055
|
+
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4150
4056
|
const isCurrentUser = Boolean(connectedUser && event.reaction.user.id === connectedUser.id);
|
|
4151
4057
|
const result = addReactionToActivities(event, currentActivities, isCurrentUser);
|
|
4152
4058
|
if (result.changed) {
|
|
@@ -4155,7 +4061,7 @@ class Feed extends FeedApi {
|
|
|
4155
4061
|
},
|
|
4156
4062
|
'feeds.activity.reaction.deleted': (event) => {
|
|
4157
4063
|
const currentActivities = this.currentState.activities;
|
|
4158
|
-
const connectedUser = this.client.state.getLatestValue().
|
|
4064
|
+
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4159
4065
|
const isCurrentUser = Boolean(connectedUser && event.reaction.user.id === connectedUser.id);
|
|
4160
4066
|
const result = removeReactionFromActivities(event, currentActivities, isCurrentUser);
|
|
4161
4067
|
if (result.changed) {
|
|
@@ -4194,7 +4100,7 @@ class Feed extends FeedApi {
|
|
|
4194
4100
|
const entityState = currentState.comments_by_entity_id[forId];
|
|
4195
4101
|
const newComments = entityState?.comments?.concat([]) ?? [];
|
|
4196
4102
|
if (entityState?.pagination?.sort === 'last' &&
|
|
4197
|
-
entityState?.pagination.next
|
|
4103
|
+
!checkHasAnotherPage(entityState.comments, entityState?.pagination.next)) {
|
|
4198
4104
|
newComments.unshift(comment);
|
|
4199
4105
|
}
|
|
4200
4106
|
else if (entityState?.pagination?.sort === 'first') {
|
|
@@ -4281,7 +4187,7 @@ class Feed extends FeedApi {
|
|
|
4281
4187
|
...currentState,
|
|
4282
4188
|
...event.follow.source_feed,
|
|
4283
4189
|
};
|
|
4284
|
-
if (currentState.following_pagination?.next
|
|
4190
|
+
if (!checkHasAnotherPage(currentState.following, currentState.following_pagination?.next)) {
|
|
4285
4191
|
// TODO: respect sort
|
|
4286
4192
|
newState.following = currentState.following
|
|
4287
4193
|
? currentState.following.concat(event.follow)
|
|
@@ -4294,7 +4200,7 @@ class Feed extends FeedApi {
|
|
|
4294
4200
|
// someone followed this feed
|
|
4295
4201
|
event.follow.target_feed.fid === this.fid) {
|
|
4296
4202
|
const source = event.follow.source_feed;
|
|
4297
|
-
const connectedUser = this.client.state.getLatestValue().
|
|
4203
|
+
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4298
4204
|
this.state.next((currentState) => {
|
|
4299
4205
|
const newState = { ...currentState, ...event.follow.target_feed };
|
|
4300
4206
|
if (source.created_by.id === connectedUser?.id) {
|
|
@@ -4302,7 +4208,7 @@ class Feed extends FeedApi {
|
|
|
4302
4208
|
? currentState.own_follows.concat(event.follow)
|
|
4303
4209
|
: [event.follow];
|
|
4304
4210
|
}
|
|
4305
|
-
if (currentState.followers_pagination?.next
|
|
4211
|
+
if (!checkHasAnotherPage(currentState.followers, currentState.followers_pagination?.next)) {
|
|
4306
4212
|
// TODO: respect sort
|
|
4307
4213
|
newState.followers = currentState.followers
|
|
4308
4214
|
? currentState.followers.concat(event.follow)
|
|
@@ -4327,7 +4233,7 @@ class Feed extends FeedApi {
|
|
|
4327
4233
|
// someone unfollowed this feed
|
|
4328
4234
|
event.follow.target_feed.fid === this.fid) {
|
|
4329
4235
|
const source = event.follow.source_feed;
|
|
4330
|
-
const connectedUser = this.client.state.getLatestValue().
|
|
4236
|
+
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4331
4237
|
this.state.next((currentState) => {
|
|
4332
4238
|
const newState = { ...currentState, ...event.follow.target_feed };
|
|
4333
4239
|
if (source.created_by.id === connectedUser?.id) {
|
|
@@ -4343,40 +4249,60 @@ class Feed extends FeedApi {
|
|
|
4343
4249
|
'feeds.comment.reaction.deleted': this.handleCommentReactionEvent.bind(this),
|
|
4344
4250
|
'feeds.comment.reaction.updated': Feed.noop,
|
|
4345
4251
|
'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;
|
|
4252
|
+
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4350
4253
|
this.state.next((currentState) => {
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4254
|
+
let newState;
|
|
4255
|
+
if (!checkHasAnotherPage(currentState.members, currentState.member_pagination?.next)) {
|
|
4256
|
+
newState ?? (newState = {
|
|
4257
|
+
...currentState,
|
|
4258
|
+
});
|
|
4259
|
+
newState.members = newState.members?.concat(event.member) ?? [
|
|
4260
|
+
event.member,
|
|
4261
|
+
];
|
|
4262
|
+
}
|
|
4263
|
+
if (connectedUser?.id === event.member.user.id) {
|
|
4264
|
+
newState ?? (newState = {
|
|
4265
|
+
...currentState,
|
|
4266
|
+
});
|
|
4267
|
+
newState.own_membership = event.member;
|
|
4268
|
+
}
|
|
4269
|
+
return newState ?? currentState;
|
|
4358
4270
|
});
|
|
4359
4271
|
},
|
|
4360
4272
|
'feeds.feed_member.removed': (event) => {
|
|
4273
|
+
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4361
4274
|
this.state.next((currentState) => {
|
|
4362
|
-
|
|
4275
|
+
const newState = {
|
|
4363
4276
|
...currentState,
|
|
4364
4277
|
members: currentState.members?.filter((member) => member.user.id !== event.user?.id),
|
|
4365
4278
|
};
|
|
4279
|
+
if (connectedUser?.id === event.member_id) {
|
|
4280
|
+
delete newState.own_membership;
|
|
4281
|
+
}
|
|
4282
|
+
return newState;
|
|
4366
4283
|
});
|
|
4367
4284
|
},
|
|
4368
4285
|
'feeds.feed_member.updated': (event) => {
|
|
4286
|
+
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4369
4287
|
this.state.next((currentState) => {
|
|
4370
4288
|
const memberIndex = currentState.members?.findIndex((member) => member.user.id === event.member.user.id) ?? -1;
|
|
4289
|
+
let newState;
|
|
4371
4290
|
if (memberIndex !== -1) {
|
|
4291
|
+
// if there's an index, there's a member to update
|
|
4372
4292
|
const newMembers = [...currentState.members];
|
|
4373
4293
|
newMembers[memberIndex] = event.member;
|
|
4374
|
-
|
|
4294
|
+
newState ?? (newState = {
|
|
4375
4295
|
...currentState,
|
|
4376
|
-
|
|
4377
|
-
|
|
4296
|
+
});
|
|
4297
|
+
newState.members = newMembers;
|
|
4378
4298
|
}
|
|
4379
|
-
|
|
4299
|
+
if (connectedUser?.id === event.member.user.id) {
|
|
4300
|
+
newState ?? (newState = {
|
|
4301
|
+
...currentState,
|
|
4302
|
+
});
|
|
4303
|
+
newState.own_membership = event.member;
|
|
4304
|
+
}
|
|
4305
|
+
return newState ?? currentState;
|
|
4380
4306
|
});
|
|
4381
4307
|
},
|
|
4382
4308
|
// the poll events should be removed from here
|
|
@@ -4422,7 +4348,7 @@ class Feed extends FeedApi {
|
|
|
4422
4348
|
}
|
|
4423
4349
|
handleCommentReactionEvent(event) {
|
|
4424
4350
|
const { comment, reaction } = event;
|
|
4425
|
-
const connectedUser = this.client.state.getLatestValue().
|
|
4351
|
+
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4426
4352
|
this.state.next((currentState) => {
|
|
4427
4353
|
const forId = comment.parent_id ?? comment.object_id;
|
|
4428
4354
|
const entityState = currentState.comments_by_entity_id[forId];
|
|
@@ -4502,29 +4428,6 @@ class Feed extends FeedApi {
|
|
|
4502
4428
|
...currentState,
|
|
4503
4429
|
...responseCopy,
|
|
4504
4430
|
};
|
|
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
4431
|
if (!request?.followers_pagination?.limit) {
|
|
4529
4432
|
delete nextState.followers;
|
|
4530
4433
|
}
|
|
@@ -4547,7 +4450,7 @@ class Feed extends FeedApi {
|
|
|
4547
4450
|
}
|
|
4548
4451
|
handleBookmarkAdded(event) {
|
|
4549
4452
|
const currentActivities = this.currentState.activities;
|
|
4550
|
-
const { connectedUser } = this.client.state.getLatestValue();
|
|
4453
|
+
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4551
4454
|
const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
|
|
4552
4455
|
const result = addBookmarkToActivities(event, currentActivities, isCurrentUser);
|
|
4553
4456
|
if (result.changed) {
|
|
@@ -4556,7 +4459,7 @@ class Feed extends FeedApi {
|
|
|
4556
4459
|
}
|
|
4557
4460
|
handleBookmarkDeleted(event) {
|
|
4558
4461
|
const currentActivities = this.currentState.activities;
|
|
4559
|
-
const { connectedUser } = this.client.state.getLatestValue();
|
|
4462
|
+
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4560
4463
|
const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
|
|
4561
4464
|
const result = removeBookmarkFromActivities(event, currentActivities, isCurrentUser);
|
|
4562
4465
|
if (result.changed) {
|
|
@@ -4565,7 +4468,7 @@ class Feed extends FeedApi {
|
|
|
4565
4468
|
}
|
|
4566
4469
|
handleBookmarkUpdated(event) {
|
|
4567
4470
|
const currentActivities = this.currentState.activities;
|
|
4568
|
-
const { connectedUser } = this.client.state.getLatestValue();
|
|
4471
|
+
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4569
4472
|
const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
|
|
4570
4473
|
const result = updateBookmarkInActivities(event, currentActivities, isCurrentUser);
|
|
4571
4474
|
if (result.changed) {
|
|
@@ -4615,6 +4518,7 @@ class Feed extends FeedApi {
|
|
|
4615
4518
|
});
|
|
4616
4519
|
}
|
|
4617
4520
|
async loadNextPageComments({ forId, base, sort, parentId, }) {
|
|
4521
|
+
let error;
|
|
4618
4522
|
try {
|
|
4619
4523
|
this.state.next((currentState) => ({
|
|
4620
4524
|
...currentState,
|
|
@@ -4629,7 +4533,7 @@ class Feed extends FeedApi {
|
|
|
4629
4533
|
},
|
|
4630
4534
|
},
|
|
4631
4535
|
}));
|
|
4632
|
-
const { next: newNextCursor
|
|
4536
|
+
const { next: newNextCursor, comments } = await base();
|
|
4633
4537
|
this.state.next((currentState) => {
|
|
4634
4538
|
const newPagination = {
|
|
4635
4539
|
...currentState.comments_by_entity_id[forId]?.pagination,
|
|
@@ -4654,9 +4558,8 @@ class Feed extends FeedApi {
|
|
|
4654
4558
|
};
|
|
4655
4559
|
});
|
|
4656
4560
|
}
|
|
4657
|
-
catch (
|
|
4658
|
-
|
|
4659
|
-
// TODO: figure out how to handle errorss
|
|
4561
|
+
catch (e) {
|
|
4562
|
+
error = e;
|
|
4660
4563
|
}
|
|
4661
4564
|
finally {
|
|
4662
4565
|
this.state.next((currentState) => ({
|
|
@@ -4673,15 +4576,21 @@ class Feed extends FeedApi {
|
|
|
4673
4576
|
},
|
|
4674
4577
|
}));
|
|
4675
4578
|
}
|
|
4579
|
+
if (error) {
|
|
4580
|
+
throw error;
|
|
4581
|
+
}
|
|
4676
4582
|
}
|
|
4677
4583
|
async loadNextPageActivityComments(activity, request) {
|
|
4678
|
-
const
|
|
4679
|
-
const
|
|
4680
|
-
const
|
|
4681
|
-
const
|
|
4682
|
-
const
|
|
4683
|
-
|
|
4584
|
+
const currentEntityState = this.currentState.comments_by_entity_id[activity.id];
|
|
4585
|
+
const currentPagination = currentEntityState?.pagination;
|
|
4586
|
+
const currentNextCursor = currentPagination?.next;
|
|
4587
|
+
const currentSort = currentPagination?.sort;
|
|
4588
|
+
const isLoading = currentPagination?.loading_next_page;
|
|
4589
|
+
const sort = currentSort ?? request?.sort ?? Constants.DEFAULT_COMMENT_PAGINATION;
|
|
4590
|
+
if (isLoading ||
|
|
4591
|
+
!checkHasAnotherPage(currentEntityState?.comments, currentNextCursor)) {
|
|
4684
4592
|
return;
|
|
4593
|
+
}
|
|
4685
4594
|
await this.loadNextPageComments({
|
|
4686
4595
|
forId: activity.id,
|
|
4687
4596
|
base: () => this.client.getComments({
|
|
@@ -4695,20 +4604,25 @@ class Feed extends FeedApi {
|
|
|
4695
4604
|
});
|
|
4696
4605
|
}
|
|
4697
4606
|
async loadNextPageCommentReplies(comment, request) {
|
|
4698
|
-
const
|
|
4699
|
-
const
|
|
4700
|
-
const
|
|
4701
|
-
const
|
|
4702
|
-
const
|
|
4703
|
-
|
|
4607
|
+
const currentEntityState = this.currentState.comments_by_entity_id[comment.id];
|
|
4608
|
+
const currentPagination = currentEntityState?.pagination;
|
|
4609
|
+
const currentNextCursor = currentPagination?.next;
|
|
4610
|
+
const currentSort = currentPagination?.sort;
|
|
4611
|
+
const isLoading = currentPagination?.loading_next_page;
|
|
4612
|
+
const sort = currentSort ?? request?.sort ?? Constants.DEFAULT_COMMENT_PAGINATION;
|
|
4613
|
+
if (isLoading ||
|
|
4614
|
+
!checkHasAnotherPage(currentEntityState?.comments, currentNextCursor)) {
|
|
4704
4615
|
return;
|
|
4616
|
+
}
|
|
4705
4617
|
await this.loadNextPageComments({
|
|
4706
4618
|
forId: comment.id,
|
|
4707
4619
|
base: () => this.client.getCommentReplies({
|
|
4708
4620
|
...request,
|
|
4709
4621
|
comment_id: comment.id,
|
|
4710
4622
|
// use known sort first (prevents broken pagination)
|
|
4711
|
-
sort: currentSort ??
|
|
4623
|
+
sort: currentSort ??
|
|
4624
|
+
request?.sort ??
|
|
4625
|
+
Constants.DEFAULT_COMMENT_PAGINATION,
|
|
4712
4626
|
next: currentNextCursor,
|
|
4713
4627
|
}),
|
|
4714
4628
|
parentId: comment.parent_id ?? comment.object_id,
|
|
@@ -4718,10 +4632,14 @@ class Feed extends FeedApi {
|
|
|
4718
4632
|
async loadNextPageFollows(type, request) {
|
|
4719
4633
|
const paginationKey = `${type}_pagination`;
|
|
4720
4634
|
const method = `query${capitalize(type)}`;
|
|
4635
|
+
const currentFollows = this.currentState[type];
|
|
4721
4636
|
const currentNextCursor = this.currentState[paginationKey]?.next;
|
|
4722
4637
|
const isLoading = this.currentState[paginationKey]?.loading_next_page;
|
|
4723
|
-
|
|
4638
|
+
const sort = this.currentState[paginationKey]?.sort ?? request.sort;
|
|
4639
|
+
let error;
|
|
4640
|
+
if (isLoading || !checkHasAnotherPage(currentFollows, currentNextCursor)) {
|
|
4724
4641
|
return;
|
|
4642
|
+
}
|
|
4725
4643
|
try {
|
|
4726
4644
|
this.state.next((currentState) => {
|
|
4727
4645
|
return {
|
|
@@ -4732,9 +4650,10 @@ class Feed extends FeedApi {
|
|
|
4732
4650
|
},
|
|
4733
4651
|
};
|
|
4734
4652
|
});
|
|
4735
|
-
const { next: newNextCursor
|
|
4653
|
+
const { next: newNextCursor, follows } = await this[method]({
|
|
4736
4654
|
...request,
|
|
4737
4655
|
next: currentNextCursor,
|
|
4656
|
+
sort,
|
|
4738
4657
|
});
|
|
4739
4658
|
this.state.next((currentState) => ({
|
|
4740
4659
|
...currentState,
|
|
@@ -4744,12 +4663,12 @@ class Feed extends FeedApi {
|
|
|
4744
4663
|
[paginationKey]: {
|
|
4745
4664
|
...currentState[paginationKey],
|
|
4746
4665
|
next: newNextCursor,
|
|
4666
|
+
sort,
|
|
4747
4667
|
},
|
|
4748
4668
|
}));
|
|
4749
4669
|
}
|
|
4750
|
-
catch (
|
|
4751
|
-
|
|
4752
|
-
// TODO: figure out how to handle errorss
|
|
4670
|
+
catch (e) {
|
|
4671
|
+
error = e;
|
|
4753
4672
|
}
|
|
4754
4673
|
finally {
|
|
4755
4674
|
this.state.next((currentState) => {
|
|
@@ -4762,6 +4681,9 @@ class Feed extends FeedApi {
|
|
|
4762
4681
|
};
|
|
4763
4682
|
});
|
|
4764
4683
|
}
|
|
4684
|
+
if (error) {
|
|
4685
|
+
throw error;
|
|
4686
|
+
}
|
|
4765
4687
|
}
|
|
4766
4688
|
async loadNextPageFollowers(request) {
|
|
4767
4689
|
await this.loadNextPageFollows('followers', request);
|
|
@@ -4769,6 +4691,59 @@ class Feed extends FeedApi {
|
|
|
4769
4691
|
async loadNextPageFollowing(request) {
|
|
4770
4692
|
await this.loadNextPageFollows('following', request);
|
|
4771
4693
|
}
|
|
4694
|
+
async loadNextPageMembers(request) {
|
|
4695
|
+
const currentMembers = this.currentState.members;
|
|
4696
|
+
const currentNextCursor = this.currentState.member_pagination?.next;
|
|
4697
|
+
const isLoading = this.currentState.member_pagination?.loading_next_page;
|
|
4698
|
+
const sort = this.currentState.member_pagination?.sort ?? request.sort;
|
|
4699
|
+
let error;
|
|
4700
|
+
if (isLoading || !checkHasAnotherPage(currentMembers, currentNextCursor)) {
|
|
4701
|
+
return;
|
|
4702
|
+
}
|
|
4703
|
+
try {
|
|
4704
|
+
this.state.next((currentState) => ({
|
|
4705
|
+
...currentState,
|
|
4706
|
+
member_pagination: {
|
|
4707
|
+
...currentState.member_pagination,
|
|
4708
|
+
loading_next_page: true,
|
|
4709
|
+
},
|
|
4710
|
+
}));
|
|
4711
|
+
const { next: newNextCursor, members } = await this.client.queryFeedMembers({
|
|
4712
|
+
...request,
|
|
4713
|
+
sort,
|
|
4714
|
+
feed_id: this.id,
|
|
4715
|
+
feed_group_id: this.group,
|
|
4716
|
+
next: currentNextCursor,
|
|
4717
|
+
});
|
|
4718
|
+
this.state.next((currentState) => ({
|
|
4719
|
+
...currentState,
|
|
4720
|
+
members: currentState.members
|
|
4721
|
+
? currentState.members.concat(members)
|
|
4722
|
+
: members,
|
|
4723
|
+
member_pagination: {
|
|
4724
|
+
...currentState.member_pagination,
|
|
4725
|
+
next: newNextCursor,
|
|
4726
|
+
// set sort if not defined yet
|
|
4727
|
+
sort: currentState.member_pagination?.sort ?? request.sort,
|
|
4728
|
+
},
|
|
4729
|
+
}));
|
|
4730
|
+
}
|
|
4731
|
+
catch (e) {
|
|
4732
|
+
error = e;
|
|
4733
|
+
}
|
|
4734
|
+
finally {
|
|
4735
|
+
this.state.next((currentState) => ({
|
|
4736
|
+
...currentState,
|
|
4737
|
+
member_pagination: {
|
|
4738
|
+
...currentState.member_pagination,
|
|
4739
|
+
loading_next_page: false,
|
|
4740
|
+
},
|
|
4741
|
+
}));
|
|
4742
|
+
}
|
|
4743
|
+
if (error) {
|
|
4744
|
+
throw error;
|
|
4745
|
+
}
|
|
4746
|
+
}
|
|
4772
4747
|
/**
|
|
4773
4748
|
* Method which queries followers of this feed (feeds which target this feed).
|
|
4774
4749
|
*
|
|
@@ -5048,7 +5023,8 @@ class StreamPoll {
|
|
|
5048
5023
|
if (!isPollVoteCastedEvent(event))
|
|
5049
5024
|
return;
|
|
5050
5025
|
const currentState = this.data;
|
|
5051
|
-
const isOwnVote = event.poll_vote.user_id ===
|
|
5026
|
+
const isOwnVote = event.poll_vote.user_id ===
|
|
5027
|
+
this.client.state.getLatestValue().connected_user?.id;
|
|
5052
5028
|
let latestAnswers = [...currentState.latest_answers];
|
|
5053
5029
|
let ownAnswer = currentState.own_answer;
|
|
5054
5030
|
const ownVotesByOptionId = currentState.own_votes_by_option_id;
|
|
@@ -5072,7 +5048,7 @@ class StreamPoll {
|
|
|
5072
5048
|
else {
|
|
5073
5049
|
maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);
|
|
5074
5050
|
}
|
|
5075
|
-
const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option } = event.poll;
|
|
5051
|
+
const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
|
|
5076
5052
|
this.state.partialNext({
|
|
5077
5053
|
answers_count,
|
|
5078
5054
|
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
@@ -5093,7 +5069,8 @@ class StreamPoll {
|
|
|
5093
5069
|
if (!isPollVoteChangedEvent(event))
|
|
5094
5070
|
return;
|
|
5095
5071
|
const currentState = this.data;
|
|
5096
|
-
const isOwnVote = event.poll_vote.user_id ===
|
|
5072
|
+
const isOwnVote = event.poll_vote.user_id ===
|
|
5073
|
+
this.client.state.getLatestValue().connected_user?.id;
|
|
5097
5074
|
let latestAnswers = [...currentState.latest_answers];
|
|
5098
5075
|
let ownAnswer = currentState.own_answer;
|
|
5099
5076
|
let ownVotesByOptionId = currentState.own_votes_by_option_id;
|
|
@@ -5140,7 +5117,7 @@ class StreamPoll {
|
|
|
5140
5117
|
else {
|
|
5141
5118
|
maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);
|
|
5142
5119
|
}
|
|
5143
|
-
const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option } = event.poll;
|
|
5120
|
+
const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
|
|
5144
5121
|
this.state.partialNext({
|
|
5145
5122
|
answers_count,
|
|
5146
5123
|
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
@@ -5160,7 +5137,8 @@ class StreamPoll {
|
|
|
5160
5137
|
if (!isPollVoteRemovedEvent(event))
|
|
5161
5138
|
return;
|
|
5162
5139
|
const currentState = this.data;
|
|
5163
|
-
const isOwnVote = event.poll_vote.user_id ===
|
|
5140
|
+
const isOwnVote = event.poll_vote.user_id ===
|
|
5141
|
+
this.client.state.getLatestValue().connected_user?.id;
|
|
5164
5142
|
let latestAnswers = [...currentState.latest_answers];
|
|
5165
5143
|
let ownAnswer = currentState.own_answer;
|
|
5166
5144
|
const ownVotesByOptionId = { ...currentState.own_votes_by_option_id };
|
|
@@ -5178,7 +5156,7 @@ class StreamPoll {
|
|
|
5178
5156
|
delete ownVotesByOptionId[event.poll_vote.option_id];
|
|
5179
5157
|
}
|
|
5180
5158
|
}
|
|
5181
|
-
const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option } = event.poll;
|
|
5159
|
+
const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
|
|
5182
5160
|
this.state.partialNext({
|
|
5183
5161
|
answers_count,
|
|
5184
5162
|
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
@@ -5236,7 +5214,7 @@ class FeedsClient extends FeedsApi {
|
|
|
5236
5214
|
this.healthyConnectionChangedEventCount = 0;
|
|
5237
5215
|
this.pollFromState = (id) => this.polls_by_id.get(id);
|
|
5238
5216
|
this.connectUser = async (user, tokenProvider) => {
|
|
5239
|
-
if (this.state.getLatestValue().
|
|
5217
|
+
if (this.state.getLatestValue().connected_user !== undefined ||
|
|
5240
5218
|
this.wsConnection) {
|
|
5241
5219
|
throw new Error(`Can't connect a new user, call "disconnectUser" first`);
|
|
5242
5220
|
}
|
|
@@ -5250,8 +5228,8 @@ class FeedsClient extends FeedsApi {
|
|
|
5250
5228
|
this.wsConnection.on('all', (event) => this.eventDispatcher.dispatch(event));
|
|
5251
5229
|
const connectedEvent = await this.wsConnection.connect();
|
|
5252
5230
|
this.state.partialNext({
|
|
5253
|
-
|
|
5254
|
-
|
|
5231
|
+
connected_user: connectedEvent?.me,
|
|
5232
|
+
is_ws_connection_healthy: !!this.wsConnection?.isHealthy,
|
|
5255
5233
|
});
|
|
5256
5234
|
}
|
|
5257
5235
|
catch (err) {
|
|
@@ -5259,6 +5237,9 @@ class FeedsClient extends FeedsApi {
|
|
|
5259
5237
|
throw err;
|
|
5260
5238
|
}
|
|
5261
5239
|
};
|
|
5240
|
+
this.devToken = (userId) => {
|
|
5241
|
+
return streamDevToken(userId);
|
|
5242
|
+
};
|
|
5262
5243
|
this.closePoll = async (request) => {
|
|
5263
5244
|
return await this.updatePollPartial({
|
|
5264
5245
|
poll_id: request.poll_id,
|
|
@@ -5307,7 +5288,10 @@ class FeedsClient extends FeedsApi {
|
|
|
5307
5288
|
removeConnectionEventListeners(this.updateNetworkConnectionStatus);
|
|
5308
5289
|
this.connectionIdManager.reset();
|
|
5309
5290
|
this.tokenManager.reset();
|
|
5310
|
-
this.state.partialNext({
|
|
5291
|
+
this.state.partialNext({
|
|
5292
|
+
connected_user: undefined,
|
|
5293
|
+
is_ws_connection_healthy: false,
|
|
5294
|
+
});
|
|
5311
5295
|
};
|
|
5312
5296
|
this.on = this.eventDispatcher.on;
|
|
5313
5297
|
this.off = this.eventDispatcher.off;
|
|
@@ -5333,8 +5317,8 @@ class FeedsClient extends FeedsApi {
|
|
|
5333
5317
|
}
|
|
5334
5318
|
};
|
|
5335
5319
|
this.state = new StateStore({
|
|
5336
|
-
|
|
5337
|
-
|
|
5320
|
+
connected_user: undefined,
|
|
5321
|
+
is_ws_connection_healthy: false,
|
|
5338
5322
|
});
|
|
5339
5323
|
this.moderation = new ModerationClient(apiClient);
|
|
5340
5324
|
this.tokenManager = tokenManager;
|
|
@@ -5346,7 +5330,7 @@ class FeedsClient extends FeedsApi {
|
|
|
5346
5330
|
switch (event.type) {
|
|
5347
5331
|
case 'connection.changed': {
|
|
5348
5332
|
const { online } = event;
|
|
5349
|
-
this.state.partialNext({
|
|
5333
|
+
this.state.partialNext({ is_ws_connection_healthy: online });
|
|
5350
5334
|
if (online) {
|
|
5351
5335
|
this.healthyConnectionChangedEventCount++;
|
|
5352
5336
|
// we skip the first event as we could potentially be querying twice
|
|
@@ -5517,18 +5501,345 @@ const useCreateFeedsClient = ({ apiKey, tokenOrProvider, userData, options, }) =
|
|
|
5517
5501
|
return client;
|
|
5518
5502
|
};
|
|
5519
5503
|
|
|
5504
|
+
const StreamFeedsContext = react.createContext(undefined);
|
|
5505
|
+
/**
|
|
5506
|
+
* Hook to access the nearest FeedsClient instance.
|
|
5507
|
+
*/
|
|
5508
|
+
const useFeedsClient = () => {
|
|
5509
|
+
return react.useContext(StreamFeedsContext);
|
|
5510
|
+
};
|
|
5511
|
+
|
|
5512
|
+
/**
|
|
5513
|
+
* A React hook that returns the currently connected user on a `FeedsClient` instance and null otherwise.
|
|
5514
|
+
*/
|
|
5515
|
+
const useClientConnectedUser = () => {
|
|
5516
|
+
const client = useFeedsClient();
|
|
5517
|
+
const { user } = useStateStore(client?.state, selector$7) ?? {};
|
|
5518
|
+
return user;
|
|
5519
|
+
};
|
|
5520
|
+
const selector$7 = (nextState) => ({
|
|
5521
|
+
user: nextState.connected_user,
|
|
5522
|
+
});
|
|
5523
|
+
|
|
5524
|
+
/**
|
|
5525
|
+
* A React hook that returns the websocket connection state of `FeedsClient`.
|
|
5526
|
+
*/
|
|
5527
|
+
const useWsConnectionState = () => {
|
|
5528
|
+
const client = useFeedsClient();
|
|
5529
|
+
const { is_healthy } = useStateStore(client?.state, selector$6) ?? {};
|
|
5530
|
+
return { is_healthy };
|
|
5531
|
+
};
|
|
5532
|
+
const selector$6 = (nextState) => ({
|
|
5533
|
+
is_healthy: nextState.is_ws_connection_healthy,
|
|
5534
|
+
});
|
|
5535
|
+
|
|
5536
|
+
const StreamFeedContext = react.createContext(undefined);
|
|
5537
|
+
/**
|
|
5538
|
+
* Hook to access the nearest Feed instance.
|
|
5539
|
+
*/
|
|
5540
|
+
const useFeedContext = () => {
|
|
5541
|
+
return react.useContext(StreamFeedContext);
|
|
5542
|
+
};
|
|
5543
|
+
|
|
5544
|
+
/**
|
|
5545
|
+
* A utility hook implementing a stable callback. It takes in an unstable method that
|
|
5546
|
+
* is supposed to be invoked somewhere deeper in the DOM tree without making it
|
|
5547
|
+
* change its reference every time the parent component rerenders. It will also return
|
|
5548
|
+
* the value of the callback if it does return one.
|
|
5549
|
+
* A common use-case would be having a function whose invocation depends on state
|
|
5550
|
+
* somewhere high up in the DOM tree and wanting to use the same function deeper
|
|
5551
|
+
* down, for example in a leaf node and simply using useCallback results in
|
|
5552
|
+
* cascading dependency hell. If we wrap it in useStableCallback, we would be able
|
|
5553
|
+
* to:
|
|
5554
|
+
* - Use the same function as a dependency of another hook (since it is stable)
|
|
5555
|
+
* - Still invoke it and get the latest state
|
|
5556
|
+
*
|
|
5557
|
+
* **Caveats:**
|
|
5558
|
+
* - Never wrap a function that is supposed to return a React.ReactElement in
|
|
5559
|
+
* useStableCallback, since React will not know that the DOM needs to be updated
|
|
5560
|
+
* whenever the callback value changes (for example, renderItem from FlatList must
|
|
5561
|
+
* never be wrapped in this hook)
|
|
5562
|
+
* - Always prefer using a standard useCallback/stable function wherever possible
|
|
5563
|
+
* (the purpose of useStableCallback is to bridge the gap between top level contexts
|
|
5564
|
+
* and cascading rereders in downstream components - **not** as an escape hatch)
|
|
5565
|
+
* @param callback - the callback we want to stabilize
|
|
5566
|
+
*/
|
|
5567
|
+
const useStableCallback = (callback) => {
|
|
5568
|
+
const ref = react.useRef(callback);
|
|
5569
|
+
ref.current = callback;
|
|
5570
|
+
return react.useCallback((...args) => {
|
|
5571
|
+
return ref.current(...args);
|
|
5572
|
+
}, []);
|
|
5573
|
+
};
|
|
5574
|
+
|
|
5575
|
+
/**
|
|
5576
|
+
* A React hook that returns a reactive object containing the current activities,
|
|
5577
|
+
* loading state and whether there is a next page to paginate to or not.
|
|
5578
|
+
*/
|
|
5579
|
+
const useFeedActivities = (feedFromProps) => {
|
|
5580
|
+
const feedFromContext = useFeedContext();
|
|
5581
|
+
const feed = feedFromProps ?? feedFromContext;
|
|
5582
|
+
const data = useStateStore(feed?.state, selector$5);
|
|
5583
|
+
const loadNextPage = useStableCallback(async () => {
|
|
5584
|
+
if (!feed || !data?.has_next_page || data?.is_loading) {
|
|
5585
|
+
return;
|
|
5586
|
+
}
|
|
5587
|
+
await feed.getNextPage();
|
|
5588
|
+
});
|
|
5589
|
+
return react.useMemo(() => ({ ...data, loadNextPage }), [data, loadNextPage]);
|
|
5590
|
+
};
|
|
5591
|
+
const selector$5 = ({ is_loading_activities, next, activities = [] }) => ({
|
|
5592
|
+
is_loading: is_loading_activities,
|
|
5593
|
+
has_next_page: typeof next !== 'undefined',
|
|
5594
|
+
activities,
|
|
5595
|
+
});
|
|
5596
|
+
|
|
5597
|
+
function useComments({ feed: feedFromProps, parent, }) {
|
|
5598
|
+
const feedFromContext = useFeedContext();
|
|
5599
|
+
const feed = feedFromProps ?? feedFromContext;
|
|
5600
|
+
const selector = react.useCallback((state) => ({
|
|
5601
|
+
comments: state.comments_by_entity_id?.[parent.id]?.comments,
|
|
5602
|
+
comments_pagination: state.comments_by_entity_id?.[parent.id]?.pagination,
|
|
5603
|
+
}), [parent.id]);
|
|
5604
|
+
const data = useStateStore(feed?.state, selector);
|
|
5605
|
+
const loadNextPage = react.useMemo(() => {
|
|
5606
|
+
if (!feed)
|
|
5607
|
+
return undefined;
|
|
5608
|
+
return (request) => {
|
|
5609
|
+
if (isCommentResponse(parent)) {
|
|
5610
|
+
return feed.loadNextPageCommentReplies(parent, request);
|
|
5611
|
+
}
|
|
5612
|
+
else {
|
|
5613
|
+
return feed.loadNextPageActivityComments(parent, request);
|
|
5614
|
+
}
|
|
5615
|
+
};
|
|
5616
|
+
}, [feed, parent]);
|
|
5617
|
+
return react.useMemo(() => {
|
|
5618
|
+
if (!data) {
|
|
5619
|
+
return undefined;
|
|
5620
|
+
}
|
|
5621
|
+
return {
|
|
5622
|
+
...data,
|
|
5623
|
+
has_next_page: checkHasAnotherPage(data.comments, data.comments_pagination?.next),
|
|
5624
|
+
is_loading_next_page: data?.comments_pagination?.loading_next_page ?? false,
|
|
5625
|
+
loadNextPage,
|
|
5626
|
+
};
|
|
5627
|
+
}, [data, loadNextPage]);
|
|
5628
|
+
}
|
|
5629
|
+
|
|
5630
|
+
const FeedOwnCapability = {
|
|
5631
|
+
ADD_ACTIVITY: 'add-activity',
|
|
5632
|
+
ADD_ACTIVITY_REACTION: 'add-activity-reaction',
|
|
5633
|
+
ADD_COMMENT: 'add-comment',
|
|
5634
|
+
ADD_COMMENT_REACTION: 'add-comment-reaction',
|
|
5635
|
+
BOOKMARK_ACTIVITY: 'bookmark-activity',
|
|
5636
|
+
CREATE_FEED: 'create-feed',
|
|
5637
|
+
DELETE_BOOKMARK: 'delete-bookmark',
|
|
5638
|
+
DELETE_COMMENT: 'delete-comment',
|
|
5639
|
+
DELETE_FEED: 'delete-feed',
|
|
5640
|
+
EDIT_BOOKMARK: 'edit-bookmark',
|
|
5641
|
+
FOLLOW: 'follow',
|
|
5642
|
+
INVITE_FEED: 'invite-feed',
|
|
5643
|
+
JOIN_FEED: 'join-feed',
|
|
5644
|
+
LEAVE_FEED: 'leave-feed',
|
|
5645
|
+
MANAGE_FEED_GROUP: 'manage-feed-group',
|
|
5646
|
+
MARK_ACTIVITY: 'mark-activity',
|
|
5647
|
+
PIN_ACTIVITY: 'pin-activity',
|
|
5648
|
+
QUERY_FEED_MEMBERS: 'query-feed-members',
|
|
5649
|
+
QUERY_FOLLOWS: 'query-follows',
|
|
5650
|
+
READ_ACTIVITIES: 'read-activities',
|
|
5651
|
+
READ_FEED: 'read-feed',
|
|
5652
|
+
REMOVE_ACTIVITY: 'remove-activity',
|
|
5653
|
+
REMOVE_ACTIVITY_REACTION: 'remove-activity-reaction',
|
|
5654
|
+
REMOVE_COMMENT_REACTION: 'remove-comment-reaction',
|
|
5655
|
+
UNFOLLOW: 'unfollow',
|
|
5656
|
+
UPDATE_ACTIVITY: 'update-activity',
|
|
5657
|
+
UPDATE_COMMENT: 'update-comment',
|
|
5658
|
+
UPDATE_FEED: 'update-feed',
|
|
5659
|
+
UPDATE_FEED_FOLLOWERS: 'update-feed-followers',
|
|
5660
|
+
UPDATE_FEED_MEMBERS: 'update-feed-members',
|
|
5661
|
+
};
|
|
5662
|
+
|
|
5663
|
+
const stableEmptyArray = [];
|
|
5664
|
+
const selector$4 = (currentState) => ({
|
|
5665
|
+
oc: currentState.own_capabilities ?? stableEmptyArray,
|
|
5666
|
+
});
|
|
5667
|
+
const useOwnCapabilities = (feedFromProps) => {
|
|
5668
|
+
const feedFromContext = useFeedContext();
|
|
5669
|
+
const feed = feedFromProps ?? feedFromContext;
|
|
5670
|
+
const { oc = stableEmptyArray } = useStateStore(feed?.state, selector$4) ?? {};
|
|
5671
|
+
return react.useMemo(() => ({
|
|
5672
|
+
can_add_activity: oc.indexOf(FeedOwnCapability.ADD_ACTIVITY) > -1,
|
|
5673
|
+
can_add_activity_reaction: oc.indexOf(FeedOwnCapability.ADD_ACTIVITY_REACTION) > -1,
|
|
5674
|
+
can_add_comment: oc.indexOf(FeedOwnCapability.ADD_COMMENT) > -1,
|
|
5675
|
+
can_add_comment_reaction: oc.indexOf(FeedOwnCapability.ADD_COMMENT_REACTION) > -1,
|
|
5676
|
+
can_bookmark_activity: oc.indexOf(FeedOwnCapability.BOOKMARK_ACTIVITY) > -1,
|
|
5677
|
+
can_create_feed: oc.indexOf(FeedOwnCapability.CREATE_FEED) > -1,
|
|
5678
|
+
can_delete_bookmark: oc.indexOf(FeedOwnCapability.DELETE_BOOKMARK) > -1,
|
|
5679
|
+
can_delete_comment: oc.indexOf(FeedOwnCapability.DELETE_COMMENT) > -1,
|
|
5680
|
+
can_delete_feed: oc.indexOf(FeedOwnCapability.DELETE_FEED) > -1,
|
|
5681
|
+
can_edit_bookmark: oc.indexOf(FeedOwnCapability.EDIT_BOOKMARK) > -1,
|
|
5682
|
+
can_follow: oc.indexOf(FeedOwnCapability.FOLLOW) > -1,
|
|
5683
|
+
can_remove_activity: oc.indexOf(FeedOwnCapability.REMOVE_ACTIVITY) > -1,
|
|
5684
|
+
can_remove_activity_reaction: oc.indexOf(FeedOwnCapability.REMOVE_ACTIVITY_REACTION) > -1,
|
|
5685
|
+
can_remove_comment_reaction: oc.indexOf(FeedOwnCapability.REMOVE_COMMENT_REACTION) > -1,
|
|
5686
|
+
can_unfollow: oc.indexOf(FeedOwnCapability.UNFOLLOW) > -1,
|
|
5687
|
+
can_update_feed: oc.indexOf(FeedOwnCapability.UPDATE_FEED) > -1,
|
|
5688
|
+
can_invite_feed: oc.indexOf(FeedOwnCapability.INVITE_FEED) > -1,
|
|
5689
|
+
can_join_feed: oc.indexOf(FeedOwnCapability.JOIN_FEED) > -1,
|
|
5690
|
+
can_leave_feed: oc.indexOf(FeedOwnCapability.LEAVE_FEED) > -1,
|
|
5691
|
+
can_manage_feed_group: oc.indexOf(FeedOwnCapability.MANAGE_FEED_GROUP) > -1,
|
|
5692
|
+
can_mark_activity: oc.indexOf(FeedOwnCapability.MARK_ACTIVITY) > -1,
|
|
5693
|
+
can_pin_activity: oc.indexOf(FeedOwnCapability.PIN_ACTIVITY) > -1,
|
|
5694
|
+
can_query_feed_members: oc.indexOf(FeedOwnCapability.QUERY_FEED_MEMBERS) > -1,
|
|
5695
|
+
can_query_follows: oc.indexOf(FeedOwnCapability.QUERY_FOLLOWS) > -1,
|
|
5696
|
+
can_read_activities: oc.indexOf(FeedOwnCapability.READ_ACTIVITIES) > -1,
|
|
5697
|
+
can_read_feed: oc.indexOf(FeedOwnCapability.READ_FEED) > -1,
|
|
5698
|
+
can_update_activity: oc.indexOf(FeedOwnCapability.UPDATE_ACTIVITY) > -1,
|
|
5699
|
+
can_update_comment: oc.indexOf(FeedOwnCapability.UPDATE_COMMENT) > -1,
|
|
5700
|
+
can_update_feed_followers: oc.indexOf(FeedOwnCapability.UPDATE_FEED_FOLLOWERS) > -1,
|
|
5701
|
+
can_update_feed_members: oc.indexOf(FeedOwnCapability.UPDATE_FEED_MEMBERS) > -1,
|
|
5702
|
+
}), [oc]);
|
|
5703
|
+
};
|
|
5704
|
+
|
|
5705
|
+
const selector$3 = ({ follower_count, followers, followers_pagination, }) => ({
|
|
5706
|
+
follower_count,
|
|
5707
|
+
followers,
|
|
5708
|
+
followers_pagination,
|
|
5709
|
+
});
|
|
5710
|
+
function useFollowers(feedFromProps) {
|
|
5711
|
+
const feedFromContext = useFeedContext();
|
|
5712
|
+
const feed = feedFromProps ?? feedFromContext;
|
|
5713
|
+
const data = useStateStore(feed?.state, selector$3);
|
|
5714
|
+
const loadNextPage = react.useCallback((...options) => feed?.loadNextPageFollowers(...options), [feed]);
|
|
5715
|
+
return react.useMemo(() => {
|
|
5716
|
+
if (!data) {
|
|
5717
|
+
return undefined;
|
|
5718
|
+
}
|
|
5719
|
+
return {
|
|
5720
|
+
...data,
|
|
5721
|
+
is_loading_next_page: data.followers_pagination?.loading_next_page ?? false,
|
|
5722
|
+
has_next_page: checkHasAnotherPage(data.followers, data.followers_pagination?.next),
|
|
5723
|
+
loadNextPage,
|
|
5724
|
+
};
|
|
5725
|
+
}, [data, loadNextPage]);
|
|
5726
|
+
}
|
|
5727
|
+
|
|
5728
|
+
const selector$2 = ({ following_count, following, following_pagination, }) => ({
|
|
5729
|
+
following_count,
|
|
5730
|
+
following,
|
|
5731
|
+
following_pagination,
|
|
5732
|
+
});
|
|
5733
|
+
function useFollowing(feedFromProps) {
|
|
5734
|
+
const feedFromContext = useFeedContext();
|
|
5735
|
+
const feed = feedFromProps ?? feedFromContext;
|
|
5736
|
+
const data = useStateStore(feed?.state, selector$2);
|
|
5737
|
+
const loadNextPage = react.useCallback((...options) => feed?.loadNextPageFollowing(...options), [feed]);
|
|
5738
|
+
return react.useMemo(() => {
|
|
5739
|
+
if (!data) {
|
|
5740
|
+
return undefined;
|
|
5741
|
+
}
|
|
5742
|
+
return {
|
|
5743
|
+
...data,
|
|
5744
|
+
is_loading_next_page: data.following_pagination?.loading_next_page ?? false,
|
|
5745
|
+
has_next_page: checkHasAnotherPage(data.following, data.following_pagination?.next),
|
|
5746
|
+
loadNextPage,
|
|
5747
|
+
};
|
|
5748
|
+
}, [data, loadNextPage]);
|
|
5749
|
+
}
|
|
5750
|
+
|
|
5751
|
+
/**
|
|
5752
|
+
* A React hook that returns a reactive object containing some often used
|
|
5753
|
+
* metadata for a feed.
|
|
5754
|
+
*/
|
|
5755
|
+
const useFeedMetadata = (feedFromProps) => {
|
|
5756
|
+
const feedFromContext = useFeedContext();
|
|
5757
|
+
const feed = feedFromProps ?? feedFromContext;
|
|
5758
|
+
return useStateStore(feed?.state, selector$1);
|
|
5759
|
+
};
|
|
5760
|
+
const selector$1 = ({ follower_count = 0, following_count = 0, created_by, created_at, updated_at, }) => ({
|
|
5761
|
+
created_by,
|
|
5762
|
+
follower_count,
|
|
5763
|
+
following_count,
|
|
5764
|
+
created_at,
|
|
5765
|
+
updated_at,
|
|
5766
|
+
});
|
|
5767
|
+
|
|
5768
|
+
/**
|
|
5769
|
+
* A React hook that returns a reactive array of feeds that the current user
|
|
5770
|
+
* owns and are following the respective feed that we are observing.
|
|
5771
|
+
*/
|
|
5772
|
+
const useOwnFollows = (feedFromProps) => {
|
|
5773
|
+
const feedFromContext = useFeedContext();
|
|
5774
|
+
const feed = feedFromProps ?? feedFromContext;
|
|
5775
|
+
return useStateStore(feed?.state, selector);
|
|
5776
|
+
};
|
|
5777
|
+
const selector = ({ own_follows }) => ({
|
|
5778
|
+
own_follows,
|
|
5779
|
+
});
|
|
5780
|
+
|
|
5781
|
+
/**
|
|
5782
|
+
* A utility hook that takes in an entity and a reaction type, and creates reaction actions
|
|
5783
|
+
* that can then be used on the UI. The entity can be either an ActivityResponse or a CommentResponse
|
|
5784
|
+
* as the hook determines internally which APIs it is supposed to use, while taking the
|
|
5785
|
+
* correct ownCapabilities into account.
|
|
5786
|
+
* @param entity - The entity to which we want to add a reaction, can be either ActivityResponse or CommentResponse.
|
|
5787
|
+
* @param type - The type of reaction we want to add or remove.
|
|
5788
|
+
*/
|
|
5789
|
+
const useReactionActions = ({ entity, type, }) => {
|
|
5790
|
+
const client = useFeedsClient();
|
|
5791
|
+
const isComment = isCommentResponse(entity);
|
|
5792
|
+
const hasOwnReaction = react.useMemo(() => !!entity.own_reactions?.find((r) => r.type === type), [entity.own_reactions, type]);
|
|
5793
|
+
const addReaction = useStableCallback(async () => {
|
|
5794
|
+
await (isComment
|
|
5795
|
+
? client?.addCommentReaction({ comment_id: entity.id, type })
|
|
5796
|
+
: client?.addReaction({ activity_id: entity.id, type }));
|
|
5797
|
+
});
|
|
5798
|
+
const removeReaction = useStableCallback(async () => {
|
|
5799
|
+
await (isComment
|
|
5800
|
+
? client?.deleteCommentReaction({ comment_id: entity.id, type })
|
|
5801
|
+
: client?.deleteActivityReaction({
|
|
5802
|
+
activity_id: entity.id,
|
|
5803
|
+
type,
|
|
5804
|
+
}));
|
|
5805
|
+
});
|
|
5806
|
+
const toggleReaction = useStableCallback(async () => {
|
|
5807
|
+
if (hasOwnReaction) {
|
|
5808
|
+
await removeReaction();
|
|
5809
|
+
}
|
|
5810
|
+
else {
|
|
5811
|
+
await addReaction();
|
|
5812
|
+
}
|
|
5813
|
+
});
|
|
5814
|
+
return react.useMemo(() => ({ addReaction, removeReaction, toggleReaction }), [addReaction, removeReaction, toggleReaction]);
|
|
5815
|
+
};
|
|
5816
|
+
|
|
5520
5817
|
const StreamFeeds = ({ client, children }) => {
|
|
5521
5818
|
return (jsxRuntime.jsx(StreamFeedsContext.Provider, { value: client, children: children }));
|
|
5522
5819
|
};
|
|
5523
5820
|
StreamFeeds.displayName = 'StreamFeeds';
|
|
5524
5821
|
|
|
5822
|
+
const StreamFeed = ({ feed, children }) => {
|
|
5823
|
+
return (jsxRuntime.jsx(StreamFeedContext.Provider, { value: feed, children: children }));
|
|
5824
|
+
};
|
|
5825
|
+
StreamFeed.displayName = 'StreamFeed';
|
|
5826
|
+
|
|
5827
|
+
exports.StreamFeed = StreamFeed;
|
|
5828
|
+
exports.StreamFeedContext = StreamFeedContext;
|
|
5525
5829
|
exports.StreamFeeds = StreamFeeds;
|
|
5526
5830
|
exports.StreamFeedsContext = StreamFeedsContext;
|
|
5527
5831
|
exports.useClientConnectedUser = useClientConnectedUser;
|
|
5528
5832
|
exports.useComments = useComments;
|
|
5529
5833
|
exports.useCreateFeedsClient = useCreateFeedsClient;
|
|
5834
|
+
exports.useFeedActivities = useFeedActivities;
|
|
5835
|
+
exports.useFeedContext = useFeedContext;
|
|
5836
|
+
exports.useFeedMetadata = useFeedMetadata;
|
|
5530
5837
|
exports.useFeedsClient = useFeedsClient;
|
|
5838
|
+
exports.useFollowers = useFollowers;
|
|
5839
|
+
exports.useFollowing = useFollowing;
|
|
5531
5840
|
exports.useOwnCapabilities = useOwnCapabilities;
|
|
5841
|
+
exports.useOwnFollows = useOwnFollows;
|
|
5842
|
+
exports.useReactionActions = useReactionActions;
|
|
5532
5843
|
exports.useStateStore = useStateStore;
|
|
5533
5844
|
exports.useWsConnectionState = useWsConnectionState;
|
|
5534
5845
|
//# sourceMappingURL=index-react-bindings.node.cjs.map
|