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

628 lines 29.9 kB
import React, { useContext } from "react"; import { View, Text } from "react-native"; //@ts-ignore import { CometChat } from "@cometchat-pro/react-native-chat"; import { ChatConfigurator, CometChatConfirmDialog, CometChatContext, localize } from "../shared"; import { Style } from "./style"; import { passwordGroupIcon, privateGroupIcon, rightTickIcon, deleteIcon } from "./resources"; import { ConversationsStyle } from "./ConversationsStyle"; import { GroupTypeConstants, MessageStatusConstants, PASSWORD_GROUP_COLOR, PRIVATE_GROUP_COLOR } from "../shared/constants/UIKitConstants"; import { AvatarStyle, BadgeStyle, CometChatBadge, CometChatDate, CometChatListItem, CometChatReceipt, DateStyle, StatusIndicatorStyle } from "../shared"; import { ListItemStyle } from "../shared"; import { CometChatSoundManager } from "../shared"; import { CometChatConversationUtils } from "../shared"; import { CometChatList } from "../shared"; import { CometChatUIEventHandler } from "../shared/events/CometChatUIEventHandler/CometChatUIEventHandler"; const conversationListenerId = "chatlist_" + new Date().getTime(); const userListenerId = "chatlist_user_" + new Date().getTime(); const groupListenerId = "chatlist_group_" + new Date().getTime(); const messageListenerId = "chatlist_message_" + new Date().getTime(); const callListenerId = "call_" + new Date().getTime(); /** * * @version 1.0.0 * @author CometChatTeam * @description CometChatConversations is a container component that wraps and * formats CometChatListBase and CometChatConversationList component, with no behavior of its own. * */ export const CometChatConversations = (props) => { /** * Props destructuring */ const { disableUsersPresence = false, disableReadReceipt = false, disableReceipt = false, disableTyping = false, disableSoundForMessages = false, customSoundForMessages, datePattern, ListItemView, AppBarOption, options, hideSeparator = true, backButtonIcon, showBackButton = false, selectionMode = "multiple", onSelection, title = localize("CHATS"), emptyStateText, EmptyStateView, errorStateText, ErrorStateView, LoadingStateView, conversationsRequestBuilder, SubtitleView, hideError = false, onItemPress, onItemLongPress, onError, onBack, conversationsStyle, } = props; //context const { theme } = useContext(CometChatContext); const conversationListRef = React.useRef(null); const loggedInUser = React.useRef(null); const [confirmDelete, setConfirmDelete] = React.useState(undefined); const [selecting, setSelecting] = React.useState(false); const [selectedConversation, setSelectedConversations] = React.useState([]); const _style = new ConversationsStyle({ backgroundColor: theme?.palette?.getBackgroundColor(), backIconTint: theme?.palette?.getPrimary(), emptyTextColor: theme?.palette?.getAccent400(), emptyTextFont: theme?.typography?.caption2, errorTextColor: theme?.palette?.getError(), errorTextFont: theme?.typography?.subtitle1, lastMessageTextColor: theme?.palette.getAccent600(), lastMessageTextFont: theme?.typography.subtitle1, loadingIconTint: theme?.palette.getAccent700(), separatorColor: theme?.palette.getAccent100(), titleColor: theme?.palette.getAccent(), titleFont: theme?.typography.heading, typingIndictorTextColor: theme?.palette.getAccent600(), typingIndictorTextFont: theme?.typography.subtitle1, threadIndicatorTextColor: theme?.palette.getAccent800(), threadIndicatorTextFont: theme?.typography.text1, ...conversationsStyle }); const _statusIndicatorStyle = new StatusIndicatorStyle(props?.statusIndicatorStyle || {}); const _avatarStyle = new AvatarStyle({ backgroundColor: theme?.palette?.getAccent600(), nameTextColor: theme?.palette?.getAccent(), nameTextFont: theme?.typography.body, ...props?.avatarStyle }); const _listItemStyle = new ListItemStyle({ backgroundColor: theme?.palette?.getBackgroundColor(), titleColor: theme?.palette.getAccent(), titleFont: theme?.typography.name, ...props?.listItemStyle }); const _badgeStyle = new BadgeStyle({ backgroundColor: theme?.palette?.getPrimary(), textColor: theme?.palette?.getSecondary(), textFont: theme?.typography?.caption2, ...props?.badgeStyle }); // const _receiptStyle = new ReceiptStyle(props?.receiptStyle || {}); const _dateStyle = new DateStyle({ textColor: theme?.palette?.getAccent600(), textFont: theme?.typography?.caption1, ...props?.dateStyle }); const _confirmDialogStyle = (props?.confirmDialogStyle || {}); const ErrorView = () => { return (<View style={Style.listContainer}> <Text style={{ ..._style?.errorTextFont, color: _style?.errorTextColor }}> {errorStateText || localize("SOMETHING_WRONG")} </Text> </View>); }; const EmptyView = () => { if (EmptyStateView) return EmptyStateView(); else return (<View style={Style.listContainer}> <Text style={{ ..._style.emptyTextFont, color: _style.emptyTextColor }}> {emptyStateText || localize("NO_CHATS_FOUND")} </Text> </View>); }; const userEventHandler = (...args) => { const { uid, blockedByMe, status } = args[0]; if (!blockedByMe) { let item = conversationListRef.current.getListItem(`${uid}_user_${loggedInUser.current.uid}`); if (item) { let updatedConversation = { ...item, conversationWith: { ...item.conversationWith, status } }; console.log(JSON.stringify(updatedConversation)); conversationListRef.current.updateList(updatedConversation); } } }; /** * Listener callback for typing event * @param {...any} args */ const typingEventHandler = (...args) => { // console.log("typing event", args[1], args[0].receiverId); let conversation = conversationListRef.current.getListItem(`${args[0]['receiverType']}_${args[0]['receiverId']}`); // console.log("typing event", conversation); let isTyping = args[1]; let newConversation = conversation; if (isTyping) { newConversation['lastMessage']["typing"] = args[0].receiverType === 'group' ? `${args[0].sender.name} : ${localize("IS_TYPING")}` : localize("IS_TYPING"); } else { delete newConversation['lastMessage']['typing']; } conversationListRef.current.updateList(conversation); }; /** * Find conversation from state and udpate its last message object. * Also remove from the current location and put it to 1st location. * * @param newMessage message object */ const updateLastMessage = (newMessage) => { CometChat.CometChatHelper.getConversationFromMessage(newMessage) .then(conversation => { const oldConversation = conversationListRef.current.getListItem(conversation['conversationId']); if (oldConversation == undefined) { CometChat.CometChatHelper.getConversationFromMessage(newMessage) .then(newConversation => { newConversation.setUnreadMessageCount(1); conversationListRef.current.updateAndMoveToFirst(newConversation); }) .catch(err => onError && onError(err)); return; } oldConversation['lastMessage'] = newMessage; if (newMessage['sender']['uid'] != loggedInUser.current?.['uid']) oldConversation.setUnreadMessageCount(oldConversation.getUnreadMessageCount() + 1); conversationListRef.current.updateAndMoveToFirst(oldConversation); }) .catch(err => { console.log("Error", err); }); }; /** * play notification sound for incoming messages */ const playNotificationSound = () => { // code for playing sound need to be added here. if (disableSoundForMessages) return; CometChatSoundManager.play(customSoundForMessages || CometChatSoundManager.SoundOutput.incomingMessageFromOther); }; const shouldMarkAsDelivered = (message) => { return !disableReceipt && !message.hasOwnProperty("deliveredAt"); }; /** * marking the incoming messages as delivered */ const markMessageAsDelivered = (message) => { if (message.hasOwnProperty('deletedAt')) return; if (shouldMarkAsDelivered(message)) { CometChat.markAsDelivered(message); playNotificationSound(); } }; /** * * When a text message / media message / custom message is received */ const messageEventHandler = (...args) => { const message = args[0]; !disableReadReceipt && markMessageAsDelivered(message); updateLastMessage(message); }; /** * callback handler for group Add / Kicked / Banned / Scope Change * @param {obj} message */ const groupHandler = (message) => { let conversation = conversationListRef.current.getListItem(message['conversationId']); if (conversation) { conversation.setLastMessage(message); conversationListRef.current.updateList(conversation); } else { CometChat.CometChatHelper.getConversationFromMessage(message) .then(newConversation => { conversationListRef.current.addItemToList(newConversation, 0); }); } }; const conversationClicked = (conversation) => { if (onItemPress) { onItemPress(conversation); return; } if (!selecting) { //fire event return; } if (selectionMode == "none") return; let index = selectedConversation.findIndex(tmpConver => tmpConver.conversationWith.conversationId == conversation.conversationWith.conversationId); if (index < 0) { if (selectionMode == "single") setSelectedConversations([conversation]); if (selectionMode == "multiple") setSelectedConversations([...selectedConversation, conversation]); } else { selectedConversation.splice(index, 1); setSelectedConversations([...selectedConversation]); } }; const conversationLongPressed = (conversation) => { if (onItemLongPress) { onItemLongPress(conversation); return; } if (selectionMode == "none") return; setSelecting(true); setSelectedConversations([...selectedConversation, conversation]); }; const removeConversation = (id) => { let conversation = conversationListRef.current.getListItem(id); const { conversationWith, conversationType } = conversation; let conversationWithId = conversationType == "group" ? conversationWith.guid : conversationWith.uid; CometChat.deleteConversation(conversationWithId, conversationType) .then(success => { conversationListRef.current.removeItemFromList(id); }) .catch(err => console.log(err)); }; const getMessagePreview = (conversations, uid) => { let lastMessage = conversations['lastMessage']; if (!lastMessage) return null; let messageText = ChatConfigurator.getDataSource().getLastConversationMessage(conversations); let groupText = ""; if (lastMessage['receiverType'] == 'group') { if (lastMessage['receiverId'] == uid) { groupText = "you: "; } else { groupText = lastMessage['sender']['name'] + ": "; } } return (<Text numberOfLines={1} ellipsizeMode={"tail"} style={[Style.subtitleTextStyle, { color: theme.palette.getAccent600() }]}> {groupText + messageText} </Text>); }; const LastMessageView = (params) => { const lastMessage = params['conversations']['lastMessage']; if (!lastMessage) return null; let readReceipt; if (!disableTyping && params.typingText) { return <View style={Style.row}> <Text>{params.typingText}</Text> </View>; } if (lastMessage && !disableReadReceipt && lastMessage['sender']['uid'] == loggedInUser.current?.uid) { let status = "ERROR"; if (lastMessage?.hasOwnProperty('readAt')) status = "READ"; else if (lastMessage?.hasOwnProperty("deliveredAt")) status = "DELIVERED"; else if (lastMessage?.hasOwnProperty("sentAt")) status = "SENT"; readReceipt = disableReceipt ? null : <CometChatReceipt receipt={status} deliveredIcon={props.deliveredIcon} errorIcon={props.errorIcon} readIcon={props.readIcon} sentIcon={props.sentIcon} waitIcon={props.waitingIcon}/>; } return (<View style={Style.row}> {readReceipt} {getMessagePreview(params['conversations'], loggedInUser.current?.uid)} </View>); }; const TailView = (params) => { return <View style={{ alignItems: "flex-end" }}> <CometChatDate timeStamp={(params.timestamp) * 1000} style={_dateStyle} customDateString={params.customPattern && params.customPattern()} pattern={"dayDateTimeFormat"}/> <CometChatBadge count={params.unreadCount} style={_badgeStyle}/> </View>; }; const ConfirmDeletionDialog = () => { if (confirmDelete == undefined) return null; return <CometChatConfirmDialog title={localize("CONFIRM")} cancelButtonText={localize("CANCEL")} confirmButtonText={localize("DELETE")} messageText={localize("DELETE_CONFIRM_MESSAGE")} isOpen={true} onCancel={() => setConfirmDelete(undefined)} onConfirm={() => { { removeConversation(confirmDelete); setConfirmDelete(undefined); } }} style={_confirmDialogStyle}/>; }; const getDefaultOptions = (conversation) => { let _defaultOptions = CometChatConversationUtils.getDefaultOptions(); _defaultOptions[0].backgroundColor = theme?.palette.getError(); _defaultOptions[0].icon = deleteIcon; _defaultOptions[0].title = localize("DELETE"); _defaultOptions[0].titleStyle = { fontSize: 14, color: theme?.palette.getSecondary() }; _defaultOptions[0].iconTint = theme?.palette.getSecondary(); _defaultOptions[0].onPress = (id) => { setConfirmDelete(id); }; return _defaultOptions; }; React.useEffect(() => { CometChat.getLoggedinUser() .then(u => { loggedInUser.current = u; }) .catch(err => console.log(err)); CometChat.addUserListener(userListenerId, new CometChat.UserListener({ onUserOnline: (onlineUser) => { console.log(onlineUser); userEventHandler(onlineUser); }, onUserOffline: (offlineUser) => { console.log(offlineUser); userEventHandler(offlineUser); }, })); CometChat.addCallListener(callListenerId, new CometChat.CallListener({ onIncomingCallReceived: (call) => { CometChat.CometChatHelper.getConversationFromMessage(call) .then((conversation) => { conversationListRef.current.updateList(conversation); }) .catch((e) => { onError && onError(e); }); }, onOutgoingCallAccepted: (call) => { CometChat.CometChatHelper.getConversationFromMessage(call) .then((conversation) => { conversationListRef.current.updateList(conversation); }) .catch((e) => { onError && onError(e); }); }, onOutgoingCallRejected: (call) => { CometChat.CometChatHelper.getConversationFromMessage(call) .then((conversation) => { conversationListRef.current.updateList(conversation); }) .catch((e) => { onError && onError(e); }); }, onIncomingCallCancelled: (call) => { CometChat.CometChatHelper.getConversationFromMessage(call) .then((conversation) => { conversationListRef.current.updateList(conversation); }) .catch((e) => { onError && onError(e); }); } })); CometChat.addGroupListener(groupListenerId, new CometChat.GroupListener({ onGroupMemberScopeChanged: (message) => { groupHandler(message); }, onGroupMemberKicked: (message) => { groupHandler(message); }, onGroupMemberLeft: (message) => { groupHandler(message); }, onGroupMemberUnbanned: (message) => { groupHandler(message); }, onGroupMemberBanned: (message) => { groupHandler(message); }, onMemberAddedToGroup: (message) => { groupHandler(message); }, onGroupMemberJoined: (message) => { groupHandler(message); } })); CometChat.addMessageListener(conversationListenerId, new CometChat.MessageListener({ onTextMessageReceived: (textMessage) => { messageEventHandler(textMessage); CometChatSoundManager.play("incomingMessage"); }, onMediaMessageReceived: (mediaMessage) => { messageEventHandler(mediaMessage); CometChatSoundManager.play("incomingMessage"); }, onCustomMessageReceived: (customMessage) => { messageEventHandler(customMessage); CometChatSoundManager.play("incomingMessage"); }, onMessageDeleted: (deletedMessage) => { messageEventHandler(deletedMessage); }, onMessageEdited: (editedMessage) => { messageEventHandler(editedMessage); }, onMessagesRead: (messageReceipt) => { messageEventHandler(messageReceipt); }, onMessageDelivered: (messageReveipt) => { messageEventHandler(messageReveipt); }, onTypingStarted: (typingIndicator) => { typingEventHandler(typingIndicator, true); }, onTypingEnded: (typingIndicator) => { typingEventHandler(typingIndicator, false); }, })); CometChatUIEventHandler.addConversationListener(conversationListenerId, { ccConversationDeleted: ({ conversation }) => { CometChat.deleteConversation(conversation.getConversationId(), conversation.getConversationType()) .then(res => { conversationListRef.current.removeItemFromList(conversation); }) .catch(err => { console.log("Error", err); }); } }); CometChatUIEventHandler.addMessageListener(messageListenerId, { ccMessageSent: ({ message, status }) => { if (status == MessageStatusConstants.success) { updateLastMessage(message); } }, ccMessageRead: ({ message }) => { CometChat.CometChatHelper.getConversationFromMessage(message) .then(conversation => { let conver = conversationListRef.current.getListItem(conversation.getConversationId()); if (!conver) return; let lastMessageId = conver['lastMessage']['id']; if (lastMessageId == message['id']) { conversationListRef.current.updateList(conversation); } }); }, ccMessageDeleted: ({ message }) => { CometChat.CometChatHelper.getConversationFromMessage(message) .then(conversation => { let conver = conversationListRef.current.getListItem(conversation.getConversationId()); if (!conver) return; let lastMessageId = conver['lastMessage']['id']; if (lastMessageId == message['id']) { conversationListRef.current.updateList(conversation); } }); }, ccMessageEdited: ({ message }) => { CometChat.CometChatHelper.getConversationFromMessage(message) .then(conversation => { let conver = conversationListRef.current.getListItem(conversation.getConversationId()); if (!conver) return; let lastMessageId = conver['lastMessage']['id']; if (lastMessageId == message['id']) { conversationListRef.current.updateList(conversation); } }); } }); CometChatUIEventHandler.addGroupListener(groupListenerId, { ccGroupDeleted: ({ group }) => { conversationListRef.current?.removeItemFromList(group['guid']); }, ccGroupLeft: ({ leftGroup }) => { conversationListRef.current?.removeItemFromList(leftGroup['conversationId']); }, ccGroupMemberKicked: ({ message, kickedFrom }) => { CometChat.CometChatHelper.getConversationFromMessage(message) .then(conversation => { conversationListRef.current?.updateList(conversation); }) .catch(e => { onError && onError(e); }); }, ccGroupMemberBanned: ({ message }) => { groupHandler(message); }, ccGroupMemberUnBanned: ({ message }) => { groupHandler(message); }, ccOwnershipChanged: ({ message }) => { CometChat.CometChatHelper.getConversationFromMessage(message) .then(conversation => { conversationListRef.current?.updateList(conversation); }) .catch(e => { onError && onError(e); }); }, ccGroupMemberAdded: ({ message }) => { CometChat.CometChatHelper.getConversationFromMessage(message) .then(conversation => { conversationListRef.current?.updateList(conversation); }) .catch(e => onError && onError(e)); } }); CometChatUIEventHandler.addUserListener(userListenerId, { ccUserBlocked: ({ user }) => { let conversation = conversationListRef.current?.getListItem(user['conversationId']); conversationListRef.current?.updateList(conversation); } }); CometChatUIEventHandler.addCallListener(callListenerId, { ccOutgoingCall: ({ call }) => { CometChat.CometChatHelper.getConversationFromMessage(call) .then((conversation) => { conversationListRef.current.updateList(conversation); }) .catch((e) => { onError && onError(e); }); }, ccCallAccepted: ({ call }) => { CometChat.CometChatHelper.getConversationFromMessage(call) .then((conversation) => { conversationListRef.current.updateList(conversation); }) .catch((e) => { onError && onError(e); }); }, ccCallRejected: ({ call }) => { CometChat.CometChatHelper.getConversationFromMessage(call) .then((conversation) => { conversationListRef.current.updateList(conversation); }) .catch((e) => { onError && onError(e); }); }, ccCallEnded: ({ call }) => { CometChat.CometChatHelper.getConversationFromMessage(call) .then((conversation) => { conversationListRef.current.updateList(conversation); }) .catch((e) => { onError && onError(e); }); } }); return () => { CometChat.removeMessageListener(conversationListenerId); CometChat.removeUserListener(userListenerId); CometChat.removeCallListener(callListenerId); CometChat.removeGroupListener(groupListenerId); CometChatUIEventHandler.removeMessageListener(messageListenerId); CometChatUIEventHandler.removeConversationListener(conversationListenerId); CometChatUIEventHandler.removeGroupListener(groupListenerId); CometChatUIEventHandler.removeUserListener(userListenerId); }; }, []); const ConversationItemView = ({ item: conversation }) => { if (!conversation) return null; //custom view check if (ListItemView) return ListItemView(conversation); const { conversationWith } = conversation; const lastMessage = CometChatConversationUtils.getLastMessage(conversation); const { name, type, conversationId } = conversationWith || {}; let image, backgroundColor, avatarIcon = conversationWith[type == "group" ? 'icon' : "avatar"]; if (type == GroupTypeConstants.password) { image = props?.protectedGroupIcon || passwordGroupIcon; backgroundColor = PASSWORD_GROUP_COLOR; } if (type == GroupTypeConstants.private) { image = props?.privateGroupIcon || privateGroupIcon; backgroundColor = PRIVATE_GROUP_COLOR; } if (conversationWith.status == "online") { backgroundColor = theme.palette.getSuccess(); } if (selecting) { let index = selectedConversation.findIndex((value) => value.conversationWith.conversationId == conversationId); if (index >= 0) { image = rightTickIcon; backgroundColor = theme?.palette.getPrimary(); } } return <CometChatListItem id={conversation.conversationId} avatarName={name} avatarURL={avatarIcon} hideSeparator={hideSeparator} SubtitleView={(SubtitleView && SubtitleView.bind(this, conversation)) || (() => <LastMessageView conversations={conversation} typingText={conversation?.['lastMessage']?.['typing']}/>)} title={name} statusIndicatorIcon={image} statusIndicatorColor={disableUsersPresence ? "transparent" : backgroundColor} listItemStyle={_listItemStyle} TailView={() => <TailView customPattern={() => datePattern && props.datePattern(conversation)} timestamp={lastMessage && lastMessage['updatedAt'] || conversationWith['createdAt'] || conversationWith['lastActiveAt']} unreadCount={conversation.unreadMessageCount}/>} avatarStyle={_avatarStyle} statusIndicatorStyle={_statusIndicatorStyle} onPress={conversationClicked.bind(this, conversation)} onLongPress={conversationLongPressed.bind(this, conversation)} options={() => options ? options(conversation) : getDefaultOptions(conversation)}/>; }; /** * Component template */ return (<View style={Style.container}> <ConfirmDeletionDialog /> <CometChatList AppBarOptions={AppBarOption} onError={onError} ref={conversationListRef} requestBuilder={conversationsRequestBuilder || new CometChat.ConversationsRequestBuilder().setLimit(30)} title={title} hideSearch={true} listItemKey={"conversationId"} LoadingStateView={LoadingStateView} ListItemView={ConversationItemView} EmptyStateView={EmptyStateView ? EmptyStateView : () => <EmptyView />} ErrorStateView={ErrorStateView ? ErrorStateView : () => <ErrorView />} onBack={onBack} backButtonIcon={backButtonIcon} showBackButton={showBackButton} onSelection={(items) => { onSelection && onSelection(items); setSelecting(false); setSelectedConversations([]); }} SubtitleView={props.SubtitleView} disableUsersPresence={disableUsersPresence} options={options} hideSeparator={hideSeparator} listStyle={{ ..._style, background: _style.backgroundColor }} selectionMode={selecting ? selectionMode : "none"} hideError={hideError}/> </View>); }; //# sourceMappingURL=CometChatConversations.js.map