import React, { useMemo } from 'react'; import { StyleProp, StyleSheet, Text, ViewStyle } from 'react-native'; import { ReactionListItemWrapper } from './ReactionListItemWrapper'; import { MessageContextValue, useMessageContext, } from '../../../../contexts/messageContext/MessageContext'; import { MessagesContextValue, useMessagesContext, } from '../../../../contexts/messagesContext/MessagesContext'; import { useTheme } from '../../../../contexts/themeContext/ThemeContext'; import { Unknown } from '../../../../icons/Unknown'; import type { IconProps } from '../../../../icons/utils/base'; import { primitives } from '../../../../theme'; import type { ReactionData } from '../../../../utils/utils'; type Props = Pick & { size: number; type: string; supportedReactions?: ReactionData[]; }; const Icon = ({ size, style, supportedReactions, type }: Props) => { const ReactionIcon = supportedReactions?.find((reaction) => reaction.type === type)?.Icon || Unknown; return ; }; export type ReactionListClusteredPropsWithContext = Partial< Pick< MessageContextValue, 'hasReactions' | 'onPress' | 'onPressIn' | 'preventPress' | 'reactions' | 'showReactionsOverlay' > > & Partial> & { containerStyle?: StyleProp; accessibilityLabel?: string; }; export const ReactionListClusteredWithContext = (props: ReactionListClusteredPropsWithContext) => { const { hasReactions, onPress, onPressIn, preventPress, reactions, showReactionsOverlay, supportedReactions, containerStyle, accessibilityLabel, } = props; const { theme: { messageItemView: { reactionListClustered: { icon }, }, }, } = useTheme(); const styles = useStyles(); const supportedReactionTypes = supportedReactions?.map( (supportedReaction) => supportedReaction.type, ); const reactionsCount = reactions?.length || 0; const moreReactionsCount = reactionsCount - 4; const reactionsCountText = moreReactionsCount < 99 ? moreReactionsCount : `+${moreReactionsCount}`; const hasSupportedReactions = reactions?.some((reaction) => supportedReactionTypes?.includes(reaction.type), ); if (!hasSupportedReactions || !hasReactions) { return null; } return ( { if (onPress) { onPress({ defaultHandler: () => { if (showReactionsOverlay) { showReactionsOverlay(undefined); } }, emitter: 'reactionList', event, }); } }} onPressIn={(event) => { if (onPressIn) { onPressIn({ defaultHandler: () => { if (showReactionsOverlay) { showReactionsOverlay(undefined); } }, emitter: 'reactionList', event, }); } }} style={containerStyle} accessibilityLabel={accessibilityLabel} > {reactions ?.slice(0, 4) .map((reaction) => ( ))} {reactionsCount > 4 ? {reactionsCountText} : null} ); }; const areEqual = ( prevProps: ReactionListClusteredPropsWithContext, nextProps: ReactionListClusteredPropsWithContext, ) => { const { hasReactions: prevHasReactions, reactions: prevReactions } = prevProps; const { hasReactions: nextHasReactions, reactions: nextReactions } = nextProps; const hasReactionsEqual = prevHasReactions === nextHasReactions; if (!hasReactionsEqual) { return false; } const reactionsEqual = prevReactions?.length === nextReactions?.length; if (!reactionsEqual) { return false; } return true; }; const MemoizedReactionListClustered = React.memo( ReactionListClusteredWithContext, areEqual, ) as typeof ReactionListClusteredWithContext; export type ReactionListClusteredProps = Partial; export const ReactionListClustered = (props: ReactionListClusteredProps) => { const { hasReactions, onPress, onPressIn, preventPress, reactions, showReactionsOverlay } = useMessageContext(); const { supportedReactions } = useMessagesContext(); return ( ); }; const useStyles = () => { const { theme: { semantics, messageItemView: { reactionListClustered: { contentContainer, reactionCount, iconStyle }, }, }, } = useTheme(); return useMemo( () => StyleSheet.create({ contentContainer: { ...contentContainer, }, reactionCount: { color: semantics.reactionText, fontSize: primitives.typographyFontSizeXxs, fontWeight: primitives.typographyFontWeightBold, lineHeight: primitives.typographyLineHeightTight, ...reactionCount, }, iconStyle: { ...iconStyle, }, }), [semantics, reactionCount, iconStyle, contentContainer], ); };