Skip to content

Commit a85f4fd

Browse files
authored
Merge pull request #530 from GetStream/limit-reactions
Limit reactions
2 parents ae9c579 + 0e67f96 commit a85f4fd

File tree

6 files changed

+72
-6
lines changed

6 files changed

+72
-6
lines changed

docusaurus/docs/Angular/components/MessageReactionsComponent.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ The `MessageReactions` component displays the reactions of a message, the curren
88

99
<img src={MessageReactionsScreenshot} width="500" />
1010

11-
**Example 2** - displaying the reacting users:
11+
**Example 2** - displaying the reacting users - only visible if a message has at maximum 1200 reactions:
1212

1313
<img src={MessageReactionsDetailsScreenshot} width="500" />
1414

projects/stream-chat-angular/src/lib/channel.service.spec.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2327,6 +2327,22 @@ describe('ChannelService', () => {
23272327
]);
23282328
});
23292329

2330+
it('should load message reactions - but no more than 1200', async () => {
2331+
await init();
2332+
const activeChannel = service.activeChannel!;
2333+
const message = service.activeChannelMessages[0]!;
2334+
const mockReactionsPage = new Array(300)
2335+
.fill(null)
2336+
.map(() => ({ type: 'wow', user: { id: 'jack' } })) as ReactionResponse[];
2337+
spyOn(activeChannel, 'getReactions').and.resolveTo({
2338+
reactions: mockReactionsPage,
2339+
duration: '',
2340+
});
2341+
const reactions = await service.getMessageReactions(message.id);
2342+
2343+
expect(reactions.length).toEqual(1200);
2344+
});
2345+
23302346
it('should load message reactions - error', async () => {
23312347
await init();
23322348
const activeChannel = service.activeChannel!;

projects/stream-chat-angular/src/lib/channel.service.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,10 @@ export class ChannelService<
304304
* You can return either an offset, or a filter using the [`$lte`/`$gte` operator](https://getstream.io/chat/docs/javascript/query_syntax_operators/). If you return a filter, it will be merged with the filter provided for the `init` method.
305305
*/
306306
customPaginator?: (channelQueryResult: Channel<T>[]) => NextPageConfiguration;
307+
/**
308+
* internal
309+
*/
310+
static readonly MAX_MESSAGE_REACTIONS_TO_FETCH = 1200;
307311
private channelsSubject = new BehaviorSubject<Channel<T>[] | undefined>(
308312
undefined
309313
);
@@ -1440,17 +1444,18 @@ export class ChannelService<
14401444
}
14411445

14421446
/**
1443-
* Get all reactions of a message in the current active channel
1447+
* Get the last 1200 reactions of a message in the current active channel. If you need to fetch more reactions please use the [following endpoint](https://getstream.io/chat/docs/javascript/send_reaction/?language=javascript#paginating-reactions).
14441448
* @param messageId
14451449
* @returns all reactions of a message
14461450
*/
14471451
async getMessageReactions(messageId: string) {
14481452
const reactions: ReactionResponse<T>[] = [];
14491453
const limit = 300;
1450-
const offset = 0;
1454+
let offset = 0;
1455+
const reactionsLimit = ChannelService.MAX_MESSAGE_REACTIONS_TO_FETCH;
14511456
let lastPageSize = limit;
14521457

1453-
while (lastPageSize === limit) {
1458+
while (lastPageSize === limit && reactions.length < reactionsLimit) {
14541459
try {
14551460
const response = await this.activeChannel?.getReactions(messageId, {
14561461
offset,
@@ -1460,6 +1465,7 @@ export class ChannelService<
14601465
if (lastPageSize > 0) {
14611466
reactions.push(...response!.reactions);
14621467
}
1468+
offset += lastPageSize;
14631469
} catch (e) {
14641470
this.notificationService.addTemporaryNotification(
14651471
'Error loading reactions'

projects/stream-chat-angular/src/lib/message-reactions/message-reactions.component.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
let reactionType of existingReactions;
1313
trackBy: trackByMessageReaction
1414
"
15+
[ngStyle]="{ cursor: shouldHandleReactionClick ? 'pointer' : 'default' }"
1516
[class.str-chat__message-reaction-own]="isOwnReaction(reactionType)"
1617
data-testclass="emoji"
1718
(click)="reactionSelected(reactionType)"
@@ -155,6 +156,9 @@
155156
let reactionType of existingReactions;
156157
trackBy: trackByMessageReaction
157158
"
159+
[ngStyle]="{
160+
cursor: shouldHandleReactionClick ? 'pointer' : 'default'
161+
}"
158162
attr.data-testid="reaction-details-selector-{{ reactionType }}"
159163
[class.str-chat__message-reactions-details-reaction-type--selected]="
160164
reactionType === selectedReactionType

projects/stream-chat-angular/src/lib/message-reactions/message-reactions.component.spec.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,17 +279,44 @@ describe('MessageReactionsComponent', () => {
279279
expect(users.length).toBe(2);
280280
}));
281281

282-
it(`should call custom reaction details handler if that's provided`, () => {
282+
it(`shouldn't display reaction details if there are more than 1200 reactions`, () => {
283283
component.messageReactionCounts = {
284284
wow: 3,
285-
sad: 2,
285+
sad: 1198,
286286
};
287287
component.messageId = 'id';
288288
component.latestReactions = [];
289+
component.ngOnChanges({ messageReactionCounts: {} as SimpleChange });
289290
fixture.detectChanges();
291+
292+
const reactions = [
293+
{ type: 'wow', user: { id: 'saraid', name: 'Sara' } },
294+
{ type: 'wow', user: { id: 'benid', name: 'Ben' } },
295+
{ type: 'wow', user: { id: 'jackid' } },
296+
{ type: 'wow' },
297+
{ type: 'sad', user: { id: 'jim' } },
298+
{ type: 'sad', user: { id: 'ben', name: 'Ben' } },
299+
] as ReactionResponse[];
300+
spyOn(channelServiceMock, 'getMessageReactions').and.resolveTo(reactions);
301+
302+
const wowEmoji = queryEmojis()[0];
303+
wowEmoji.click();
304+
305+
expect(component.selectedReactionType).toBe(undefined);
306+
});
307+
308+
it(`should call custom reaction details handler if that's provided`, () => {
290309
const messageReactionsService = TestBed.inject(MessageReactionsService);
291310
const spy = jasmine.createSpy();
292311
messageReactionsService.customReactionClickHandler = spy;
312+
component.messageReactionCounts = {
313+
wow: 1500,
314+
sad: 2,
315+
};
316+
component.messageId = 'id';
317+
component.latestReactions = [];
318+
component.ngOnChanges({ messageReactionCounts: {} as SimpleChange });
319+
fixture.detectChanges();
293320

294321
const wowEmoji = queryEmojis()[0];
295322
wowEmoji.click();

projects/stream-chat-angular/src/lib/message-reactions/message-reactions.component.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export class MessageReactionsComponent implements AfterViewChecked, OnChanges {
6666
selectedReactionType: string | undefined;
6767
isLoading = true;
6868
reactions: ReactionResponse[] = [];
69+
shouldHandleReactionClick = true;
6970

7071
constructor(
7172
private cdRef: ChangeDetectorRef,
@@ -81,6 +82,15 @@ export class MessageReactionsComponent implements AfterViewChecked, OnChanges {
8182
? setTimeout(() => this.watchForOutsideClicks()) // setTimeout: wait for current click to bubble up, and only watch for clicks after that
8283
: this.stopWatchForOutsideClicks();
8384
}
85+
if (changes.messageReactionCounts && this.messageReactionCounts) {
86+
const reactionsCount = Object.keys(this.messageReactionCounts).reduce(
87+
(acc, key) => acc + (this.messageReactionCounts[key] || 0),
88+
0
89+
);
90+
this.shouldHandleReactionClick =
91+
reactionsCount <= ChannelService.MAX_MESSAGE_REACTIONS_TO_FETCH ||
92+
!!this.messageReactionsService.customReactionClickHandler;
93+
}
8494
}
8595

8696
ngAfterViewChecked(): void {
@@ -117,6 +127,9 @@ export class MessageReactionsComponent implements AfterViewChecked, OnChanges {
117127
}
118128

119129
reactionSelected(reactionType: string) {
130+
if (!this.shouldHandleReactionClick) {
131+
return;
132+
}
120133
if (this.themeService.themeVersion === '1') {
121134
return;
122135
}

0 commit comments

Comments
 (0)