import * as React from 'react'; import { groupBy, mapValues, orderBy, sortBy } from 'lodash'; import classNames from 'classnames'; import { ContactName } from './ContactName'; import { Avatar, Props as AvatarProps } from '../Avatar'; import { Emoji } from '../emoji/Emoji'; import { useRestoreFocus } from '../../util/hooks'; import { ColorType } from '../../types/Colors'; export type Reaction = { emoji: string; timestamp: number; from: { id: string; color?: ColorType; avatarPath?: string; name?: string; profileName?: string; title: string; isMe?: boolean; phoneNumber?: string; }; }; export type OwnProps = { reactions: Array; pickedReaction?: string; onClose?: () => unknown; }; export type Props = OwnProps & Pick, 'style'> & Pick; const emojisOrder = ['❤️', '👍', '👎', '😂', '😮', '😢', '😡']; export const ReactionViewer = React.forwardRef( ({ i18n, reactions, onClose, pickedReaction, ...rest }, ref) => { const grouped = mapValues(groupBy(reactions, 'emoji'), res => orderBy(res, ['timestamp'], ['desc']) ); const [selected, setSelected] = React.useState(pickedReaction || 'all'); const focusRef = React.useRef(null); // Handle escape key React.useEffect(() => { const handler = (e: KeyboardEvent) => { if (onClose && e.key === 'Escape') { onClose(); } }; document.addEventListener('keydown', handler); return () => { document.removeEventListener('keydown', handler); }; }, [onClose]); // Focus first button and restore focus on unmount useRestoreFocus(focusRef); // Create sorted reaction categories, supporting reaction types we don't // explicitly know about yet const renderedEmojis = React.useMemo(() => { const emojiSet = new Set(); reactions.forEach(re => emojiSet.add(re.emoji)); const arr = sortBy(Array.from(emojiSet), emoji => { const idx = emojisOrder.indexOf(emoji); if (idx > -1) { return idx; } return Infinity; }); return ['all', ...arr]; }, [reactions]); const allSorted = React.useMemo(() => { return orderBy(reactions, ['timestamp'], ['desc']); }, [reactions]); // If we have previously selected a reaction type that is no longer present // (removed on another device, for instance) we should select another // reaction type React.useEffect(() => { if (!grouped[selected]) { const toSelect = renderedEmojis[0]; if (toSelect) { setSelected(toSelect); } else if (onClose) { // We have nothing to render! onClose(); } } }, [grouped, onClose, renderedEmojis, selected, setSelected]); const selectedReactions = grouped[selected] || allSorted; return (
{renderedEmojis .filter(e => e === 'all' || Boolean(grouped[e])) .map((cat, index) => { const re = grouped[cat] || reactions; const maybeFocusRef = index === 0 ? focusRef : undefined; const isAll = cat === 'all'; return ( ); })}
{selectedReactions.map(({ from, emoji }) => (
{from.isMe ? ( i18n('you') ) : ( )}
))}
); } );