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