diff --git a/src/GiftedChat.tsx b/src/GiftedChat.tsx index 492007251..8fd2c8bf3 100644 --- a/src/GiftedChat.tsx +++ b/src/GiftedChat.tsx @@ -38,6 +38,7 @@ import MessageContainer from './MessageContainer' import { Send, SendProps } from './Send' import { GiftedChatContext } from './GiftedChatContext' import { Time, TimeProps } from './Time' +import { QuickRepliesProps } from './QuickReplies' import GiftedAvatar from './GiftedAvatar' import { @@ -55,7 +56,6 @@ import { MessageVideoProps, MessageAudioProps, } from './Models' -import QuickReplies from './QuickReplies' dayjs.extend(localizedFormat) @@ -207,7 +207,7 @@ export interface GiftedChatProps { /* Custom parse patterns for react-native-parsed-text used to linking message content (like URLs and phone numbers) */ parsePatterns?(linkStyle: TextStyle): any onQuickReply?(replies: Reply[]): void - renderQuickReplies?(quickReplies: QuickReplies['props']): React.ReactNode + renderQuickReplies?(quickReplies: QuickRepliesProps): React.ReactNode renderQuickReplySend?(): React.ReactNode /* Scroll to bottom custom component */ scrollToBottomComponent?(): React.ReactNode diff --git a/src/QuickReplies.tsx b/src/QuickReplies.tsx index a6c33b35e..7f855e1c7 100644 --- a/src/QuickReplies.tsx +++ b/src/QuickReplies.tsx @@ -1,5 +1,5 @@ import PropTypes from 'prop-types' -import React, { Component } from 'react' +import React, { useState, useMemo } from 'react' import { Text, StyleSheet, @@ -11,6 +11,7 @@ import { import { IMessage, Reply } from './Models' import Color from './Color' import { warning, StylePropType } from './utils' +import { useCallbackOne } from 'use-memo-one' const styles = StyleSheet.create({ container: { @@ -52,90 +53,26 @@ export interface QuickRepliesProps { renderQuickReplySend?(): React.ReactNode } -export interface QuickRepliesState { - replies: Reply[] -} - const sameReply = (currentReply: Reply) => (reply: Reply) => currentReply.value === reply.value const diffReply = (currentReply: Reply) => (reply: Reply) => currentReply.value !== reply.value -export default class QuickReplies extends Component< - QuickRepliesProps, - QuickRepliesState -> { - static defaultProps = { - currentMessage: { - quickReplies: [], - }, - onQuickReply: () => {}, - color: Color.peterRiver, - sendText: 'Send', - keepReplies: false, - renderQuickReplySend: undefined, - quickReplyStyle: undefined, - } - - static propTypes = { - currentMessage: PropTypes.object.isRequired, - onQuickReply: PropTypes.func, - color: PropTypes.string, - sendText: PropTypes.string, - keepReplies: PropTypes.bool, - renderQuickReplySend: PropTypes.func, - quickReplyStyle: StylePropType, - } - - state = { - replies: [], - } - - handlePress = (reply: Reply) => () => { - const { currentMessage } = this.props - const { replies } = this.state - if (currentMessage) { - const { type } = currentMessage.quickReplies! - switch (type) { - case 'radio': { - this.handleSend([reply])() - return - } - - case 'checkbox': { - if (replies.find(sameReply(reply))) { - this.setState({ - replies: this.state.replies.filter(diffReply(reply)), - }) - } else { - this.setState({ replies: [...this.state.replies, reply] }) - } - return - } - - default: { - warning(`onQuickReply unknown type: ${type}`) - return - } - } - } - } - - handleSend = (replies: Reply[]) => () => { - const { currentMessage } = this.props - if (this.props.onQuickReply) { - this.props.onQuickReply( - replies.map((reply: Reply) => ({ - ...reply, - messageId: currentMessage!._id, - })), - ) - } - } - - shouldComponentDisplay = () => { - const { currentMessage, nextMessage } = this.props +export function QuickReplies(props: QuickRepliesProps) { + const { + currentMessage, + nextMessage, + color, + quickReplyStyle, + onQuickReply, + sendText, + renderQuickReplySend, + } = props + const { type } = currentMessage!.quickReplies! + const [replies, setReplies] = useState([]) + + const shouldComponentDisplay = useMemo(() => { const hasReplies = !!currentMessage && !!currentMessage!.quickReplies const hasNext = !!nextMessage && !!nextMessage!._id const keepIt = currentMessage!.quickReplies!.keepIt @@ -143,73 +80,117 @@ export default class QuickReplies extends Component< if (hasReplies && !hasNext) { return true } + if (hasReplies && hasNext && keepIt) { return true } + return false + }, [currentMessage, nextMessage]) + + if (!shouldComponentDisplay) { + return null } - renderQuickReplySend = () => { - const { replies } = this.state - const { sendText, renderQuickReplySend: customSend } = this.props - - return ( - - {customSend ? ( - customSend() - ) : ( - {sendText} - )} - + const handlePress = useCallbackOne( + (reply: Reply) => () => { + if (currentMessage) { + const { type } = currentMessage.quickReplies! + switch (type) { + case 'radio': { + handleSend([reply])() + return + } + case 'checkbox': { + if (replies.find(sameReply(reply))) { + setReplies(replies.filter(diffReply(reply))) + } else { + setReplies([...replies, reply]) + } + return + } + default: { + warning(`onQuickReply unknown type: ${type}`) + return + } + } + } + }, + [replies, currentMessage], + ) + + const handleSend = (repliesData: Reply[]) => () => { + onQuickReply?.( + repliesData.map((reply: Reply) => ({ + ...reply, + messageId: currentMessage!._id, + })), ) } - render() { - const { currentMessage, color, quickReplyStyle } = this.props - const { replies } = this.state - - if (!this.shouldComponentDisplay()) { - return null - } - - const { type } = currentMessage!.quickReplies! - - return ( - - {currentMessage!.quickReplies!.values.map( - (reply: Reply, index: number) => { - const selected = - type === 'checkbox' && replies.find(sameReply(reply)) - return ( - + {currentMessage!.quickReplies!.values.map( + (reply: Reply, index: number) => { + const selected = type === 'checkbox' && replies.find(sameReply(reply)) + + return ( + + - - {reply.title} - - - ) - }, - )} - {replies.length > 0 && this.renderQuickReplySend()} - - ) - } + {reply.title} + + + ) + }, + )} + {replies.length > 0 && ( + + {renderQuickReplySend?.() || ( + {sendText} + )} + + )} + + ) +} + +QuickReplies.defaultProps = { + currentMessage: { + quickReplies: [], + }, + onQuickReply: () => {}, + color: Color.peterRiver, + sendText: 'Send', + keepReplies: false, + renderQuickReplySend: undefined, + quickReplyStyle: undefined, +} + +QuickReplies.propTypes = { + currentMessage: PropTypes.object.isRequired, + onQuickReply: PropTypes.func, + color: PropTypes.string, + sendText: PropTypes.string, + keepReplies: PropTypes.bool, + renderQuickReplySend: PropTypes.func, + quickReplyStyle: StylePropType, }