Skip to content

Commit 2e36720

Browse files
Add handle-follow-updated & re-organize handlers
1 parent daa288e commit 2e36720

20 files changed

+948
-785
lines changed

packages/feeds-client/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
"@types/react": "^19.1.8",
6868
"@vitest/coverage-v8": "3.2.4",
6969
"dotenv": "^16.4.5",
70+
"human-id": "^4.1.1",
7071
"react": "19.0.0",
7172
"rimraf": "^6.0.1",
7273
"rollup": "^4.24.0",

packages/feeds-client/src/Feed.ts

Lines changed: 12 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import {
1616
BookmarkUpdatedEvent,
1717
QueryFeedMembersRequest,
1818
SortParamRequest,
19-
FollowResponse,
2019
ThreadedCommentResponse,
2120
} from './gen/models';
2221
import { StateStore } from './common/StateStore';
@@ -38,10 +37,10 @@ import {
3837
updateBookmarkInActivities,
3938
} from './state-updates/bookmark-utils';
4039
import {
40+
handleFollowUpdated,
4141
handleFollowCreated,
4242
handleFollowDeleted,
43-
handleFollowUpdated,
44-
} from './state-updates/follow-utils';
43+
} from './event-handlers/feed';
4544
import { StreamResponse } from './gen-imports';
4645
import { capitalize } from './common/utils';
4746
import type {
@@ -52,11 +51,6 @@ import type {
5251
PagerResponseWithLoadingStates,
5352
} from './types';
5453
import { checkHasAnotherPage, Constants, uniqueArrayMerge } from './utils';
55-
import {
56-
getStateUpdateQueueIdForFollow,
57-
getStateUpdateQueueIdForUnfollow,
58-
shouldUpdateState,
59-
} from './state-updates/state-update-queue';
6054

6155
export type FeedState = Omit<
6256
Partial<GetOrCreateFeedResponse & FeedResponse>,
@@ -143,7 +137,7 @@ type EventHandlerByEventType = {
143137
export class Feed extends FeedApi {
144138
readonly state: StateStore<FeedState>;
145139
private static readonly noop = () => {};
146-
private readonly stateUpdateQueue: Set<string> = new Set();
140+
protected readonly stateUpdateQueue: Set<string> = new Set();
147141

148142
private readonly eventHandlers: EventHandlerByEventType = {
149143
'feeds.activity.added': (event) => {
@@ -330,18 +324,9 @@ export class Feed extends FeedApi {
330324
},
331325
'feeds.feed_group.changed': Feed.noop,
332326
'feeds.feed_group.deleted': Feed.noop,
333-
'feeds.follow.created': (event) => {
334-
this.handleFollowCreated(event.follow);
335-
},
336-
'feeds.follow.deleted': (event) => {
337-
this.handleFollowDeleted(event.follow);
338-
},
339-
'feeds.follow.updated': (_event) => {
340-
const result = handleFollowUpdated(this.currentState);
341-
if (result.changed) {
342-
this.state.next(result.data);
343-
}
344-
},
327+
'feeds.follow.created': handleFollowCreated.bind(this),
328+
'feeds.follow.deleted': handleFollowDeleted.bind(this),
329+
'feeds.follow.updated': handleFollowUpdated.bind(this),
345330
'feeds.comment.reaction.added': this.handleCommentReactionEvent.bind(this),
346331
'feeds.comment.reaction.deleted':
347332
this.handleCommentReactionEvent.bind(this),
@@ -476,7 +461,7 @@ export class Feed extends FeedApi {
476461
this.client = client;
477462
}
478463

479-
private readonly client: FeedsClient;
464+
protected readonly client: FeedsClient;
480465

481466
get fid() {
482467
return `${this.group}:${this.id}`;
@@ -630,62 +615,6 @@ export class Feed extends FeedApi {
630615
}
631616
}
632617

633-
/**
634-
* @internal
635-
*/
636-
handleFollowCreated(follow: FollowResponse) {
637-
if (
638-
!shouldUpdateState({
639-
stateUpdateId: getStateUpdateQueueIdForFollow(follow),
640-
stateUpdateQueue: this.stateUpdateQueue,
641-
watch: this.currentState.watch,
642-
})
643-
) {
644-
return;
645-
}
646-
const connectedUser = this.client.state.getLatestValue().connected_user;
647-
const result = handleFollowCreated(
648-
follow,
649-
this.currentState,
650-
this.fid,
651-
connectedUser?.id,
652-
);
653-
if (result.changed) {
654-
this.state.next(result.data);
655-
}
656-
}
657-
658-
/**
659-
* @internal
660-
*/
661-
handleFollowDeleted(
662-
follow:
663-
| FollowResponse
664-
// Backend doesn't return the follow in delete follow response https://getstream.slack.com/archives/C06RK9WCR09/p1753176937507209
665-
| { source_feed: { fid: string }; target_feed: { fid: string } },
666-
) {
667-
if (
668-
!shouldUpdateState({
669-
stateUpdateId: getStateUpdateQueueIdForUnfollow(follow),
670-
stateUpdateQueue: this.stateUpdateQueue,
671-
watch: this.currentState.watch,
672-
})
673-
) {
674-
return;
675-
}
676-
677-
const connectedUser = this.client.state.getLatestValue().connected_user;
678-
const result = handleFollowDeleted(
679-
follow,
680-
this.currentState,
681-
this.fid,
682-
connectedUser?.id,
683-
);
684-
if (result.changed) {
685-
this.state.next(result.data);
686-
}
687-
}
688-
689618
/**
690619
* @internal
691620
*/
@@ -1112,7 +1041,11 @@ export class Feed extends FeedApi {
11121041
this.state.next((currentState) => ({
11131042
...currentState,
11141043
members: currentState.members
1115-
? uniqueArrayMerge(currentState.members, members, ({ user }) => user.id)
1044+
? uniqueArrayMerge(
1045+
currentState.members,
1046+
members,
1047+
({ user }) => user.id,
1048+
)
11161049
: members,
11171050
member_pagination: {
11181051
...currentState.member_pagination,

packages/feeds-client/src/FeedsClient.ts

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
QueryFeedsRequest,
1212
QueryPollVotesRequest,
1313
SingleFollowRequest,
14+
UpdateFollowRequest,
1415
UserRequest,
1516
WSEvent,
1617
} from './gen/models';
@@ -35,6 +36,11 @@ import {
3536
} from './common/types';
3637
import { ModerationClient } from './ModerationClient';
3738
import { StreamPoll } from './common/Poll';
39+
import {
40+
handleFollowCreated,
41+
handleFollowDeleted,
42+
handleFollowUpdated,
43+
} from './event-handlers/feed';
3844

3945
export type FeedsClientState = {
4046
connected_user: OwnUser | undefined;
@@ -363,6 +369,21 @@ export class FeedsClient extends FeedsApi {
363369
this.eventDispatcher.dispatch(networkEvent);
364370
};
365371

372+
async updateFollow(request: UpdateFollowRequest) {
373+
const response = await super.updateFollow(request);
374+
375+
[response.follow.source_feed.fid, response.follow.target_feed.fid].forEach(
376+
(fid) => {
377+
const feed = this.activeFeeds[fid];
378+
if (feed) {
379+
handleFollowUpdated.bind(feed)(response);
380+
}
381+
},
382+
);
383+
384+
return response;
385+
}
386+
366387
// For follow API endpoints we update the state after HTTP response to allow queryFeeds with watch: false
367388
async follow(request: SingleFollowRequest) {
368389
const response = await super.follow(request);
@@ -371,7 +392,7 @@ export class FeedsClient extends FeedsApi {
371392
(fid) => {
372393
const feed = this.activeFeeds[fid];
373394
if (feed) {
374-
feed.handleFollowCreated(response.follow);
395+
handleFollowCreated.bind(feed)(response);
375396
}
376397
},
377398
);
@@ -385,7 +406,7 @@ export class FeedsClient extends FeedsApi {
385406
response.follows.forEach((follow) => {
386407
const feed = this.activeFeeds[follow.source_feed.fid];
387408
if (feed) {
388-
feed.handleFollowCreated(follow);
409+
handleFollowCreated.bind(feed)({ follow });
389410
}
390411
});
391412

@@ -398,9 +419,11 @@ export class FeedsClient extends FeedsApi {
398419
[request.source, request.target].forEach((fid) => {
399420
const feed = this.activeFeeds[fid];
400421
if (feed) {
401-
feed.handleFollowDeleted({
402-
source_feed: { fid: request.source },
403-
target_feed: { fid: request.target },
422+
handleFollowDeleted.bind(feed)({
423+
follow: {
424+
source_feed: { fid: request.source },
425+
target_feed: { fid: request.target },
426+
},
404427
});
405428
}
406429
});

0 commit comments

Comments
 (0)