import React, { useEffect, useState } from 'react' import Clipboard from '@react-native-clipboard/clipboard'; import { Messages as MessagesController, useSession, useUtils, useLanguage, ToastType, useToast, useConfig } from 'ordering-components/native' import { useTheme } from 'styled-components/native'; import { launchImageLibrary } from 'react-native-image-picker' import { GiftedChat, Actions, ActionsProps, InputToolbar, Composer, Send, Bubble, MessageImage, InputToolbarProps, ComposerProps } from 'react-native-gifted-chat' import { USER_TYPE } from '../../config/constants' import MaterialCommunityIcon from 'react-native-vector-icons/MaterialCommunityIcons' import AntDesignIcon from 'react-native-vector-icons/AntDesign' import { OIcon, OIconButton, OText, OButton } from '../shared' import { TouchableOpacity, ActivityIndicator, StyleSheet, View, Platform, Keyboard } from 'react-native' import { Header, TitleHeader, Wrapper, QuickMessageContainer, ProfileMessageHeader, MessageTypeItem } from './styles' import { MessagesParams } from '../../types' import { useWindowDimensions } from 'react-native' import { useSafeAreaInsets } from 'react-native-safe-area-context' import { getLogisticTag } from '../../utils' const ORDER_STATUS: any = { 0: 'ORDER_STATUS_PENDING', 1: 'ORDERS_COMPLETED', 2: 'ORDER_REJECTED', 3: 'ORDER_STATUS_IN_BUSINESS', 4: 'ORDER_READY', 5: 'ORDER_REJECTED_RESTAURANT', 6: 'ORDER_STATUS_CANCELLEDBYDRIVER', 7: 'ORDER_STATUS_ACCEPTEDBYRESTAURANT', 8: 'ORDER_CONFIRMED_ACCEPTED_BY_DRIVER', 9: 'ORDER_PICKUP_COMPLETED_BY_DRIVER', 10: 'ORDER_PICKUP_FAILED_BY_DRIVER', 11: 'ORDER_DELIVERY_COMPLETED_BY_DRIVER', 12: 'ORDER_DELIVERY_FAILED_BY_DRIVER', 13: 'PREORDER', 14: 'ORDER_NOT_READY', 15: 'ORDER_PICKEDUP_COMPLETED_BY_CUSTOMER', 16: 'ORDER_STATUS_CANCELLED_BY_CUSTOMER', 17: 'ORDER_NOT_PICKEDUP_BY_CUSTOMER', 18: 'ORDER_DRIVER_ALMOST_ARRIVED_BUSINESS', 19: 'ORDER_DRIVER_ALMOST_ARRIVED_CUSTOMER', 20: 'ORDER_CUSTOMER_ALMOST_ARRIVED_BUSINESS', 21: 'ORDER_CUSTOMER_ARRIVED_BUSINESS', 22: 'ORDER_LOOKING_FOR_DRIVER', 23: 'ORDER_DRIVER_ON_WAY', 24: 'ORDER_DRIVER_WAITING_FOR_ORDER', 25: 'ORDER_ACCEPTED_BY_DRIVER_COMPANY', 26: 'ORDER_DRIVER_ARRIVED_CUSTOMER' } const filterSpecialStatus = ['prepared_in', 'delivered_in', 'delivery_datetime'] const MessagesUI = (props: MessagesParams) => { const { type, order, messages, image, message, sendMessage, setCanRead, setMessage, handleSend, setImage, readMessages, onClose, business, driver, onMessages, isMeesageListing } = props const [{ user }] = useSession() const [{ configs }] = useConfig() const [{ parseDate }] = useUtils() const [, t] = useLanguage() const [, { showToast }] = useToast(); const [formattedMessages, setFormattedMessages] = useState>([]) const [isKeyboardShow, setIsKeyboardShow] = useState(false) const previousStatus = [1, 2, 5, 6, 10, 11, 12, 15, 16, 17] const chatDisabled = previousStatus.includes(order?.status) const { height } = useWindowDimensions(); const { top, bottom } = useSafeAreaInsets(); const theme = useTheme(); const quickMessageList = [ { key: 'customer_message_1', text: t('CUSTOMER_MESSAGE_1', 'Lorem ipsum 1') }, { key: 'customer_message_2', text: t('CUSTOMER_MESSAGE_2', 'Lorem ipsum 2') }, { key: 'customer_message_3', text: t('CUSTOMER_MESSAGE_3', 'Lorem ipsum 3') }, { key: 'customer_message_4', text: t('CUSTOMER_MESSAGE_4', 'Lorem ipsum 4') } ] const handleClickQuickMessage = (text: string) => { setMessage && setMessage(`${message}${text}`) } const onChangeMessage = (val: string) => { setMessage && setMessage(val) } const removeImage = () => { setImage && setImage(null) } const handleImagePicker = () => { launchImageLibrary({ mediaType: 'photo', maxHeight: 2048, maxWidth: 2048, includeBase64: true }, (response: any) => { if (response?.didCancel) { showToast(ToastType.Error, t('IMAGE_CANCELLED', 'User cancelled image picker')); } else if (response?.errorMessage) { showToast(ToastType.Error, response.errorMessage); } else { if (response?.assets?.length > 0) { const image = response?.assets[0] const url = `data:${image.type};base64,${image.base64}` setImage && setImage(url); } else { showToast(ToastType.Error, t('IMAGE_NOT_FOUND', 'Image not found')); } } }); }; const onSubmit = (values: any) => { handleSend && handleSend() setImage && setImage(null) setMessage && setMessage('') } const messageConsole = (message: any) => { return message.change?.attribute !== 'driver_id' ? `${t('ORDER', 'Order')} ${t(message.change.attribute.toUpperCase(), message.change.attribute.replace('_', ' '))} ${t('CHANGED_FROM', 'Changed from')} ${filterSpecialStatus.includes(message.change.attribute) ? `${message.change.old === null ? '0' : message.change.old} ${t('TO', 'to')} ${message.change.new} ${t('MINUTES', 'Minutes')}` : `${message.change?.attribute !== 'logistic_status' ? message.change.old !== null && t(ORDER_STATUS[parseInt(message.change.old, 10)]) : message.change.old !== null && getLogisticTag(message.change.old, t)} ${t('TO', 'to')} ${message.change?.attribute !== 'logistic_status' ? t(ORDER_STATUS[parseInt(message.change.new, 10)]) : getLogisticTag(message.change.new, t)}` }` : message.change.new ? `${message.driver?.name} ${message.driver?.lastname !== null ? message.driver.lastname : ''} ${t('WAS_ASSIGNED_AS_DRIVER', 'Was assigned as driver')} ${message.comment ? message.comment.length : ''}` : `${t('DRIVER_UNASSIGNED', 'Driver unassigned')}` } useEffect(() => { const newMessages: Array = [] const _console = `${t('ORDER_PLACED_FOR', 'Order placed for')} ${parseDate(order?.created_at)} ${t('VIA', 'Via')} ${order?.app_id ? t(order?.app_id.toUpperCase(), order?.app_id) : t('OTHER', 'Other')}` const firstMessage = { _id: 0, type: 0, text: _console, createdAt: parseDate(order?.created_at, { outputFormat: 'YYYY-MM-DD HH:mm:ss' }), system: true } messages.messages.map((message: any) => { if (message.change?.attribute === 'driver_group_id') return if (business && message.type !== 0 && (props?.messagesToShow?.messages?.length || message?.can_see?.includes('2'))) { newMessages.push({ _id: message?.id, text: message.type === 1 ? messageConsole(message) : message.comment, createdAt: message.type !== 0 && parseDate(message?.created_at, { outputFormat: 'YYYY-MM-DD HH:mm:ss' }), image: message.source, type: message.type, system: message.type === 1, user: { _id: message.author && message.author.id, name: message.author && message.author.name, avatar: message.author && (message.author.id !== user.id && type === USER_TYPE.DRIVER ? order?.driver?.photo : order?.business?.logo) } }); } if (driver && message.type !== 0 && (props?.messagesToShow?.messages?.length || message?.can_see?.includes('4'))) { newMessages.push({ _id: message?.id, text: message.type === 1 ? messageConsole(message) : message.comment, createdAt: message.type !== 0 && parseDate(message?.created_at, { outputFormat: 'YYYY-MM-DD HH:mm:ss' }), image: message.source, type: message.type, system: message.type === 1, user: { _id: message.author && message.author.id, name: message.author && message.author.name, avatar: message.author && (message.author.id !== user.id && type === USER_TYPE.DRIVER ? order?.driver?.photo : order?.business?.logo) } }); } if (message.type === 0) { newMessages.push(firstMessage); } }) let _arrayMessages = [...newMessages.reverse()] setFormattedMessages(_arrayMessages); }, [messages.messages.length, business, driver]) useEffect(() => { const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', () => { setIsKeyboardShow(true) }) const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => { setIsKeyboardShow(false) }) const keyboardWillHideListener = Keyboard.addListener('keyboardWillHide', () => { setIsKeyboardShow(false) }) return () => { keyboardDidShowListener.remove() keyboardDidHideListener.remove() keyboardWillHideListener.remove() } }, []) useEffect(() => { if (business) setCanRead({ business: true, administrator: true, customer: true, driver: false }) else if (driver) setCanRead({ business: false, administrator: true, customer: true, driver: true }) }, [business, driver]) const RenderActions = (props: any) => { return ( handleImagePicker(), }} containerStyle={styles.containerActions} optionTintColor='#222845' icon={() => ( <> {image && ( )} )} /> ) } const renderAccessory = () => { return ( !chatDisabled && {quickMessageList.map((quickMessage, i) => ( handleClickQuickMessage(quickMessage.text)} /> ))} ) } const renderInputToolbar = (props: typeof InputToolbarProps) => ( renderAccessory()} /> ) const renderComposer = (props: typeof ComposerProps) => ( chatDisabled ? ( {t('NOT_SEND_MESSAGES', 'You can\'t send messages because the order has ended')} ) : ( ) ) const renderSend = (props: any) => { const isDisabled = (sendMessage?.loading || (message === '' && !image) || messages?.loading) return ( ) } const renderBubble = (props: any) => ( ) const renderMessageImage = (props: any) => ( ) const renderScrollToBottomComponent = () => ( ) const getViewHeight = () => { if (Platform.OS === 'android') { return '100%'; } else { return height - top - bottom - (isKeyboardShow ? 48 : 0); } } const onLongPress = (context: any, message: any) => { const options = [ t('COPY_TEXT', 'Copy text'), t('CANCEL', 'Cancel'), ]; const cancelButtonIndex = options.length - 1; context.actionSheet().showActionSheetWithOptions({ options, cancelButtonIndex }, (buttonIndex: any) => buttonIndex === 0 && Clipboard.setString(message.text) ); } useEffect(() => { if (!order?.id || messages?.loading) return readMessages && readMessages() }, [order?.id, messages?.loading]) return ( {!isMeesageListing ? (
{type === USER_TYPE.DRIVER ? order?.driver?.name : order?.business?.name} {type === USER_TYPE.DRIVER ? t('DRIVER', 'Driver') : t('BUSINESS', 'Business')}
) : ( {t('ORDER', theme?.defaultLanguages?.ORDER || 'Order')} #{order?.id} {order.business && ( onMessages({ business: true, driver: false })} > )} {order?.driver && ( onMessages({ business: false, driver: true })} > )} )} onLongPress(context, message)} scrollToBottom renderAvatarOnTop renderUsernameOnMessage renderAvatar={() => null} renderInputToolbar={renderInputToolbar} renderComposer={renderComposer} renderSend={renderSend} renderBubble={renderBubble} renderMessageImage={renderMessageImage} scrollToBottomComponent={() => renderScrollToBottomComponent()} messagesContainerStyle={{ paddingTop: 18, paddingHorizontal: 28, paddingBottom: 55 }} isLoadingEarlier={messages.loading} renderLoading={() => } keyboardShouldPersistTaps='handled' />
) } const styles = StyleSheet.create({ containerActions: { width: 44, height: 44, alignItems: 'center', justifyContent: 'center', marginHorizontal: 4, marginBottom: 0, }, containerSend: { width: 64, height: 44, alignItems: 'center', justifyContent: 'center', marginHorizontal: 4 }, editButton: { borderRadius: 50, backgroundColor: '#E9ECEF', marginRight: 10, height: 24, borderWidth: 1, paddingLeft: 0, paddingRight: 0 }, headerTitle: { flexDirection: 'row', alignItems: 'center' }, headerItem: { overflow: 'hidden', width: 35, marginVertical: 18, }, typeWraper: { flexDirection: 'row', height: 45, alignItems: 'center' } }) export const Messages = (props: MessagesParams) => { const [allMessages, setAllMessages] = useState(props.messages) useEffect(() => { setAllMessages(props.messages) }, [props.messages]) const MessagesProps = { ...props, UIComponent: MessagesUI, messages: allMessages, setMessages: (values: any) => { props.setMessages && props.setMessages(values) setAllMessages(values) } } return }