pl-fe: Fix reactions sorting, fix remote custom reactions
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
@ -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);
|
||||
});
|
||||
});
|
||||
@ -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<IStatusReaction> = ({ 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<IStatusReactionsBar> = ({ 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 (
|
||||
<HStack className='pt-2' space={2} wrap>
|
||||
|
||||
@ -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([
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
import { emojiReactionSchema, type EmojiReaction } from 'pl-api';
|
||||
|
||||
const sortEmoji = (emojiReacts: Array<EmojiReaction>): Array<EmojiReaction> =>
|
||||
emojiReacts.toSorted(emojiReact => -(emojiReact.count || 0));
|
||||
|
||||
const simulateEmojiReact = (emojiReacts: Array<EmojiReaction>, emoji: string, url?: string) => {
|
||||
const idx = emojiReacts.findIndex(e => e.name === emoji);
|
||||
const emojiReact = emojiReacts[idx];
|
||||
@ -44,7 +41,6 @@ const simulateUnEmojiReact = (emojiReacts: Array<EmojiReaction>, emoji: string)
|
||||
};
|
||||
|
||||
export {
|
||||
sortEmoji,
|
||||
simulateEmojiReact,
|
||||
simulateUnEmojiReact,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user