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