From 9f122d6828d0a5f089cf87605983c5e2052ba582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Wed, 11 Sep 2024 15:56:42 +0200 Subject: [PATCH] pl-fe: Fix reactions sorting, fix remote custom reactions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- packages/pl-fe/src/actions/pl-fe.test.ts | 21 --- .../src/components/status-reactions-bar.tsx | 5 +- packages/pl-fe/src/utils/emoji-reacts.test.ts | 148 ------------------ packages/pl-fe/src/utils/emoji-reacts.ts | 4 - 4 files changed, 2 insertions(+), 176 deletions(-) delete mode 100644 packages/pl-fe/src/actions/pl-fe.test.ts diff --git a/packages/pl-fe/src/actions/pl-fe.test.ts b/packages/pl-fe/src/actions/pl-fe.test.ts deleted file mode 100644 index 4c1aa4505..000000000 --- a/packages/pl-fe/src/actions/pl-fe.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { rootState } from 'pl-fe/jest/test-helpers'; -import { RootState } from 'pl-fe/store'; - -import { getPlFeConfig } from './pl-fe'; - -const ASCII_HEART = '❤'; // '\u2764\uFE0F' -const RED_HEART_RGI = '❤️'; // '\u2764' - -describe('getPlFeConfig()', () => { - it('returns RGI heart on Pleroma > 2.3', () => { - const state = rootState.setIn(['instance', 'version'], '2.7.2 (compatible; Pleroma 2.3.0)') as RootState; - expect(getPlFeConfig(state).allowedEmoji.includes(RED_HEART_RGI)).toBe(true); - expect(getPlFeConfig(state).allowedEmoji.includes(ASCII_HEART)).toBe(false); - }); - - it('returns an ASCII heart on Pleroma < 2.3', () => { - const state = rootState.setIn(['instance', 'version'], '2.7.2 (compatible; Pleroma 2.0.0)') as RootState; - expect(getPlFeConfig(state).allowedEmoji.includes(ASCII_HEART)).toBe(true); - expect(getPlFeConfig(state).allowedEmoji.includes(RED_HEART_RGI)).toBe(false); - }); -}); diff --git a/packages/pl-fe/src/components/status-reactions-bar.tsx b/packages/pl-fe/src/components/status-reactions-bar.tsx index 6dd94c116..16d5e599e 100644 --- a/packages/pl-fe/src/components/status-reactions-bar.tsx +++ b/packages/pl-fe/src/components/status-reactions-bar.tsx @@ -7,7 +7,6 @@ import { emojiReact, unEmojiReact } from 'pl-fe/actions/emoji-reacts'; import EmojiPickerDropdown from 'pl-fe/features/emoji/containers/emoji-picker-dropdown-container'; import unicodeMapping from 'pl-fe/features/emoji/mapping'; import { useAppDispatch, useSettings } from 'pl-fe/hooks'; -import { sortEmoji } from 'pl-fe/utils/emoji-reacts'; import AnimatedNumber from './animated-number'; import { Emoji, HStack, Icon, Text } from './ui'; @@ -43,7 +42,7 @@ const StatusReaction: React.FC = ({ reaction, status, obfuscate if (reaction.me) { dispatch(unEmojiReact(status, reaction.name)); } else { - dispatch(emojiReact(status, reaction.name)); + dispatch(emojiReact(status, reaction.name, reaction.url)); } }; @@ -88,7 +87,7 @@ const StatusReactionsBar: React.FC = ({ status, collapsed } if ((demetricator || status.emoji_reactions.length === 0) && collapsed) return null; - const sortedReactions = sortEmoji(status.emoji_reactions); + const sortedReactions = status.emoji_reactions.toSorted((a, b) => (b.count || 0) - (a.count || 0)); return ( diff --git a/packages/pl-fe/src/utils/emoji-reacts.test.ts b/packages/pl-fe/src/utils/emoji-reacts.test.ts index 75cad80db..1eff793b0 100644 --- a/packages/pl-fe/src/utils/emoji-reacts.test.ts +++ b/packages/pl-fe/src/utils/emoji-reacts.test.ts @@ -1,159 +1,11 @@ import { List as ImmutableList, fromJS } from 'immutable'; import { emojiReactionSchema } from 'pl-api'; -import { normalizeStatus } from 'pl-fe/normalizers'; - import { - sortEmoji, - mergeEmojiFavourites, - reduceEmoji, - getReactForStatus, simulateEmojiReact, simulateUnEmojiReact, } from './emoji-reacts'; -const ALLOWED_EMOJI = ImmutableList([ - '👍', - '❤', - '😂', - '😯', - '😢', - '😡', -]); - -describe('sortEmoji', () => { - describe('with an unsorted list of emoji', () => { - const emojiReacts = ImmutableList([ - { 'count': 7, 'me': true, 'name': '😃' }, - { 'count': 7, 'me': true, 'name': '😯' }, - { 'count': 3, 'me': true, 'name': '😢' }, - { 'count': 1, 'me': true, 'name': '😡' }, - { 'count': 20, 'me': true, 'name': '👍' }, - { 'count': 7, 'me': true, 'name': '😂' }, - { 'count': 15, 'me': true, 'name': '❤' }, - ].map((react) => emojiReactionSchema.parse(react))); - it('sorts the emoji by count', () => { - expect(sortEmoji(emojiReacts, ALLOWED_EMOJI)).toEqual(fromJS([ - { 'count': 20, 'me': true, 'name': '👍' }, - { 'count': 15, 'me': true, 'name': '❤' }, - { 'count': 7, 'me': true, 'name': '😯' }, - { 'count': 7, 'me': true, 'name': '😂' }, - { 'count': 7, 'me': true, 'name': '😃' }, - { 'count': 3, 'me': true, 'name': '😢' }, - { 'count': 1, 'me': true, 'name': '😡' }, - ])); - }); - }); -}); - -describe('mergeEmojiFavourites', () => { - const favouritesCount = 12; - const favourited = true; - - describe('with existing 👍 reacts', () => { - const emojiReacts = ImmutableList([ - { 'count': 20, 'me': false, 'name': '👍', 'url': undefined }, - { 'count': 15, 'me': false, 'name': '❤', 'url': undefined }, - { 'count': 7, 'me': false, 'name': '😯', 'url': undefined }, - ].map((react) => emojiReactionSchema.parse(react))); - it('combines 👍 reacts with favourites', () => { - expect(mergeEmojiFavourites(emojiReacts, favouritesCount, favourited)).toEqual(fromJS([ - { 'count': 32, 'me': true, 'name': '👍', 'url': undefined }, - { 'count': 15, 'me': false, 'name': '❤', 'url': undefined }, - { 'count': 7, 'me': false, 'name': '😯', 'url': undefined }, - ])); - }); - }); - - describe('without existing 👍 reacts', () => { - const emojiReacts = ImmutableList([ - { 'count': 15, 'me': false, 'name': '❤' }, - { 'count': 7, 'me': false, 'name': '😯' }, - ].map((react) => emojiReactionSchema.parse(react))); - it('adds 👍 reacts to the map equaling favourite count', () => { - expect(mergeEmojiFavourites(emojiReacts, favouritesCount, favourited)).toEqual(fromJS([ - { 'count': 15, 'me': false, 'name': '❤' }, - { 'count': 7, 'me': false, 'name': '😯' }, - { 'count': 12, 'me': true, 'name': '👍' }, - ])); - }); - it('does not add 👍 reacts when there are no favourites', () => { - expect(mergeEmojiFavourites(emojiReacts, 0, false)).toEqual(fromJS([ - { 'count': 15, 'me': false, 'name': '❤' }, - { 'count': 7, 'me': false, 'name': '😯' }, - ])); - }); - }); -}); - -describe('reduceEmoji', () => { - describe('with a clusterfuck of emoji', () => { - const emojiReacts = ImmutableList([ - { 'count': 1, 'me': false, 'name': '😡' }, - { 'count': 1, 'me': true, 'name': '🔪' }, - { 'count': 7, 'me': true, 'name': '😯' }, - { 'count': 3, 'me': false, 'name': '😢' }, - { 'count': 1, 'me': true, 'name': '🌵' }, - { 'count': 20, 'me': true, 'name': '👍' }, - { 'count': 7, 'me': false, 'name': '😂' }, - { 'count': 15, 'me': true, 'name': '❤' }, - { 'count': 1, 'me': false, 'name': '👀' }, - { 'count': 1, 'me': false, 'name': '🍩' }, - ].map((react) => emojiReactionSchema.parse(react))); - it('sorts, filters, and combines emoji and favourites', () => { - expect(reduceEmoji(emojiReacts, 7, true, ALLOWED_EMOJI)).toEqual(fromJS([ - { 'count': 27, 'me': true, 'name': '👍' }, - { 'count': 15, 'me': true, 'name': '❤' }, - { 'count': 7, 'me': true, 'name': '😯' }, - { 'count': 7, 'me': false, 'name': '😂' }, - { 'count': 3, 'me': false, 'name': '😢' }, - { 'count': 1, 'me': false, 'name': '😡' }, - { 'count': 1, 'me': true, 'name': '🔪' }, - { 'count': 1, 'me': true, 'name': '🌵' }, - { 'count': 1, 'me': false, 'name': '👀' }, - { 'count': 1, 'me': false, 'name': '🍩' }, - ])); - }); - }); -}); - -describe('getReactForStatus', () => { - it('returns a single owned react (including favourite) for the status', () => { - const status = normalizeStatus(fromJS({ - favourited: false, - pleroma: { - emoji_reactions: [ - { 'count': 20, 'me': false, 'name': '👍' }, - { 'count': 15, 'me': true, 'name': '❤' }, - { 'count': 7, 'me': true, 'name': '😯' }, - { 'count': 7, 'me': false, 'name': '😂' }, - ], - }, - })); - expect(getReactForStatus(status, ALLOWED_EMOJI)?.name).toEqual('❤'); - }); - - it('returns a thumbs-up for a favourite', () => { - const status = normalizeStatus(fromJS({ favourites_count: 1, favourited: true })); - expect(getReactForStatus(status)?.name).toEqual('👍'); - }); - - it('returns undefined when a status has no reacts (or favourites)', () => { - const status = normalizeStatus(fromJS({})); - expect(getReactForStatus(status)).toEqual(undefined); - }); - - it('returns undefined when a status has no valid reacts (or favourites)', () => { - const status = normalizeStatus(fromJS([ - { 'count': 1, 'me': true, 'name': '🔪' }, - { 'count': 1, 'me': true, 'name': '🌵' }, - { 'count': 1, 'me': false, 'name': '👀' }, - { 'count': 1, 'me': false, 'name': '🍩' }, - ])); - expect(getReactForStatus(status)).toEqual(undefined); - }); -}); - describe('simulateEmojiReact', () => { it('adds the emoji to the list', () => { const emojiReacts = ImmutableList([ diff --git a/packages/pl-fe/src/utils/emoji-reacts.ts b/packages/pl-fe/src/utils/emoji-reacts.ts index a5e743a13..f93516b6d 100644 --- a/packages/pl-fe/src/utils/emoji-reacts.ts +++ b/packages/pl-fe/src/utils/emoji-reacts.ts @@ -1,8 +1,5 @@ import { emojiReactionSchema, type EmojiReaction } from 'pl-api'; -const sortEmoji = (emojiReacts: Array): Array => - emojiReacts.toSorted(emojiReact => -(emojiReact.count || 0)); - const simulateEmojiReact = (emojiReacts: Array, emoji: string, url?: string) => { const idx = emojiReacts.findIndex(e => e.name === emoji); const emojiReact = emojiReacts[idx]; @@ -44,7 +41,6 @@ const simulateUnEmojiReact = (emojiReacts: Array, emoji: string) }; export { - sortEmoji, simulateEmojiReact, simulateUnEmojiReact, };