signal-desktop/ts/util/groupAndOrderReactions.ts

86 lines
2.4 KiB
TypeScript
Raw Normal View History

2025-06-06 12:44:38 -05:00
// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
2025-09-19 13:05:51 -07:00
import lodash from 'lodash';
2025-06-06 12:44:38 -05:00
import { useMemo } from 'react';
import type { Reaction } from '../components/conversation/ReactionViewer.js';
2025-06-06 12:44:38 -05:00
import {
isEmojiVariantValue,
getEmojiVariantKeyByValue,
getEmojiParentKeyByVariantKey,
getEmojiVariantByKey,
type EmojiVariantKey,
2025-08-06 14:41:37 -04:00
type EmojiParentKey,
} from '../components/fun/data/emojis.js';
import { isNotNil } from './isNotNil.js';
import { useFunEmojiLocalizer } from '../components/fun/useFunEmojiLocalizer.js';
2025-06-06 12:44:38 -05:00
2025-09-19 13:05:51 -07:00
const { groupBy, orderBy } = lodash;
2025-06-06 12:44:38 -05:00
type ReactionWithEmojiData = Reaction & {
short_name: string | undefined;
short_names: Array<string>;
sheet_x: number;
sheet_y: number;
2025-08-06 14:41:37 -04:00
parentKey: EmojiParentKey;
2025-06-06 12:44:38 -05:00
variantKey: EmojiVariantKey;
};
export function useGroupedAndOrderedReactions(
reactions: ReadonlyArray<Reaction> | undefined,
2025-08-06 14:41:37 -04:00
groupByKey: 'variantKey' | 'parentKey'
2025-06-06 12:44:38 -05:00
): Array<Array<ReactionWithEmojiData>> {
const emojiLocalization = useFunEmojiLocalizer();
return useMemo(() => {
if (!reactions || reactions.length === 0) {
return [];
}
const reactionsWithEmojiData: Array<ReactionWithEmojiData> = reactions
.map(reaction => {
if (!isEmojiVariantValue(reaction.emoji)) {
return undefined;
}
try {
const variantKey = getEmojiVariantKeyByValue(reaction.emoji);
const parentKey = getEmojiParentKeyByVariantKey(variantKey);
const variant = getEmojiVariantByKey(variantKey);
const shortName = emojiLocalization.getLocaleShortName(variantKey);
return {
...reaction,
short_name: shortName,
short_names: [shortName].filter(isNotNil),
variantKey,
parentKey,
sheet_x: variant.sheetX,
sheet_y: variant.sheetY,
};
} catch {
return undefined;
}
})
.filter(isNotNil);
const groupedReactions = Object.values(
groupBy(reactionsWithEmojiData, groupByKey)
).map(groupedReaction =>
orderBy(
groupedReaction,
[reaction => reaction.from.isMe, 'timestamp'],
['desc', 'desc']
)
);
return orderBy(
groupedReactions,
['length', ([{ timestamp }]) => timestamp],
['desc', 'desc']
);
}, [reactions, groupByKey, emojiLocalization]);
}