UNPKG

react-native-chating-ui-kit

Version:

CometChat React Native UI Kit is a collection of custom UI Components designed to build text , chat and calling features in your application. The UI Kit is developed to keep developers in mind and aims to reduce development efforts significantly

804 lines (803 loc) 38.7 kB
import React, { forwardRef, useEffect, useRef, useState, useImperativeHandle, useContext, useCallback } from "react"; import { View, FlatList, Text, Image, TouchableOpacity, ActivityIndicator } from "react-native"; //@ts-ignore import { CometChat } from "@cometchat-pro/react-native-chat"; import { rightArrowIcon } from "./resources"; import { BaseStyle, CometChatContext, CometChatLiveReactions } from "../shared"; import { MessageBubbleStyle } from "../shared/views/CometChatMessageBubble/MessageBubbleStyle"; import { AvatarStyle } from "../shared"; import { CometChatAvatar, CometChatDate, CometChatReceipt, DateStyle } from "../shared"; import { MessageListStyle } from "./MessageListStyle"; import { CometChatMessageBubble } from "../shared/views/CometChatMessageBubble"; import { CallTypeConstants, MessageCategoryConstants, MessageOptionConstants, MessageStatusConstants, ReceiverTypeConstants, ViewAlignment } from "../shared/constants/UIKitConstants"; import { localize } from "../shared"; import { downArrowIcon } from "./resources"; import { Style } from "./style"; import { CometChatSoundManager } from "../shared"; import { MessageEvents } from "../shared/events/messages"; import { ChatConfigurator } from "../shared/framework/ChatConfigurator"; import { CometChatActionSheet, ActionSheetStyles, CometChatBottomSheet } from "../shared"; import { getUnixTimestamp, messageStatus } from "../shared/utils/CometChatMessageHelper"; import { CometChatUIEventHandler } from "../shared/events/CometChatUIEventHandler/CometChatUIEventHandler"; import Clipboard from "@react-native-community/clipboard"; let templatesMap = new Map(); let _defaultRequestBuilder; export const CometChatMessageList = forwardRef((props, ref) => { const { parentMessageId, user, group, EmptyStateView, emptyStateText, ErrorStateView, errorStateText, LoadingStateView, disableReceipt, disableSoundForMessages, customSoundForMessages, readIcon, deliveredIcon, sentIcon, waitIcon, errorIcon, alignment, showAvatar, datePattern, timeStampAlignment, dateSeperatorPattern, templates, messageRequestBuilder, newMessageIndicatorText, scrollToBottomOnNewMessages, onThreadRepliesPress, HeaderView, FooterView, wrapperMessageBubbleStyle, avatarStyle, dateSeperatorStyle, actionSheetStyle, messageListStyle, onError, onBack, } = props; const messageListenerId = "message_" + new Date().getTime(); const callListenerId = "call_" + new Date().getTime(); const groupListenerId = "group_" + new Date().getTime(); const uiEventListener = "uiEvent_" + new Date().getTime(); const uiEventListenerShow = "uiEvent_show_" + new Date().getTime(); const uiEventListenerHide = "uiEvent_hide_" + new Date().getTime(); if (user) { _defaultRequestBuilder = new CometChat.MessagesRequestBuilder() .setLimit(30) .setTags([]) .setUID(user["uid"]); } else if (group) { _defaultRequestBuilder = new CometChat.MessagesRequestBuilder() .setLimit(30) .setTags([]) .setGUID(group["guid"]); } _defaultRequestBuilder.setTypes(ChatConfigurator.dataSource.getAllMessageTypes()); _defaultRequestBuilder.setCategories(ChatConfigurator.dataSource.getAllMessageCategories()); const { theme } = useContext(CometChatContext); // creating style based on styles from users const _messageListStyle = new MessageListStyle({ backgroundColor: theme?.palette.getBackgroundColor(), emptyStateTextColor: theme?.palette.getError(), emptyStateTextFont: theme?.typography.subtitle1, errorStateTextColor: theme?.palette.getAccent(), errorStateTextFont: theme?.typography.title1, loadingIconTint: theme?.palette.getAccent700(), nameTextColor: theme?.palette.getAccent(), nameTextFont: theme?.typography.name, threadReplyIconTint: theme?.palette.getAccent700(), threadReplySeparatorColor: theme?.palette.getAccent100(), threadReplyTextColor: theme?.palette.getPrimary(), threadReplyTextFont: theme?.typography.body, timestampTextColor: theme?.palette.getAccent500(), timestampTextFont: theme?.typography.caption1, ...messageListStyle }); const _avatarStyle = new AvatarStyle({ backgroundColor: _messageListStyle.backgroundColor, nameTextColor: _messageListStyle.nameTextColor, nameTextFont: _messageListStyle.nameTextFont, ...avatarStyle }); const _dateSeperatorStyle = new DateStyle({ textColor: _messageListStyle.timestampTextColor, textFont: theme?.typography.title2, ...dateSeperatorStyle }); const messageBubbleDateStyle = new DateStyle({ textColor: _messageListStyle.timestampTextColor, textFont: _messageListStyle.timestampTextFont }); const _actionStyle = new ActionSheetStyles({ ...actionSheetStyle }); const _messageBubbleStyle = new MessageBubbleStyle({ ...wrapperMessageBubbleStyle }); // refs const currentScrollPosition = useRef(null); const messageListRef = useRef(null); const loggedInUser = useRef(null); const messageRequest = useRef(null); //updating users request builder let _updatedCustomRequestBuilder = _defaultRequestBuilder; if (messageRequestBuilder) { _updatedCustomRequestBuilder = messageRequestBuilder; } _updatedCustomRequestBuilder.hideReplies(true); if (user) _updatedCustomRequestBuilder = _updatedCustomRequestBuilder.setUID(user["uid"]); if (group) _updatedCustomRequestBuilder = _updatedCustomRequestBuilder.setGUID(group["guid"]); if (parentMessageId) _updatedCustomRequestBuilder = _updatedCustomRequestBuilder.setParentMessageId(parseInt(parentMessageId)); let types = [], categories = []; if (templates.length) { types = templates.map(template => template.type); categories = templates.map(template => template.category); } else { types = ChatConfigurator.dataSource.getAllMessageTypes(); categories = ChatConfigurator.dataSource.getAllMessageCategories(); } _updatedCustomRequestBuilder = _updatedCustomRequestBuilder.setTypes(types); _updatedCustomRequestBuilder = _updatedCustomRequestBuilder.setCategories(categories); const msgRequestBuilder = useRef(_updatedCustomRequestBuilder); const lastMessageDate = useRef(new Date().getTime()); // states const [messagesList, setMessagesList] = useState([]); const [listState, setListState] = useState("loading"); const [loadingMessages, setLoadingMessages] = useState(false); const [unreadCount, setUnreadCount] = useState(0); const [showMessageOptions, setShowMessageOptions] = useState([]); const [liveReaction, setliveReaction] = useState(false); const [ExtensionsComponent, setExtensionsComponent] = useState(null); const [CustomListHeader, setCustomListHeader] = useState(null); const bottomSheetRef = useRef(null); const conversationId = useRef(null); const scrollHandler = (event) => { currentScrollPosition.current = event.nativeEvent.contentOffset.y; }; const newMsgIndicatorPressed = () => { scrollToBottom(); for (let index = 0; index < unreadCount; index++) { const message = messagesList[index]; if (index == 0) CometChatUIEventHandler.emitMessageEvent(MessageEvents.ccMessageRead, { message }); CometChat.markAsRead(message); } setUnreadCount(0); }; const getPreviousMessages = async () => { if (messagesList.length == 0) setListState("loading"); else setLoadingMessages(true); // TODO: this condition is applied because somewhere from whiteboard extention group scope is set to undefined. if (group != undefined && group['scope'] == undefined) { let fetchedGroup = await CometChat.getGroup(group['guid']).catch(e => { console.log("Error: fetching group", e); onError && onError(e); }); group['scope'] = fetchedGroup['scope']; } messageRequest.current.fetchPrevious() .then(msgs => { let reversed = msgs.reverse(); if (messagesList.length === 0 && reversed?.length > 0) { if (conversationId.current == null) conversationId.current = reversed[0].getConversationId(); CometChatUIEventHandler.emitMessageEvent(MessageEvents.ccActiveChatChanged, { message: reversed[0] }); } for (let index = 0; index < reversed.length; index++) { const message = reversed[index]; if (!disableReceipt && !message.hasOwnProperty("readAt")) { CometChat.markAsRead(message); CometChatUIEventHandler.emitMessageEvent(MessageEvents.ccMessageRead, { message }); } else break; } setMessagesList([...messagesList, ...reversed]); if (messagesList.length == 0) setListState(""); else setLoadingMessages(false); }) .catch(e => { if (messagesList.length == 0) setListState("error"); else setLoadingMessages(false); console.log(e); onError && onError(e); }); }; const loadTemplates = () => { let templates = ChatConfigurator.dataSource.getAllMessageTemplates(theme); templates.forEach(template => { if (templatesMap.get(`${template.category}_${template.type}`)) return; templatesMap.set(`${template.category}_${template.type}`, template); }); }; const playNotificationSound = (message) => { if (disableSoundForMessages) return; if (message?.category === MessageCategoryConstants.message) { if (customSoundForMessages) { CometChatSoundManager.play(loggedInUser.current.getUid() == message['sender']['uid'] ? "outgoingMessage" : "incomingMessage", customSoundForMessages); } else { CometChatSoundManager.play( // "incomingMessage" loggedInUser.current.getUid() == message['sender']['uid'] ? "outgoingMessage" : "incomingMessage"); } } }; const scrollToBottom = (scrollToFirstUnread = false) => { if (messageListRef && messagesList.length > 0) { messageListRef.current.scrollToIndex({ index: scrollToFirstUnread ? unreadCount - 1 : 0 }); } }; const markMessageAsRead = (message) => { if (!disableReceipt && !message?.readAt) { CometChatUIEventHandler.emitMessageEvent(MessageEvents.ccMessageRead, { message }); CometChat.markAsRead(message) .catch((error) => { console.log("Error", error); onError && onError(error); // errorHandler(error); }); } }; function checkMessageInSameConversation(message) { return (message.getReceiverType() == ReceiverTypeConstants.user && user?.getUid() == message.getSender()?.getUid()) || (message.getReceiverType() == ReceiverTypeConstants.group && group?.getGuid() == message.getReceiverId()); } function messageToSameConversation(message) { return (message.getReceiverType() == ReceiverTypeConstants.user && user?.getUid() == message.getReceiverId()) || (message.getReceiverType() == ReceiverTypeConstants.group && group?.getGuid() == message.getReceiverId()); } function checkSameConversation(message) { return conversationId.current != null && (message.getConversationId() == conversationId.current); } const newMessage = (newMessage, isReceived = true) => { let baseMessage = newMessage; if (checkSameConversation(baseMessage) || checkMessageInSameConversation(baseMessage) || messageToSameConversation(baseMessage)) { //need to add if (baseMessage.getParentMessageId()) { if (baseMessage.getParentMessageId() == parseInt(parentMessageId)) { // add to list setMessagesList([newMessage, ...messagesList]); } else { //increase count let index = messagesList.findIndex(msg => msg.id === newMessage.parentMessageId); let oldMsg = messagesList[index]; oldMsg.setReplyCount(oldMsg.getReplyCount() ? oldMsg.getReplyCount() + 1 : 1); let tmpList = [...messagesList]; tmpList[index] = oldMsg; setMessagesList(tmpList); } } else if (parentMessageId == undefined) { setMessagesList([newMessage, ...messagesList]); } // if scroll is not at bottom if (!scrollToBottomOnNewMessages && (Math.round(currentScrollPosition.current) >= 15)) { if (baseMessage['sender']['uid'] == loggedInUser.current?.['uid']) { scrollToBottom(); return; } CometChat.markAsDelivered(newMessage); CometChatUIEventHandler.emitMessageEvent(MessageEvents.ccMessageDelivered, { message: newMessage }); setUnreadCount(unreadCount + 1); } else { scrollToBottom(); if (isReceived) { markMessageAsRead(newMessage); CometChatUIEventHandler.emitMessageEvent(MessageEvents.ccMessageRead, { message: newMessage }); } } } playNotificationSound(newMessage); }; const messageEdited = (editedMessage, withMuid = false) => { let condition; if (withMuid) condition = (msg) => msg['muid'] == editedMessage['muid']; else condition = (msg) => msg.getId() == editedMessage.getId(); let msgIndex = messagesList.findIndex(condition); if (msgIndex > -1) { let tmpList = [...messagesList]; tmpList[msgIndex] = editedMessage; setMessagesList(tmpList); } }; const removeMessage = (message) => { let msgIndex = messagesList.findIndex(msg => msg.getId() == message.getId()); if (msgIndex == -1) return; let tmpList = [...messagesList]; tmpList.splice(msgIndex, 1); setMessagesList(tmpList); }; const deleteMessage = (message) => { CometChat.deleteMessage(message.getId().toString()) .then(res => { messageEdited(res, false); setShowMessageOptions([]); }) .catch(rej => { console.log(rej); onError && onError(rej); }); }; const showTransientMessage = (transientMessage) => { setliveReaction(true); setTimeout(() => { setliveReaction(false); }, 1500); }; const createActionMessage = () => { }; const updateMessageReceipt = (receipt) => { let index = messagesList.findIndex((msg, index) => msg['id'] == receipt['messageId'] || msg['messageId'] == receipt['messageId']); if (index == -1) return; let tmpList = [...messagesList]; let tmpMsg = tmpList[index]; if (receipt.hasOwnProperty('deliveredAt')) { tmpMsg['deliveredAt'] = receipt['deliveredAt']; } if (receipt.hasOwnProperty('readAt')) { tmpMsg['readAt'] = receipt['readAt']; } tmpMsg['updatedAt'] = receipt['timestamp']; setMessagesList(tmpList); }; const handlePannel = (item) => { if (item.alignment === ViewAlignment.messageListBottom && item.child) setCustomListHeader(() => item.child); else setCustomListHeader(null); }; useEffect(() => { CometChatUIEventHandler.addUIListener(uiEventListenerShow, { showPanel: (item) => handlePannel(item) }); CometChatUIEventHandler.addUIListener(uiEventListenerHide, { hidePanel: (item) => handlePannel(item) }); return () => { CometChatUIEventHandler.removeUIListener(uiEventListenerShow); CometChatUIEventHandler.removeUIListener(uiEventListenerHide); }; }, []); useEffect(() => { //add listeners CometChat.addMessageListener(messageListenerId, new CometChat.MessageListener({ onTextMessageReceived: (textMessage) => { newMessage(textMessage); }, onMediaMessageReceived: (mediaMessage) => { newMessage(mediaMessage); }, onCustomMessageReceived: (customMessage) => { newMessage(customMessage); }, onMessagesDelivered: (messageReceipt) => { updateMessageReceipt(messageReceipt); }, onMessagesRead: (messageReceipt) => { updateMessageReceipt(messageReceipt); }, onMessageDeleted: (deletedMessage) => { messageEdited(deletedMessage); }, onMessageEdited: (editedMessage) => { messageEdited(editedMessage); }, onTransientMessageReceived: (transientMessage) => { showTransientMessage(transientMessage); } })); CometChat.addGroupListener(groupListenerId, new CometChat.GroupListener({ onGroupMemberScopeChanged: (message) => { newMessage(message); }, onGroupMemberLeft: (message) => { newMessage(message); }, onGroupMemberKicked: (message) => { newMessage(message); }, onGroupMemberBanned: (message) => { newMessage(message); }, onGroupMemberUnbanned: (message) => { }, onMemberAddedToGroup: (message) => { newMessage(message); }, onGroupMemberJoined: (message) => { newMessage(message); }, })); CometChatUIEventHandler.addMessageListener(uiEventListener, { ccMessageSent: ({ message, status }) => { if (status == MessageStatusConstants.inprogress) { newMessage(message, false); } if (status == MessageStatusConstants.success) { messageEdited(message, true); } }, ccMessageEdited: ({ message, status }) => { if (status == messageStatus.success) messageEdited(message, false); }, ccMessageDeleted: ({ message }) => { messageEdited(message, false); }, }); CometChatUIEventHandler.addGroupListener(uiEventListener, { ccGroupMemberUnBanned: ({ message }) => { newMessage(message, false); }, ccGroupMemberBanned: ({ message }) => { newMessage(message, false); }, ccGroupMemberAdded: ({ message, usersAdded, userAddedIn }) => { usersAdded.forEach(user => { message['message'] = `${loggedInUser.current['name']} added ${user.name}`; message['muid'] = String(getUnixTimestamp()); message['sentAt'] = getUnixTimestamp(); newMessage(message, false); }); }, ccGroupMemberKicked: ({ message }) => { newMessage(message, false); }, ccGroupMemberScopeChanged: ({ action, updatedUser, scopeChangedTo, scopeChangedFrom, group }) => { newMessage(action, false); }, ccOwnershipChanged: ({ group, message }) => { // newMessage(message, false); removed after discussion. } }); CometChat.addCallListener(callListenerId, new CometChat.CallListener({ onIncomingCallReceived: (call) => { newMessage(call); }, onOutgoingCallAccepted: (call) => { newMessage(call); }, onOutgoingCallRejected: (call) => { newMessage(call); }, onIncomingCallCancelled: (call) => { newMessage(call); } })); CometChatUIEventHandler.addCallListener(uiEventListener, { ccCallInitiated: ({ call }) => { if (call['type'] == CallTypeConstants.audio || call['type'] == CallTypeConstants.video) { newMessage(call); } }, ccOutgoingCall: ({ call }) => { if (call['type'] == CallTypeConstants.audio || call['type'] == CallTypeConstants.video) { newMessage(call); } }, ccCallAccepted: ({ call }) => { if (call['type'] == CallTypeConstants.audio || call['type'] == CallTypeConstants.video) { newMessage(call); } }, ccCallRejected: ({ call }) => { if (call['type'] == CallTypeConstants.audio || call['type'] == CallTypeConstants.video) { newMessage(call); } }, ccCallEnded: ({ call }) => { if (call['type'] == CallTypeConstants.audio || call['type'] == CallTypeConstants.video) { newMessage(call); } } }); return () => { // clean up code like removing listeners CometChatUIEventHandler.removeMessageListener(uiEventListener); CometChatUIEventHandler.removeGroupListener(uiEventListener); CometChatUIEventHandler.removeCallListener(uiEventListener); CometChat.removeGroupListener(groupListenerId); CometChat.removeMessageListener(messageListenerId); CometChat.removeCallListener(callListenerId); }; }, [messagesList, unreadCount, user, group]); useEffect(() => { CometChatUIEventHandler.addUIListener(uiEventListener, { ccToggleBottomSheet: (item) => { bottomSheetRef.current?.togglePanel(); }, }); return () => CometChatUIEventHandler.removeUIListener(uiEventListener); }, []); // effects useEffect(() => { CometChat.getLoggedinUser() .then(u => { loggedInUser.current = u; messageRequest.current = msgRequestBuilder.current.build(); getPreviousMessages(); loadTemplates(); }) .catch(e => { console.log("Error while getting loggedInUser"); onError && onError(e); loggedInUser.current = null; }); return () => { onBack && onBack(); }; }, []); useImperativeHandle(ref, () => { return { addMessage: newMessage, updateMessage: messageEdited, removeMessage, deleteMessage, scrollToBottom, /// todo: not handeled yet createActionMessage, updateMessageReceipt, }; }); // functions returning view const getLeadingView = (item) => { if (showAvatar && (item.getSender()?.getUid() || item['sender']['uid']) !== loggedInUser.current['uid'] && item['category'] != MessageCategoryConstants.action) { return <CometChatAvatar image={item.getSender().getAvatar() ? { uri: item.getSender().getAvatar() } : undefined} name={item.getSender().getName()} style={_avatarStyle}/>; } return null; }; const getHeaderView = (item) => { let senderName = ""; if ((item.getSender()?.getUid() || item['sender']['uid']) != loggedInUser.current['uid']) senderName = item.getSender().getName(); if (item.getCategory() == MessageCategoryConstants.action || item.getCategory() == MessageCategoryConstants.call) return null; return (<View style={{ flexDirection: "row" }}> <Text style={[Style.nameStyle, { color: _messageListStyle.nameTextColor, ..._messageListStyle.nameTextFont, }]}>{senderName}</Text> {timeStampAlignment == "bottom" || item['category'] == "action" ? null : <CometChatDate timeStamp={((item.getDeletedAt() || item.getReadAt() || item.getDeliveredAt() || item.getSentAt()) * 1000) || getSentAtTimestamp(item)} style={messageBubbleDateStyle} pattern={"timeFormat"} customDateString={datePattern && datePattern(item)}/>} </View>); }; const getFooterView = (item, bubbleAlignment) => { // return null if time alignment is top if (timeStampAlignment == "top" || item['category'] == "action") return null; let isSender = (item.getSender()?.getUid() || item['sender']['uid']) == loggedInUser.current['uid']; let messageState; if (item.getReadAt()) messageState = "READ"; else if (item.getDeliveredAt()) messageState = "DELIVERED"; else if (item.getSentAt()) messageState = "SENT"; else if (isSender) messageState = "WAIT"; else messageState = "ERROR"; return <View style={[{ flexDirection: "row", justifyContent: bubbleAlignment === "right" ? "flex-end" : "flex-start" }]}> <CometChatDate timeStamp={((item.getDeletedAt() || item.getReadAt() || item.getDeliveredAt() || item.getSentAt()) * 1000) || getSentAtTimestamp(item)} style={messageBubbleDateStyle} pattern={"timeFormat"} customDateString={datePattern && datePattern(item)}/> {!disableReceipt && isSender ? <CometChatReceipt receipt={messageState} deliveredIcon={deliveredIcon} readIcon={readIcon} sentIcon={sentIcon} waitIcon={waitIcon} errorIcon={errorIcon}/> : null} </View>; }; const getAlignment = (item) => { if (item && item.getCategory() == MessageCategoryConstants.action) return "center"; if (alignment == "standard" && (item.getSender()?.getUid() || item['sender']['uid']) == loggedInUser.current['uid']) return "right"; return "left"; }; const openThreadView = (...params) => { if (onThreadRepliesPress) { onThreadRepliesPress(params[0], MessageView.bind(this, { message: params[0], isThreaded: true, showOptions: false })); } setShowMessageOptions([]); return onThreadRepliesPress; }; const editMessage = (item) => { CometChatUIEventHandler.emitMessageEvent(MessageEvents.ccMessageEdited, { message: item, status: messageStatus.inprogress }); setShowMessageOptions([]); }; const copyMessage = (item) => { Clipboard.setString(item['text']); setShowMessageOptions([]); }; const getThreadView = (item) => { let isThreaded = item.getReplyCount() > 0; let style = { color: theme?.palette.getPrimary() }; if (item['sender']['uid'] == loggedInUser.current['uid']) { style.color = theme?.palette.getSecondary(); } return !isThreaded ? null : <TouchableOpacity onPress={() => openThreadView(item, null)} style={{ flexDirection: "row", margin: 4, borderTopWidth: 1, borderColor: theme?.palette.getAccent50(), justifyContent: "space-between", padding: 4 }}> <Text style={style}>{`View ${item.getReplyCount()} replies`}</Text> <Image style={{ resizeMode: "contain", tintColor: theme?.palette.getPrimary() }} source={rightArrowIcon}/> </TouchableOpacity>; }; const getStyle = (item) => { let _style = new BaseStyle({ ..._messageBubbleStyle, backgroundColor: theme?.palette.getAccent50() }); if ((item.getSender()?.getUid() || item['sender']['uid']) == loggedInUser.current?.['uid'] && item.getCategory() == MessageCategoryConstants.message) _style.backgroundColor = theme?.palette.getPrimary(); return _style; }; const openOptionsForMessage = (item, template) => { let options = template?.options ? template.options(loggedInUser.current, item, group) : []; let optionsWithPressHandling = options.map(option => { if (!option.onPress) switch (option.id) { case MessageOptionConstants.replyInThread: option.onPress = openThreadView.bind(this, item); break; case MessageOptionConstants.deleteMessage: option.onPress = deleteMessage.bind(this, item); break; case MessageOptionConstants.editMessage: option.onPress = editMessage.bind(this, item); break; case MessageOptionConstants.copyMessage: option.onPress = copyMessage.bind(this, item); break; } if (option.id === MessageOptionConstants.reactToMessage) { option.onPress = () => { if (option.CustomView) { let view = option.CustomView(item); setExtensionsComponent(() => view); } }; } return option; }); setShowMessageOptions(optionsWithPressHandling); }; const MessageView = (params) => { const { message, showOptions = true, isThreaded = false } = params; let hasTemplate = templatesMap.get(`${message.getCategory()}_${message.getType()}`); if (templates?.length > 0) { let customTemplate = templates.find(template => template.type == message.getType() && template.category == message.getCategory()); if (customTemplate) hasTemplate = customTemplate; } if (hasTemplate) { if (hasTemplate.BubbleView) return hasTemplate.BubbleView(message); let bubbleAlignment = getAlignment(message); return <> <TouchableOpacity onLongPress={() => showOptions ? openOptionsForMessage(message, hasTemplate) : undefined}> <CometChatMessageBubble id={`${message.getId()}`} LeadingView={() => !isThreaded && getLeadingView(message)} HeaderView={() => !isThreaded && getHeaderView(message)} FooterView={() => getFooterView(message, bubbleAlignment)} alignment={isThreaded ? "left" : bubbleAlignment} ContentView={hasTemplate.ContentView?.bind(this, message, bubbleAlignment)} ThreadView={() => !isThreaded && getThreadView(message)} BottomView={() => ChatConfigurator.dataSource.getBottomView(message, bubbleAlignment)} // Note please rewrite this style={getStyle(message)}/> </TouchableOpacity> </>; } else { return null; } }; const getSentAtTimestamp = (item) => { if (!item['sentAt']) { return item['_composedAt']; } return item['sentAt'] * 1000; }; const RenderMessageItem = ({ item, index }) => { let seperatorView = null; const previousMessageDate = messagesList[index + 1] ? new Date(getSentAtTimestamp(messagesList[index + 1])) : null; const currentMessageDate = new Date(getSentAtTimestamp(item)); const currentDate = isNaN(currentMessageDate.getDate()) ? undefined : `${currentMessageDate.getDate()}-${currentMessageDate.getMonth()}-${currentMessageDate.getFullYear()}`; const previousDate = `${previousMessageDate?.getDate()}-${previousMessageDate?.getMonth()}-${previousMessageDate?.getFullYear()}`; if (currentDate != undefined && previousDate !== currentDate) { seperatorView = (<View style={{ marginBottom: 10 }}> <CometChatDate timeStamp={getSentAtTimestamp(item)} pattern={"dayDateFormat"} style={_dateSeperatorStyle} customDateString={dateSeperatorPattern ? dateSeperatorPattern(item['sentAt']) : undefined}/> </View>); } lastMessageDate.current = getSentAtTimestamp(item); return <> <MessageView message={item}/> {seperatorView} </>; }; const keyExtractor = useCallback((item) => `${item.id}_${item.muid}`, []); const itemSeperator = useCallback(() => <View style={{ height: 8 }}/>, []); const getEmptyTextView = () => { if (EmptyStateView) return <EmptyStateView />; return (<View style={Style.msgContainerStyle}> <Text style={[ Style.msgTxtStyle, { ...(messageListStyle?.emptyStateTextFont), color: messageListStyle?.emptyStateTextColor } ]}> {emptyStateText} </Text> </View>); }; const getErrorStateView = () => { if (ErrorStateView) return ErrorStateView(new CometChat.CometChatException({ message: "Something went wrong" })); return (<View style={Style.msgContainerStyle}> <Text style={[Style.msgTxtStyle, { ...messageListStyle?.errorStateTextFont, color: messageListStyle?.errorStateTextColor }]}> {errorStateText} </Text> </View>); }; const getLoadingStateView = () => { if (LoadingStateView) return LoadingStateView; return (<View style={Style.msgContainerStyle}> <ActivityIndicator size="large" color={messageListStyle?.loadingIconTint}/> </View>); }; const { height, width, backgroundColor, border, borderRadius, } = _messageListStyle; return (<View style={{ height, width, backgroundColor, borderRadius, ...border }}> {listState == "loading" && messagesList.length == 0 ? getLoadingStateView() : listState == "error" ? getErrorStateView() : listState == "" ? messagesList.length == 0 ? getEmptyTextView() : <View style={{ height: "100%", width: "100%" }}> {HeaderView && <View style={[Style.stickyHeaderFooterStyle, { top: 0 }]}> <HeaderView group={group && group['guid']} user={user && user['uid']} id={{ guid: group && group['guid'], uid: user && user['uid'], parentMessageId: parentMessageId }}/> </View>} {loadingMessages && <ActivityIndicator size="small" color={_messageListStyle.loadingIconTint}/>} <FlatList ref={messageListRef} inverted={true} ListEmptyComponent={getEmptyTextView} data={messagesList} ItemSeparatorComponent={itemSeperator} keyExtractor={keyExtractor} renderItem={RenderMessageItem} onEndReached={getPreviousMessages} onEndReachedThreshold={0.8} onScroll={scrollHandler} ListHeaderComponent={() => { if (CustomListHeader) return <CustomListHeader />; else return null; }}/> {FooterView && <View style={[Style.stickyHeaderFooterStyle, { bottom: 0 }]}> <FooterView group={group && group['guid']} user={user && user['uid']} id={{ guid: group && group['guid'], uid: user && user['uid'], parentMessageId: parentMessageId }}/> </View>} </View> : null} {liveReaction ? <View style={{ alignItems: "flex-end" }}> <CometChatLiveReactions /> </View> : null} {unreadCount > 0 ? <TouchableOpacity onPress={newMsgIndicatorPressed.bind(this)} style={Style.newMessageIndicatorStyle}> <Text style={[Style.newMessageIndicatorText]}> {newMessageIndicatorText ? newMessageIndicatorText : `${unreadCount} ${localize("NEW_MESSAGE")}`} </Text> <Image source={downArrowIcon} style={Style.newMessageIndicatorImage}/> </TouchableOpacity> : null} <CometChatBottomSheet ref={bottomSheetRef} onClose={() => { if (ExtensionsComponent) setExtensionsComponent(null); setShowMessageOptions([]); }} isOpen={showMessageOptions.length > 0 || ExtensionsComponent}> {ExtensionsComponent ? ExtensionsComponent : <CometChatActionSheet actions={showMessageOptions} style={_actionStyle}/>} </CometChatBottomSheet> </View>); }); CometChatMessageList.defaultProps = { timeStampAlignment: "bottom", templates: [], showAvatar: true, alignment: "standard", errorStateText: localize("SOMETHING_WRONG"), emptyStateText: localize("NO_MESSAGES_FOUND"), disableReceipt: false }; //# sourceMappingURL=CometChatMessageList.js.map