@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
|
@@ -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))
|
|
@@ -2014,6 +1898,7 @@ class FeedsApi {
|
|
|
2014
1898
|
};
|
|
2015
1899
|
const body = {
|
|
2016
1900
|
type: request?.type,
|
|
1901
|
+
create_notification_activity: request?.create_notification_activity,
|
|
2017
1902
|
custom: request?.custom,
|
|
2018
1903
|
};
|
|
2019
1904
|
const response = await this.apiClient.sendRequest('POST', '/api/v2/feeds/activities/{activity_id}/reactions', pathParams, undefined, body, 'application/json');
|
|
@@ -2108,6 +1993,7 @@ class FeedsApi {
|
|
|
2108
1993
|
comment: request?.comment,
|
|
2109
1994
|
object_id: request?.object_id,
|
|
2110
1995
|
object_type: request?.object_type,
|
|
1996
|
+
create_notification_activity: request?.create_notification_activity,
|
|
2111
1997
|
parent_id: request?.parent_id,
|
|
2112
1998
|
attachments: request?.attachments,
|
|
2113
1999
|
mentioned_user_ids: request?.mentioned_user_ids,
|
|
@@ -2171,6 +2057,7 @@ class FeedsApi {
|
|
|
2171
2057
|
};
|
|
2172
2058
|
const body = {
|
|
2173
2059
|
type: request?.type,
|
|
2060
|
+
create_notification_activity: request?.create_notification_activity,
|
|
2174
2061
|
custom: request?.custom,
|
|
2175
2062
|
};
|
|
2176
2063
|
const response = await this.apiClient.sendRequest('POST', '/api/v2/feeds/comments/{comment_id}/reactions', pathParams, undefined, body, 'application/json');
|
|
@@ -2396,6 +2283,7 @@ class FeedsApi {
|
|
|
2396
2283
|
const body = {
|
|
2397
2284
|
source: request?.source,
|
|
2398
2285
|
target: request?.target,
|
|
2286
|
+
create_notification_activity: request?.create_notification_activity,
|
|
2399
2287
|
follower_role: request?.follower_role,
|
|
2400
2288
|
push_preference: request?.push_preference,
|
|
2401
2289
|
custom: request?.custom,
|
|
@@ -2408,6 +2296,7 @@ class FeedsApi {
|
|
|
2408
2296
|
const body = {
|
|
2409
2297
|
source: request?.source,
|
|
2410
2298
|
target: request?.target,
|
|
2299
|
+
create_notification_activity: request?.create_notification_activity,
|
|
2411
2300
|
push_preference: request?.push_preference,
|
|
2412
2301
|
custom: request?.custom,
|
|
2413
2302
|
};
|
|
@@ -2828,6 +2717,13 @@ function removeConnectionEventListeners(cb) {
|
|
|
2828
2717
|
window.removeEventListener('online', cb);
|
|
2829
2718
|
}
|
|
2830
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
|
+
};
|
|
2831
2727
|
const capitalize = (s) => {
|
|
2832
2728
|
return `${s.charAt(0).toLocaleUpperCase()}${s.slice(1)}`;
|
|
2833
2729
|
};
|
|
@@ -3098,7 +2994,10 @@ class StableWSConnection {
|
|
|
3098
2994
|
this.onmessage = (wsID, event) => {
|
|
3099
2995
|
if (this.wsID !== wsID)
|
|
3100
2996
|
return;
|
|
3101
|
-
this._log('onmessage() - onmessage callback', {
|
|
2997
|
+
this._log('onmessage() - onmessage callback', {
|
|
2998
|
+
event: { ...event, data: JSON.parse(event.data) },
|
|
2999
|
+
wsID,
|
|
3000
|
+
});
|
|
3102
3001
|
let data = typeof event.data === 'string' ? JSON.parse(event.data) : null;
|
|
3103
3002
|
this.decoders.forEach((decode) => {
|
|
3104
3003
|
data = decode(data);
|
|
@@ -4113,8 +4012,15 @@ const updateBookmarkInActivities = (event, activities, isCurrentUser) => {
|
|
|
4113
4012
|
return updateActivityInActivities(updatedActivity, activities);
|
|
4114
4013
|
};
|
|
4115
4014
|
|
|
4116
|
-
const
|
|
4117
|
-
|
|
4015
|
+
const checkHasAnotherPage = (v, cursor) => (typeof v === 'undefined' && typeof cursor === 'undefined') ||
|
|
4016
|
+
typeof cursor === 'string';
|
|
4017
|
+
const isCommentResponse = (entity) => {
|
|
4018
|
+
return typeof entity?.object_id === 'string';
|
|
4019
|
+
};
|
|
4020
|
+
const Constants = {
|
|
4021
|
+
DEFAULT_COMMENT_PAGINATION: 'first',
|
|
4022
|
+
};
|
|
4023
|
+
|
|
4118
4024
|
class Feed extends FeedApi {
|
|
4119
4025
|
constructor(client, groupId, id, data) {
|
|
4120
4026
|
// Need this ugly cast because fileUpload endpoints :(
|
|
@@ -4187,7 +4093,7 @@ class Feed extends FeedApi {
|
|
|
4187
4093
|
const entityState = currentState.comments_by_entity_id[forId];
|
|
4188
4094
|
const newComments = entityState?.comments?.concat([]) ?? [];
|
|
4189
4095
|
if (entityState?.pagination?.sort === 'last' &&
|
|
4190
|
-
entityState?.pagination.next
|
|
4096
|
+
!checkHasAnotherPage(entityState.comments, entityState?.pagination.next)) {
|
|
4191
4097
|
newComments.unshift(comment);
|
|
4192
4098
|
}
|
|
4193
4099
|
else if (entityState?.pagination?.sort === 'first') {
|
|
@@ -4274,7 +4180,7 @@ class Feed extends FeedApi {
|
|
|
4274
4180
|
...currentState,
|
|
4275
4181
|
...event.follow.source_feed,
|
|
4276
4182
|
};
|
|
4277
|
-
if (currentState.following_pagination?.next
|
|
4183
|
+
if (!checkHasAnotherPage(currentState.following, currentState.following_pagination?.next)) {
|
|
4278
4184
|
// TODO: respect sort
|
|
4279
4185
|
newState.following = currentState.following
|
|
4280
4186
|
? currentState.following.concat(event.follow)
|
|
@@ -4295,7 +4201,7 @@ class Feed extends FeedApi {
|
|
|
4295
4201
|
? currentState.own_follows.concat(event.follow)
|
|
4296
4202
|
: [event.follow];
|
|
4297
4203
|
}
|
|
4298
|
-
if (currentState.followers_pagination?.next
|
|
4204
|
+
if (!checkHasAnotherPage(currentState.followers, currentState.followers_pagination?.next)) {
|
|
4299
4205
|
// TODO: respect sort
|
|
4300
4206
|
newState.followers = currentState.followers
|
|
4301
4207
|
? currentState.followers.concat(event.follow)
|
|
@@ -4336,40 +4242,60 @@ class Feed extends FeedApi {
|
|
|
4336
4242
|
'feeds.comment.reaction.deleted': this.handleCommentReactionEvent.bind(this),
|
|
4337
4243
|
'feeds.comment.reaction.updated': Feed.noop,
|
|
4338
4244
|
'feeds.feed_member.added': (event) => {
|
|
4339
|
-
const {
|
|
4340
|
-
// do not add a member if the pagination has reached the end of the list
|
|
4341
|
-
if (this.currentState.member_pagination?.next !== END_OF_LIST)
|
|
4342
|
-
return;
|
|
4245
|
+
const { connectedUser } = this.client.state.getLatestValue();
|
|
4343
4246
|
this.state.next((currentState) => {
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4247
|
+
let newState;
|
|
4248
|
+
if (!checkHasAnotherPage(currentState.members, currentState.member_pagination?.next)) {
|
|
4249
|
+
newState ?? (newState = {
|
|
4250
|
+
...currentState,
|
|
4251
|
+
});
|
|
4252
|
+
newState.members = newState.members?.concat(event.member) ?? [
|
|
4253
|
+
event.member,
|
|
4254
|
+
];
|
|
4255
|
+
}
|
|
4256
|
+
if (connectedUser?.id === event.member.user.id) {
|
|
4257
|
+
newState ?? (newState = {
|
|
4258
|
+
...currentState,
|
|
4259
|
+
});
|
|
4260
|
+
newState.own_membership = event.member;
|
|
4261
|
+
}
|
|
4262
|
+
return newState ?? currentState;
|
|
4351
4263
|
});
|
|
4352
4264
|
},
|
|
4353
4265
|
'feeds.feed_member.removed': (event) => {
|
|
4266
|
+
const { connectedUser } = this.client.state.getLatestValue();
|
|
4354
4267
|
this.state.next((currentState) => {
|
|
4355
|
-
|
|
4268
|
+
const newState = {
|
|
4356
4269
|
...currentState,
|
|
4357
4270
|
members: currentState.members?.filter((member) => member.user.id !== event.user?.id),
|
|
4358
4271
|
};
|
|
4272
|
+
if (connectedUser?.id === event.member_id) {
|
|
4273
|
+
delete newState.own_membership;
|
|
4274
|
+
}
|
|
4275
|
+
return newState;
|
|
4359
4276
|
});
|
|
4360
4277
|
},
|
|
4361
4278
|
'feeds.feed_member.updated': (event) => {
|
|
4279
|
+
const { connectedUser } = this.client.state.getLatestValue();
|
|
4362
4280
|
this.state.next((currentState) => {
|
|
4363
4281
|
const memberIndex = currentState.members?.findIndex((member) => member.user.id === event.member.user.id) ?? -1;
|
|
4282
|
+
let newState;
|
|
4364
4283
|
if (memberIndex !== -1) {
|
|
4284
|
+
// if there's an index, there's a member to update
|
|
4365
4285
|
const newMembers = [...currentState.members];
|
|
4366
4286
|
newMembers[memberIndex] = event.member;
|
|
4367
|
-
|
|
4287
|
+
newState ?? (newState = {
|
|
4368
4288
|
...currentState,
|
|
4369
|
-
|
|
4370
|
-
|
|
4289
|
+
});
|
|
4290
|
+
newState.members = newMembers;
|
|
4291
|
+
}
|
|
4292
|
+
if (connectedUser?.id === event.member.user.id) {
|
|
4293
|
+
newState ?? (newState = {
|
|
4294
|
+
...currentState,
|
|
4295
|
+
});
|
|
4296
|
+
newState.own_membership = event.member;
|
|
4371
4297
|
}
|
|
4372
|
-
return currentState;
|
|
4298
|
+
return newState ?? currentState;
|
|
4373
4299
|
});
|
|
4374
4300
|
},
|
|
4375
4301
|
// the poll events should be removed from here
|
|
@@ -4495,29 +4421,6 @@ class Feed extends FeedApi {
|
|
|
4495
4421
|
...currentState,
|
|
4496
4422
|
...responseCopy,
|
|
4497
4423
|
};
|
|
4498
|
-
// if there is no next cursor, set it to END_OF_LIST
|
|
4499
|
-
// request has to have a limit set for this to work
|
|
4500
|
-
if ((request?.followers_pagination?.limit ?? 0) > 0 &&
|
|
4501
|
-
typeof nextState.followers_pagination?.next === 'undefined') {
|
|
4502
|
-
nextState.followers_pagination = {
|
|
4503
|
-
...nextState.followers_pagination,
|
|
4504
|
-
next: END_OF_LIST,
|
|
4505
|
-
};
|
|
4506
|
-
}
|
|
4507
|
-
if ((request?.following_pagination?.limit ?? 0) > 0 &&
|
|
4508
|
-
typeof nextState.following_pagination?.next === 'undefined') {
|
|
4509
|
-
nextState.following_pagination = {
|
|
4510
|
-
...nextState.following_pagination,
|
|
4511
|
-
next: END_OF_LIST,
|
|
4512
|
-
};
|
|
4513
|
-
}
|
|
4514
|
-
if ((request?.member_pagination?.limit ?? 0) > 0 &&
|
|
4515
|
-
typeof nextState.member_pagination?.next === 'undefined') {
|
|
4516
|
-
nextState.member_pagination = {
|
|
4517
|
-
...nextState.member_pagination,
|
|
4518
|
-
next: END_OF_LIST,
|
|
4519
|
-
};
|
|
4520
|
-
}
|
|
4521
4424
|
if (!request?.followers_pagination?.limit) {
|
|
4522
4425
|
delete nextState.followers;
|
|
4523
4426
|
}
|
|
@@ -4608,6 +4511,7 @@ class Feed extends FeedApi {
|
|
|
4608
4511
|
});
|
|
4609
4512
|
}
|
|
4610
4513
|
async loadNextPageComments({ forId, base, sort, parentId, }) {
|
|
4514
|
+
let error;
|
|
4611
4515
|
try {
|
|
4612
4516
|
this.state.next((currentState) => ({
|
|
4613
4517
|
...currentState,
|
|
@@ -4622,7 +4526,7 @@ class Feed extends FeedApi {
|
|
|
4622
4526
|
},
|
|
4623
4527
|
},
|
|
4624
4528
|
}));
|
|
4625
|
-
const { next: newNextCursor
|
|
4529
|
+
const { next: newNextCursor, comments } = await base();
|
|
4626
4530
|
this.state.next((currentState) => {
|
|
4627
4531
|
const newPagination = {
|
|
4628
4532
|
...currentState.comments_by_entity_id[forId]?.pagination,
|
|
@@ -4647,9 +4551,8 @@ class Feed extends FeedApi {
|
|
|
4647
4551
|
};
|
|
4648
4552
|
});
|
|
4649
4553
|
}
|
|
4650
|
-
catch (
|
|
4651
|
-
|
|
4652
|
-
// TODO: figure out how to handle errorss
|
|
4554
|
+
catch (e) {
|
|
4555
|
+
error = e;
|
|
4653
4556
|
}
|
|
4654
4557
|
finally {
|
|
4655
4558
|
this.state.next((currentState) => ({
|
|
@@ -4666,15 +4569,21 @@ class Feed extends FeedApi {
|
|
|
4666
4569
|
},
|
|
4667
4570
|
}));
|
|
4668
4571
|
}
|
|
4572
|
+
if (error) {
|
|
4573
|
+
throw error;
|
|
4574
|
+
}
|
|
4669
4575
|
}
|
|
4670
4576
|
async loadNextPageActivityComments(activity, request) {
|
|
4671
|
-
const
|
|
4672
|
-
const
|
|
4673
|
-
const
|
|
4674
|
-
const
|
|
4675
|
-
const
|
|
4676
|
-
|
|
4577
|
+
const currentEntityState = this.currentState.comments_by_entity_id[activity.id];
|
|
4578
|
+
const currentPagination = currentEntityState?.pagination;
|
|
4579
|
+
const currentNextCursor = currentPagination?.next;
|
|
4580
|
+
const currentSort = currentPagination?.sort;
|
|
4581
|
+
const isLoading = currentPagination?.loading_next_page;
|
|
4582
|
+
const sort = currentSort ?? request?.sort ?? Constants.DEFAULT_COMMENT_PAGINATION;
|
|
4583
|
+
if (isLoading ||
|
|
4584
|
+
!checkHasAnotherPage(currentEntityState?.comments, currentNextCursor)) {
|
|
4677
4585
|
return;
|
|
4586
|
+
}
|
|
4678
4587
|
await this.loadNextPageComments({
|
|
4679
4588
|
forId: activity.id,
|
|
4680
4589
|
base: () => this.client.getComments({
|
|
@@ -4688,20 +4597,25 @@ class Feed extends FeedApi {
|
|
|
4688
4597
|
});
|
|
4689
4598
|
}
|
|
4690
4599
|
async loadNextPageCommentReplies(comment, request) {
|
|
4691
|
-
const
|
|
4692
|
-
const
|
|
4693
|
-
const
|
|
4694
|
-
const
|
|
4695
|
-
const
|
|
4696
|
-
|
|
4600
|
+
const currentEntityState = this.currentState.comments_by_entity_id[comment.id];
|
|
4601
|
+
const currentPagination = currentEntityState?.pagination;
|
|
4602
|
+
const currentNextCursor = currentPagination?.next;
|
|
4603
|
+
const currentSort = currentPagination?.sort;
|
|
4604
|
+
const isLoading = currentPagination?.loading_next_page;
|
|
4605
|
+
const sort = currentSort ?? request?.sort ?? Constants.DEFAULT_COMMENT_PAGINATION;
|
|
4606
|
+
if (isLoading ||
|
|
4607
|
+
!checkHasAnotherPage(currentEntityState?.comments, currentNextCursor)) {
|
|
4697
4608
|
return;
|
|
4609
|
+
}
|
|
4698
4610
|
await this.loadNextPageComments({
|
|
4699
4611
|
forId: comment.id,
|
|
4700
4612
|
base: () => this.client.getCommentReplies({
|
|
4701
4613
|
...request,
|
|
4702
4614
|
comment_id: comment.id,
|
|
4703
4615
|
// use known sort first (prevents broken pagination)
|
|
4704
|
-
sort: currentSort ??
|
|
4616
|
+
sort: currentSort ??
|
|
4617
|
+
request?.sort ??
|
|
4618
|
+
Constants.DEFAULT_COMMENT_PAGINATION,
|
|
4705
4619
|
next: currentNextCursor,
|
|
4706
4620
|
}),
|
|
4707
4621
|
parentId: comment.parent_id ?? comment.object_id,
|
|
@@ -4711,10 +4625,14 @@ class Feed extends FeedApi {
|
|
|
4711
4625
|
async loadNextPageFollows(type, request) {
|
|
4712
4626
|
const paginationKey = `${type}_pagination`;
|
|
4713
4627
|
const method = `query${capitalize(type)}`;
|
|
4628
|
+
const currentFollows = this.currentState[type];
|
|
4714
4629
|
const currentNextCursor = this.currentState[paginationKey]?.next;
|
|
4715
4630
|
const isLoading = this.currentState[paginationKey]?.loading_next_page;
|
|
4716
|
-
|
|
4631
|
+
const sort = this.currentState[paginationKey]?.sort ?? request.sort;
|
|
4632
|
+
let error;
|
|
4633
|
+
if (isLoading || !checkHasAnotherPage(currentFollows, currentNextCursor)) {
|
|
4717
4634
|
return;
|
|
4635
|
+
}
|
|
4718
4636
|
try {
|
|
4719
4637
|
this.state.next((currentState) => {
|
|
4720
4638
|
return {
|
|
@@ -4725,9 +4643,10 @@ class Feed extends FeedApi {
|
|
|
4725
4643
|
},
|
|
4726
4644
|
};
|
|
4727
4645
|
});
|
|
4728
|
-
const { next: newNextCursor
|
|
4646
|
+
const { next: newNextCursor, follows } = await this[method]({
|
|
4729
4647
|
...request,
|
|
4730
4648
|
next: currentNextCursor,
|
|
4649
|
+
sort,
|
|
4731
4650
|
});
|
|
4732
4651
|
this.state.next((currentState) => ({
|
|
4733
4652
|
...currentState,
|
|
@@ -4737,12 +4656,12 @@ class Feed extends FeedApi {
|
|
|
4737
4656
|
[paginationKey]: {
|
|
4738
4657
|
...currentState[paginationKey],
|
|
4739
4658
|
next: newNextCursor,
|
|
4659
|
+
sort,
|
|
4740
4660
|
},
|
|
4741
4661
|
}));
|
|
4742
4662
|
}
|
|
4743
|
-
catch (
|
|
4744
|
-
|
|
4745
|
-
// TODO: figure out how to handle errorss
|
|
4663
|
+
catch (e) {
|
|
4664
|
+
error = e;
|
|
4746
4665
|
}
|
|
4747
4666
|
finally {
|
|
4748
4667
|
this.state.next((currentState) => {
|
|
@@ -4755,6 +4674,9 @@ class Feed extends FeedApi {
|
|
|
4755
4674
|
};
|
|
4756
4675
|
});
|
|
4757
4676
|
}
|
|
4677
|
+
if (error) {
|
|
4678
|
+
throw error;
|
|
4679
|
+
}
|
|
4758
4680
|
}
|
|
4759
4681
|
async loadNextPageFollowers(request) {
|
|
4760
4682
|
await this.loadNextPageFollows('followers', request);
|
|
@@ -4762,6 +4684,59 @@ class Feed extends FeedApi {
|
|
|
4762
4684
|
async loadNextPageFollowing(request) {
|
|
4763
4685
|
await this.loadNextPageFollows('following', request);
|
|
4764
4686
|
}
|
|
4687
|
+
async loadNextPageMembers(request) {
|
|
4688
|
+
const currentMembers = this.currentState.members;
|
|
4689
|
+
const currentNextCursor = this.currentState.member_pagination?.next;
|
|
4690
|
+
const isLoading = this.currentState.member_pagination?.loading_next_page;
|
|
4691
|
+
const sort = this.currentState.member_pagination?.sort ?? request.sort;
|
|
4692
|
+
let error;
|
|
4693
|
+
if (isLoading || !checkHasAnotherPage(currentMembers, currentNextCursor)) {
|
|
4694
|
+
return;
|
|
4695
|
+
}
|
|
4696
|
+
try {
|
|
4697
|
+
this.state.next((currentState) => ({
|
|
4698
|
+
...currentState,
|
|
4699
|
+
member_pagination: {
|
|
4700
|
+
...currentState.member_pagination,
|
|
4701
|
+
loading_next_page: true,
|
|
4702
|
+
},
|
|
4703
|
+
}));
|
|
4704
|
+
const { next: newNextCursor, members } = await this.client.queryFeedMembers({
|
|
4705
|
+
...request,
|
|
4706
|
+
sort,
|
|
4707
|
+
feed_id: this.id,
|
|
4708
|
+
feed_group_id: this.group,
|
|
4709
|
+
next: currentNextCursor,
|
|
4710
|
+
});
|
|
4711
|
+
this.state.next((currentState) => ({
|
|
4712
|
+
...currentState,
|
|
4713
|
+
members: currentState.members
|
|
4714
|
+
? currentState.members.concat(members)
|
|
4715
|
+
: members,
|
|
4716
|
+
member_pagination: {
|
|
4717
|
+
...currentState.member_pagination,
|
|
4718
|
+
next: newNextCursor,
|
|
4719
|
+
// set sort if not defined yet
|
|
4720
|
+
sort: currentState.member_pagination?.sort ?? request.sort,
|
|
4721
|
+
},
|
|
4722
|
+
}));
|
|
4723
|
+
}
|
|
4724
|
+
catch (e) {
|
|
4725
|
+
error = e;
|
|
4726
|
+
}
|
|
4727
|
+
finally {
|
|
4728
|
+
this.state.next((currentState) => ({
|
|
4729
|
+
...currentState,
|
|
4730
|
+
member_pagination: {
|
|
4731
|
+
...currentState.member_pagination,
|
|
4732
|
+
loading_next_page: false,
|
|
4733
|
+
},
|
|
4734
|
+
}));
|
|
4735
|
+
}
|
|
4736
|
+
if (error) {
|
|
4737
|
+
throw error;
|
|
4738
|
+
}
|
|
4739
|
+
}
|
|
4765
4740
|
/**
|
|
4766
4741
|
* Method which queries followers of this feed (feeds which target this feed).
|
|
4767
4742
|
*
|
|
@@ -5252,6 +5227,9 @@ class FeedsClient extends FeedsApi {
|
|
|
5252
5227
|
throw err;
|
|
5253
5228
|
}
|
|
5254
5229
|
};
|
|
5230
|
+
this.devToken = (userId) => {
|
|
5231
|
+
return streamDevToken(userId);
|
|
5232
|
+
};
|
|
5255
5233
|
this.closePoll = async (request) => {
|
|
5256
5234
|
return await this.updatePollPartial({
|
|
5257
5235
|
poll_id: request.poll_id,
|
|
@@ -5510,10 +5488,298 @@ const useCreateFeedsClient = ({ apiKey, tokenOrProvider, userData, options, }) =
|
|
|
5510
5488
|
return client;
|
|
5511
5489
|
};
|
|
5512
5490
|
|
|
5491
|
+
const StreamFeedsContext = createContext(undefined);
|
|
5492
|
+
/**
|
|
5493
|
+
* Hook to access the nearest FeedsClient instance.
|
|
5494
|
+
*/
|
|
5495
|
+
const useFeedsClient = () => {
|
|
5496
|
+
return useContext(StreamFeedsContext);
|
|
5497
|
+
};
|
|
5498
|
+
|
|
5499
|
+
/**
|
|
5500
|
+
* A React hook that returns the currently connected user on a `FeedsClient` instance and null otherwise.
|
|
5501
|
+
*/
|
|
5502
|
+
const useClientConnectedUser = () => {
|
|
5503
|
+
const client = useFeedsClient();
|
|
5504
|
+
const { user } = useStateStore(client?.state, selector$5) ?? {};
|
|
5505
|
+
return user;
|
|
5506
|
+
};
|
|
5507
|
+
const selector$5 = (nextState) => ({
|
|
5508
|
+
user: nextState.connectedUser,
|
|
5509
|
+
});
|
|
5510
|
+
|
|
5511
|
+
/**
|
|
5512
|
+
* A React hook that returns the websocket connection state of `FeedsClient`.
|
|
5513
|
+
*/
|
|
5514
|
+
const useWsConnectionState = () => {
|
|
5515
|
+
const client = useFeedsClient();
|
|
5516
|
+
const { isHealthy } = useStateStore(client?.state, selector$4) ?? {};
|
|
5517
|
+
return { isHealthy };
|
|
5518
|
+
};
|
|
5519
|
+
const selector$4 = (nextState) => ({
|
|
5520
|
+
isHealthy: nextState.isWsConnectionHealthy,
|
|
5521
|
+
});
|
|
5522
|
+
|
|
5523
|
+
const StreamFeedContext = createContext(undefined);
|
|
5524
|
+
/**
|
|
5525
|
+
* Hook to access the nearest Feed instance.
|
|
5526
|
+
*/
|
|
5527
|
+
const useFeedContext = () => {
|
|
5528
|
+
return useContext(StreamFeedContext);
|
|
5529
|
+
};
|
|
5530
|
+
|
|
5531
|
+
/**
|
|
5532
|
+
* A utility hook implementing a stable callback. It takes in an unstable method that
|
|
5533
|
+
* is supposed to be invoked somewhere deeper in the DOM tree without making it
|
|
5534
|
+
* change its reference every time the parent component rerenders. It will also return
|
|
5535
|
+
* the value of the callback if it does return one.
|
|
5536
|
+
* A common use-case would be having a function whose invocation depends on state
|
|
5537
|
+
* somewhere high up in the DOM tree and wanting to use the same function deeper
|
|
5538
|
+
* down, for example in a leaf node and simply using useCallback results in
|
|
5539
|
+
* cascading dependency hell. If we wrap it in useStableCallback, we would be able
|
|
5540
|
+
* to:
|
|
5541
|
+
* - Use the same function as a dependency of another hook (since it is stable)
|
|
5542
|
+
* - Still invoke it and get the latest state
|
|
5543
|
+
*
|
|
5544
|
+
* **Caveats:**
|
|
5545
|
+
* - Never wrap a function that is supposed to return a React.ReactElement in
|
|
5546
|
+
* useStableCallback, since React will not know that the DOM needs to be updated
|
|
5547
|
+
* whenever the callback value changes (for example, renderItem from FlatList must
|
|
5548
|
+
* never be wrapped in this hook)
|
|
5549
|
+
* - Always prefer using a standard useCallback/stable function wherever possible
|
|
5550
|
+
* (the purpose of useStableCallback is to bridge the gap between top level contexts
|
|
5551
|
+
* and cascading rereders in downstream components - **not** as an escape hatch)
|
|
5552
|
+
* @param callback - the callback we want to stabilize
|
|
5553
|
+
*/
|
|
5554
|
+
const useStableCallback = (callback) => {
|
|
5555
|
+
const ref = useRef(callback);
|
|
5556
|
+
ref.current = callback;
|
|
5557
|
+
return useCallback((...args) => {
|
|
5558
|
+
return ref.current(...args);
|
|
5559
|
+
}, []);
|
|
5560
|
+
};
|
|
5561
|
+
|
|
5562
|
+
/**
|
|
5563
|
+
* A React hook that returns a reactive object containing the current activities,
|
|
5564
|
+
* loading state and whether there is a next page to paginate to or not.
|
|
5565
|
+
*/
|
|
5566
|
+
const useFeedActivities = (feedFromProps) => {
|
|
5567
|
+
const feedFromContext = useFeedContext();
|
|
5568
|
+
const feed = feedFromProps ?? feedFromContext;
|
|
5569
|
+
const data = useStateStore(feed?.state, selector$3);
|
|
5570
|
+
const loadNextPage = useStableCallback(async () => {
|
|
5571
|
+
if (!feed || !data?.hasNextPage || data?.isLoading) {
|
|
5572
|
+
return;
|
|
5573
|
+
}
|
|
5574
|
+
await feed.getNextPage();
|
|
5575
|
+
});
|
|
5576
|
+
return useMemo(() => ({ ...data, loadNextPage }), [data, loadNextPage]);
|
|
5577
|
+
};
|
|
5578
|
+
const selector$3 = (nextState) => ({
|
|
5579
|
+
isLoading: nextState.is_loading_activities,
|
|
5580
|
+
hasNextPage: typeof nextState.next !== 'undefined',
|
|
5581
|
+
activities: nextState.activities ?? [],
|
|
5582
|
+
});
|
|
5583
|
+
|
|
5584
|
+
function useComments({ feed: feedFromProps, parent, }) {
|
|
5585
|
+
const feedFromContext = useFeedContext();
|
|
5586
|
+
const feed = feedFromProps ?? feedFromContext;
|
|
5587
|
+
const selector = useCallback((state) => ({
|
|
5588
|
+
comments: state.comments_by_entity_id?.[parent.id]?.comments,
|
|
5589
|
+
comments_pagination: state.comments_by_entity_id?.[parent.id]?.pagination,
|
|
5590
|
+
}), [parent.id]);
|
|
5591
|
+
const data = useStateStore(feed?.state, selector);
|
|
5592
|
+
const loadNextPage = useMemo(() => {
|
|
5593
|
+
if (!feed)
|
|
5594
|
+
return undefined;
|
|
5595
|
+
return (request) => {
|
|
5596
|
+
if (isCommentResponse(parent)) {
|
|
5597
|
+
return feed.loadNextPageCommentReplies(parent, request);
|
|
5598
|
+
}
|
|
5599
|
+
else {
|
|
5600
|
+
return feed.loadNextPageActivityComments(parent, request);
|
|
5601
|
+
}
|
|
5602
|
+
};
|
|
5603
|
+
}, [feed, parent]);
|
|
5604
|
+
return useMemo(() => {
|
|
5605
|
+
if (!data) {
|
|
5606
|
+
return undefined;
|
|
5607
|
+
}
|
|
5608
|
+
return {
|
|
5609
|
+
...data,
|
|
5610
|
+
hasNextPage: checkHasAnotherPage(data.comments, data.comments_pagination?.next),
|
|
5611
|
+
isLoadingNextPage: data?.comments_pagination?.loading_next_page ?? false,
|
|
5612
|
+
loadNextPage,
|
|
5613
|
+
};
|
|
5614
|
+
}, [data, loadNextPage]);
|
|
5615
|
+
}
|
|
5616
|
+
|
|
5617
|
+
const FeedOwnCapability = {
|
|
5618
|
+
ADD_ACTIVITY: 'add-activity',
|
|
5619
|
+
ADD_ACTIVITY_REACTION: 'add-activity-reaction',
|
|
5620
|
+
ADD_COMMENT: 'add-comment',
|
|
5621
|
+
ADD_COMMENT_REACTION: 'add-comment-reaction',
|
|
5622
|
+
BOOKMARK_ACTIVITY: 'bookmark-activity',
|
|
5623
|
+
CREATE_FEED: 'create-feed',
|
|
5624
|
+
DELETE_BOOKMARK: 'delete-bookmark',
|
|
5625
|
+
DELETE_COMMENT: 'delete-comment',
|
|
5626
|
+
DELETE_FEED: 'delete-feed',
|
|
5627
|
+
EDIT_BOOKMARK: 'edit-bookmark',
|
|
5628
|
+
FOLLOW: 'follow',
|
|
5629
|
+
INVITE_FEED: 'invite-feed',
|
|
5630
|
+
JOIN_FEED: 'join-feed',
|
|
5631
|
+
LEAVE_FEED: 'leave-feed',
|
|
5632
|
+
MANAGE_FEED_GROUP: 'manage-feed-group',
|
|
5633
|
+
MARK_ACTIVITY: 'mark-activity',
|
|
5634
|
+
PIN_ACTIVITY: 'pin-activity',
|
|
5635
|
+
QUERY_FEED_MEMBERS: 'query-feed-members',
|
|
5636
|
+
QUERY_FOLLOWS: 'query-follows',
|
|
5637
|
+
READ_ACTIVITIES: 'read-activities',
|
|
5638
|
+
READ_FEED: 'read-feed',
|
|
5639
|
+
REMOVE_ACTIVITY: 'remove-activity',
|
|
5640
|
+
REMOVE_ACTIVITY_REACTION: 'remove-activity-reaction',
|
|
5641
|
+
REMOVE_COMMENT_REACTION: 'remove-comment-reaction',
|
|
5642
|
+
UNFOLLOW: 'unfollow',
|
|
5643
|
+
UPDATE_ACTIVITY: 'update-activity',
|
|
5644
|
+
UPDATE_COMMENT: 'update-comment',
|
|
5645
|
+
UPDATE_FEED: 'update-feed',
|
|
5646
|
+
UPDATE_FEED_FOLLOWERS: 'update-feed-followers',
|
|
5647
|
+
UPDATE_FEED_MEMBERS: 'update-feed-members',
|
|
5648
|
+
};
|
|
5649
|
+
|
|
5650
|
+
const stableEmptyArray = [];
|
|
5651
|
+
const selector$2 = (currentState) => ({
|
|
5652
|
+
oc: currentState.own_capabilities ?? stableEmptyArray,
|
|
5653
|
+
});
|
|
5654
|
+
const useOwnCapabilities = (feedFromProps) => {
|
|
5655
|
+
const feedFromContext = useFeedContext();
|
|
5656
|
+
const feed = feedFromProps ?? feedFromContext;
|
|
5657
|
+
const { oc = stableEmptyArray } = useStateStore(feed?.state, selector$2) ?? {};
|
|
5658
|
+
return useMemo(() => ({
|
|
5659
|
+
canAddActivity: oc.indexOf(FeedOwnCapability.ADD_ACTIVITY) > -1,
|
|
5660
|
+
canAddActivityReaction: oc.indexOf(FeedOwnCapability.ADD_ACTIVITY_REACTION) > -1,
|
|
5661
|
+
canAddComment: oc.indexOf(FeedOwnCapability.ADD_COMMENT) > -1,
|
|
5662
|
+
canAddCommentReaction: oc.indexOf(FeedOwnCapability.ADD_COMMENT_REACTION) > -1,
|
|
5663
|
+
canBookmarkActivity: oc.indexOf(FeedOwnCapability.BOOKMARK_ACTIVITY) > -1,
|
|
5664
|
+
canCreateFeed: oc.indexOf(FeedOwnCapability.CREATE_FEED) > -1,
|
|
5665
|
+
canDeleteBookmark: oc.indexOf(FeedOwnCapability.DELETE_BOOKMARK) > -1,
|
|
5666
|
+
canDeleteComment: oc.indexOf(FeedOwnCapability.DELETE_COMMENT) > -1,
|
|
5667
|
+
canDeleteFeed: oc.indexOf(FeedOwnCapability.DELETE_FEED) > -1,
|
|
5668
|
+
canEditBookmark: oc.indexOf(FeedOwnCapability.EDIT_BOOKMARK) > -1,
|
|
5669
|
+
canFollow: oc.indexOf(FeedOwnCapability.FOLLOW) > -1,
|
|
5670
|
+
canRemoveActivity: oc.indexOf(FeedOwnCapability.REMOVE_ACTIVITY) > -1,
|
|
5671
|
+
canRemoveActivityReaction: oc.indexOf(FeedOwnCapability.REMOVE_ACTIVITY_REACTION) > -1,
|
|
5672
|
+
canRemoveCommentReaction: oc.indexOf(FeedOwnCapability.REMOVE_COMMENT_REACTION) > -1,
|
|
5673
|
+
canUnfollow: oc.indexOf(FeedOwnCapability.UNFOLLOW) > -1,
|
|
5674
|
+
canUpdateFeed: oc.indexOf(FeedOwnCapability.UPDATE_FEED) > -1,
|
|
5675
|
+
canInviteFeed: oc.indexOf(FeedOwnCapability.INVITE_FEED) > -1,
|
|
5676
|
+
canJoinFeed: oc.indexOf(FeedOwnCapability.JOIN_FEED) > -1,
|
|
5677
|
+
canLeaveFeed: oc.indexOf(FeedOwnCapability.LEAVE_FEED) > -1,
|
|
5678
|
+
canManageFeedGroup: oc.indexOf(FeedOwnCapability.MANAGE_FEED_GROUP) > -1,
|
|
5679
|
+
canMarkActivity: oc.indexOf(FeedOwnCapability.MARK_ACTIVITY) > -1,
|
|
5680
|
+
canPinActivity: oc.indexOf(FeedOwnCapability.PIN_ACTIVITY) > -1,
|
|
5681
|
+
canQueryFeedMembers: oc.indexOf(FeedOwnCapability.QUERY_FEED_MEMBERS) > -1,
|
|
5682
|
+
canQueryFollows: oc.indexOf(FeedOwnCapability.QUERY_FOLLOWS) > -1,
|
|
5683
|
+
canReadActivities: oc.indexOf(FeedOwnCapability.READ_ACTIVITIES) > -1,
|
|
5684
|
+
canReadFeed: oc.indexOf(FeedOwnCapability.READ_FEED) > -1,
|
|
5685
|
+
canUpdateActivity: oc.indexOf(FeedOwnCapability.UPDATE_ACTIVITY) > -1,
|
|
5686
|
+
canUpdateComment: oc.indexOf(FeedOwnCapability.UPDATE_COMMENT) > -1,
|
|
5687
|
+
canUpdateFeedFollowers: oc.indexOf(FeedOwnCapability.UPDATE_FEED_FOLLOWERS) > -1,
|
|
5688
|
+
canUpdateFeedMembers: oc.indexOf(FeedOwnCapability.UPDATE_FEED_MEMBERS) > -1,
|
|
5689
|
+
}), [oc]);
|
|
5690
|
+
};
|
|
5691
|
+
|
|
5692
|
+
const selector$1 = ({ follower_count, followers, followers_pagination, }) => ({
|
|
5693
|
+
follower_count,
|
|
5694
|
+
followers,
|
|
5695
|
+
followers_pagination,
|
|
5696
|
+
});
|
|
5697
|
+
function useFollowers(feedFromProps) {
|
|
5698
|
+
const feedFromContext = useFeedContext();
|
|
5699
|
+
const feed = feedFromProps ?? feedFromContext;
|
|
5700
|
+
const data = useStateStore(feed?.state, selector$1);
|
|
5701
|
+
const loadNextPage = useCallback((...options) => feed?.loadNextPageFollowers(...options), [feed]);
|
|
5702
|
+
return useMemo(() => {
|
|
5703
|
+
if (!data) {
|
|
5704
|
+
return undefined;
|
|
5705
|
+
}
|
|
5706
|
+
return {
|
|
5707
|
+
...data,
|
|
5708
|
+
isLoadingNextPage: data.followers_pagination?.loading_next_page ?? false,
|
|
5709
|
+
hasNextPage: checkHasAnotherPage(data.followers, data.followers_pagination?.next),
|
|
5710
|
+
loadNextPage,
|
|
5711
|
+
};
|
|
5712
|
+
}, [data, loadNextPage]);
|
|
5713
|
+
}
|
|
5714
|
+
|
|
5715
|
+
const selector = ({ following_count, following, following_pagination, }) => ({
|
|
5716
|
+
following_count,
|
|
5717
|
+
following,
|
|
5718
|
+
following_pagination,
|
|
5719
|
+
});
|
|
5720
|
+
function useFollowing(feedFromProps) {
|
|
5721
|
+
const feedFromContext = useFeedContext();
|
|
5722
|
+
const feed = feedFromProps ?? feedFromContext;
|
|
5723
|
+
const data = useStateStore(feed?.state, selector);
|
|
5724
|
+
const loadNextPage = useCallback((...options) => feed?.loadNextPageFollowing(...options), [feed]);
|
|
5725
|
+
return useMemo(() => {
|
|
5726
|
+
if (!data) {
|
|
5727
|
+
return undefined;
|
|
5728
|
+
}
|
|
5729
|
+
return {
|
|
5730
|
+
...data,
|
|
5731
|
+
isLoadingNextPage: data.following_pagination?.loading_next_page ?? false,
|
|
5732
|
+
hasNextPage: checkHasAnotherPage(data.following, data.following_pagination?.next),
|
|
5733
|
+
loadNextPage,
|
|
5734
|
+
};
|
|
5735
|
+
}, [data, loadNextPage]);
|
|
5736
|
+
}
|
|
5737
|
+
|
|
5738
|
+
/**
|
|
5739
|
+
* A utility hook that takes in an entity and a reaction type, and creates reaction actions
|
|
5740
|
+
* that can then be used on the UI. The entity can be either an ActivityResponse or a CommentResponse
|
|
5741
|
+
* as the hook determines internally which APIs it is supposed to use, while taking the
|
|
5742
|
+
* correct ownCapabilities into account.
|
|
5743
|
+
* @param entity - The entity to which we want to add a reaction, can be either ActivityResponse or CommentResponse.
|
|
5744
|
+
* @param type - The type of reaction we want to add or remove.
|
|
5745
|
+
*/
|
|
5746
|
+
const useReactionActions = ({ entity, type, }) => {
|
|
5747
|
+
const client = useFeedsClient();
|
|
5748
|
+
const isComment = isCommentResponse(entity);
|
|
5749
|
+
const hasOwnReaction = useMemo(() => !!entity.own_reactions?.find((r) => r.type === type), [entity.own_reactions, type]);
|
|
5750
|
+
const addReaction = useStableCallback(async () => {
|
|
5751
|
+
await (isComment
|
|
5752
|
+
? client?.addCommentReaction({ comment_id: entity.id, type })
|
|
5753
|
+
: client?.addReaction({ activity_id: entity.id, type }));
|
|
5754
|
+
});
|
|
5755
|
+
const removeReaction = useStableCallback(async () => {
|
|
5756
|
+
await (isComment
|
|
5757
|
+
? client?.deleteCommentReaction({ comment_id: entity.id, type })
|
|
5758
|
+
: client?.deleteActivityReaction({
|
|
5759
|
+
activity_id: entity.id,
|
|
5760
|
+
type,
|
|
5761
|
+
}));
|
|
5762
|
+
});
|
|
5763
|
+
const toggleReaction = useStableCallback(async () => {
|
|
5764
|
+
if (hasOwnReaction) {
|
|
5765
|
+
await removeReaction();
|
|
5766
|
+
}
|
|
5767
|
+
else {
|
|
5768
|
+
await addReaction();
|
|
5769
|
+
}
|
|
5770
|
+
});
|
|
5771
|
+
return useMemo(() => ({ addReaction, removeReaction, toggleReaction }), [addReaction, removeReaction, toggleReaction]);
|
|
5772
|
+
};
|
|
5773
|
+
|
|
5513
5774
|
const StreamFeeds = ({ client, children }) => {
|
|
5514
5775
|
return (jsx(StreamFeedsContext.Provider, { value: client, children: children }));
|
|
5515
5776
|
};
|
|
5516
5777
|
StreamFeeds.displayName = 'StreamFeeds';
|
|
5517
5778
|
|
|
5518
|
-
|
|
5779
|
+
const StreamFeed = ({ feed, children }) => {
|
|
5780
|
+
return (jsx(StreamFeedContext.Provider, { value: feed, children: children }));
|
|
5781
|
+
};
|
|
5782
|
+
StreamFeed.displayName = 'StreamFeed';
|
|
5783
|
+
|
|
5784
|
+
export { StreamFeed, StreamFeedContext, StreamFeeds, StreamFeedsContext, useClientConnectedUser, useComments, useCreateFeedsClient, useFeedActivities, useFeedContext, useFeedsClient, useFollowers, useFollowing, useOwnCapabilities, useReactionActions, useStateStore, useWsConnectionState };
|
|
5519
5785
|
//# sourceMappingURL=index-react-bindings.browser.js.map
|