import PropTypes from 'prop-types' import React from 'react' import { View, StyleSheet, ViewStyle, LayoutChangeEvent } from 'react-native' import { Avatar, AvatarProps } from './Avatar' import Bubble from './Bubble' import { SystemMessage, SystemMessageProps } from './SystemMessage' import { Day, DayProps } from './Day' import { StylePropType, isSameUser } from './utils' import { IMessage, User, LeftRightStyle } from './Models' const styles = { left: StyleSheet.create({ container: { flexDirection: 'row', alignItems: 'flex-end', justifyContent: 'flex-start', marginLeft: 8, marginRight: 0, }, }), right: StyleSheet.create({ container: { flexDirection: 'row', alignItems: 'flex-end', justifyContent: 'flex-end', marginLeft: 0, marginRight: 8, }, }), } export interface MessageProps { key: any showUserAvatar?: boolean position: 'left' | 'right' currentMessage?: TMessage nextMessage?: TMessage previousMessage?: TMessage user: User inverted?: boolean containerStyle?: LeftRightStyle renderBubble?(props: Bubble['props']): React.ReactNode renderDay?(props: DayProps): React.ReactNode renderSystemMessage?(props: SystemMessageProps): React.ReactNode renderAvatar?(props: AvatarProps): React.ReactNode shouldUpdateMessage?( props: MessageProps, nextProps: MessageProps, ): boolean onMessageLayout?(event: LayoutChangeEvent): void } export default class Message< TMessage extends IMessage = IMessage > extends React.Component> { static defaultProps = { renderAvatar: undefined, renderBubble: null, renderDay: null, renderSystemMessage: null, position: 'left', currentMessage: {}, nextMessage: {}, previousMessage: {}, user: {}, containerStyle: {}, showUserAvatar: false, inverted: true, shouldUpdateMessage: undefined, onMessageLayout: undefined, } static propTypes = { renderAvatar: PropTypes.func, showUserAvatar: PropTypes.bool, renderBubble: PropTypes.func, renderDay: PropTypes.func, renderSystemMessage: PropTypes.func, position: PropTypes.oneOf(['left', 'right']), currentMessage: PropTypes.object, nextMessage: PropTypes.object, previousMessage: PropTypes.object, user: PropTypes.object, inverted: PropTypes.bool, containerStyle: PropTypes.shape({ left: StylePropType, right: StylePropType, }), shouldUpdateMessage: PropTypes.func, onMessageLayout: PropTypes.func, } shouldComponentUpdate (nextProps: MessageProps) { const next = nextProps.currentMessage! const current = this.props.currentMessage! const { previousMessage, nextMessage } = this.props const nextPropsMessage = nextProps.nextMessage const nextPropsPreviousMessage = nextProps.previousMessage const shouldUpdate = (this.props.shouldUpdateMessage && this.props.shouldUpdateMessage(this.props, nextProps)) || false return ( next.sent !== current.sent || next.received !== current.received || next.pending !== current.pending || next.createdAt !== current.createdAt || next.text !== current.text || next.image !== current.image || next.video !== current.video || next.audio !== current.audio || previousMessage !== nextPropsPreviousMessage || nextMessage !== nextPropsMessage || shouldUpdate ) } renderDay () { if (this.props.currentMessage && this.props.currentMessage.createdAt) { const { containerStyle, onMessageLayout, ...props } = this.props if (this.props.renderDay) return this.props.renderDay(props) return } return null } renderBubble () { const { containerStyle, onMessageLayout, ...props } = this.props if (this.props.renderBubble) return this.props.renderBubble(props) // @ts-ignore return } renderSystemMessage () { const { containerStyle, onMessageLayout, ...props } = this.props if (this.props.renderSystemMessage) return this.props.renderSystemMessage(props) return } renderAvatar () { const { user, currentMessage, showUserAvatar } = this.props if ( user && user._id && currentMessage && currentMessage.user && user._id === currentMessage.user._id && !showUserAvatar ) return null if ( currentMessage && currentMessage.user && currentMessage.user.avatar === null ) return null const { containerStyle, onMessageLayout, ...props } = this.props return } render () { const { currentMessage, onMessageLayout, nextMessage, position, containerStyle, } = this.props if (currentMessage) { const sameUser = isSameUser(currentMessage, nextMessage!) return ( {this.renderDay()} {currentMessage.system ? ( this.renderSystemMessage() ) : ( {this.props.position === 'left' ? this.renderAvatar() : null} {this.renderBubble()} {this.props.position === 'right' ? this.renderAvatar() : null} )} ) } return null } }