import React, { useState } from 'react'; import { StyleSheet, View } from 'react-native'; import { MessageContextValue, useMessageContext, } from '../../../contexts/messageContext/MessageContext'; import { MessagesContextValue, useMessagesContext, } from '../../../contexts/messagesContext/MessagesContext'; import { useTheme } from '../../../contexts/themeContext/ThemeContext'; import type { DefaultAttachmentType, DefaultChannelType, DefaultCommandType, DefaultEventType, DefaultMessageType, DefaultReactionType, DefaultUserType, UnknownType, } from '../../../types/types'; const styles = StyleSheet.create({ container: { alignItems: 'flex-end', flexDirection: 'row', }, }); export type MessageSimplePropsWithContext< At extends UnknownType = DefaultAttachmentType, Ch extends UnknownType = DefaultChannelType, Co extends string = DefaultCommandType, Ev extends UnknownType = DefaultEventType, Me extends UnknownType = DefaultMessageType, Re extends UnknownType = DefaultReactionType, Us extends UnknownType = DefaultUserType, > = Pick< MessageContextValue, 'alignment' | 'channel' | 'groupStyles' | 'hasReactions' | 'message' > & Pick< MessagesContextValue, 'enableMessageGroupingByUser' | 'MessageAvatar' | 'MessageContent' | 'ReactionList' >; const MessageSimpleWithContext = < At extends UnknownType = DefaultAttachmentType, Ch extends UnknownType = DefaultChannelType, Co extends string = DefaultCommandType, Ev extends UnknownType = DefaultEventType, Me extends UnknownType = DefaultMessageType, Re extends UnknownType = DefaultReactionType, Us extends UnknownType = DefaultUserType, >( props: MessageSimplePropsWithContext, ) => { const { alignment, channel, enableMessageGroupingByUser, groupStyles, hasReactions, message, MessageAvatar, MessageContent, ReactionList, } = props; const { theme: { messageSimple: { container }, }, } = useTheme(); const [messageContentWidth, setMessageContentWidth] = useState(0); const isVeryLastMessage = channel?.state.messages[channel?.state.messages.length - 1]?.id === message.id; const hasMarginBottom = groupStyles.includes('single') || groupStyles.includes('bottom'); const showReactions = hasReactions && ReactionList; return ( {alignment === 'left' && } {showReactions && } ); }; const areEqual = < At extends UnknownType = DefaultAttachmentType, Ch extends UnknownType = DefaultChannelType, Co extends string = DefaultCommandType, Ev extends UnknownType = DefaultEventType, Me extends UnknownType = DefaultMessageType, Re extends UnknownType = DefaultReactionType, Us extends UnknownType = DefaultUserType, >( prevProps: MessageSimplePropsWithContext, nextProps: MessageSimplePropsWithContext, ) => { const { channel: prevChannel, groupStyles: prevGroupStyles, hasReactions: prevHasReactions, message: prevMessage, } = prevProps; const { channel: nextChannel, groupStyles: nextGroupStyles, hasReactions: nextHasReactions, message: nextMessage, } = nextProps; const hasReactionsEqual = prevHasReactions === nextHasReactions; if (!hasReactionsEqual) return false; const repliesEqual = prevMessage.reply_count === nextMessage.reply_count; if (!repliesEqual) return false; const groupStylesEqual = JSON.stringify(prevGroupStyles) === JSON.stringify(nextGroupStyles); if (!groupStylesEqual) return false; const messageEqual = prevMessage.deleted_at === nextMessage.deleted_at && prevMessage.status === nextMessage.status && prevMessage.type === nextMessage.type && prevMessage.text === nextMessage.text; if (!messageEqual) return false; const quotedMessageEqual = prevMessage.quoted_message?.id === nextMessage.quoted_message?.id && prevMessage.quoted_message?.deleted_at === nextMessage.quoted_message?.deleted_at; if (!quotedMessageEqual) return false; const channelEqual = prevChannel?.state.messages.length === nextChannel?.state.messages.length; if (!channelEqual) return false; const prevAttachments = prevMessage.attachments; const nextAttachments = nextMessage.attachments; const attachmentsEqual = Array.isArray(prevAttachments) && Array.isArray(nextAttachments) ? prevAttachments.length === nextAttachments.length && prevAttachments.every( (attachment, index) => attachment.image_url === nextAttachments[index].image_url && attachment.og_scrape_url === nextAttachments[index].og_scrape_url && attachment.thumb_url === nextAttachments[index].thumb_url, ) : prevAttachments === nextAttachments; if (!attachmentsEqual) return false; const latestReactionsEqual = Array.isArray(prevMessage.latest_reactions) && Array.isArray(nextMessage.latest_reactions) ? prevMessage.latest_reactions.length === nextMessage.latest_reactions.length && prevMessage.latest_reactions.every( ({ type }, index) => type === nextMessage.latest_reactions?.[index].type, ) : prevMessage.latest_reactions === nextMessage.latest_reactions; if (!latestReactionsEqual) return false; return true; }; const MemoizedMessageSimple = React.memo( MessageSimpleWithContext, areEqual, ) as typeof MessageSimpleWithContext; export type MessageSimpleProps< At extends UnknownType = DefaultAttachmentType, Ch extends UnknownType = DefaultChannelType, Co extends string = DefaultCommandType, Ev extends UnknownType = DefaultEventType, Me extends UnknownType = DefaultMessageType, Re extends UnknownType = DefaultReactionType, Us extends UnknownType = DefaultUserType, > = Partial>; /** * * Message UI component */ export const MessageSimple = < At extends UnknownType = DefaultAttachmentType, Ch extends UnknownType = DefaultChannelType, Co extends string = DefaultCommandType, Ev extends UnknownType = DefaultEventType, Me extends UnknownType = DefaultMessageType, Re extends UnknownType = DefaultReactionType, Us extends UnknownType = DefaultUserType, >( props: MessageSimpleProps, ) => { const { alignment, channel, groupStyles, hasReactions, message } = useMessageContext(); const { enableMessageGroupingByUser, MessageAvatar, MessageContent, ReactionList } = useMessagesContext(); return ( {...{ alignment, channel, enableMessageGroupingByUser, groupStyles, hasReactions, message, MessageAvatar, MessageContent, ReactionList, }} {...props} /> ); }; MessageSimple.displayName = 'MessageSimple{messageSimple{container}}';