diff --git a/resources/js/lib/reactions.ts b/resources/js/lib/reactions.ts index 3b4022221..8604e740e 100644 --- a/resources/js/lib/reactions.ts +++ b/resources/js/lib/reactions.ts @@ -87,19 +87,20 @@ export function summarizeReactions( const byEmoji = new Map(); for (const reaction of reactions ?? []) { - const summary = byEmoji.get(reaction.emoji) ?? { - emoji: reaction.emoji, - count: 0, - isMine: false, - userIds: [], - }; - - byEmoji.set(reaction.emoji, { - ...summary, - count: summary.count + 1, - isMine: summary.isMine || reaction.user_id === userId, - userIds: [...summary.userIds, reaction.user_id], - }); + const summary = byEmoji.get(reaction.emoji); + + if (summary) { + summary.count++; + summary.isMine ||= reaction.user_id === userId; + summary.userIds.push(reaction.user_id); + } else { + byEmoji.set(reaction.emoji, { + emoji: reaction.emoji, + count: 1, + isMine: reaction.user_id === userId, + userIds: [reaction.user_id], + }); + } } return [...byEmoji.values()]; diff --git a/tests/Unit/Reactions.test.ts b/tests/Unit/Reactions.test.ts index 534244197..6ede576e7 100644 --- a/tests/Unit/Reactions.test.ts +++ b/tests/Unit/Reactions.test.ts @@ -102,3 +102,22 @@ await test('takes two quick taps close together as a double tap', () => { assert.equal(isDoubleTap(first, { x: 160, y: 200, time: 1_100 }), false); assert.equal(isDoubleTap(null, first), false); }); + +await test('summarizes repeated reactions without changing their order', () => { + const reactions = Array.from({ length: 120 }, (_, index) => ({ + user_id: String(index), + emoji: index % 2 === 0 ? '🚀' : '❤️', + })); + const summaries = summarizeReactions(reactions, '63'); + + assert.deepEqual(summaries.map(({ emoji, count, isMine }) => ({ + emoji, + count, + isMine, + })), [ + { emoji: '🚀', count: 60, isMine: false }, + { emoji: '❤️', count: 60, isMine: true }, + ]); + assert.equal(summaries[0].userIds[0], '0'); + assert.equal(summaries[0].userIds.at(-1), '118'); +});