From 162a4a564a8bb1ab78f41868b1d1517ab877442f Mon Sep 17 00:00:00 2001 From: "Tirath.CometChat" Date: Tue, 20 Apr 2021 14:12:38 +0530 Subject: [PATCH] optimistic ui --- README.md | 2 + package.json | 7 +- .../Calls/CometChatIncomingCall/index.js | 129 ++++---- .../CometChatIncomingDirectCall/controller.js | 24 ++ .../CometChatIncomingDirectCall/index.js | 279 ++++++++++++++++++ .../resources/avatar.png | Bin 0 -> 40029 bytes .../resources/incomingaudiocall.png | Bin 0 -> 796 bytes .../resources/incomingvideocall.png | Bin 0 -> 643 bytes .../CometChatIncomingDirectCall/styles.js | 49 +++ .../Calls/CometChatOutgoingCall/index.js | 3 +- .../CometChatOutgoingDirectCall/index.js | 132 +++++++++ src/components/Calls/index.js | 2 + .../Chats/CometChatConversationList/index.js | 23 +- .../Chats/CometChatConversationList/styles.js | 7 +- .../CometChatConversationListItem/index.js | 43 ++- .../CometChatConversationListItem/styles.js | 43 +-- .../index.js | 100 ++++++- src/components/CometChatUI/index.js | 6 +- .../CometChatAddGroupMemberList/index.js | 245 +++++++-------- .../CometChatAddGroupMemberList/styles.js | 8 +- .../CometChatAddGroupMemberListItem/index.js | 6 +- .../CometChatAddGroupMemberListItem/styles.js | 9 +- .../CometChatBanGroupMemberList/index.js | 16 +- .../CometChatBanGroupMemberListItem/index.js | 8 +- .../CometChatBanGroupMemberListItem/styles.js | 17 +- .../Groups/CometChatCreateGroup/index.js | 25 +- .../Groups/CometChatGroupDetails/index.js | 92 ++++-- .../Groups/CometChatGroupDetails/styles.js | 7 +- .../Groups/CometChatGroupList/index.js | 44 ++- .../Groups/CometChatGroupList/styles.js | 20 +- .../Groups/CometChatGroupListItem/styles.js | 32 +- .../CometChatGroupListWithMessages/index.js | 112 ++++++- .../CometChatViewGroupMemberList/index.js | 88 ++++-- .../CometChatViewGroupMemberList/styles.js | 11 +- .../CometChatViewGroupMemberListItem/index.js | 4 +- .../CometChatViewGroupMemberListItem/style.js | 25 +- .../Messages/CometChatImageViewer/styles.js | 8 +- .../Messages/CometChatLiveReactions/index.js | 10 +- .../CometChatMessageActions/actions.js | 4 +- .../CometChatMessageComposer/index.js | 91 +++++- .../CometChatMessageComposer/styles.js | 5 +- .../Messages/CometChatMessageHeader/index.js | 14 +- .../Messages/CometChatMessageHeader/styles.js | 12 +- .../CometChatMessageList/MessageFilter.js | 1 + .../Messages/CometChatMessageList/index.js | 68 ++++- .../Messages/CometChatMessageList/styles.js | 11 +- .../Messages/CometChatMessageThread/index.js | 16 + .../Messages/CometChatMessages/index.js | 74 ++++- .../Messages/CometChatReadReceipt/index.js | 68 +++-- .../CometChatReadReceipt/resources/error.png | Bin 0 -> 604 bytes .../resources/sending.png | Bin 0 -> 522 bytes .../Messages/CometChatReadReceipt/styles.js | 8 +- .../index.js | 1 + .../index.js | 127 ++++++++ .../resources/receivervideocall.png | Bin 0 -> 1251 bytes .../style.js | 42 +++ .../index.js | 15 +- .../styles.js | 17 +- .../index.js | 25 +- .../styles.js | 11 +- .../index.js | 33 ++- .../styles.js | 25 +- .../index.js | 15 +- .../styles.js | 15 +- .../index.js | 1 + .../CometChatSenderDirectCallBubble/index.js | 108 +++++++ .../resources/sendervideocall.png | Bin 0 -> 932 bytes .../CometChatSenderDirectCallBubble/style.js | 35 +++ .../CometChatSenderFileMessageBubble/index.js | 3 +- .../styles.js | 6 +- .../index.js | 3 +- .../styles.js | 5 +- .../CometChatSenderTextMessageBubble/index.js | 1 + .../styles.js | 11 +- .../index.js | 3 +- .../styles.js | 4 +- .../styles.js | 2 +- .../Extensions/CometChatCreatePoll/index.js | 9 +- .../CometChatMessageReactions/index.js | 19 +- .../reactionDetails.js | 1 + .../CometChatMessageReactions/styles.js | 10 +- .../index.js | 31 +- .../styles.js | 1 - .../index.js | 14 +- .../styles.js | 2 +- .../CometChatSenderPollMessageBubble/index.js | 1 + .../styles.js | 2 +- .../index.js | 17 +- .../styles.js | 2 + .../CometChatSmartReplyPreview/styles.js | 4 +- src/components/Messages/index.js | 2 + .../Shared/CometChatBadgeCount/index.js | 44 ++- .../Shared/CometChatBadgeCount/styles.js | 18 +- .../Shared/CometChatSharedMedia/index.js | 8 +- .../Shared/CometChatSharedMedia/styles.js | 1 + .../Shared/CometChatUserPresence/index.js | 12 +- .../Shared/CometChatUserPresence/styles.js | 10 +- src/components/Shared/DropDownAlert/index.js | 104 +++++++ .../Shared/DropDownAlert/resources/close.png | Bin 0 -> 659 bytes .../Shared/DropDownAlert/resources/error.png | Bin 0 -> 546 bytes .../DropDownAlert/resources/success.png | Bin 0 -> 889 bytes src/components/Shared/DropDownAlert/styles.js | 43 +++ .../UserProfile/CometChatUserProfile/index.js | 56 ++-- .../CometChatUserProfile/styles.js | 22 +- .../Users/CometChatUserDetails/index.js | 5 + .../Users/CometChatUserList/index.js | 13 +- .../Users/CometChatUserList/styles.js | 23 +- .../Users/CometChatUserListItem/index.js | 5 +- .../Users/CometChatUserListItem/styles.js | 15 +- .../CometChatUserListWithMessages/index.js | 33 ++- src/resources/theme.js | 4 +- src/utils/actions.js | 3 + src/utils/enums.js | 1 + 113 files changed, 2377 insertions(+), 674 deletions(-) create mode 100644 src/components/Calls/CometChatIncomingDirectCall/controller.js create mode 100644 src/components/Calls/CometChatIncomingDirectCall/index.js create mode 100644 src/components/Calls/CometChatIncomingDirectCall/resources/avatar.png create mode 100644 src/components/Calls/CometChatIncomingDirectCall/resources/incomingaudiocall.png create mode 100644 src/components/Calls/CometChatIncomingDirectCall/resources/incomingvideocall.png create mode 100644 src/components/Calls/CometChatIncomingDirectCall/styles.js create mode 100644 src/components/Calls/CometChatOutgoingDirectCall/index.js create mode 100644 src/components/Messages/CometChatReadReceipt/resources/error.png create mode 100644 src/components/Messages/CometChatReadReceipt/resources/sending.png create mode 100644 src/components/Messages/CometChatReceiverDirectCallBubble/index.js create mode 100644 src/components/Messages/CometChatReceiverDirectCallBubble/resources/receivervideocall.png create mode 100644 src/components/Messages/CometChatReceiverDirectCallBubble/style.js create mode 100644 src/components/Messages/CometChatSenderDirectCallBubble/index.js create mode 100644 src/components/Messages/CometChatSenderDirectCallBubble/resources/sendervideocall.png create mode 100644 src/components/Messages/CometChatSenderDirectCallBubble/style.js create mode 100644 src/components/Shared/DropDownAlert/index.js create mode 100644 src/components/Shared/DropDownAlert/resources/close.png create mode 100644 src/components/Shared/DropDownAlert/resources/error.png create mode 100644 src/components/Shared/DropDownAlert/resources/success.png create mode 100644 src/components/Shared/DropDownAlert/styles.js diff --git a/README.md b/README.md index d46ebf6..089d905 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,8 @@ These packages help make the ui-kit smooth and functioning [react-native-autolink](https://www.npmjs.com/package/react-native-autolink)
[react-native-screens](https://www.npmjs.com/package/react-native-screens)
[emoji-mart-native](https://www.npmjs.com/package/emoji-mart-native)
+[react-native-keep-awake](https://www.npmjs.com/package/react-native-keep-awake)
+
## 2. Configure CometChat inside your app diff --git a/package.json b/package.json index b411ede..b41f837 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,8 @@ { "name": "cometchat-pro-react-native-ui-kit", - "version": "3.0.0-beta1-1", + + "version": "3.0.0-beta1-2", + "description": "Chat UI Kit for React Native App", "main": "./src/index.js", "scripts": { @@ -9,9 +11,10 @@ }, "repository": { "type": "git", - "url": "git@git.geekyants.com:cometchat/react-native.git" + "url": "git@github.com:cometchat-pro/react-native-chat-sdk.git" }, "peerDependencies": { + "react-native-keep-awake": "^4.0.0", "@react-native-community/async-storage": "^1.12.1", "react-native-sound": "^0.11.0", "react-native-vector-icons": "^7.1.0", diff --git a/src/components/Calls/CometChatIncomingCall/index.js b/src/components/Calls/CometChatIncomingCall/index.js index 6576026..32717fb 100644 --- a/src/components/Calls/CometChatIncomingCall/index.js +++ b/src/components/Calls/CometChatIncomingCall/index.js @@ -24,6 +24,8 @@ import audioCallIcon from './resources/incomingaudiocall.png'; import videoCallIcon from './resources/incomingvideocall.png'; import { incomingCallAlert } from '../../../resources/audio'; import { logger } from '../../../utils/common'; +import DropDownAlert from '../../Shared/DropDownAlert'; + export default (props) => { let callAlertManager = null; const viewTheme = { ...theme, ...props.theme }; @@ -105,6 +107,8 @@ export default (props) => { }) .catch((error) => { props.actionGenerated(actions.CALL_ERROR, error); + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); }); } else if (incomingCall === null) { playIncomingAlert(); @@ -170,10 +174,14 @@ export default (props) => { setIncomingCall(null); }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); props.actionGenerated(actions.CALL_ERROR, error); setIncomingCall(null); }); } catch (error) { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger(error); } }; @@ -189,6 +197,8 @@ export default (props) => { props.actionGenerated(actions.ACCEPT_INCOMING_CALL, incomingCall); setIncomingCall(null); } catch (error) { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger(error); } }; @@ -209,69 +219,72 @@ export default (props) => { if (incomingCall) { return ( - - - - - - - {incomingCall.sender.name} - - {incomingCall.type === 'video' ? ( - - Incoming video call - - - Incoming video call - + <> + + + + + + + {incomingCall.sender.name} + + {incomingCall.type === 'video' ? ( + + Incoming video call + + + Incoming video call + + - - ) : ( - - Incoming video call - - - Incoming audio call - + ) : ( + + Incoming video call + + + Incoming audio call + + - - )} + )} + + + + - - + + + Decline + + + Accept + - - - Decline - - - Accept - - - - - + + + (this.dropDownAlertRef = ref)} /> + ); } diff --git a/src/components/Calls/CometChatIncomingDirectCall/controller.js b/src/components/Calls/CometChatIncomingDirectCall/controller.js new file mode 100644 index 0000000..2aa492d --- /dev/null +++ b/src/components/Calls/CometChatIncomingDirectCall/controller.js @@ -0,0 +1,24 @@ +import { CometChat } from '@cometchat-pro/react-native-chat'; + +import * as enums from '../../../utils/enums'; + +export class messageAlertManager { + msgListenerId = 'incoming_message_' + new Date().getTime(); + + attachListeners(callback) { + CometChat.addMessageListener( + this.msgListenerId, + new CometChat.MessageListener({ + onCustomMessageReceived: (customMessage) => { + if (customMessage.type == enums.CUSTOM_TYPE_MEETING) { + callback(enums.CUSTOM_MESSAGE_RECEIVED, customMessage); + } + }, + }), + ); + } + + removeListeners() { + CometChat.removeMessageListener(this.msgListenerId); + } +} diff --git a/src/components/Calls/CometChatIncomingDirectCall/index.js b/src/components/Calls/CometChatIncomingDirectCall/index.js new file mode 100644 index 0000000..3d88341 --- /dev/null +++ b/src/components/Calls/CometChatIncomingDirectCall/index.js @@ -0,0 +1,279 @@ +import React, { useState, useEffect } from 'react'; +import { + View, + TouchableOpacity, + Image, + Modal, + SafeAreaView, + Text, +} from 'react-native'; +import { CometChat } from '@cometchat-pro/react-native-chat'; +import Sound from 'react-native-sound'; + +import { CometChatManager } from '../../../utils/controller'; +import * as enums from '../../../utils/enums'; +import * as actions from '../../../utils/actions'; +import theme from '../../../resources/theme'; +import { CometChatAvatar } from '../../Shared'; + +import { messageAlertManager } from './controller'; + +import style from './styles'; + +import audioCallIcon from './resources/incomingaudiocall.png'; +import videoCallIcon from './resources/incomingvideocall.png'; +import { incomingCallAlert } from '../../../resources/audio'; +import { logger } from '../../../utils/common'; +export default (props) => { + let callAlertManager = null; + const viewTheme = { ...theme, ...props.theme }; + const incomingAlert = new Sound(incomingCallAlert); + + const [incomingCall, setIncomingCall] = useState(null); + + /** + * Play call alerts + * @param + */ + const playIncomingAlert = () => { + try { + incomingAlert.setCurrentTime(0); + incomingAlert.setNumberOfLoops(-1); + incomingAlert.play(); + } catch (error) { + logger(error); + } + }; + + /** + * Pause incoming alerts + * @param + */ + const pauseIncomingAlert = () => { + try { + incomingAlert.pause(); + } catch (error) { + logger(error); + } + }; + + /** + * Mark message as read + * @param message + */ + const markMessageAsRead = (message) => { + try { + const { receiverType } = message; + const receiverId = + receiverType === 'user' ? message.sender.uid : message.receiverId; + + if (Object.prototype.hasOwnProperty.call(message, 'readAt') === false) { + CometChat.markAsRead(message); + } + } catch (error) { + logger(error); + } + }; + + /** + * Handle incoming calls + * if already an active call -> reject call + * else play incoming call alert + * @param call - call object + */ + const incomingCallReceived = (call) => { + try { + if ( + props.loggedInUser && + call.callInitiator.uid === props.loggedInUser.uid + ) { + return; + } + + const activeCall = CometChat.getActiveCall(); + // if there is another call in progress + if (activeCall) { + CometChat.rejectCall(call.sessionId, CometChat.CALL_STATUS.BUSY) + .then((rejectedCall) => { + // mark as read incoming call message + markMessageAsRead(call); + props.actionGenerated( + actions.REJECTED_INCOMING_CALL, + call, + rejectedCall, + ); + }) + .catch((error) => { + props.actionGenerated(actions.CALL_ERROR, error); + }); + } else if (incomingCall === null) { + playIncomingAlert(); + setIncomingCall(call); + } + } catch (error) { + logger(error); + } + }; + + /** + * Handles if incoming call cancelled + * @param + */ + const incomingCallCancelled = () => { + try { + pauseIncomingAlert(); + setIncomingCall(null); + } catch (error) { + logger(error); + } + }; + + /** + * Updates the call screen and opens/closes outgoing callAlert , depending on action taken by user + * @param key - actionType, @param call - callObject + */ + const callScreenUpdated = (key, call) => { + try { + switch (key) { + case enums.CUSTOM_MESSAGE_RECEIVED: // occurs at the callee end + incomingCallReceived(call); + break; + case enums.INCOMING_CALL_CANCELLED: // occurs(call dismissed) at the callee end, caller cancels the call + incomingCallCancelled(call); + break; + default: + break; + } + } catch (error) { + logger(error); + } + }; + + /** + * Reject calls + * @param + */ + const rejectCall = () => { + try { + pauseIncomingAlert(); + + CometChatManager.rejectCall( + incomingCall.sessionId, + CometChat.CALL_STATUS.REJECTED, + ) + .then((rejectedCall) => { + props.actionGenerated( + actions.REJECTED_INCOMING_CALL, + incomingCall, + rejectedCall, + ); + setIncomingCall(null); + }) + .catch((error) => { + props.actionGenerated(actions.CALL_ERROR, error); + setIncomingCall(null); + }); + } catch (error) { + logger(error); + } + }; + + /** + * Accept calls + * @param + */ + const acceptCall = () => { + try { + pauseIncomingAlert(); + + props.actionGenerated(actions.ACCEPT_DIRECT_CALL, incomingCall); + setIncomingCall(null); + } catch (error) { + logger(error); + } + }; + + /** + * Add call listeners on mount and remove listeners on unmount + * @param + */ + useEffect(() => { + callAlertManager = new messageAlertManager(); + callAlertManager.attachListeners(callScreenUpdated); + + return () => { + pauseIncomingAlert(); + callAlertManager.removeListeners(); + }; + }); + + if (incomingCall) { + return ( + + + + + + + {incomingCall.sender.name} + + {incomingCall.type === 'video' ? ( + + Incoming video call + + + Incoming video call + + + + ) : ( + + Incoming audio call + + + Incoming audio call + + + + )} + + + + + + + + Ignore + + + Accept + + + + + + ); + } + + return null; +}; diff --git a/src/components/Calls/CometChatIncomingDirectCall/resources/avatar.png b/src/components/Calls/CometChatIncomingDirectCall/resources/avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..7c77776afabb9576549a08ccad67efb249b67fc2 GIT binary patch literal 40029 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�}b?p31_H^L<@HWz7 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 + diff --git a/src/components/Calls/CometChatOutgoingDirectCall/index.js b/src/components/Calls/CometChatOutgoingDirectCall/index.js new file mode 100644 index 0000000..62b1d8a --- /dev/null +++ b/src/components/Calls/CometChatOutgoingDirectCall/index.js @@ -0,0 +1,132 @@ +import React from 'react'; +import { Text, View, Modal, TouchableOpacity } from 'react-native'; +import { CometChat } from '@cometchat-pro/react-native-chat'; +import * as actions from '../../../utils/actions'; +import KeepAwake from 'react-native-keep-awake'; +import * as enums from '../../../utils/enums'; +import { theme } from '../../../resources/theme'; + +class CometChatOutgoingDirectCall extends React.Component { + sessionID; + + constructor(props) { + super(props); + this.sessionID = `${props.item.guid}`; + this.state = { + callSettings: null, + }; + } + + componentDidMount() { + this.startCall(); + } + + getReceiverDetails = () => { + let receiverId; + let receiverType; + + if (this.props.type === CometChat.RECEIVER_TYPE.USER) { + receiverId = this.props.item.uid; + receiverType = CometChat.RECEIVER_TYPE.USER; + } else if (this.props.type === CometChat.RECEIVER_TYPE.GROUP) { + receiverId = this.props.item.guid; + receiverType = CometChat.RECEIVER_TYPE.GROUP; + } + + return { receiverId: receiverId, receiverType: receiverType }; + }; + + sendCustomMessage = () => { + const { receiverId, receiverType } = this.getReceiverDetails(); + + const customData = { + sessionID: this.sessionID, + callType: this.props.callType, + }; + const customType = enums.CUSTOM_TYPE_MEETING; + + let conversationId = null; + if (this.props.type === CometChat.RECEIVER_TYPE.USER) { + const users = [this.props.loggedInUser.uid, this.props.item.uid]; + conversationId = users.sort().join('_user_'); + } else if (this.props.type === CometChat.RECEIVER_TYPE.GROUP) { + conversationId = `group_${this.props.item.guid}`; + } + + const customMessage = new CometChat.CustomMessage( + receiverId, + receiverType, + customType, + customData, + ); + customMessage.setSender(this.props.loggedInUser); + customMessage.setReceiver(this.props.type); + customMessage.setConversationId(conversationId); + customMessage._composedAt = Math.round(+new Date() / 1000); + customMessage._id = '_' + Math.random().toString(36).substr(2, 9); + + this.props.actionGenerated(actions['MESSAGE_COMPOSED'], [customMessage]); + CometChat.sendCustomMessage(customMessage) + .then((message) => { + const newMessageObj = { ...message, _id: customMessage._id }; + this.props.actionGenerated(actions['MESSAGE_SENT'], newMessageObj); + }) + .catch((error) => { + console.log('custom message sending failed with error', error); + + const newMessageObj = { ...customMessage, error: error }; + this.props.actionGenerated( + enums.ACTIONS['ERROR_IN_SENDING_MESSAGE'], + newMessageObj, + ); + }); + }; + + startCall = () => { + let sessionID = `${this.props.item.guid}`; + let audioOnly = false; + let defaultLayout = true; + let callListener = new CometChat.OngoingCallListener({ + onCallEnded: (call) => { + this.props.actionGenerated(actions.DIRECT_CALL_ENDED, call); + this.setState({ + outgoingCallScreen: false, + callInProgress: null, + callSettings: null, + }); + }, + onError: (error) => { + console.log('Call Error: ', error); + }, + }); + + let callSettings = new CometChat.CallSettingsBuilder() + .enableDefaultLayout(defaultLayout) + .setSessionID(sessionID) + .setIsAudioOnlyCall(audioOnly) + .setCallEventListener(callListener) + .build(); + this.setState({ callSettings }); + //send custom message only when someone starts a direct call + if (this.props.joinDirectCall === false) { + this.sendCustomMessage(); + } + }; + + render() { + return ( + + + + {this.state.callSettings ? ( + + ) : null} + + + ); + } +} + +export default CometChatOutgoingDirectCall; diff --git a/src/components/Calls/index.js b/src/components/Calls/index.js index 1e6c3a4..235234d 100644 --- a/src/components/Calls/index.js +++ b/src/components/Calls/index.js @@ -1,2 +1,4 @@ export { default as CometChatIncomingCall } from './CometChatIncomingCall'; export { default as CometChatOutgoingCall } from './CometChatOutgoingCall'; +export { default as CometChatOutgoingDirectCall } from './CometChatOutgoingDirectCall'; +export { default as CometChatIncomingDirectCall } from './CometChatIncomingDirectCall'; diff --git a/src/components/Chats/CometChatConversationList/index.js b/src/components/Chats/CometChatConversationList/index.js index 0e610c9..5879148 100644 --- a/src/components/Chats/CometChatConversationList/index.js +++ b/src/components/Chats/CometChatConversationList/index.js @@ -10,7 +10,7 @@ import { CometChatConversationListItem } from '../index'; import theme from '../../../resources/theme'; import styles from './styles'; import Sound from 'react-native-sound'; - +import DropDownAlert from '../../Shared/DropDownAlert'; import { incomingOtherMessageAlert } from '../../../resources/audio'; import { View, @@ -75,7 +75,7 @@ class CometChatConversationList extends React.Component { this.props.type === 'user' && c.conversationWith.uid === this.props.item.uid) || (c.conversationType === this.props.type && - this.props.type === 'group' && + this.props.type === CometChat.ACTION_TYPE.TYPE_GROUP && c.conversationWith.guid === this.props.item.guid) ) { return c; @@ -187,6 +187,8 @@ class CometChatConversationList extends React.Component { } }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger( 'This is an error in converting message to conversation', error, @@ -460,6 +462,8 @@ class CometChatConversationList extends React.Component { }) .catch((error) => { logger('This is an error in converting message to conversation', error); + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); }); }; @@ -488,6 +492,8 @@ class CometChatConversationList extends React.Component { }) .catch((error) => { logger('This is an error in converting message to conversation', error); + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); }); }; @@ -551,6 +557,8 @@ class CometChatConversationList extends React.Component { } }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger('This is an error in converting message to conversation', error); }); }; @@ -599,6 +607,8 @@ class CometChatConversationList extends React.Component { } }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger('This is an error in converting message to conversation', error); }); }; @@ -645,6 +655,8 @@ class CometChatConversationList extends React.Component { } }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger('This is an error in converting message to conversation', error); }); }; @@ -693,6 +705,8 @@ class CometChatConversationList extends React.Component { } }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger('This is an error in converting message to conversation', error); }); }; @@ -737,6 +751,8 @@ class CometChatConversationList extends React.Component { }) .catch((error) => { this.decoratorMessage = 'Error'; + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger( '[CometChatConversationList] getConversations fetchNext error', error, @@ -842,6 +858,7 @@ class CometChatConversationList extends React.Component { {this.listHeaderComponent()} { return ( @@ -856,7 +873,6 @@ class CometChatConversationList extends React.Component { ); }} ListEmptyComponent={this.listEmptyContainer} - ItemSeparatorComponent={this.itemSeparatorComponent} onScroll={this.handleScroll} onEndReached={this.endReached} onEndReachedThreshold={0.3} @@ -864,6 +880,7 @@ class CometChatConversationList extends React.Component { scrollEnabled /> + (this.dropDownAlertRef = ref)} /> ); } diff --git a/src/components/Chats/CometChatConversationList/styles.js b/src/components/Chats/CometChatConversationList/styles.js index 11fcb5d..96125c1 100644 --- a/src/components/Chats/CometChatConversationList/styles.js +++ b/src/components/Chats/CometChatConversationList/styles.js @@ -12,7 +12,7 @@ export default StyleSheet.create({ alignItems: 'center', }, conversationHeaderStyle: { - paddingBottom: 12 * heightRatio, + paddingBottom: 32, position: 'relative', paddingHorizontal: 22 * widthRatio, }, @@ -34,7 +34,7 @@ export default StyleSheet.create({ }, contactMsgStyle: { overflow: 'hidden', - width: '100%', + flex: 1, justifyContent: 'center', alignItems: 'center', }, @@ -52,8 +52,9 @@ export default StyleSheet.create({ }, headerContainer: { alignItems: 'center', - height: 32 * heightRatio, + height: 48, width: '100%', justifyContent: 'center', }, + flexGrow1: { flexGrow: 1 }, }); diff --git a/src/components/Chats/CometChatConversationListItem/index.js b/src/components/Chats/CometChatConversationListItem/index.js index 84da85a..2fd13cf 100644 --- a/src/components/Chats/CometChatConversationListItem/index.js +++ b/src/components/Chats/CometChatConversationListItem/index.js @@ -157,7 +157,7 @@ class CometChatConversationListItem extends React.Component { let time = timestamp.split(':'); // convert to array var hours = Number(time[0]); - var minutes = Number(time[1]); + var minutes = Number(time[1]?.split(' ')[0]); var timeValue; if (hours > 0 && hours <= 12) { @@ -175,8 +175,10 @@ class CometChatConversationListItem extends React.Component { } else if (diffTimestamp < 48 * 60 * 60 * 1000) { timestamp = 'Yesterday'; } else if (diffTimestamp < 7 * 24 * 60 * 60 * 1000) { - timestamp = messageTimestamp.toLocaleString('en-US', { - weekday: 'long', + timestamp = messageTimestamp.toLocaleDateString('en-US', { + year: '2-digit', + month: '2-digit', + day: '2-digit', }); } else { timestamp = messageTimestamp.toLocaleDateString('en-US', { @@ -206,6 +208,9 @@ class CometChatConversationListItem extends React.Component { case enums.CUSTOM_TYPE_STICKER: message = 'Sticker'; break; + case 'meeting': + message = 'Video Call'; + break; default: break; } @@ -308,19 +313,21 @@ class CometChatConversationListItem extends React.Component { } let presence; + if (this.props.conversation.conversationType === 'user') { const { status } = this.props.conversation.conversationWith; presence = ( ); } return ( - + - + {this.props.conversation.conversationWith.name} - - {this.state.lastMessage} - - - {lastMessageTimeStamp} + + + + {this.state.lastMessage} + { + this.videoCall(true); + }); break; case actions.VIEW_DETAIL: case actions.CLOSE_DETAIL_CLICKED: @@ -167,6 +175,36 @@ class CometChatConversationListWithMessages extends React.Component { case actions.MESSAGE_DELETED: this.updateLastMessage(item[0]); break; + case actions.JOIN_DIRECT_CALL: + this.setState({ joinDirectCall: true }, () => { + this.videoCall(true); + }); + break; + case actions.DIRECT_CALL_ENDED: + this.setState( + { joinDirectCall: false, ongoingDirectCall: null }, + () => { + this.props.navigation.navigate( + enums.NAVIGATION_CONSTANTS.COMET_CHAT_MESSAGES, + { + theme: this.theme, + item: { ...this.state.item }, + tab: this.state.tab, + type: this.state.type, + composedThreadMessage: this.state.composedThreadMessage, + callMessage: this.state.callMessage, + loggedInUser: this.loggedInUser, + actionGenerated: this.actionHandler, + }, + ); + }, + ); + + break; + case actions.ACCEPT_DIRECT_CALL: + this.setState({ joinDirectCall: true }, () => { + this.videoCall(true); + }); default: break; } @@ -188,7 +226,7 @@ class CometChatConversationListWithMessages extends React.Component { try { const usersList = [this.state.item.uid]; CometChatManager.blockUsers(usersList) - .then(() => { + .then((response) => { this.setState({ item: { ...this.state.item, blockedByMe: true } }); }) .catch((error) => { @@ -207,11 +245,23 @@ class CometChatConversationListWithMessages extends React.Component { try { const usersList = [this.state.item.uid]; CometChatManager.unblockUsers(usersList) - .then(() => { - this.setState({ item: { ...this.state.item, blockedByMe: false } }); + .then((response) => { + if (response) { + this.dropDownAlertRef?.showMessage('success', 'Unblocked user'); + this.setState({ + item: { ...this.state.item, blockedByMe: false }, + }); + } else { + this.dropDownAlertRef?.showMessage( + 'success', + 'Failed to unblocked user', + ); + } }) .catch((error) => { logger('unblocking user fails with error', error); + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); }); } catch (error) { logger(error); @@ -251,17 +301,18 @@ class CometChatConversationListWithMessages extends React.Component { * Handle initiating a video call * @param */ - videoCall = () => { + + videoCall = (flag) => { try { let receiverId; let receiverType; - if (this.state.type === 'user') { - receiverId = this.state.item.uid; - receiverType = CometChat.RECEIVER_TYPE.USER; - } else if (this.state.type === 'group') { - receiverId = this.state.item.guid; - receiverType = CometChat.RECEIVER_TYPE.GROUP; + if (this.state.type === CometChat.RECEIVER_TYPE.GROUP) { + this.setState({ ongoingDirectCall: flag }); + + return; } + receiverId = this.state.item.uid; + receiverType = CometChat.RECEIVER_TYPE.USER; CometChatManager.call(receiverId, receiverType, CometChat.CALL_TYPE.VIDEO) .then((call) => { @@ -556,6 +607,9 @@ class CometChatConversationListWithMessages extends React.Component { {imageView} { + this.dropDownAlertRef?.showMessage(type, message); + }} theme={this.theme} loggedInUser={this.loggedInUser} actionGenerated={this.actionHandler} @@ -570,6 +624,28 @@ class CometChatConversationListWithMessages extends React.Component { loggedInUser={this.loggedInUser} actionGenerated={this.actionHandler} /> + + (this.dropDownAlertRef = ref)} /> + + + {this.state.ongoingDirectCall ? ( + this.actionHandler(actions.DIRECT_CALL_ENDED)} + theme={this.props.theme} + item={this.state.item} + type={this.state.type} + lang={this.state.lang} + callType={CometChat.CALL_TYPE.VIDEO} + joinDirectCall={this.state.joinDirectCall} + loggedInUser={this.loggedInUser} + actionGenerated={this.actionHandler} + /> + ) : null} ); } diff --git a/src/components/CometChatUI/index.js b/src/components/CometChatUI/index.js index 2e234f7..f701e53 100644 --- a/src/components/CometChatUI/index.js +++ b/src/components/CometChatUI/index.js @@ -23,14 +23,14 @@ export default () => { if (route.name === 'Chats') { return ( - + ); } if (route.name === 'More') { return ( ); @@ -52,7 +52,7 @@ export default () => { inactiveTintColor: 'rgba(0,0,0,0.5)', activeBackgroundColor: theme.color.white, inactiveBackgroundColor: theme.color.white, - labelStyle: { fontSize: 8 * heightRatio }, + labelStyle: { fontSize: 12 }, }}> { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); this.decoratorMessage = 'Error'; logger( '[CometChatAddGroupMemberList] getUsers fetchNext error', @@ -275,10 +277,14 @@ class CometChatAddGroupMemberList extends React.Component { } }) .catch(() => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger('addMembersToGroup failed with exception:', error); }); } } catch (error) { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger('121', error); } }; @@ -323,9 +329,6 @@ class CometChatAddGroupMemberList extends React.Component { */ itemSeparatorComponent = ({ leadingItem }) => { - if (leadingItem.header) { - return null; - } return ( - - { - return ( - - - - - Add Members - - - { - this.sheetRef.current.snapTo(1); - this.props.close(); - }} - style={{}}> - - Close - - + { + return ( + + + + + Add Members + - this.textInputRef.current.focus()}> - - - { - this.setState({ textInputFocused: true }); - }} - onBlur={() => { - this.setState({ textInputFocused: false }); - }} - clearButtonMode="always" - numberOfLines={1} - style={[ - style.contactSearchInputStyle, - { - color: `${this.theme.color.primary}`, - }, - ]} - /> - - - { - const chr = item.name[0].toUpperCase(); - let firstLetter = null; - if (chr !== currentLetter) { - currentLetter = chr; - firstLetter = currentLetter; - } - - return ( - - - - ); - }} - ListEmptyComponent={this.listEmptyContainer} - ItemSeparatorComponent={this.itemSeparatorComponent} - onScroll={this.handleScroll} - onEndReached={this.endReached} - onEndReachedThreshold={0.3} - showsVerticalScrollIndicator={false} - /> { + this.sheetRef.current.snapTo(1); + this.props.close(); + }} + style={{}}> + + Close + + + + this.textInputRef.current.focus()}> + - + + { + this.setState({ textInputFocused: true }); + }} + onBlur={() => { + this.setState({ textInputFocused: false }); + }} + clearButtonMode="always" + numberOfLines={1} style={[ - style.addBtnTxtStyle, + style.contactSearchInputStyle, { - color: `${this.theme.color.white}`, + color: `${this.theme.color.primary}`, }, - ]}> - Add - - - - ); - }} - onCloseEnd={() => { - this.props.close(); - }} - /> - + ]} + /> + + + { + const chr = item.name[0].toUpperCase(); + let firstLetter = null; + if (chr !== currentLetter) { + currentLetter = chr; + firstLetter = currentLetter; + } + + return ( + + + + ); + }} + ListEmptyComponent={this.listEmptyContainer} + ItemSeparatorComponent={this.itemSeparatorComponent} + onScroll={this.handleScroll} + onEndReached={this.endReached} + onEndReachedThreshold={0.3} + showsVerticalScrollIndicator={false} + /> + + + Add + + + + ); + }} + onCloseEnd={() => { + this.props.close(); + }} + /> + (this.dropDownAlertRef = ref)} /> ); diff --git a/src/components/Groups/CometChatAddGroupMemberList/styles.js b/src/components/Groups/CometChatAddGroupMemberList/styles.js index 5bfdf24..d56e941 100644 --- a/src/components/Groups/CometChatAddGroupMemberList/styles.js +++ b/src/components/Groups/CometChatAddGroupMemberList/styles.js @@ -50,8 +50,8 @@ export default StyleSheet.create({ contactSearchInputStyle: { flex: 1, paddingVertical: 4, - marginHorizontal: 8, - fontSize: 15, + marginHorizontal: 10, + fontSize: 14, }, contactMsgStyle: { overflow: 'hidden', @@ -99,10 +99,12 @@ export default StyleSheet.create({ borderRadius: 10, padding: 10, paddingHorizontal: 15, + width: '40%', + alignItems: 'center', alignSelf: 'center', }, addBtnTxtStyle: { - fontSize: 14, + fontSize: 16, fontWeight: '500', }, }); diff --git a/src/components/Groups/CometChatAddGroupMemberListItem/index.js b/src/components/Groups/CometChatAddGroupMemberListItem/index.js index 8df3dad..e30b865 100644 --- a/src/components/Groups/CometChatAddGroupMemberListItem/index.js +++ b/src/components/Groups/CometChatAddGroupMemberListItem/index.js @@ -10,7 +10,9 @@ const CometChatAddGroupMemberListItem = (props) => { const viewTheme = { ...theme, ...props.theme }; const [checked, setChecked] = useState(() => { - const found = props.members.find((member) => member.uid === props.user.uid); + const found = props.membersToAdd.find( + (member) => member.uid === props.user.uid, + ); const value = !!found; return value; @@ -43,7 +45,7 @@ const CometChatAddGroupMemberListItem = (props) => { status={props.user.status} cornerRadius={18} borderColor={viewTheme.color.darkSecondary} - borderWidth={1} + borderWidth={2} /> diff --git a/src/components/Groups/CometChatAddGroupMemberListItem/styles.js b/src/components/Groups/CometChatAddGroupMemberListItem/styles.js index 738b845..871bd5d 100644 --- a/src/components/Groups/CometChatAddGroupMemberListItem/styles.js +++ b/src/components/Groups/CometChatAddGroupMemberListItem/styles.js @@ -1,6 +1,6 @@ import { StyleSheet } from 'react-native'; import { heightRatio, widthRatio } from '../../../utils/consts'; - +import theme from '../../../resources/theme'; export default StyleSheet.create({ nameStyle: { flexDirection: 'row', @@ -8,7 +8,7 @@ export default StyleSheet.create({ width: '50%', marginRight: 15, }, - userName: { fontSize: 14 }, + userName: { fontSize: 16, color: theme.color.primary }, rowStyle: { flexDirection: 'row', alignItems: 'center', @@ -17,13 +17,14 @@ export default StyleSheet.create({ paddingRight: 20 * widthRatio, justifyContent: 'space-between', width: '100%', + height: 64, fontSize: 14, }, avatarStyle: { flexWrap: 'wrap', flexDirection: 'row', - width: 44, - height: 44, + width: 40, + height: 40, borderRadius: 22, backgroundColor: 'rgba(51,153,255,0.25)', marginRight: 15 * widthRatio, diff --git a/src/components/Groups/CometChatBanGroupMemberList/index.js b/src/components/Groups/CometChatBanGroupMemberList/index.js index 4b02d83..2dd3f61 100644 --- a/src/components/Groups/CometChatBanGroupMemberList/index.js +++ b/src/components/Groups/CometChatBanGroupMemberList/index.js @@ -4,6 +4,7 @@ import React from 'react'; import { CometChat } from '@cometchat-pro/react-native-chat'; import { View, Text, FlatList, Modal, TouchableOpacity } from 'react-native'; import BottomSheet from 'reanimated-bottom-sheet'; +import DropDownAlert from '../../Shared/DropDownAlert'; import { CometChatBanGroupMemberListItem } from '../index'; import GroupDetailContext from '../CometChatGroupDetails/context'; @@ -40,12 +41,24 @@ export default class CometChatBanGroupMemberList extends React.Component { CometChat.unbanGroupMember(guid, memberToUnBan.uid) .then((response) => { if (response) { + this.dropDownAlertRef?.showMessage( + 'success', + 'Group member unbanned', + ); this.props.actionGenerated(actions.UNBAN_GROUP_MEMBERS, [ memberToUnBan, ]); + } else { + this.dropDownAlertRef?.showMessage( + 'error', + 'Failed to unban group member ', + ); } }) - .catch(() => {}); + .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); + }); }; /** @@ -219,6 +232,7 @@ export default class CometChatBanGroupMemberList extends React.Component { }} /> + (this.dropDownAlertRef = ref)} /> ); diff --git a/src/components/Groups/CometChatBanGroupMemberListItem/index.js b/src/components/Groups/CometChatBanGroupMemberListItem/index.js index 5012b6b..5b2db6f 100644 --- a/src/components/Groups/CometChatBanGroupMemberListItem/index.js +++ b/src/components/Groups/CometChatBanGroupMemberListItem/index.js @@ -50,11 +50,13 @@ export default (props) => { - + {name} diff --git a/src/components/Groups/CometChatBanGroupMemberListItem/styles.js b/src/components/Groups/CometChatBanGroupMemberListItem/styles.js index 02d322d..73febf4 100644 --- a/src/components/Groups/CometChatBanGroupMemberListItem/styles.js +++ b/src/components/Groups/CometChatBanGroupMemberListItem/styles.js @@ -1,6 +1,6 @@ import { StyleSheet } from 'react-native'; import { heightRatio, widthRatio } from '../../../utils/consts'; - +import theme from '../../../resources/theme'; export default StyleSheet.create({ nameStyle: { flexDirection: 'row', @@ -10,10 +10,15 @@ export default StyleSheet.create({ }, roleStyle: { width: '30%', - fontSize: 13, + fontSize: 16, + color: theme.color.helpText, }, - imageContainer: { alignItems: 'center', justifyContent: 'center' }, - unbanText: { fontSize: 10, textAlign: 'center' }, + imageContainer: { + alignItems: 'center', + justifyContent: 'center', + opacity: 0.6, + }, + unbanText: { fontSize: 12, textAlign: 'center', color: theme.color.primary }, rowStyle: { flexDirection: 'row', paddingVertical: 7 * heightRatio, @@ -27,8 +32,8 @@ export default StyleSheet.create({ avatarStyle: { flexWrap: 'wrap', flexDirection: 'row', - width: 44, - height: 44, + width: 40, + height: 40, borderRadius: 22, backgroundColor: 'rgba(51,153,255,0.25)', marginRight: 6 * widthRatio, diff --git a/src/components/Groups/CometChatCreateGroup/index.js b/src/components/Groups/CometChatCreateGroup/index.js index 68e145a..e09b25d 100644 --- a/src/components/Groups/CometChatCreateGroup/index.js +++ b/src/components/Groups/CometChatCreateGroup/index.js @@ -17,6 +17,7 @@ import Icon from 'react-native-vector-icons/MaterialIcons'; import * as actions from '../../../utils/actions'; import * as enums from '../../../utils/enums'; import { logger } from '../../../utils/common'; +import DropDownAlert from '../../Shared/DropDownAlert'; const closeIcon = ; class CometChatCreateGroup extends React.Component { @@ -80,17 +81,23 @@ class CometChatCreateGroup extends React.Component { */ validate = () => { - try { - const groupName = this.state.name.trim(); - const groupType = this.state.type.trim(); + const groupName = this.state.name?.trim(); + const groupType = this.state.type?.trim(); + try { if (!groupName) { - this.setState({ error: 'Group name cannot be blank.' }); + this.dropDownAlertRef?.showMessage( + 'error', + 'Group name cannot be blank.', + ); return false; } - if (!groupType) { - this.setState({ error: 'Group type cannot be blank.' }); + if (!groupType || groupType === 'Select group type') { + this.dropDownAlertRef?.showMessage( + 'error', + 'Group type cannot be blank.', + ); return false; } @@ -99,7 +106,10 @@ class CometChatCreateGroup extends React.Component { password = this.state.password; if (!password.length) { - this.setState({ error: 'Group password cannot be blank.' }); + this.dropDownAlertRef?.showMessage( + 'error', + 'Group password cannot be blank.', + ); return false; } } @@ -288,6 +298,7 @@ class CometChatCreateGroup extends React.Component { + (this.dropDownAlertRef = ref)} /> ); } diff --git a/src/components/Groups/CometChatGroupDetails/index.js b/src/components/Groups/CometChatGroupDetails/index.js index 6e7301d..ab3257c 100644 --- a/src/components/Groups/CometChatGroupDetails/index.js +++ b/src/components/Groups/CometChatGroupDetails/index.js @@ -20,6 +20,7 @@ import { } from '../index'; import { deviceHeight } from '../../../utils/consts'; import { logger } from '../../../utils/common'; +import DropDownAlert from '../../Shared/DropDownAlert'; const ADD_MEMBER = 'addMember'; const VIEW_MEMBER = 'viewMember'; @@ -235,6 +236,8 @@ export default class CometChatGroupDetails extends React.Component { '[CometChatGroupDetails] getGroupMembers fetchNextGroupMembers error', error, ); + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); }); }) .catch((error) => { @@ -242,6 +245,8 @@ export default class CometChatGroupDetails extends React.Component { '[CometChatGroupDetails] getGroupMembers getLoggedInUser error', error, ); + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); }); }; @@ -272,6 +277,8 @@ export default class CometChatGroupDetails extends React.Component { '[CometChatGroupDetails] getGroupMembers fetchNextGroupMembers error', error, ); + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); }); }) .catch((error) => { @@ -279,6 +286,8 @@ export default class CometChatGroupDetails extends React.Component { '[CometChatGroupDetails] getGroupMembers getLoggedInUser error', error, ); + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); }); }; @@ -291,10 +300,20 @@ export default class CometChatGroupDetails extends React.Component { const item = { ...this.props.item }; const { guid } = item; CometChat.deleteGroup(guid) - .then(() => { - this.props.actionGenerated(actions.GROUP_DELETED, item); + .then((response) => { + if (response) { + this.dropDownAlertRef?.showMessage( + 'success', + 'Group deleted Successfully', + ); + this.props.actionGenerated(actions.GROUP_DELETED, item); + } else { + this.dropDownAlertRef?.showMessage('error', 'Failed to delete group'); + } }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger('Group delete failed with exception:', error); }); }; @@ -309,13 +328,29 @@ export default class CometChatGroupDetails extends React.Component { const item = { ...this.props.item }; const { guid } = item; CometChat.leaveGroup(guid) - .then(() => { - this.props.actionGenerated(actions.LEFT_GROUP, item); + .then((response) => { + if (response) { + this.dropDownAlertRef?.showMessage( + 'success', + 'Group left successfully', + ); + this.props.actionGenerated(actions.LEFT_GROUP, item); + } else { + this.dropDownAlertRef?.showMessage( + 'error', + 'Failed to leave group', + ); + } }) .catch((error) => { logger('Group leaving failed with exception:', error); + + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); }); } catch (error) { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger(error); } }; @@ -596,21 +631,23 @@ export default class CometChatGroupDetails extends React.Component { ); } - - let leaveGroupBtn = ( - { - this.leaveGroup(); - }}> - - Leave group - - - ); + let leaveGroupBtn = null; + if (this.props.item.scope !== CometChat.GROUP_MEMBER_SCOPE.ADMIN) { + leaveGroupBtn = ( + { + this.leaveGroup(); + }}> + + Leave group + + + ); + } let sharedMediaView = ( { + this.dropDownAlertRef?.showMessage(type, message); + }} /> ); let members = ( - - Members - + Members {viewMembersBtn} {addMembersBtn} @@ -642,10 +676,7 @@ export default class CometChatGroupDetails extends React.Component { let options = ( + style={[style.sectionHeaderStyle, { color: theme.color.helpText }]}> Options @@ -771,6 +802,7 @@ export default class CometChatGroupDetails extends React.Component { }} /> + (this.dropDownAlertRef = ref)} /> ); } diff --git a/src/components/Groups/CometChatGroupDetails/styles.js b/src/components/Groups/CometChatGroupDetails/styles.js index cfaee67..bb2e188 100644 --- a/src/components/Groups/CometChatGroupDetails/styles.js +++ b/src/components/Groups/CometChatGroupDetails/styles.js @@ -1,12 +1,14 @@ import { Dimensions, StyleSheet } from 'react-native'; import { heightRatio, widthRatio } from '../../../utils/consts'; - +import theme from '../../../resources/theme'; export default StyleSheet.create({ container: { flex: 1, backgroundColor: 'rgba(0,0,0,0.7)' }, itemLinkStyle: { - fontSize: 15, + fontSize: 16, lineHeight: 20, fontWeight: '600', + marginVertical: 4, + color: theme.color.primary, }, fullWidth: { width: '100%' }, listItemContainer: { width: '100%', marginVertical: 6 }, @@ -17,6 +19,7 @@ export default StyleSheet.create({ fontWeight: '500', lineHeight: 20, textTransform: 'uppercase', + color: theme.color.helpText, }, headerStyle: { flexDirection: 'row', diff --git a/src/components/Groups/CometChatGroupList/index.js b/src/components/Groups/CometChatGroupList/index.js index a24ee27..81ffc30 100644 --- a/src/components/Groups/CometChatGroupList/index.js +++ b/src/components/Groups/CometChatGroupList/index.js @@ -6,6 +6,7 @@ import { CometChat } from '@cometchat-pro/react-native-chat'; import { CometChatManager } from '../../../utils/controller'; import * as enums from '../../../utils/enums'; import * as actions from '../../../utils/actions'; +import DropDownAlert from '../../Shared/DropDownAlert'; import { GroupListManager } from './controller'; import { CometChatCreateGroup, CometChatGroupListItem } from '../index'; @@ -355,6 +356,18 @@ class CometChatGroupList extends React.Component { if (passcode !== null) { CometChat.joinGroup(this.state.guid, this.state.groupType, passcode) .then((response) => { + if (typeof response === 'object') { + this.dropDownAlertModelRef?.showMessage( + 'success', + 'Group joined Successfully', + ); + } else { + this.dropDownAlertModelRef?.showMessage( + 'error', + 'Failed to join group', + ); + return; + } const groups = [...this.state.grouplist]; const groupKey = groups.findIndex((g) => g.guid === this.state.guid); if (groupKey > -1) { @@ -371,7 +384,8 @@ class CometChatGroupList extends React.Component { } }) .catch((error) => { - if (error.code === 'ERR_WRONG_GROUP_PASS') Alert.alert(error.message); + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertModelRef?.showMessage('error', errorCode); }); } }; @@ -396,7 +410,17 @@ class CometChatGroupList extends React.Component { CometChat.joinGroup(group.guid, group.type, '') .then((response) => { const groups = [...this.state.grouplist]; - + if (typeof response === 'object') { + this.dropDownAlertRef?.showMessage( + 'success', + 'Group Joined Successfully', + ); + } else { + this.dropDownAlertRef?.showMessage( + 'error', + 'Failed to join group', + ); + } const groupKey = groups.findIndex((g) => g.guid === group.guid); if (groupKey > -1) { const groupObj = groups[groupKey]; @@ -416,6 +440,8 @@ class CometChatGroupList extends React.Component { } }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger('Group joining failed with exception:', error); }); } @@ -484,6 +510,8 @@ class CometChatGroupList extends React.Component { }); }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); this.decoratorMessage = 'Error'; logger( '[CometChatGroupList] getGroups fetchNextGroups error', @@ -492,6 +520,8 @@ class CometChatGroupList extends React.Component { }); }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); this.decoratorMessage = 'Error'; logger('[CometChatGroupList] getUsers getLoggedInUser error', error); }); @@ -632,11 +662,7 @@ class CometChatGroupList extends React.Component { backgroundColor: `${this.theme.backgroundColor.grey}`, }, ]}> - + + (this.dropDownAlertModelRef = ref)} /> ); } @@ -794,6 +821,7 @@ class CometChatGroupList extends React.Component { {this.ListHeaderComponent()} { return ( @@ -806,7 +834,6 @@ class CometChatGroupList extends React.Component { ); }} ListEmptyComponent={this.listEmptyContainer} - ItemSeparatorComponent={this.itemSeparatorComponent} onScroll={this.handleScroll} onEndReached={this.endReached} onEndReachedThreshold={0.3} @@ -820,6 +847,7 @@ class CometChatGroupList extends React.Component { /> {passwordScreen} + (this.dropDownAlertRef = ref)} /> ); diff --git a/src/components/Groups/CometChatGroupList/styles.js b/src/components/Groups/CometChatGroupList/styles.js index 4c25ba0..73d4f5e 100644 --- a/src/components/Groups/CometChatGroupList/styles.js +++ b/src/components/Groups/CometChatGroupList/styles.js @@ -12,9 +12,9 @@ export default StyleSheet.create({ alignItems: 'center', }, groupHeaderStyle: { - paddingBottom: 12 * heightRatio, + paddingBottom: 16, position: 'relative', - paddingHorizontal: 22 * widthRatio, + paddingHorizontal: 16, }, contactHeaderCloseStyle: { height: 24, @@ -27,14 +27,14 @@ export default StyleSheet.create({ fontSize: 28, }, groupSearchStyle: { - padding: 4 * heightRatio, - marginTop: 10 * heightRatio, + padding: 8, + marginTop: 16, flexDirection: 'row', position: 'relative', alignItems: 'center', width: '100%', borderWidth: 0, - borderRadius: 8, + borderRadius: 10, shadowColor: '#000', shadowOffset: { width: 0, @@ -45,13 +45,13 @@ export default StyleSheet.create({ }, contactSearchInputStyle: { flex: 1, - paddingVertical: 4 * heightRatio, - marginHorizontal: 8 * widthRatio, - fontSize: 15, + paddingVertical: 4, + marginHorizontal: 2, + fontSize: 17, }, contactMsgStyle: { overflow: 'hidden', - width: '100%', + flex: 1, justifyContent: 'center', alignItems: 'center', }, @@ -69,7 +69,7 @@ export default StyleSheet.create({ }, headerContainer: { alignItems: 'center', - height: 32 * heightRatio, + height: 48, width: '100%', justifyContent: 'center', }, diff --git a/src/components/Groups/CometChatGroupListItem/styles.js b/src/components/Groups/CometChatGroupListItem/styles.js index e336cc5..4bed56f 100644 --- a/src/components/Groups/CometChatGroupListItem/styles.js +++ b/src/components/Groups/CometChatGroupListItem/styles.js @@ -1,34 +1,44 @@ import { StyleSheet } from 'react-native'; import { widthRatio } from '../../../utils/consts'; - +import theme from '../../../resources/theme'; export default StyleSheet.create({ fullFlex: { flex: 1 }, listItem: { flexDirection: 'row', - alignItems: 'center', width: '100%', - maxHeight: 62, - paddingHorizontal: 20, + maxHeight: 64, + paddingHorizontal: 16, + marginBottom: 16, }, avatarStyle: { flexWrap: 'wrap', flexDirection: 'row', - width: 44, - height: 44, - marginRight: 15 * widthRatio, + width: 40, + height: 40, + marginRight: 10, justifyContent: 'center', backgroundColor: 'rgba(51,153,255,0.25)', borderRadius: 25, }, groupDetailsContainer: { - borderBottomWidth: 0.5, + borderBottomWidth: 1, flex: 1, paddingBottom: 10, - paddingTop: 10, justifyContent: 'space-between', alignItems: 'center', flexDirection: 'row', }, - memberCountStyle: { fontSize: 14, fontWeight: '200', maxWidth: '80%' }, - groupNameStyle: { fontSize: 18, fontWeight: '600', maxWidth: '80%' }, + memberCountStyle: { + fontSize: 12, + fontWeight: '200', + maxWidth: '80%', + color: theme.color.helpText, + }, + + groupNameStyle: { + fontSize: 16, + fontWeight: '600', + maxWidth: '80%', + color: theme.color.primary, + }, }); diff --git a/src/components/Groups/CometChatGroupListWithMessages/index.js b/src/components/Groups/CometChatGroupListWithMessages/index.js index 2ebdce3..69c656b 100644 --- a/src/components/Groups/CometChatGroupListWithMessages/index.js +++ b/src/components/Groups/CometChatGroupListWithMessages/index.js @@ -6,10 +6,16 @@ import { CometChat } from '@cometchat-pro/react-native-chat'; import { CometChatManager } from '../../../utils/controller'; import * as enums from '../../../utils/enums'; import * as actions from '../../../utils/actions'; -import { CometChatIncomingCall, CometChatOutgoingCall } from '../../Calls'; +import { + CometChatIncomingCall, + CometChatOutgoingCall, + CometChatOutgoingDirectCall, + CometChatIncomingDirectCall, +} from '../../Calls'; import { CometChatGroupList } from '../index'; import { CometChatImageViewer } from '../../Messages'; +import DropDownAlert from '../../Shared/DropDownAlert'; import theme from '../../../resources/theme'; import style from './styles'; import { logger } from '../../../utils/common'; @@ -40,6 +46,7 @@ class CometChatGroupListWithMessages extends React.Component { sidebarView: false, imageView: null, groupMessage: {}, + ongoingDirectCall: false, }; this.theme = { ...theme, ...this.props.theme }; @@ -130,7 +137,9 @@ class CometChatGroupListWithMessages extends React.Component { this.audioCall(); break; case actions.VIDEO_CALL: - this.videoCall(); + this.setState({ joinDirectCall: false }, () => { + this.videoCall(true); + }); break; // eslint-disable-next-line no-lone-blocks case actions.MENU_CLICKED: { @@ -196,6 +205,39 @@ class CometChatGroupListWithMessages extends React.Component { case actions.UPDATE_THREAD_MESSAGE: this.updateThreadMessage(item[0], count); break; + case actions.MESSAGE_COMPOSED: + this.callInitiated(item); + break; + case actions.JOIN_DIRECT_CALL: + this.setState({ joinDirectCall: true }, () => { + this.videoCall(true); + }); + break; + case actions.DIRECT_CALL_ENDED: + this.setState( + { joinDirectCall: false, ongoingDirectCall: null }, + () => { + this.props.navigation.navigate( + enums.NAVIGATION_CONSTANTS.COMET_CHAT_MESSAGES, + { + theme: this.theme, + item: { ...this.state.item }, + tab: this.state.tab, + type: this.state.type, + composedThreadMessage: this.state.composedThreadMessage, + callMessage: this.state.callMessage, + loggedInUser: this.loggedInUser, + actionGenerated: this.actionHandler, + }, + ); + }, + ); + break; + case actions.ACCEPT_DIRECT_CALL: + this.setState({ joinDirectCall: true }, () => { + this.videoCall(true); + }); + default: break; } @@ -234,10 +276,17 @@ class CometChatGroupListWithMessages extends React.Component { try { const usersList = [this.state.item.uid]; CometChatManager.blockUsers(usersList) - .then(() => { - this.setState({ item: { ...this.state.item, blockedByMe: true } }); + .then((response) => { + if (response) { + this.dropDownAlertRef?.showMessage('success', 'Blocked User'); + this.setState({ item: { ...this.state.item, blockedByMe: true } }); + } else { + this.dropDownAlertRef?.showMessage('error', 'Failed to block user'); + } }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger('Blocking user fails with error', error); }); } catch (error) { @@ -254,13 +303,25 @@ class CometChatGroupListWithMessages extends React.Component { try { const usersList = [this.state.item.uid]; CometChatManager.unblockUsers(usersList) - .then(() => { - this.setState({ item: { ...this.state.item, blockedByMe: false } }); + .then((response) => { + if (response) { + this.dropDownAlertRef?.showMessage('success', 'Unblocked user'); + this.setState({ item: { ...this.state.item, blockedByMe: false } }); + } else { + this.dropDownAlertRef?.showMessage( + 'error', + 'Failed to unblock user', + ); + } }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger('unblocking user fails with error', error); }); } catch (error) { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger(error); } }; @@ -300,17 +361,17 @@ class CometChatGroupListWithMessages extends React.Component { * @param */ - videoCall = () => { + videoCall = (flag) => { try { let receiverId; let receiverType; - if (this.state.type === CometChat.RECEIVER_TYPE.USER) { - receiverId = this.state.item.uid; - receiverType = CometChat.RECEIVER_TYPE.USER; - } else if (this.state.type === CometChat.RECEIVER_TYPE.GROUP) { - receiverId = this.state.item.guid; - receiverType = CometChat.RECEIVER_TYPE.GROUP; + if (this.state.type === CometChat.RECEIVER_TYPE.GROUP) { + this.setState({ ongoingDirectCall: flag }); + + return; } + receiverId = this.state.item.uid; + receiverType = CometChat.RECEIVER_TYPE.USER; CometChatManager.call(receiverId, receiverType, CometChat.CALL_TYPE.VIDEO) .then((call) => { @@ -664,12 +725,15 @@ class CometChatGroupListWithMessages extends React.Component { /> {imageView} { + this.dropDownAlertRef?.showMessage(type, message); + }} theme={this.props.theme} loggedInUser={this.loggedInUser} outgoingCall={this.state.outgoingCall} actionGenerated={this.actionHandler} /> - */} + + (this.dropDownAlertRef = ref)} /> + {this.state.ongoingDirectCall ? ( + this.actionHandler(actions.DIRECT_CALL_ENDED)} + theme={this.props.theme} + item={this.state.item} + type={this.state.type} + lang={this.state.lang} + callType={CometChat.CALL_TYPE.VIDEO} + joinDirectCall={this.state.joinDirectCall} + loggedInUser={this.loggedInUser} + actionGenerated={this.actionHandler} + /> + ) : null} ); } diff --git a/src/components/Groups/CometChatViewGroupMemberList/index.js b/src/components/Groups/CometChatViewGroupMemberList/index.js index bea5c2f..859d354 100644 --- a/src/components/Groups/CometChatViewGroupMemberList/index.js +++ b/src/components/Groups/CometChatViewGroupMemberList/index.js @@ -3,6 +3,7 @@ /* eslint-disable react/static-property-placement */ import React from 'react'; import { CometChat } from '@cometchat-pro/react-native-chat'; +import DropDownAlert from '../../Shared/DropDownAlert'; import { View, Text, FlatList, Modal, TouchableOpacity } from 'react-native'; import BottomSheet from 'reanimated-bottom-sheet'; @@ -66,10 +67,21 @@ export default class CometChatViewGroupMemberList extends React.Component { CometChat.banGroupMember(guid, memberToBan.uid) .then((response) => { if (response) { + this.dropDownAlertRef?.showMessage( + 'success', + 'Group member banned', + ); this.props.actionGenerated(actions.BAN_GROUP_MEMBERS, memberToBan); + } else { + this.dropDownAlertRef?.showMessage( + 'error', + 'Failed to ban group member', + ); } }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger('banGroupMember failed with error: ', error); }); } catch (error) { @@ -87,16 +99,29 @@ export default class CometChatViewGroupMemberList extends React.Component { CometChat.kickGroupMember(guid, memberToKick.uid) .then((response) => { if (response) { + this.dropDownAlertRef?.showMessage( + 'success', + 'Group member kicked', + ); this.props.actionGenerated( actions.REMOVE_GROUP_PARTICIPANTS, memberToKick, ); + } else { + this.dropDownAlertRef?.showMessage( + 'error', + 'Failed to kick group member', + ); } }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger('kickGroupMember failed with error: ', error); }); } catch (error) { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger(error); } }; @@ -114,17 +139,30 @@ export default class CometChatViewGroupMemberList extends React.Component { CometChat.updateGroupMemberScope(guid, member.uid, scope) .then((response) => { if (response) { + this.dropDownAlertRef?.showMessage( + 'success', + 'Group member scope changed', + ); const updatedMember = { ...member, scope }; this.props.actionGenerated( actions.UPDATE_GROUP_PARTICIPANTS, updatedMember, ); + } else { + this.dropDownAlertRef?.showMessage( + 'error', + 'Failed to change scope of group member', + ); } }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger('updateGroupMemberScope failed with error: ', error); }); } catch (error) { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger(error); } }; @@ -235,30 +273,31 @@ export default class CometChatViewGroupMemberList extends React.Component { - { - return ( - - ); - }} - ListEmptyComponent={this.listEmptyContainer} - ItemSeparatorComponent={this.itemSeparatorComponent} - onScroll={this.handleScroll} - onEndReached={this.endReached} - onEndReachedThreshold={0.3} - contentContainerStyle={style.contentContainerStyle} - style={style.listStyle} - showsVerticalScrollIndicator={false} - /> + + { + return ( + + ); + }} + ListEmptyComponent={this.listEmptyContainer} + // ItemSeparatorComponent={this.itemSeparatorComponent} + onScroll={this.handleScroll} + onEndReached={this.endReached} + contentContainerStyle={{ flexGrow: 1 }} + onEndReachedThreshold={0.3} + showsVerticalScrollIndicator={false} + /> + ); }} @@ -268,6 +307,7 @@ export default class CometChatViewGroupMemberList extends React.Component { /> + (this.dropDownAlertRef = ref)} /> ); } diff --git a/src/components/Groups/CometChatViewGroupMemberList/styles.js b/src/components/Groups/CometChatViewGroupMemberList/styles.js index 2e4fc10..d1603bf 100644 --- a/src/components/Groups/CometChatViewGroupMemberList/styles.js +++ b/src/components/Groups/CometChatViewGroupMemberList/styles.js @@ -3,12 +3,14 @@ import { StyleSheet } from 'react-native'; import { calc, deviceHeight } from '../../../utils/consts'; export default StyleSheet.create({ - container: { flex: 1, backgroundColor: 'rgba(0,0,0,0.7)' }, + container: { + flex: 1, + backgroundColor: 'rgba(0,0,0,0.7)', + }, reactionDetailsContainer: { backgroundColor: 'white', paddingVertical: 20, borderRadius: 20, - minHeight: deviceHeight, }, headerContainerStyle: { justifyContent: 'center', @@ -69,7 +71,7 @@ export default StyleSheet.create({ fontWeight: '600', }, contactListStyle: { - height: calc(), + height: 400, margin: 0, padding: 0, }, @@ -107,4 +109,7 @@ export default StyleSheet.create({ fontSize: 14, fontWeight: '500', }, + listContainer: { + height: deviceHeight * 0.8, + }, }); diff --git a/src/components/Groups/CometChatViewGroupMemberListItem/index.js b/src/components/Groups/CometChatViewGroupMemberListItem/index.js index cd070f2..0a7e69f 100644 --- a/src/components/Groups/CometChatViewGroupMemberListItem/index.js +++ b/src/components/Groups/CometChatViewGroupMemberListItem/index.js @@ -185,8 +185,8 @@ export default (props) => { ); diff --git a/src/components/Groups/CometChatViewGroupMemberListItem/style.js b/src/components/Groups/CometChatViewGroupMemberListItem/style.js index 933f42c..6462920 100644 --- a/src/components/Groups/CometChatViewGroupMemberListItem/style.js +++ b/src/components/Groups/CometChatViewGroupMemberListItem/style.js @@ -1,6 +1,6 @@ import { StyleSheet } from 'react-native'; import { deviceWidth, heightRatio, widthRatio } from '../../../utils/consts'; - +import theme from '../../../resources/theme'; export default StyleSheet.create({ container: { flexDirection: 'row', @@ -27,8 +27,8 @@ export default StyleSheet.create({ avatarContainer: { flexWrap: 'wrap', flexDirection: 'row', - width: 44, - height: 44, + width: 40, + height: 40, borderRadius: 22, backgroundColor: 'rgba(51,153,255,0.25)', marginRight: 6 * widthRatio, @@ -41,7 +41,12 @@ export default StyleSheet.create({ marginRight: 12 * widthRatio, }, fullFlex: { flex: 1 }, - pickerItemStyle: { fontSize: 14 }, + pickerItemStyle: { + fontSize: 16, + color: theme.color.helpText, + + borderRadius: 24, + }, pickerItemDetail: { height: 20 * heightRatio }, doneContainer: { width: 30, alignItems: 'center', justifyContent: 'center' }, editText: { fontSize: 10, textAlign: 'center' }, @@ -52,9 +57,17 @@ export default StyleSheet.create({ alignItems: 'center', justifyContent: 'space-between', }, - actionText: { fontSize: 10, textAlign: 'center' }, - changeContainer: { flex: 1, flexDirection: 'row' }, + actionText: { + fontSize: 12, + textAlign: 'center', + color: theme.color.primary, + + marginHorizontal: 5, + }, + changeContainer: { flex: 1, flexDirection: 'row', opacity: 0.6 }, nameText: { width: 0.2 * deviceWidth, + fontSize: 16, + color: theme.color.primary, }, }); diff --git a/src/components/Messages/CometChatImageViewer/styles.js b/src/components/Messages/CometChatImageViewer/styles.js index 0f04070..6684ed0 100644 --- a/src/components/Messages/CometChatImageViewer/styles.js +++ b/src/components/Messages/CometChatImageViewer/styles.js @@ -22,8 +22,7 @@ export default StyleSheet.create({ }, bottomSheetContainer: { backgroundColor: 'white', - height: deviceHeight + 200 * heightRatio, - paddingBottom: 40 * heightRatio, + height: deviceHeight * 0.9, }, crossImgContainer: { alignSelf: 'flex-end', @@ -38,11 +37,10 @@ export default StyleSheet.create({ backgroundColor: 'white', justifyContent: 'center', alignItems: 'center', - height: 450 * heightRatio, + flex: 1, }, imageStyles: { + width: '90%', height: '100%', - width: deviceWidth, - maxHeight: deviceHeight * 0.4, }, }); diff --git a/src/components/Messages/CometChatLiveReactions/index.js b/src/components/Messages/CometChatLiveReactions/index.js index 4f00cd6..f74f415 100644 --- a/src/components/Messages/CometChatLiveReactions/index.js +++ b/src/components/Messages/CometChatLiveReactions/index.js @@ -23,11 +23,11 @@ function getRandomNumber(min, max) { } class AnimatedHeart extends Component { - state = { - position: new Animated.Value(0), - }; - - componentWillMount() { + constructor(props) { + super(props); + this.state = { + position: new Animated.Value(0), + }; this._yAnimation = this.state.position.interpolate({ inputRange: [NEGATIVE_END_Y, 0], outputRange: [ANIMATION_END_Y, 0], diff --git a/src/components/Messages/CometChatMessageActions/actions.js b/src/components/Messages/CometChatMessageActions/actions.js index f818059..5145889 100644 --- a/src/components/Messages/CometChatMessageActions/actions.js +++ b/src/components/Messages/CometChatMessageActions/actions.js @@ -11,7 +11,7 @@ import MCIIcon from 'react-native-vector-icons/MaterialCommunityIcons'; import styles from './styles'; import * as actions from '../../../utils/actions'; import * as enums from '../../../utils/enums'; -import CometChat from '@cometchat-pro/react-native-chat'; +import { CometChat } from '@cometchat-pro/react-native-chat'; const actionIconSize = 26; @@ -29,7 +29,7 @@ export default (props) => { // if threaded messages need to be disabled if ( - props.message.category === CometChat.MESSAGE_TYPE.CUSTOM || + props.message.category === CometChat.CATEGORY_CUSTOM || props.message.parentMessageId ) { threadedChats = null; diff --git a/src/components/Messages/CometChatMessageComposer/index.js b/src/components/Messages/CometChatMessageComposer/index.js index 660bed0..114cc7f 100644 --- a/src/components/Messages/CometChatMessageComposer/index.js +++ b/src/components/Messages/CometChatMessageComposer/index.js @@ -60,6 +60,12 @@ export default class CometChatMessageComposer extends React.PureComponent { }; this.audio = new Sound(outgoingMessageAlert); + CometChat.getLoggedinUser() + .then((user) => (this.loggedInUser = user)) + .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.props?.showMessage('error', errorCode); + }); } componentDidMount() { @@ -171,6 +177,7 @@ export default class CometChatMessageComposer extends React.PureComponent { this.messageSending = true; const { receiverId, receiverType } = this.getReceiverDetails(); + const conversationId = this.props.getConversationId(); const mediaMessage = new CometChat.MediaMessage( receiverId, @@ -183,15 +190,36 @@ export default class CometChatMessageComposer extends React.PureComponent { } this.endTyping(); + // mediaMessage.setSender(this.loggedInUser); + mediaMessage.setReceiver(receiverType); + mediaMessage.setConversationId(conversationId); + mediaMessage.setType(messageType); + mediaMessage._composedAt = Math.round(+new Date() / 1000); + mediaMessage._id = '_' + Math.random().toString(36).substr(2, 9); + mediaMessage.setData({ + type: messageType, + category: CometChat.CATEGORY_MESSAGE, + name: messageInput['name'], + file: messageInput, + url: messageInput['uri'], + sender: this.loggedInUser, + }); + this.props.actionGenerated(actions.MESSAGE_COMPOSED, [mediaMessage]); CometChat.sendMessage(mediaMessage) .then((response) => { this.messageSending = false; this.playAudio(); - this.props.actionGenerated(actions.MESSAGE_COMPOSED, [response]); + const newMessageObj = { ...response, _id: mediaMessage._id }; + this.props.actionGenerated('messageSent', newMessageObj); }) .catch((error) => { + const newMessageObj = { ...mediaMessage, error: error }; + const errorCode = error?.message || 'ERROR'; + this.props.actionGenerated('errorSentInMessage', newMessageObj); + + this.props?.showMessage('error', errorCode); this.messageSending = false; - logger('Message sending failed with error:', error); + logger('Message sending failed with error: ', error); }); } catch (error) { logger(error); @@ -223,9 +251,11 @@ export default class CometChatMessageComposer extends React.PureComponent { this.editMessage(); return false; } + this.endTyping(); const { receiverId, receiverType } = this.getReceiverDetails(); const messageInput = this.state.messageInput.trim(); + const conversationId = this.props.getConversationId(); const textMessage = new CometChat.TextMessage( receiverId, messageInput, @@ -235,18 +265,32 @@ export default class CometChatMessageComposer extends React.PureComponent { textMessage.setParentMessageId(this.props.parentMessageId); } - this.endTyping(); - + textMessage.setSender(this.loggedInUser); + textMessage.setReceiver(receiverType); + textMessage.setText(messageInput); + textMessage.setConversationId(conversationId); + textMessage._composedAt = Math.round(+new Date() / 1000); + textMessage._id = '_' + Math.random().toString(36).substr(2, 9); + this.props.actionGenerated(actions.MESSAGE_COMPOSED, [textMessage]); + this.setState({ messageInput: '', replyPreview: false }); + + this.messageInputRef.current.textContent = ''; + this.playAudio(); CometChat.sendMessage(textMessage) .then((message) => { + const newMessageObj = { ...message, _id: textMessage._id }; this.setState({ messageInput: '' }); this.messageSending = false; this.messageInputRef.current.textContent = ''; - this.playAudio(); - this.props.actionGenerated(actions.MESSAGE_COMPOSED, [message]); + // this.playAudio(); + this.props.actionGenerated('messageSent', newMessageObj); }) .catch((error) => { + const newMessageObj = { ...textMessage, error: error }; + this.props.actionGenerated('errorSentInMessage', newMessageObj); logger('Message sending failed with error:', error); + const errorCode = error?.message || 'ERROR'; + this.props?.showMessage('error', errorCode); this.messageSending = false; }); } catch (error) { @@ -287,6 +331,8 @@ export default class CometChatMessageComposer extends React.PureComponent { }) .catch((error) => { this.messageSending = false; + const errorCode = error?.message || 'ERROR'; + this.props?.showMessage('error', errorCode); logger('Message editing failed with error:', error); }); } catch (error) { @@ -397,11 +443,10 @@ export default class CometChatMessageComposer extends React.PureComponent { switch (action) { case actions.POLL_CREATED: this.toggleCreatePoll(); - - // temporary check; custom data listener working for sender too - if (this.props.type === CometChat.RECEIVER_TYPE.USER) { + if (this.props.type === enums.TYPE_USER) { this.props.actionGenerated(actions.POLL_CREATED, [message]); } + // temporary check; custom data listener working for sender too\ break; case actions.SEND_STICKER: @@ -429,7 +474,7 @@ export default class CometChatMessageComposer extends React.PureComponent { sticker_name: stickerMessage.stickerName, }; const customType = enums.CUSTOM_TYPE_STICKER; - + const conversationId = this.props.getConversationId(); const customMessage = new CometChat.CustomMessage( receiverId, receiverType, @@ -439,13 +484,27 @@ export default class CometChatMessageComposer extends React.PureComponent { if (this.props.parentMessageId) { customMessage.setParentMessageId(this.props.parentMessageId); } + customMessage.setConversationId(conversationId); + customMessage.setSender(this.loggedInUser); + customMessage.setReceiver(receiverType); + customMessage.setConversationId(conversationId); + customMessage._composedAt = Math.round(+new Date() / 1000); + customMessage._id = '_' + Math.random().toString(36).substr(2, 9); + this.props.actionGenerated(actions.MESSAGE_COMPOSED, [customMessage]); CometChat.sendCustomMessage(customMessage) .then((message) => { this.messageSending = false; this.playAudio(); - this.props.actionGenerated(actions.MESSAGE_COMPOSED, [message]); + const newMessageObj = { ...message, _id: customMessage._id }; + + this.props.actionGenerated('messageSent', newMessageObj); }) .catch((error) => { + const newMessageObj = { ...customMessage, error: error }; + this.props.actionGenerated('errorSentInMessage', newMessageObj); + const errorCode = error?.message || 'ERROR'; + + this.props?.showMessage('error', errorCode); this.messageSending = false; logger('custom message sending failed with error', error); }); @@ -475,6 +534,8 @@ export default class CometChatMessageComposer extends React.PureComponent { this.props.actionGenerated(actions.MESSAGE_COMPOSED, [message]); }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.props?.showMessage('error', errorCode); logger('Message sending failed with error:', error); }); } catch (error) { @@ -692,8 +753,12 @@ export default class CometChatMessageComposer extends React.PureComponent { {blockedPreview} {editPreview} diff --git a/src/components/Messages/CometChatMessageComposer/styles.js b/src/components/Messages/CometChatMessageComposer/styles.js index f221372..c95bfbf 100644 --- a/src/components/Messages/CometChatMessageComposer/styles.js +++ b/src/components/Messages/CometChatMessageComposer/styles.js @@ -36,11 +36,12 @@ export default StyleSheet.create({ }, messageInputStyle: { color: 'black', - fontSize: 16, + fontSize: 15, padding: 10, - backgroundColor: 'rgba(0,0,0,0.1)', + backgroundColor: 'rgba(0,0,0,0.05)', borderRadius: 20, flex: 1, + height: 36, }, inputStickyStyle: { padding: 7, diff --git a/src/components/Messages/CometChatMessageHeader/index.js b/src/components/Messages/CometChatMessageHeader/index.js index 2e1b160..52014a4 100644 --- a/src/components/Messages/CometChatMessageHeader/index.js +++ b/src/components/Messages/CometChatMessageHeader/index.js @@ -223,9 +223,10 @@ class CometChatMessageHeader extends React.Component { presence = ( ); } else { @@ -258,7 +259,8 @@ class CometChatMessageHeader extends React.Component { if ( this.props.item.blockedByMe === true || - this.props.audioCall === false + this.props.audioCall === false || + this.props.type === CometChat.ACTION_TYPE.TYPE_GROUP ) { audioCallBtn = null; } @@ -269,6 +271,10 @@ class CometChatMessageHeader extends React.Component { ) { videoCallBtn = null; } + if (this.props.item.blockedByMe) { + status = null; + presence = null; + } return ( @@ -277,7 +283,7 @@ class CometChatMessageHeader extends React.Component { onPress={() => this.props.actionGenerated(actions.GO_BACK)}> diff --git a/src/components/Messages/CometChatMessageHeader/styles.js b/src/components/Messages/CometChatMessageHeader/styles.js index c079043..b2db85b 100644 --- a/src/components/Messages/CometChatMessageHeader/styles.js +++ b/src/components/Messages/CometChatMessageHeader/styles.js @@ -11,7 +11,7 @@ export default StyleSheet.create({ }, callMessageTxtStyle: { alignSelf: 'center', - fontSize: 13, + fontSize: 12, fontWeight: '500', margin: 0, }, @@ -19,6 +19,10 @@ export default StyleSheet.create({ flexDirection: 'row', height: 60, paddingRight: 12, + elevation: 5, + backgroundColor: '#fff', + zIndex: 5, + alignItems: 'center', }, backButtonContainer: { flexDirection: 'row', @@ -42,7 +46,7 @@ export default StyleSheet.create({ paddingRight: 5, }, callIcon: { - height: 24, + height: 20, resizeMode: 'contain', }, itemDetailContainer: { @@ -57,8 +61,8 @@ export default StyleSheet.create({ color: theme.color.blue, }, avatarContainer: { - height: 32 * heightRatio, - width: 38 * widthRatio, + height: 40, + width: 40, borderRadius: 25, marginRight: 12, }, diff --git a/src/components/Messages/CometChatMessageList/MessageFilter.js b/src/components/Messages/CometChatMessageList/MessageFilter.js index 12de903..cf0858b 100644 --- a/src/components/Messages/CometChatMessageList/MessageFilter.js +++ b/src/components/Messages/CometChatMessageList/MessageFilter.js @@ -24,6 +24,7 @@ export default class MessageFilter { [enums.ACTION_TYPE_GROUPMEMBER]: enums.ACTION_TYPE_GROUPMEMBER, [CometChat.CALL_TYPE.AUDIO]: CometChat.CALL_TYPE.AUDIO, [CometChat.CALL_TYPE.VIDEO]: CometChat.CALL_TYPE.VIDEO, + [enums.CUSTOM_TYPE_MEETING]: enums.CUSTOM_TYPE_MEETING, }; } diff --git a/src/components/Messages/CometChatMessageList/index.js b/src/components/Messages/CometChatMessageList/index.js index cc41884..51ee856 100644 --- a/src/components/Messages/CometChatMessageList/index.js +++ b/src/components/Messages/CometChatMessageList/index.js @@ -28,6 +28,8 @@ import { CometChatReceiverImageMessageBubble, CometChatSenderTextMessageBubble, CometChatReceiverTextMessageBubble, + CometChatReceiverDirectCallBubble, + CometChatSenderDirectCallBubble, } from '../index'; import styles from './styles'; import { logger } from '../../../utils/common'; @@ -282,7 +284,6 @@ class CometChatMessageList extends React.PureComponent { const messageList = [...this.props.messages]; const updateEditedMessage = (message) => { const messageKey = messageList.findIndex((m) => m.id === message.id); - if (messageKey > -1) { const messageObj = messageList[messageKey]; const newMessageObj = { ...messageObj, ...message }; @@ -452,6 +453,11 @@ class CometChatMessageList extends React.PureComponent { this.props.actionGenerated(actions.CUSTOM_MESSAGE_RECEIVED, [ newMessage, ]); + } else if (message.type === enums.CUSTOM_TYPE_MEETING) { + // custom data (poll extension) does not have metadata + this.props.actionGenerated(actions.CUSTOM_MESSAGE_RECEIVED, [ + message, + ]); } } else if ( this.props.type === CometChat.RECEIVER_TYPE.USER && @@ -477,6 +483,17 @@ class CometChatMessageList extends React.PureComponent { newMessage, ]); } + } else if ( + this.props.type === CometChat.RECEIVER_TYPE.USER && + message.getReceiverType() === CometChat.RECEIVER_TYPE.USER && + message.getSender().uid === this.loggedInUser.uid + ) { + if (message.type === enums.CUSTOM_TYPE_POLL) { + // custom data (poll extension) does not have metadata + this.props.actionGenerated(actions.CUSTOM_MESSAGE_RECEIVED, [ + message, + ]); + } } } catch (error) { logger(error); @@ -620,6 +637,7 @@ class CometChatMessageList extends React.PureComponent { message={message} widgetconfig={this.props.widgetconfig} actionGenerated={this.props.actionGenerated} + showMessage={this.props?.showMessage} /> ) : null; break; @@ -634,6 +652,7 @@ class CometChatMessageList extends React.PureComponent { message={message} widgetconfig={this.props.widgetconfig} actionGenerated={this.props.actionGenerated} + showMessage={this.props?.showMessage} /> ) : null; break; @@ -648,6 +667,7 @@ class CometChatMessageList extends React.PureComponent { message={message} widgetconfig={this.props.widgetconfig} actionGenerated={this.props.actionGenerated} + showMessage={this.props?.showMessage} /> ) : null; break; @@ -662,6 +682,7 @@ class CometChatMessageList extends React.PureComponent { message={message} widgetconfig={this.props.widgetconfig} actionGenerated={this.props.actionGenerated} + showMessage={this.props?.showMessage} /> ) : null; break; @@ -676,6 +697,7 @@ class CometChatMessageList extends React.PureComponent { message={message} widgetconfig={this.props.widgetconfig} actionGenerated={this.props.actionGenerated} + showMessage={this.props?.showMessage} /> ) : null; break; @@ -719,6 +741,7 @@ class CometChatMessageList extends React.PureComponent { message={message} widgetconfig={this.props.widgetconfig} actionGenerated={this.props.actionGenerated} + showMessage={this.props?.showMessage} /> ) : null; break; @@ -733,6 +756,7 @@ class CometChatMessageList extends React.PureComponent { message={message} widgetconfig={this.props.widgetconfig} actionGenerated={this.props.actionGenerated} + showMessage={this.props?.showMessage} /> ) : null; break; @@ -747,6 +771,7 @@ class CometChatMessageList extends React.PureComponent { message={message} widgetconfig={this.props.widgetconfig} actionGenerated={this.props.actionGenerated} + showMessage={this.props?.showMessage} /> ) : null; break; @@ -761,6 +786,7 @@ class CometChatMessageList extends React.PureComponent { message={message} widgetconfig={this.props.widgetconfig} actionGenerated={this.props.actionGenerated} + showMessage={this.props?.showMessage} /> ) : null; break; @@ -775,6 +801,7 @@ class CometChatMessageList extends React.PureComponent { message={message} widgetconfig={this.props.widgetconfig} actionGenerated={this.props.actionGenerated} + showMessage={this.props?.showMessage} /> ) : null; break; @@ -816,6 +843,7 @@ class CometChatMessageList extends React.PureComponent { type={this.props.type} message={message} actionGenerated={this.props.actionGenerated} + showMessage={this.props?.showMessage} /> ); break; @@ -829,6 +857,18 @@ class CometChatMessageList extends React.PureComponent { type={this.props.type} message={message} actionGenerated={this.props.actionGenerated} + showMessage={this.props?.showMessage} + /> + ); + break; + case 'meeting': + component = ( + ); break; @@ -868,6 +908,7 @@ class CometChatMessageList extends React.PureComponent { type={this.props.type} message={message} actionGenerated={this.props.actionGenerated} + showMessage={this.props?.showMessage} /> ); break; @@ -884,6 +925,17 @@ class CometChatMessageList extends React.PureComponent { /> ); break; + case 'meeting': + component = ( + + ); + break; default: break; } @@ -955,7 +1007,10 @@ class CometChatMessageList extends React.PureComponent { component = this.getCallMessageComponent(message, key); break; case 'message': - if (this.loggedInUser.uid === message.sender.uid) { + if ( + this.loggedInUser.uid === message?.sender?.uid || + this.loggedInUser.uid === message?.data?.sender?.uid + ) { component = this.getSenderMessageComponent(message, key); } else { component = this.getReceiverMessageComponent(message, key); @@ -967,6 +1022,7 @@ class CometChatMessageList extends React.PureComponent { } else { component = this.getReceiverCustomMessageComponent(message, key); } + break; default: break; @@ -1010,13 +1066,7 @@ class CometChatMessageList extends React.PureComponent { : null; if (cDate !== messageSentDate) { dateSeparator = ( - + { + const messageList = [...this.state.messageList]; + let messageKey = messageList.findIndex((m) => m._id === message._id); + if (messageKey > -1) { + const newMessageObj = { ...message }; + + messageList.splice(messageKey, 1, newMessageObj); + this.updateMessages(messageList); + } + }; + // messages are fetched from backend prependMessages = (messages) => { const messageList = [...messages, ...this.state.messageList]; @@ -704,6 +719,7 @@ class CometChatMessageThread extends React.PureComponent { ref={(el) => { this.composerRef = el; }} + getConversationId={this.props.getConversationId} theme={this.props.theme} item={this.props.item} type={this.props.type} diff --git a/src/components/Messages/CometChatMessages/index.js b/src/components/Messages/CometChatMessages/index.js index 29aa123..750aa84 100644 --- a/src/components/Messages/CometChatMessages/index.js +++ b/src/components/Messages/CometChatMessages/index.js @@ -9,6 +9,7 @@ import { KeyboardAvoidingView, } from 'react-native'; import { CometChat } from '@cometchat-pro/react-native-chat'; +import * as actions from '../../../utils/actions'; import _ from 'lodash'; import { CometChatUserDetails } from '../../Users'; import { @@ -25,7 +26,7 @@ import theme from '../../../resources/theme'; import { CometChatManager } from '../../../utils/controller'; import * as enums from '../../../utils/enums'; import { checkMessageForExtensionsData } from '../../../utils/common'; - +import DropDownAlert from '../../Shared/DropDownAlert'; import BottomSheet from 'reanimated-bottom-sheet'; import style from './styles'; @@ -124,7 +125,8 @@ class CometChatMessages extends React.PureComponent { }, () => { this.props.route?.params?.actionGenerated('groupDeleted', group) || - this.props.actionGenerated('groupDeleted', group); + (this.props.actionGenerated && + this.props.actionGenerated('groupDeleted', group)); this.props.navigation?.goBack(); }, ); @@ -157,7 +159,6 @@ class CometChatMessages extends React.PureComponent { actionHandler = (action, messages, key, group, options) => { const { route } = this.props; const params = route?.params || this.props; - switch (action) { case 'customMessageReceived': case 'messageReceived': @@ -183,9 +184,11 @@ class CometChatMessages extends React.PureComponent { case 'messageRead': params.actionGenerated(action, messages); break; + case 'messageSent': + case 'errorSentInMessage': + this.messageSent(messages); case 'messageComposed': { this.appendMessage(messages); - params.actionGenerated('messageComposed', messages); break; } case 'viewMessageThread': @@ -245,6 +248,7 @@ class CometChatMessages extends React.PureComponent { case 'audioCall': case 'videoCall': case 'menuClicked': + case actions.JOIN_DIRECT_CALL: params.actionGenerated(action); break; case 'sendReaction': @@ -307,11 +311,26 @@ class CometChatMessages extends React.PureComponent { case 'memberUnbanned': this.memberUnbanned(messages); break; + default: break; } }; + messageSent = (message) => { + const messageList = [...this.state.messageList]; + + let messageKey = messageList.findIndex((m) => m._id === message._id); + if (messageKey > -1) { + const newMessageObj = { ...message }; + + messageList.splice(messageKey, 1, newMessageObj); + + messageList.sort((a, b) => a.id - b.id); + this.setState({ messageList: [...messageList] }); + } + }; + memberUnbanned = (members) => { const messageList = [...this.state.messageList]; let filteredMembers = _.uniqBy(members, 'id'); @@ -445,11 +464,14 @@ class CometChatMessages extends React.PureComponent { const usersList = [this.state.item.uid]; CometChatManager.blockUsers(usersList) - .then(() => { + .then((response) => { + this.dropDownAlertRef?.showMessage('success', 'Blocked user'); this.setState({ user: { ...this.state.item, blockedByMe: true } }); params.actionGenerated('blockUser'); }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); console.log('Blocking user fails with error', error); }); }; @@ -633,6 +655,7 @@ class CometChatMessages extends React.PureComponent { // messages = messages.reverse(); messages = messages.concat(newMessages); messages = _.uniqBy(messages, 'id'); + this.setState({ messageList: messages, scrollToBottom: true }); }; @@ -735,6 +758,20 @@ class CometChatMessages extends React.PureComponent { this.setState({ messageToReact: message }); }; + getConversationId = () => { + const { route } = this.props; + const params = route?.params || this.props; + let conversationId = null; + if (params.type === CometChat.RECEIVER_TYPE.USER) { + const users = [this.loggedInUser.uid, params.item.uid]; + conversationId = users.sort().join('_user_'); + } else if (params.type === CometChat.RECEIVER_TYPE.GROUP) { + conversationId = `group_${params.item.guid}`; + } + + return conversationId; + }; + render() { const { route } = this.props; const params = route?.params || this.props; @@ -754,6 +791,10 @@ class CometChatMessages extends React.PureComponent { reaction={this.reactionName} messageToReact={this.state.messageToReact} actionGenerated={this.actionHandler} + getConversationId={this.getConversationId} + showMessage={(type, message) => { + this.DropDownAlertRef?.showMessage(type, message); + }} /> ); @@ -799,6 +840,7 @@ class CometChatMessages extends React.PureComponent { parentMessage={this.state.threadMessageParent} loggedInUser={this.loggedInUser} actionGenerated={this.actionHandler} + getConversationId={this.getConversationId} /> ); @@ -826,14 +868,16 @@ class CometChatMessages extends React.PureComponent { /> ) : null} {threadMessageView} - + {this.state.groupDetailVisible ? ( + + ) : null} { + this.DropDownAlertRef?.showMessage(type, message); + }} // widgetsettings={route.params.widgetsettings} // widgetconfig={route.params.widgetconfig} loggedInUser={params.loggedInUser} @@ -869,6 +916,7 @@ class CometChatMessages extends React.PureComponent { {liveReactionView} {messageComposer} + (this.DropDownAlertRef = ref)} /> ); } diff --git a/src/components/Messages/CometChatReadReceipt/index.js b/src/components/Messages/CometChatReadReceipt/index.js index 17dbbae..ed7b0c5 100644 --- a/src/components/Messages/CometChatReadReceipt/index.js +++ b/src/components/Messages/CometChatReadReceipt/index.js @@ -5,44 +5,61 @@ import { get as _get } from 'lodash'; import blueDoubleTick from './resources/blue-double-tick-icon.png'; import greyDoubleTick from './resources/grey-double-tick-icon.png'; import greyTick from './resources/grey-tick-icon.png'; - +import sendingTick from './resources/sending.png'; +import errorTick from './resources/error.png'; import styles from './styles'; - +import { CometChat } from '@cometchat-pro/react-native-chat'; const CometChatReadReceipt = (props) => { let ticks = blueDoubleTick; - if ( - _get(props, 'message.sentAt', null) && - !_get(props, 'message.readAt', null) && - !_get(props, 'message.deliveredAt', null) - ) { - ticks = greyTick; - } else if ( - _get(props, 'message.sentAt', null) && - !_get(props, 'message.readAt', null) && - _get(props, 'message.deliveredAt', null) - ) { - ticks = greyDoubleTick; - } + if (props.message.messageFrom === 'sender') { + if (props.message.receiverType === CometChat.RECEIVER_TYPE.GROUP) { + if (props.message.hasOwnProperty('error')) { + ticks = errorTick; + } else { + ticks = sendingTick; + + if (props.message.hasOwnProperty('sentAt')) { + ticks = greyTick; + } + } + } else { + if (props.message.hasOwnProperty('error')) { + ticks = errorTick; + } else { + ticks = sendingTick; + + if (props.message.hasOwnProperty('sentAt')) { + ticks = greyTick; + if (props.message.hasOwnProperty('deliveredAt')) { + ticks = greyDoubleTick; + if (props.message.hasOwnProperty('readAt')) { + ticks = blueDoubleTick; + } + } + } + } + } + } if (props.message.messageFrom !== 'sender') { ticks = null; } - let timestamp = new Date(props.message.sentAt * 1000).toLocaleTimeString( - 'en-US', - { - hour: 'numeric', - minute: 'numeric', - hour12: true, - }, - ); - + let timestamp = new Date( + props.message.sentAt + ? props.message.sentAt * 1000 + : props.message._composedAt, + ).toLocaleTimeString('en-US', { + hour: 'numeric', + minute: 'numeric', + hour12: true, + }); if (Platform.OS === 'android') { let time = timestamp.split(':'); // convert to array // fetch var hours = Number(time[0]); - var minutes = Number(time[1]); + var minutes = Number(time[1]?.split(' ')[0]); // calculate var timeValue; @@ -63,6 +80,7 @@ const CometChatReadReceipt = (props) => { return ( {timestamp} + {ticks ? ( time ) : null} diff --git a/src/components/Messages/CometChatReadReceipt/resources/error.png b/src/components/Messages/CometChatReadReceipt/resources/error.png new file mode 100644 index 0000000000000000000000000000000000000000..5b75c534ac97b25451973bca12a420ae58e81d89 GIT binary patch literal 604 zcmV-i0;BzjP)WU z6GT^6h|6WPB~m$&$aT|Ezd*eCd6?&Cu+{noaHpr?7z1~76z=3C>}n(p833z%a^Bw$ zHX7Y7{My`vQ>(#UTZ1z`j)a`b=h0Ir0KL5_*cWB}^aN*cFlEH&CQ`lw$KsKY^eYK8vg*6ok|JBc$KXH0000 literal 0 HcmV?d00001 diff --git a/src/components/Messages/CometChatReadReceipt/resources/sending.png b/src/components/Messages/CometChatReadReceipt/resources/sending.png new file mode 100644 index 0000000000000000000000000000000000000000..44b76356fddc484a59ba41121601b53cba3be698 GIT binary patch literal 522 zcmV+l0`>igP)SH}OT{-UDwY2K-%zbkrCuH?f}&JyqA`i-%xWYO-+bsmU^ChIcIKRo zur15R1EJu-@Vj4Z+lCMVhG9TeRcQOY%=vsiL?RKyV==kD3vi0L@N+Q0{&0X#Q4k0O zV3;OMf@ZT>JXb0b=7ex-u-$Ia?e!3k$K}RwI1Gg#r_)ISKl*({skqT-AQTMVYM|@7 zJUNj_pw(<5nM~qmv%zRQhTrc;lJakzjvQ||9Ks{wYPEu@X?Q9W zAylhX%;$42;Jw?$dcDTiXe2i~5OEQWbNr;JGakzW5R_!mSSWERU;$awKlBn*aa+ literal 0 HcmV?d00001 diff --git a/src/components/Messages/CometChatReadReceipt/styles.js b/src/components/Messages/CometChatReadReceipt/styles.js index 92548d7..6eb2d0f 100644 --- a/src/components/Messages/CometChatReadReceipt/styles.js +++ b/src/components/Messages/CometChatReadReceipt/styles.js @@ -1,16 +1,20 @@ import { StyleSheet } from 'react-native'; - +import theme from '../../../resources/theme'; export default StyleSheet.create({ containerStyle: { - alignItems: 'center', flexDirection: 'row', + marginTop: 5, }, msgTimestampStyle: { fontSize: 11, fontWeight: '500', + color: theme.color.helpText, + textTransform: 'uppercase', }, tickImageStyle: { marginLeft: 3, + width: 14, + height: 10, }, }); diff --git a/src/components/Messages/CometChatReceiverAudioMessageBubble/index.js b/src/components/Messages/CometChatReceiverAudioMessageBubble/index.js index ceaf069..e0c726d 100644 --- a/src/components/Messages/CometChatReceiverAudioMessageBubble/index.js +++ b/src/components/Messages/CometChatReceiverAudioMessageBubble/index.js @@ -65,6 +65,7 @@ const CometChatReceiverAudioMessageBubble = (props) => { theme={props.theme} {...props} message={message} + showMessage={props?.showMessage} /> ); diff --git a/src/components/Messages/CometChatReceiverDirectCallBubble/index.js b/src/components/Messages/CometChatReceiverDirectCallBubble/index.js new file mode 100644 index 0000000..9ea3674 --- /dev/null +++ b/src/components/Messages/CometChatReceiverDirectCallBubble/index.js @@ -0,0 +1,127 @@ +import React from 'react'; +import { + CometChatMessageActions, + CometChatThreadedMessageReplyCount, + CometChatReadReceipt, +} from '../'; +import { CometChat } from '@cometchat-pro/react-native-chat'; +import { View, Text, Image, TouchableOpacity } from 'react-native'; +import { CometChatMessageReactions } from '../Extensions'; +import { CometChatAvatar } from '../../Shared'; +import Styles from './style'; +import { checkMessageForExtensionsData } from '../../../utils/common'; +import * as actions from '../../../utils/actions'; +import theme from '../../../resources/theme'; + +import callIcon from './resources/receivervideocall.png'; + +class CometChatReceiverDirectCallBubble extends React.Component { + messageFrom = 'receiver'; + + constructor(props) { + super(props); + + const message = Object.assign({}, props.message, { + messageFrom: this.messageFrom, + }); + this.state = { + message: message, + isHovering: false, + }; + } + + componentDidUpdate(prevProps) { + const previousMessageStr = JSON.stringify(prevProps.message); + const currentMessageStr = JSON.stringify(this.props.message); + + if (previousMessageStr !== currentMessageStr) { + const message = Object.assign({}, this.props.message, { + messageFrom: this.messageFrom, + }); + this.setState({ message: message }); + } + } + + render() { + let senderAvatar = null, + name = null; + + let messageReactions = null; + const reactionsData = checkMessageForExtensionsData( + this.state.message, + 'reactions', + ); + if (reactionsData) { + if (Object.keys(reactionsData).length) { + messageReactions = ( + + + + ); + } + } + + if (this.state?.message?.receiverType === CometChat.RECEIVER_TYPE.GROUP) { + senderAvatar = { uri: this.state?.message?.sender.avatar }; + } + + return ( + + + + + + {this.state?.message?.receiverType === + CometChat.RECEIVER_TYPE.GROUP ? ( + + + {this.state?.message?.sender.name} + + + ) : null} + + + + + {`${this.state?.message?.sender?.name} have initiated a call`} + + + + this.props.actionGenerated( + actions.JOIN_DIRECT_CALL, + this.state.message, + ) + } + style={Styles.buttonStyle}> + Join + + + + + + {messageReactions} + + + + ); + } +} + +export default CometChatReceiverDirectCallBubble; diff --git a/src/components/Messages/CometChatReceiverDirectCallBubble/resources/receivervideocall.png b/src/components/Messages/CometChatReceiverDirectCallBubble/resources/receivervideocall.png new file mode 100644 index 0000000000000000000000000000000000000000..6be2e2cbdb1fad17a5ff47bd7ef3bf7e87ecade3 GIT binary patch literal 1251 zcmV<91RVQ`P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91F`xqg1ONa40RR91AOHXW06cLp%>V!dO-V#SR9Fe^m|cjKMHt7QdH1a5 zSM6S82pcN75nYJ6d)zXWT}mMcvA_=~BsDiIA(OfYq}`kHMy(4G+>={KUmJMkh4cZg zpS8P+7AT}tq==-&7Ak)1@tuCpoHM7_!+Q1{&e_9z;T+yGGtVr-H1Gk_z^2oFIK2lE*T>?80{}>~A+`O6}|0I}#9hi&@|1h0ML>cOC<0n6bf}yvzc|Y8YZVwi?MNMuxjc zx#{?8M)MIz~rwA0oGM&1mqbTGCj z^93YcDrAd(i_mWd-%KX@L`_0o>05112M~Azg(E=z)5JzuIGO|$Bw&ZIv4uVHs@63z zdCTW_+XpkXJO8ba`D@h=32H~wG7~ABgQ-yNp{&}I+T9&Ph|BM zAhh7vTCIu4xj|YB9lwd#FaQWguAY?jiV6R}4VkxbpO3U&D8-5dKpg?{ zL414}r`Pv|zf?@>uN&Tt^q=QG+n37M) zSdkdXZSJPON8)ZXQ*C*?R>DYY%V+lfQYRr^B&^I&Uz5I;Pi$i;MB+svgZ#1dE$M4c z*@eXti5rQ3v%ob#u@52}iXjp!61)|*^S!UY^^s&l`H=U2_tLLz!Qe%#NB}zI!ncXr z?91@D>Bxwz`u!i-&jaZptq+$1Zi?J`9rH=UH5hFfH&-7h;Od&e!oBHpf>?L;lQS zn@cQUfOp31;qd56ct4!7Xt$j(T%*yHaa)a^L>`OuuQ5O1Qga~ov)X5-AExc$WXi5W z-Vnv4FS|dy;P2~ns&aBbvo-;l!=fTCg6AgH$0W zxI){pQX-tk9h?lET6QV3!Oo#P%it9aW8xCiu<g#| N002ovPDHLkV1krSOtSz0 literal 0 HcmV?d00001 diff --git a/src/components/Messages/CometChatReceiverDirectCallBubble/style.js b/src/components/Messages/CometChatReceiverDirectCallBubble/style.js new file mode 100644 index 0000000..a6eb524 --- /dev/null +++ b/src/components/Messages/CometChatReceiverDirectCallBubble/style.js @@ -0,0 +1,42 @@ +import { StyleSheet } from 'react-native'; +import { widthRatio } from '../../../utils/consts'; +import theme from '../../../resources/theme'; + +export default StyleSheet.create({ + marginBottom: 16, + mainContainer: { flexDirection: 'row' }, + mainWrapper: { + flexWrap: 'wrap', + flexDirection: 'row', + width: 36, + height: 36, + marginRight: 10 * widthRatio, + backgroundColor: 'rgba(51,153,255,0.25)', + borderRadius: 25, + marginTop: 30, + }, + nameContainer: { width: '100%' }, + messageContainer: { + width: '70%', + flexShrink: 1, + backgroundColor: '#F8F8F8', + borderRadius: 8, + padding: 15, + alignSelf: 'flex-start', + }, + imageContainer: { flexDirection: 'row', alignItems: 'center' }, + imageStyle: { marginRight: 10 }, + textStyle: { + fontSize: 16, + width: '80%', + color: theme.color.primary, + }, + buttonStyle: { + backgroundColor: '#fff', + borderRadius: 8, + padding: 5, + justifyContent: 'center', + alignItems: 'center', + marginVertical: 10, + }, +}); diff --git a/src/components/Messages/CometChatReceiverFileMessageBubble/index.js b/src/components/Messages/CometChatReceiverFileMessageBubble/index.js index b10d098..e4e4503 100644 --- a/src/components/Messages/CometChatReceiverFileMessageBubble/index.js +++ b/src/components/Messages/CometChatReceiverFileMessageBubble/index.js @@ -72,7 +72,9 @@ const CometChatReceiverFileMessageBubble = (props) => { {props.message.receiverType === CometChat.RECEIVER_TYPE.GROUP ? ( - {message.sender.name} + + {message.sender.name} + ) : null} @@ -104,12 +106,13 @@ const CometChatReceiverFileMessageBubble = (props) => { message={message} /> + - diff --git a/src/components/Messages/CometChatReceiverFileMessageBubble/styles.js b/src/components/Messages/CometChatReceiverFileMessageBubble/styles.js index ee96330..f851dd0 100644 --- a/src/components/Messages/CometChatReceiverFileMessageBubble/styles.js +++ b/src/components/Messages/CometChatReceiverFileMessageBubble/styles.js @@ -1,22 +1,20 @@ import { StyleSheet } from 'react-native'; import { heightRatio, widthRatio } from '../../../utils/consts'; - +import theme from '../../../resources/theme'; export default StyleSheet.create({ messageWrapperStyle: { flexDirection: 'row', alignItems: 'center', - backgroundColor: '#f8f8f8', - marginBottom: 8, + backgroundColor: '#F8F8F8', alignSelf: 'flex-start', justifyContent: 'space-between', - paddingHorizontal: 12 * widthRatio, - paddingVertical: 8 * heightRatio, - borderRadius: 12, + paddingHorizontal: 12, + paddingVertical: 8, + borderRadius: 10, paddingRight: 30, }, messageInfoWrapperStyle: { flexDirection: 'row', - alignItems: 'center', justifyContent: 'flex-start', }, messagePreviewContainerStyle: { @@ -65,14 +63,15 @@ export default StyleSheet.create({ marginRight: 10 * widthRatio, backgroundColor: 'rgba(51,153,255,0.25)', borderRadius: 25, + marginTop: 30, }, containerStyle: { flexDirection: 'row', alignItems: 'center', }, - mainContainerStyle: { marginBottom: 16 }, + mainContainerStyle: { marginBottom: 16, marginLeft: 4 }, messageContainer: { flexDirection: 'row', alignItems: 'flex-start' }, messageContainerStyle: { minWidth: '65%' }, - attachmentNameStyle: { flex: 1, marginRight: 4 }, + attachmentNameStyle: { flex: 1, marginRight: 4, color: theme.color.primary }, senderNameContainer: { marginBottom: 5 }, }); diff --git a/src/components/Messages/CometChatReceiverImageMessageBubble/index.js b/src/components/Messages/CometChatReceiverImageMessageBubble/index.js index 52b46dc..a6b10da 100644 --- a/src/components/Messages/CometChatReceiverImageMessageBubble/index.js +++ b/src/components/Messages/CometChatReceiverImageMessageBubble/index.js @@ -86,7 +86,9 @@ const CometChatReceiverImageMessageBubble = (props) => { {props.message.receiverType === CometChat.RECEIVER_TYPE.GROUP ? ( - {message.sender.name} + + {message.sender.name} + ) : null} @@ -107,18 +109,19 @@ const CometChatReceiverImageMessageBubble = (props) => { /> - - - - + + - + + + + - ); }; diff --git a/src/components/Messages/CometChatReceiverImageMessageBubble/styles.js b/src/components/Messages/CometChatReceiverImageMessageBubble/styles.js index 52659a6..8a0d795 100644 --- a/src/components/Messages/CometChatReceiverImageMessageBubble/styles.js +++ b/src/components/Messages/CometChatReceiverImageMessageBubble/styles.js @@ -4,14 +4,13 @@ import { widthRatio } from '../../../utils/consts'; export default StyleSheet.create({ messageWrapperStyle: { flexDirection: 'row', - backgroundColor: '#f2f3f4', - marginBottom: 8, + backgroundColor: '#F8F8F8', alignItems: 'flex-start', justifyContent: 'flex-start', maxWidth: '81%', - borderRadius: 12, + borderRadius: 10, }, - container: { marginBottom: 16 }, + container: { marginBottom: 16, marginLeft: 4 }, mainContainer: { flexDirection: 'row', alignItems: 'flex-start' }, senderNameContainer: { marginBottom: 5 }, containerStyle: { @@ -28,9 +27,10 @@ export default StyleSheet.create({ flexDirection: 'row', width: 36, height: 36, - marginRight: 10 * widthRatio, + marginRight: 8, backgroundColor: 'rgba(51,153,255,0.25)', borderRadius: 25, + marginTop: 30, }, messageImgWrapperStyle: { width: '100%', @@ -44,7 +44,6 @@ export default StyleSheet.create({ }, messageInfoWrapperStyle: { flexDirection: 'row', - alignItems: 'center', justifyContent: 'flex-start', }, }); diff --git a/src/components/Messages/CometChatReceiverTextMessageBubble/index.js b/src/components/Messages/CometChatReceiverTextMessageBubble/index.js index 3723213..2cf160c 100644 --- a/src/components/Messages/CometChatReceiverTextMessageBubble/index.js +++ b/src/components/Messages/CometChatReceiverTextMessageBubble/index.js @@ -184,7 +184,9 @@ const CometChatReceiverTextMessageBubble = (props) => { {props.message.receiverType === CometChat.RECEIVER_TYPE.GROUP ? ( - {message.sender.name} + + {message.sender.name} + ) : null} @@ -192,14 +194,16 @@ const CometChatReceiverTextMessageBubble = (props) => { onLongPress={() => { props.actionGenerated(actions.OPEN_MESSAGE_ACTIONS, message); }}> - - {messageText} + + + {messageText} + @@ -211,13 +215,14 @@ const CometChatReceiverTextMessageBubble = (props) => { {...props} message={message} /> + - diff --git a/src/components/Messages/CometChatReceiverTextMessageBubble/styles.js b/src/components/Messages/CometChatReceiverTextMessageBubble/styles.js index 2d21788..2f9882f 100644 --- a/src/components/Messages/CometChatReceiverTextMessageBubble/styles.js +++ b/src/components/Messages/CometChatReceiverTextMessageBubble/styles.js @@ -1,16 +1,21 @@ import { StyleSheet } from 'react-native'; import { heightRatio, widthRatio } from '../../../utils/consts'; - +import theme from '../../../resources/theme'; export default StyleSheet.create({ messageLinkStyle: { textDecorationLine: 'underline', color: 'blue', fontSize: 15, }, - container: { marginBottom: 16 }, + container: { marginBottom: 16, marginLeft: 4 }, innerContainer: { flexDirection: 'row', alignItems: 'flex-start' }, - senderNameStyle: { marginBottom: 5 }, - autolinkStyle: { color: 'black', fontSize: 15 }, + senderNameStyle: { + marginBottom: 2, + color: theme.color.helpText, + fontSize: 12, + paddingLeft: 8, + }, + autolinkStyle: { color: theme.color.primary, fontSize: 15 }, messageContainer: { maxWidth: '81%', minWidth: '81%' }, linkObjectDescription: { fontStyle: 'italic', @@ -22,19 +27,18 @@ export default StyleSheet.create({ messageWrapperStyle: { flexDirection: 'row', alignItems: 'center', - backgroundColor: '#f6f6f6', - marginBottom: 4, + marginBottom: 0, alignSelf: 'flex-start', justifyContent: 'space-between', - paddingHorizontal: 12 * widthRatio, - paddingVertical: 8 * heightRatio, + paddingHorizontal: 8, + paddingVertical: 8, maxWidth: '100%', borderRadius: 12, }, messageInfoWrapperStyle: { flexDirection: 'row', - alignItems: 'center', justifyContent: 'flex-start', + marginLeft: 8, }, messagePreviewContainerStyle: { borderRadius: 12, @@ -87,9 +91,10 @@ export default StyleSheet.create({ flexDirection: 'row', width: 36, height: 36, - marginRight: 10 * widthRatio, + marginRight: 8, backgroundColor: 'rgba(51,153,255,0.25)', borderRadius: 25, + alignSelf: 'center', }, containerStyle: { flexDirection: 'row', diff --git a/src/components/Messages/CometChatReceiverVideoMessageBubble/index.js b/src/components/Messages/CometChatReceiverVideoMessageBubble/index.js index dc54a2a..fb8e89c 100644 --- a/src/components/Messages/CometChatReceiverVideoMessageBubble/index.js +++ b/src/components/Messages/CometChatReceiverVideoMessageBubble/index.js @@ -39,7 +39,9 @@ const CometChatReceiverVideoMessageBubble = (props) => { {props.message.receiverType === CometChat.RECEIVER_TYPE.GROUP ? ( - {message.sender.name} + + {message.sender.name} + ) : null} @@ -72,13 +74,14 @@ const CometChatReceiverVideoMessageBubble = (props) => { {...props} message={message} /> + - diff --git a/src/components/Messages/CometChatReceiverVideoMessageBubble/styles.js b/src/components/Messages/CometChatReceiverVideoMessageBubble/styles.js index 0847271..796fec5 100644 --- a/src/components/Messages/CometChatReceiverVideoMessageBubble/styles.js +++ b/src/components/Messages/CometChatReceiverVideoMessageBubble/styles.js @@ -2,24 +2,22 @@ import { StyleSheet } from 'react-native'; import { widthRatio } from '../../../utils/consts'; export default StyleSheet.create({ - container: { marginBottom: 16 }, + container: { marginBottom: 16, marginLeft: 4 }, innerContainer: { flexDirection: 'row', alignItems: 'flex-start' }, senderNameContainer: { marginBottom: 5 }, messageWrapperStyle: { flexDirection: 'row', justifyContent: 'center', alignItems: 'center', - backgroundColor: '#f2f3f4', - marginBottom: 8, + backgroundColor: '#F8F8F8', alignSelf: 'flex-start', - paddingHorizontal: 18 * widthRatio, - paddingVertical: 5, + paddingHorizontal: 12, + paddingVertical: 8, maxWidth: '87.5%', - borderRadius: 12, + borderRadius: 10, }, messageInfoWrapperStyle: { flexDirection: 'row', - alignItems: 'center', justifyContent: 'flex-start', }, avatarStyle: { @@ -30,6 +28,7 @@ export default StyleSheet.create({ marginRight: 10 * widthRatio, backgroundColor: 'rgba(51,153,255,0.25)', borderRadius: 25, + marginTop: 30, }, msgTimestampStyle: { fontSize: 11, @@ -50,6 +49,6 @@ export default StyleSheet.create({ messageVideo: { height: '100%', width: '100%', - borderRadius: 12, + borderRadius: 10, }, }); diff --git a/src/components/Messages/CometChatSenderAudioMessageBubble/index.js b/src/components/Messages/CometChatSenderAudioMessageBubble/index.js index d7cd874..1c14dc3 100644 --- a/src/components/Messages/CometChatSenderAudioMessageBubble/index.js +++ b/src/components/Messages/CometChatSenderAudioMessageBubble/index.js @@ -36,6 +36,7 @@ const CometChatSenderAudioMessageBubble = (props) => { theme={props.theme} {...props} message={message} + showMessage={props?.showMessage} /> ); diff --git a/src/components/Messages/CometChatSenderDirectCallBubble/index.js b/src/components/Messages/CometChatSenderDirectCallBubble/index.js new file mode 100644 index 0000000..b3bbb30 --- /dev/null +++ b/src/components/Messages/CometChatSenderDirectCallBubble/index.js @@ -0,0 +1,108 @@ +import React from 'react'; +import { + CometChatMessageActions, + CometChatThreadedMessageReplyCount, + CometChatReadReceipt, +} from '../'; +import Styles from './style'; +import * as actions from '../../../utils/actions'; +import { CometChatMessageReactions } from '../Extensions'; +import { checkMessageForExtensionsData } from '../../../utils/common'; +import * as enums from '../../../utils/enums'; +import theme from '../../../resources/theme'; +import callIcon from './resources/sendervideocall.png'; +import { View, Text, Image, TouchableOpacity } from 'react-native'; +import { TouchableWithoutFeedback } from 'react-native'; + +class CometChatSenderDirectCallBubble extends React.Component { + messageFrom = 'sender'; + + constructor(props) { + super(props); + const message = Object.assign({}, props.message, { + messageFrom: this.messageFrom, + }); + + this.state = { + message: message, + isHovering: false, + }; + } + + componentDidUpdate(prevProps) { + const previousMessageStr = JSON.stringify(prevProps.message); + const currentMessageStr = JSON.stringify(this.props.message); + + if (previousMessageStr !== currentMessageStr) { + const message = Object.assign({}, this.props.message, { + messageFrom: this.messageFrom, + }); + this.setState({ message: message }); + } + } + + render() { + let messageReactions = null; + const reactionsData = checkMessageForExtensionsData( + this.state.message, + 'reactions', + ); + if (reactionsData) { + if (Object.keys(reactionsData).length) { + messageReactions = ( + + + + ); + } + } + + return ( + { + this.props.actionGenerated( + actions.OPEN_MESSAGE_ACTIONS, + this.state?.message, + ); + }}> + + + + + {`You have initiated a call`} + + + this.props.actionGenerated( + actions.JOIN_DIRECT_CALL, + this.state.message, + ) + } + style={Styles.buttonStyle}> + Join + + + {messageReactions} + + + + + + + + ); + } +} + +export default CometChatSenderDirectCallBubble; diff --git a/src/components/Messages/CometChatSenderDirectCallBubble/resources/sendervideocall.png b/src/components/Messages/CometChatSenderDirectCallBubble/resources/sendervideocall.png new file mode 100644 index 0000000000000000000000000000000000000000..2a69dadd0ca5d717813434617cf9b2d483942c07 GIT binary patch literal 932 zcmV;V16%xwP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91F`xqg1ONa40RR91AOHXW06cLp%>V!c4oO5oR9Fe^m`!Xs)Bh2@ff_HPW#>dB>~~-|=Z)9+?xeH3We2|dpxN|2LAOC*z_jy}NcbdLz$Yo_ zI+$(>yNYgyz+boD*mfdQP?$PIK*|J-qdO_SE9@cPNLT{;!0v{?-7o^`_l<;VdJT3! z;GG(kh;Jmcn72cqs!hhXh5evf0-7n`NL2FgDT?_|qUe?UBZqG@(ay(icD3)qHxlb1 z&<7D6nkp9GNT~4TKt#4w%EC7iUrpiqa^Hr?kxGd8M&c4hpD~5&Jbn=(SHQG#WPBqr z!N=}61@8r;rtp2}9*E30?II--y4jG-npCm>y0;$LS|HL*6&t}PQ_VW`07O=scAgRm z`#)?ZXl7n-JPmgzvb7{2@|g5%!An!dLbT4~ni(Bi{|HXqa99!hScSw7ZE|#}i-Jb{ zx15+lvq@*!F2}2z4=t!zgj^j??s8W)N#f2qvDO^S7D}rXj9V}I9+^7dLYmbjZ>)8vW;kgy$8C9&?ze_(JZHd?q1ymt@Crm*O z3nX+vKLIqQaZ5B8%9a+@FTp+lw7}C~F38RnIx30$YX3KxTmQ3iXXxkv0000 { - + ); diff --git a/src/components/Messages/CometChatSenderFileMessageBubble/styles.js b/src/components/Messages/CometChatSenderFileMessageBubble/styles.js index a604d67..a1e9719 100644 --- a/src/components/Messages/CometChatSenderFileMessageBubble/styles.js +++ b/src/components/Messages/CometChatSenderFileMessageBubble/styles.js @@ -2,16 +2,16 @@ import { StyleSheet } from 'react-native'; import { widthRatio } from '../../../utils/consts'; export default StyleSheet.create({ - container: { marginBottom: 16 }, + container: { marginBottom: 16, marginRight: 8 }, messageWrapperStyle: { flexDirection: 'row', alignItems: 'center', backgroundColor: '#3399FF', - marginBottom: 8, + marginBottom: 4, alignSelf: 'flex-end', justifyContent: 'space-between', paddingHorizontal: 12 * widthRatio, - paddingVertical: 5, + paddingVertical: 8, maxWidth: '65%', borderRadius: 10, }, diff --git a/src/components/Messages/CometChatSenderImageMessageBubble/index.js b/src/components/Messages/CometChatSenderImageMessageBubble/index.js index 5b15975..a9326d5 100644 --- a/src/components/Messages/CometChatSenderImageMessageBubble/index.js +++ b/src/components/Messages/CometChatSenderImageMessageBubble/index.js @@ -87,12 +87,13 @@ const CometChatSenderImageMessageBubble = (props) => { - + ); diff --git a/src/components/Messages/CometChatSenderImageMessageBubble/styles.js b/src/components/Messages/CometChatSenderImageMessageBubble/styles.js index 5bec67d..7c51752 100644 --- a/src/components/Messages/CometChatSenderImageMessageBubble/styles.js +++ b/src/components/Messages/CometChatSenderImageMessageBubble/styles.js @@ -1,15 +1,15 @@ import { StyleSheet } from 'react-native'; export default StyleSheet.create({ - container: { marginBottom: 16 }, + container: { marginBottom: 16, marginRight: 8 }, messageWrapperStyle: { flexDirection: 'row', alignItems: 'center', - marginBottom: 8, alignSelf: 'flex-end', justifyContent: 'space-between', maxWidth: '65%', borderRadius: 10, + marginBottom: 4, }, messageImgWrapperStyle: { alignSelf: 'flex-end', @@ -25,5 +25,6 @@ export default StyleSheet.create({ flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-end', + width: '100%', }, }); diff --git a/src/components/Messages/CometChatSenderTextMessageBubble/index.js b/src/components/Messages/CometChatSenderTextMessageBubble/index.js index 5e9e186..293af99 100644 --- a/src/components/Messages/CometChatSenderTextMessageBubble/index.js +++ b/src/components/Messages/CometChatSenderTextMessageBubble/index.js @@ -190,6 +190,7 @@ const CometChatSenderTextMessageBubble = (props) => { /> { - + ); diff --git a/src/components/Messages/CometChatSenderVideoMessageBubble/styles.js b/src/components/Messages/CometChatSenderVideoMessageBubble/styles.js index 233dea1..652c0ce 100644 --- a/src/components/Messages/CometChatSenderVideoMessageBubble/styles.js +++ b/src/components/Messages/CometChatSenderVideoMessageBubble/styles.js @@ -1,7 +1,7 @@ import { StyleSheet } from 'react-native'; export default StyleSheet.create({ - container: { marginBottom: 16 }, + container: { marginBottom: 16, marginRight: 8 }, messageWrapperStyle: { flexDirection: 'row', alignItems: 'center', @@ -10,7 +10,7 @@ export default StyleSheet.create({ alignSelf: 'flex-end', justifyContent: 'space-between', maxWidth: '65%', - borderRadius: 8, + borderRadius: 10, }, messageVideoWrapperStyle: { alignSelf: 'flex-end', diff --git a/src/components/Messages/CometChatThreadedMessageReplyCount/styles.js b/src/components/Messages/CometChatThreadedMessageReplyCount/styles.js index fb0d5df..de76beb 100644 --- a/src/components/Messages/CometChatThreadedMessageReplyCount/styles.js +++ b/src/components/Messages/CometChatThreadedMessageReplyCount/styles.js @@ -2,7 +2,7 @@ import { StyleSheet } from 'react-native'; export default StyleSheet.create({ replyTextStyle: { - fontSize: 11, + fontSize: 14, fontWeight: '500', lineHeight: 12, textTransform: 'lowercase', diff --git a/src/components/Messages/Extensions/CometChatCreatePoll/index.js b/src/components/Messages/Extensions/CometChatCreatePoll/index.js index 37a5428..aaf40bd 100644 --- a/src/components/Messages/Extensions/CometChatCreatePoll/index.js +++ b/src/components/Messages/Extensions/CometChatCreatePoll/index.js @@ -9,6 +9,7 @@ import { TextInput, Modal, } from 'react-native'; +import DropDownAlert from '../../../Shared/DropDownAlert'; import { CometChatCreatePollOptions } from '../index'; import styles from './styles'; import Icon from 'react-native-vector-icons/AntDesign'; @@ -28,6 +29,7 @@ const CometChatCreatePoll = (props) => { const [questionRef, setQuestionRef] = useState(''); const [optionOneRef, setOneRef] = useState(''); const [optionTwoRef, setTwoRef] = useState(''); + const dropDownAlertRef = useRef(null); const QuestionChangeHandler = (value) => { setQuestionRef(value); }; @@ -112,7 +114,9 @@ const CometChatCreatePoll = (props) => { props.actionGenerated(actions.POLL_CREATED, message); }) .catch((err) => { - console.log("err",err) + console.log('err', err); + const errorCode = err?.details?.message || err?.message || 'ERROR'; + dropDownAlertRef?.current?.showMessage('error', errorCode); setError(err); }); }; @@ -236,7 +240,7 @@ const CometChatCreatePoll = (props) => { {close} - {error && (error.error || error.error.message) ? ( + {error && (error.error || error.error?.message) ? ( {error.error.message || error.error} @@ -257,6 +261,7 @@ const CometChatCreatePoll = (props) => { + ); }; diff --git a/src/components/Messages/Extensions/CometChatMessageReactions/index.js b/src/components/Messages/Extensions/CometChatMessageReactions/index.js index 4438b47..88f8d91 100644 --- a/src/components/Messages/Extensions/CometChatMessageReactions/index.js +++ b/src/components/Messages/Extensions/CometChatMessageReactions/index.js @@ -18,6 +18,7 @@ import { import * as enums from '../../../../utils/enums'; import { ModalPicker, Emoji } from 'emoji-mart-native'; import ReactionDetails from './reactionDetails'; +import DropDownAlert from '../../../Shared/DropDownAlert'; class CometChatMessageReactions extends Component { constructor(props) { @@ -30,7 +31,9 @@ class CometChatMessageReactions extends Component { } componentDidUpdate(prevProps) { - if (prevProps.message !== this.props.message) { + if ( + JSON.stringify(prevProps.message) !== JSON.stringify(this.props.message) + ) { this.setState({ message: this.props.message }); } } @@ -46,7 +49,10 @@ class CometChatMessageReactions extends Component { .then(() => { // Reaction added successfully }) - .catch(() => { + .catch((error) => { + const errorCode = + error?.details?.message || error?.message || 'ERROR'; + this.props?.showMessage('error', errorCode); // Some error occured }); } catch (error) { @@ -74,6 +80,7 @@ class CometChatMessageReactions extends Component { Object.keys(reactionData).forEach((user) => { if (reactionData[user].name) userList.push(reactionData[user].name); }); + return ( this.reactToMessages({ colons: data })} @@ -135,11 +142,19 @@ class CometChatMessageReactions extends Component { messageReactions.unshift(addReactionEmoji); } } + if (this.props.item.blockedByMe) { + return null; + } return ( // eslint-disable-next-line react/jsx-fragments <> + + (this.dropDownAlertRef = ref)} /> + + { id: pollId, }) .then((response) => { - props.actionGenerated(actions.POLL_ANSWERED, response); + // props.actionGenerated(actions.POLL_ANSWERED, message); }) .catch((error) => { - logger(error); + const errorCode = error?.details?.message || error?.message || 'ERROR'; + props?.showMessage('error', errorCode); + logger('here', error); }); }; if (!Object.prototype.hasOwnProperty.call(props.message, 'metadata')) { @@ -151,7 +154,9 @@ const CometChatReceiverPollMessageBubble = (props) => { {props.message.receiverType === CometChat.RECEIVER_TYPE.GROUP ? ( - {message.sender.name} + + {message.sender.name} + ) : null} @@ -169,18 +174,18 @@ const CometChatReceiverPollMessageBubble = (props) => { {totalText} - - - - + + - + + + + - ); }; diff --git a/src/components/Messages/Extensions/CometChatReceiverPollMessageBubble/styles.js b/src/components/Messages/Extensions/CometChatReceiverPollMessageBubble/styles.js index 3272dc3..fc1c111 100644 --- a/src/components/Messages/Extensions/CometChatReceiverPollMessageBubble/styles.js +++ b/src/components/Messages/Extensions/CometChatReceiverPollMessageBubble/styles.js @@ -6,7 +6,6 @@ export default StyleSheet.create({ innerContainer: { flexDirection: 'row', alignItems: 'flex-start' }, messageWrapperStyle: { backgroundColor: '#f8f8f8', - marginBottom: 8, alignSelf: 'flex-start', paddingHorizontal: 12 * widthRatio, paddingVertical: 8 * heightRatio, diff --git a/src/components/Messages/Extensions/CometChatReceiverStickerMessageBubble/index.js b/src/components/Messages/Extensions/CometChatReceiverStickerMessageBubble/index.js index b78d3f6..b8aca34 100644 --- a/src/components/Messages/Extensions/CometChatReceiverStickerMessageBubble/index.js +++ b/src/components/Messages/Extensions/CometChatReceiverStickerMessageBubble/index.js @@ -58,7 +58,9 @@ const CometChatReceiverStickerMessageBubble = (props) => { {props.message.receiverType === CometChat.RECEIVER_TYPE.GROUP ? ( - {message.sender.name} + + {message.sender.name} + ) : null} @@ -72,12 +74,12 @@ const CometChatReceiverStickerMessageBubble = (props) => { {...props} message={message} /> + - diff --git a/src/components/Messages/Extensions/CometChatReceiverStickerMessageBubble/styles.js b/src/components/Messages/Extensions/CometChatReceiverStickerMessageBubble/styles.js index 8b32924..e23b49a 100644 --- a/src/components/Messages/Extensions/CometChatReceiverStickerMessageBubble/styles.js +++ b/src/components/Messages/Extensions/CometChatReceiverStickerMessageBubble/styles.js @@ -6,7 +6,6 @@ export default StyleSheet.create({ innerContainer: { flexDirection: 'row', alignItems: 'flex-start' }, senderNameContainer: { marginBottom: 5 }, messageWrapperStyle: { - marginBottom: 4, alignSelf: 'flex-start', paddingHorizontal: 12 * widthRatio, paddingVertical: 8 * heightRatio, @@ -32,6 +31,7 @@ export default StyleSheet.create({ marginRight: 10 * widthRatio, backgroundColor: 'rgba(51,153,255,0.25)', borderRadius: 25, + marginTop: 30, }, containerStyle: { flexDirection: 'row', diff --git a/src/components/Messages/Extensions/CometChatSenderPollMessageBubble/index.js b/src/components/Messages/Extensions/CometChatSenderPollMessageBubble/index.js index aaf75ee..ddfbf97 100644 --- a/src/components/Messages/Extensions/CometChatSenderPollMessageBubble/index.js +++ b/src/components/Messages/Extensions/CometChatSenderPollMessageBubble/index.js @@ -126,6 +126,7 @@ const CometChatSenderPollMessageBubble = (props) => { theme={props.theme} {...props} message={message} + showMessage={props?.showMessage} /> ); diff --git a/src/components/Messages/Extensions/CometChatSenderPollMessageBubble/styles.js b/src/components/Messages/Extensions/CometChatSenderPollMessageBubble/styles.js index fc40fd5..9796c78 100644 --- a/src/components/Messages/Extensions/CometChatSenderPollMessageBubble/styles.js +++ b/src/components/Messages/Extensions/CometChatSenderPollMessageBubble/styles.js @@ -2,7 +2,7 @@ import { StyleSheet } from 'react-native'; import { heightRatio, widthRatio } from '../../../../utils/consts'; export default StyleSheet.create({ - container: { marginBottom: 16 }, + container: { marginBottom: 16, marginRight: 8 }, pollQuestionText: { fontSize: 14, textAlign: 'left', color: 'white' }, totalText: { fontSize: 14, diff --git a/src/components/Messages/Extensions/CometChatSenderStickerMessageBubble/index.js b/src/components/Messages/Extensions/CometChatSenderStickerMessageBubble/index.js index 6cbb6b3..0764be1 100644 --- a/src/components/Messages/Extensions/CometChatSenderStickerMessageBubble/index.js +++ b/src/components/Messages/Extensions/CometChatSenderStickerMessageBubble/index.js @@ -12,10 +12,10 @@ import * as enums from '../../../../utils/enums'; import * as actions from '../../../../utils/actions'; const CometChatSenderStickerMessageBubble = (props) => { - const [message] = useState({ + const message = { ...props.message, - messageFrom: enums.MESSAGE_FROM_SENDER, - }); + messageFrom: enums.MESSAGE_FROM_RECEIVER, + }; let stickerData = null; let stickerImg = null; if ( @@ -45,10 +45,13 @@ const CometChatSenderStickerMessageBubble = (props) => { - + + + ); }; diff --git a/src/components/Messages/Extensions/CometChatSenderStickerMessageBubble/styles.js b/src/components/Messages/Extensions/CometChatSenderStickerMessageBubble/styles.js index c382ad0..5780fcc 100644 --- a/src/components/Messages/Extensions/CometChatSenderStickerMessageBubble/styles.js +++ b/src/components/Messages/Extensions/CometChatSenderStickerMessageBubble/styles.js @@ -10,6 +10,8 @@ export default StyleSheet.create({ position: 'relative', flexDirection: 'column', flexShrink: 0, + marginRight: 8, + alignItems: 'flex-end', }, messageWrapperStyle: { width: '100%', diff --git a/src/components/Messages/Extensions/CometChatSmartReplyPreview/styles.js b/src/components/Messages/Extensions/CometChatSmartReplyPreview/styles.js index 2892d83..965ad56 100644 --- a/src/components/Messages/Extensions/CometChatSmartReplyPreview/styles.js +++ b/src/components/Messages/Extensions/CometChatSmartReplyPreview/styles.js @@ -1,6 +1,6 @@ import { StyleSheet } from 'react-native'; import { heightRatio, widthRatio } from '../../../../utils/consts'; - +import theme from '../../../../resources/theme'; export default StyleSheet.create({ previewWrapperStyle: { width: '100%', @@ -12,7 +12,7 @@ export default StyleSheet.create({ paddingVertical: 8 * heightRatio, borderRadius: 18, marginVertical: 8, - shadowColor: '#141414', + shadowColor: theme.color.primary, shadowOffset: { width: 0, height: 1, diff --git a/src/components/Messages/index.js b/src/components/Messages/index.js index 49907f4..07c9d54 100644 --- a/src/components/Messages/index.js +++ b/src/components/Messages/index.js @@ -21,3 +21,5 @@ export { default as CometChatSenderTextMessageBubble } from './CometChatSenderTe export { default as CometChatSenderVideoMessageBubble } from './CometChatSenderVideoMessageBubble'; export { default as CometChatStickerKeyboard } from './CometChatStickerKeyboard'; export { default as CometChatThreadedMessageReplyCount } from './CometChatThreadedMessageReplyCount'; +export { default as CometChatReceiverDirectCallBubble } from './CometChatReceiverDirectCallBubble'; +export { default as CometChatSenderDirectCallBubble } from './CometChatSenderDirectCallBubble'; diff --git a/src/components/Shared/CometChatBadgeCount/index.js b/src/components/Shared/CometChatBadgeCount/index.js index ed63d4a..97c6595 100644 --- a/src/components/Shared/CometChatBadgeCount/index.js +++ b/src/components/Shared/CometChatBadgeCount/index.js @@ -1,8 +1,8 @@ import React, { useRef, useEffect } from 'react'; -import { Animated } from 'react-native'; +import { Animated, View } from 'react-native'; import theme from '../../../resources/theme'; import styles from './styles'; - +import PropTypes from 'prop-types'; const CometChatBadgeCount = (props) => { const badgeTheme = { ...theme, ...props.theme }; @@ -18,20 +18,38 @@ const CometChatBadgeCount = (props) => { if (props.count) { return ( - - {props.count} - + + + {props.count} + + ); } return null; }; export default CometChatBadgeCount; + +CometChatBadgeCount.defaultProps = { + containerStyle: {}, + theme: {}, + count: 0, +}; + +CometChatBadgeCount.propTypes = { + count: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + containerStyle: PropTypes.object, + theme: PropTypes.object, +}; diff --git a/src/components/Shared/CometChatBadgeCount/styles.js b/src/components/Shared/CometChatBadgeCount/styles.js index 24a64e7..313709f 100644 --- a/src/components/Shared/CometChatBadgeCount/styles.js +++ b/src/components/Shared/CometChatBadgeCount/styles.js @@ -2,17 +2,19 @@ import { StyleSheet } from 'react-native'; export default StyleSheet.create({ badgeStyle: { - fontSize: 12, - height: 18, - borderRadius: 8, + aspectRatio: 1, + height: 24, + borderRadius: 900, + marginLeft: 4, + marginRight: 2, + opacity: 1, + justifyContent: 'center', + }, + textStyle: { + fontSize: 11, overflow: 'hidden', textAlign: 'center', fontWeight: '700', - lineHeight: 18, - marginLeft: 4, - paddingVertical: 0, - paddingHorizontal: 9, - marginRight: 2, opacity: 1, }, }); diff --git a/src/components/Shared/CometChatSharedMedia/index.js b/src/components/Shared/CometChatSharedMedia/index.js index 2a62db1..8138b44 100644 --- a/src/components/Shared/CometChatSharedMedia/index.js +++ b/src/components/Shared/CometChatSharedMedia/index.js @@ -9,6 +9,7 @@ import _ from 'lodash'; import * as enums from '../../../utils/enums'; import styles from './styles'; import VideoPlayer from 'react-native-video-controls'; +import DropDownAlert from '../../Shared/DropDownAlert'; import Icon from 'react-native-vector-icons/FontAwesome5'; import { CometChat } from '@cometchat-pro/react-native-chat'; @@ -131,6 +132,8 @@ export default class CometChatSharedMedia extends React.Component { this.setState({ messageList }); }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.props?.showMessage('error', errorCode); logger( '[CometChatSharedMedia] getMessages fetchPrevious error', error, @@ -138,6 +141,8 @@ export default class CometChatSharedMedia extends React.Component { }); }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.props?.showMessage('error', errorCode); logger( '[CometChatSharedMedia] getMessages getLoggedInUser error', error, @@ -295,7 +300,7 @@ export default class CometChatSharedMedia extends React.Component { style={[ styles.sectionHeaderStyle, { - color: `${currentTheme.color.secondary}`, + color: currentTheme.color.helpText, }, ]}> Shared Media @@ -359,6 +364,7 @@ export default class CometChatSharedMedia extends React.Component { onEndReached={this.getMessages} /> + (this.dropDownAlertRef = ref)} /> ); } diff --git a/src/components/Shared/CometChatSharedMedia/styles.js b/src/components/Shared/CometChatSharedMedia/styles.js index afc68ec..1775471 100644 --- a/src/components/Shared/CometChatSharedMedia/styles.js +++ b/src/components/Shared/CometChatSharedMedia/styles.js @@ -58,6 +58,7 @@ export default StyleSheet.create({ }, mediaItemStyle: { justifyContent: 'center', + flexGrow: 1, }, mediaItemColumnStyle: { justifyContent: 'space-between', diff --git a/src/components/Shared/CometChatUserPresence/index.js b/src/components/Shared/CometChatUserPresence/index.js index f452e5a..3f2aaf5 100644 --- a/src/components/Shared/CometChatUserPresence/index.js +++ b/src/components/Shared/CometChatUserPresence/index.js @@ -19,7 +19,7 @@ const CometChatUserPresence = (props) => { presenceStatus = { backgroundColor: 'rgb(0, 255, 0)', }; - borderWidth = 0; + // borderWidth = 0; } const borderStyle = { @@ -29,7 +29,15 @@ const CometChatUserPresence = (props) => { borderRadius: cornerRadius, }; return ( - + ); }; export default CometChatUserPresence; diff --git a/src/components/Shared/CometChatUserPresence/styles.js b/src/components/Shared/CometChatUserPresence/styles.js index d6d5dbe..8daa312 100644 --- a/src/components/Shared/CometChatUserPresence/styles.js +++ b/src/components/Shared/CometChatUserPresence/styles.js @@ -2,10 +2,12 @@ import { StyleSheet } from 'react-native'; export default StyleSheet.create({ statueIndicatorStyle: { - width: 8, - height: 8, - top: 25, - right: -2, + width: 12, + height: 12, + top: 30, + right: 0, + borderColor: '#fff', + borderWidth: 1, position: 'absolute', }, }); diff --git a/src/components/Shared/DropDownAlert/index.js b/src/components/Shared/DropDownAlert/index.js new file mode 100644 index 0000000..dfbe8ac --- /dev/null +++ b/src/components/Shared/DropDownAlert/index.js @@ -0,0 +1,104 @@ +import React, { Component } from 'react'; + +import { View, Text, Animated, Image, Platform } from 'react-native'; +import theme from '../../../resources/theme'; +import ErrorIcon from './resources/error.png'; +import SuccessIcon from './resources/success.png'; +import CloseIcon from './resources/close.png'; +import styles from './styles'; +import { StatusBar } from 'react-native'; +import { TouchableOpacity } from 'react-native'; + +export default class DropDownAlert extends Component { + constructor(props) { + super(props); + this.state = { + errorText: null, + type: null, + }; + this.animatedY = new Animated.Value(-100); + } + + slideIn = () => { + Animated.timing(this.animatedY, { + duration: 1000, + toValue: 0, + useNativeDriver: true, + }).start(); + }; + + slideOut = () => { + if (this.props.onClose) { + this.props.onClose(); + } + const self = this; + Animated.timing(this.animatedY, { + duration: 1000, + toValue: -100, + useNativeDriver: true, + }).start(() => { + self.setState({ errorText: null, type: null }); + }); + }; + + showMessage = (type = 'error', text = 'Something went wrong') => { + return; + this.setState({ errorText: text, type }, () => { + this.slideIn(); + }); + }; + + render() { + let { type, errorText } = this.state; + + if (!errorText) { + return null; + } + + return ( + <> + + + + + + + + {errorText} + + + this.slideOut()}> + + + + + ); + } +} diff --git a/src/components/Shared/DropDownAlert/resources/close.png b/src/components/Shared/DropDownAlert/resources/close.png new file mode 100644 index 0000000000000000000000000000000000000000..704a4318cc8129f6cd0a8216d047542defe7c108 GIT binary patch literal 659 zcmV;E0&M+>P)P000>X1^@s6#OZ}&00009a7bBm000XU z000XU0RWnu7ytkO0drDELIAGL9O(c600d`2O+f$vv5yP_>i|MbOLOhB!8QF;~NI7gDehu~%COZ}DGtS74q9jP+ zpTb0CVQ0FP1>R&Y6*y3ss4i@EK#5|YENt@Lq=7L??||k5eZ%@bZ3%sB3FcHGuwfd5 zw5%i%J8&fCS|!Mj;8;0&(n}(E;{)-^?<7^7d>$i4h%az;MW^r>L7QIlOTiuOi^4lTAnWixt!%NZIQq7Y{12Et t$Xei9`3dBIFbl}rITiB=yP000>X1^@s6#OZ}&00009a7bBm000XU z000XU0RWnu7ytkO0drDELIAGL9O(c600d`2O+f$vv5yPEE=yGr7AWRG_KW@4axe zFS)Om?~))Kfwi^=WqAdNLw+2w^@0Jvo3q0lh^C163T+{qvrTMSuGp-?7UJKAAa+5z z&Fhv({BeTydeGwQ4_PYvZ10QPCjet+Q04q@Sg}@TtkrUtgj2*z4BcT7h%#~nUbMI| z%-UOwBIFzQ2+in2QQUvWYJ~Qwto)H}rqYLRD%qmAQJ$i%l}0;PXOgZF=nywN?*nqt zo)iC^f)bk=Ac{eck(^|pcF%L4qN0dFj~+oA5cv;6Y*R~)BvZQ+U2@9$yk0{K;6D^$ zjR9xGYQDD!S+Tuut;`!gJ2ah_E1p*$=__6{4ifPv zX<*!apPRqQ%FTKZf*^d{cnV|O#6%y@EyI`(kfzoh5>D-j{Bd>SPD6A7Uf3>>2Hjvo z5{Q=E%(@^-d7p7Lu=XO%_~aL3*RXvy&iEa&JbwygMzMLy{uBFi95`SjnV&bq(5VveFWr|SWH0RvuJ2#aQo#Q*>R07*qoM6N<$f`-uPumAu6 literal 0 HcmV?d00001 diff --git a/src/components/Shared/DropDownAlert/resources/success.png b/src/components/Shared/DropDownAlert/resources/success.png new file mode 100644 index 0000000000000000000000000000000000000000..b7cb2f8a3345c1a1481a76c51713dc2e7201e0df GIT binary patch literal 889 zcmV-<1BU#GP)500001b5ch_0Itp) z=>Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91BcKBS1ONa40RR91BLDyZ0JywErvLx~<4Ht8R9FeUn7wNhK^Vq8qbNoY zl0ZCB38EH~c%(S3MC>hsh5ta*fFc&6VDO{TDpf#i6l)QJMZhkorRicN#ydYSXQ5)i z4+84>dp0-g+}&<=WnZ!!4A*|K7&RJ&uJf( zN~Hzbd<6o%;2L-hd_?wFL2qV81nB{1Km%kE`72IODpEKOfTti&QM>^!LO2YAIw(Tw z1RZuFBtx(aiWJ4~B2=;&VxU_%4~A@gLH#$xt@6ZuGV#}&4n$O3GhoQ*3T~BWrj<8H z6_R0e3LFWv|L>xF${R?qOt8~Fun4xVs&l(GTantzp(FZ7#(P<=@8-^2M3Fax7eHn=hm>lY_ejr5Bvl^vLZ4|4j$n?fbDpM{Q^2IOCa>; zB5aaWOIjvXf0FDs2Gqno`lpE}Or zlNm?o07hT4WO4A-xoISlK&KKz5i05q)rj47fa~PYHpZb3L>H?`=+Y8I`_LrtT{^G-XVyAgMe>A@3Qr&LI*RC%Rp)RFYJ9D P00000NkvXXu0mjfKcjS0 literal 0 HcmV?d00001 diff --git a/src/components/Shared/DropDownAlert/styles.js b/src/components/Shared/DropDownAlert/styles.js new file mode 100644 index 0000000..1f1f303 --- /dev/null +++ b/src/components/Shared/DropDownAlert/styles.js @@ -0,0 +1,43 @@ +import { StyleSheet, Platform, Dimensions } from 'react-native'; +import theme from '../../../resources/theme'; + +export default StyleSheet.create({ + mainContainer: { + bottom: Platform.OS == 'ios' ? '80%' : '85%', + position: 'absolute', + top: 0, + left: 0, + right: 0, + flexDirection: 'row', + elevation: 100, + alignItems: 'center', + paddingTop: Platform.OS === 'ios' ? 40 : 0, + zIndex: 1000, + }, + iconContainer: { + width: '10%', + height: '10%', + justifyContent: 'center', + alignItems: 'center', + }, + actionContainer: { + justifyContent: 'center', + minHeight: '10%', + }, + textContainer: { + width: '80%', + justifyContent: 'center', + alignItems: 'center', + padding: 5, + }, + iconsStyle: { + width: '90%', + aspectRatio: 1, + }, + textStyle: { + fontSize: 14, + // fontFamily: theme.fontFamily, + textAlign: 'center', + color: theme.color.white, + }, +}); diff --git a/src/components/UserProfile/CometChatUserProfile/index.js b/src/components/UserProfile/CometChatUserProfile/index.js index f45f9bf..d868920 100644 --- a/src/components/UserProfile/CometChatUserProfile/index.js +++ b/src/components/UserProfile/CometChatUserProfile/index.js @@ -8,14 +8,20 @@ import theme from '../../../resources/theme'; import Icon from 'react-native-vector-icons/MaterialIcons'; import { logger } from '../../../utils/common'; -const notificationIcon = ; -const privacyIcon = ; -const chatIcon = ; -const helpIcon = ; -const problemIcon = ; +const notificationIcon = ( + +); +const privacyIcon = ( + +); +const chatIcon = ; +const helpIcon = ; +const problemIcon = ( + +); const CometChatUserProfile = (props) => { - const [user, setUser] = useState({ name: '', avatar: null }); + const [user, setUser] = useState({}); const viewTheme = { ...theme, ...props.theme }; /** @@ -39,18 +45,20 @@ const CometChatUserProfile = (props) => { useEffect(() => { getProfile(); }, []); - - const avatar = ( - - - - ); + let avatar = null; + if (user) { + avatar = ( + + + + ); + } return ( @@ -59,12 +67,14 @@ const CometChatUserProfile = (props) => { {avatar} - - - {user.name} + {user?.name ? ( + + + {user?.name} + + Online - Online - + ) : null} diff --git a/src/components/UserProfile/CometChatUserProfile/styles.js b/src/components/UserProfile/CometChatUserProfile/styles.js index 7ad8368..f3f2f77 100644 --- a/src/components/UserProfile/CometChatUserProfile/styles.js +++ b/src/components/UserProfile/CometChatUserProfile/styles.js @@ -1,6 +1,6 @@ import { StyleSheet } from 'react-native'; import { widthRatio, heightRatio } from '../../../utils/consts'; - +import theme from '../../../resources/theme'; export default StyleSheet.create({ userInfoScreenStyle: { flex: 1, @@ -38,7 +38,8 @@ export default StyleSheet.create({ }, userName: { fontSize: 16 * heightRatio, - fontWeight: '700', + color: theme.color.primary, + fontWeight: '500', }, status: { fontWeight: '500', @@ -46,8 +47,8 @@ export default StyleSheet.create({ color: '#349afe', }, avatarStyle: { - width: 36 * widthRatio, - height: 36 * heightRatio, + width: 40, + height: 40, borderColor: 'green', marginTop: 10, }, @@ -56,18 +57,18 @@ export default StyleSheet.create({ width: '100%', }, infoItemHeadingContainer: { - marginLeft: 16 * widthRatio, + marginLeft: 16, marginTop: 8 * heightRatio, }, infoItemHeadingText: { - color: '#cccccc', + color: theme.color.helpText, fontWeight: '500', - fontSize: 16 * heightRatio, + fontSize: 16, }, infoItemsContainer: { borderColor: 'orange', - marginLeft: 32 * widthRatio, + marginLeft: 16, marginTop: 16 * heightRatio, }, infoItem: { @@ -77,9 +78,8 @@ export default StyleSheet.create({ alignItems: 'center', }, infoItemText: { - fontSize: 14 * heightRatio, - fontWeight: '700', - + fontSize: 14, + color: theme.color.primary, marginLeft: 8, }, }); diff --git a/src/components/Users/CometChatUserDetails/index.js b/src/components/Users/CometChatUserDetails/index.js index 06f5772..60458e5 100644 --- a/src/components/Users/CometChatUserDetails/index.js +++ b/src/components/Users/CometChatUserDetails/index.js @@ -7,6 +7,7 @@ import style from './styles'; import BottomSheet from 'reanimated-bottom-sheet'; import * as actions from '../../../utils/actions'; import { deviceHeight } from '../../../utils/consts'; +import DropDownAlert from '../../Shared/DropDownAlert'; export default class CometChatUserDetails extends React.Component { constructor(props) { @@ -71,6 +72,9 @@ export default class CometChatUserDetails extends React.Component { { + this.dropDownAlertRef?.showMessage(type, message); + }} item={this.props.item} type={this.props.type} /> @@ -125,6 +129,7 @@ export default class CometChatUserDetails extends React.Component { }} /> + (this.dropDownAlertRef = ref)} /> ); } diff --git a/src/components/Users/CometChatUserList/index.js b/src/components/Users/CometChatUserList/index.js index 4f9bb92..bcf901f 100644 --- a/src/components/Users/CometChatUserList/index.js +++ b/src/components/Users/CometChatUserList/index.js @@ -22,6 +22,7 @@ import theme from '../../../resources/theme'; import { logger } from '../../../utils/common'; import * as enums from '../../../utils/enums'; import { CometChat } from '@cometchat-pro/react-native-chat'; +import DropDownAlert from '../../Shared/DropDownAlert'; class CometChatUserList extends React.PureComponent { timeout; @@ -208,11 +209,15 @@ class CometChatUserList extends React.PureComponent { this.setState({ userList: [...this.state.userList, ...userList] }); }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); this.decoratorMessage = 'Error'; logger('[CometChatUserList] getUsers fetchNext error', error); }); }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); this.decoratorMessage = 'Error'; logger('[CometChatUserList] getUsers getLoggedInUser error', error); }); @@ -304,11 +309,7 @@ class CometChatUserList extends React.PureComponent { backgroundColor: `${this.theme.backgroundColor.grey}`, }, ]}> - + + (this.dropDownAlertRef = ref)} /> ); diff --git a/src/components/Users/CometChatUserList/styles.js b/src/components/Users/CometChatUserList/styles.js index d0c0081..15fc4bb 100644 --- a/src/components/Users/CometChatUserList/styles.js +++ b/src/components/Users/CometChatUserList/styles.js @@ -9,7 +9,7 @@ export default StyleSheet.create({ }, contactHeaderStyle: { paddingBottom: 14, - paddingHorizontal: 25, + paddingHorizontal: 16, }, contactHeaderCloseStyle: { height: 24, @@ -22,14 +22,14 @@ export default StyleSheet.create({ fontSize: 28, }, contactSearchStyle: { - padding: 4, - marginTop: 10, + padding: 8, + marginTop: 16, flexDirection: 'row', position: 'relative', alignItems: 'center', width: '100%', borderWidth: 0, - borderRadius: 8, + borderRadius: 10, shadowColor: '#000', shadowOffset: { width: 0, @@ -41,17 +41,18 @@ export default StyleSheet.create({ contactSearchInputStyle: { flex: 1, paddingVertical: 4, - marginHorizontal: 8, - fontSize: 15, + marginHorizontal: 2, + fontSize: 17, }, contactMsgStyle: { overflow: 'hidden', - width: '100%', + flex: 1, justifyContent: 'center', alignItems: 'center', }, contactMsgTxtStyle: { margin: 0, + fontSize: 24, fontWeight: '600', }, @@ -68,18 +69,18 @@ export default StyleSheet.create({ paddingHorizontal: 15, }, contactAlphabetTextStyle: { - fontSize: 18, - opacity: 0.4, + fontSize: 13, + opacity: 0.5, }, itemSeparatorStyle: { borderBottomWidth: 1, width: '85%', alignSelf: 'flex-end', - paddingHorizontal: 15, + marginHorizontal: 16, }, headerContainer: { alignItems: 'center', - height: 40, + height: 48, width: '100%', justifyContent: 'center', }, diff --git a/src/components/Users/CometChatUserListItem/index.js b/src/components/Users/CometChatUserListItem/index.js index eebea09..2119402 100644 --- a/src/components/Users/CometChatUserListItem/index.js +++ b/src/components/Users/CometChatUserListItem/index.js @@ -24,8 +24,9 @@ const CometChatUserListItem = (props) => { diff --git a/src/components/Users/CometChatUserListItem/styles.js b/src/components/Users/CometChatUserListItem/styles.js index 7548775..5e7436a 100644 --- a/src/components/Users/CometChatUserListItem/styles.js +++ b/src/components/Users/CometChatUserListItem/styles.js @@ -1,19 +1,19 @@ import { StyleSheet } from 'react-native'; import { widthRatio } from '../../../utils/consts'; - +import theme from '../../../resources/theme'; export default StyleSheet.create({ listItem: { flexDirection: 'row', alignItems: 'center', width: '100%', paddingVertical: 8, - paddingHorizontal: 15, + paddingHorizontal: 16, }, avatarStyle: { flexWrap: 'wrap', flexDirection: 'row', - width: 44, - height: 44, + width: 40, + height: 40, backgroundColor: 'rgba(51,153,255,0.25)', marginRight: 15 * widthRatio, }, @@ -21,5 +21,10 @@ export default StyleSheet.create({ width: '100%', justifyContent: 'center', }, - userNameText: { fontSize: 16, fontWeight: '600', maxWidth: '80%' }, + userNameText: { + fontSize: 16, + fontWeight: '600', + maxWidth: '80%', + color: theme.color.primary, + }, }); diff --git a/src/components/Users/CometChatUserListWithMessages/index.js b/src/components/Users/CometChatUserListWithMessages/index.js index 59cab9e..e4344c6 100644 --- a/src/components/Users/CometChatUserListWithMessages/index.js +++ b/src/components/Users/CometChatUserListWithMessages/index.js @@ -1,6 +1,6 @@ /* eslint-disable react/no-unused-state */ import React from 'react'; -import { SafeAreaView } from 'react-native'; +import { SafeAreaView, View } from 'react-native'; import { CometChat } from '@cometchat-pro/react-native-chat'; import { CometChatOutgoingCall, CometChatIncomingCall } from '../../Calls'; @@ -11,6 +11,7 @@ import theme from '../../../resources/theme'; import * as actions from '../../../utils/actions'; import * as enums from '../../../utils/enums'; import { logger } from '../../../utils/common'; +import DropDownAlert from '../../Shared/DropDownAlert'; class CometChatUserListWithMessages extends React.Component { loggedInUser = null; @@ -111,10 +112,17 @@ class CometChatUserListWithMessages extends React.Component { blockUser = () => { const usersList = [this.state.item.uid]; CometChatManager.blockUsers(usersList) - .then(() => { - this.setState({ item: { ...this.state.item, blockedByMe: true } }); + .then((response) => { + if (response) { + this.dropDownAlertRef?.showMessage('success', 'Blocked user'); + this.setState({ item: { ...this.state.item, blockedByMe: true } }); + } else { + this.dropDownAlertRef?.showMessage('error', 'Failed to block user'); + } }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger('Blocking user fails with error', error); }); }; @@ -126,10 +134,17 @@ class CometChatUserListWithMessages extends React.Component { unblockUser = () => { const usersList = [this.state.item.uid]; CometChatManager.unblockUsers(usersList) - .then(() => { - this.setState({ item: { ...this.state.item, blockedByMe: false } }); + .then((response) => { + if (response) { + this.dropDownAlertRef?.showMessage('success', 'Unblocked user'); + this.setState({ item: { ...this.state.item, blockedByMe: false } }); + } else { + this.dropDownAlertRef?.showMessage('error', 'Failed to unblock user'); + } }) .catch((error) => { + const errorCode = error?.message || 'ERROR'; + this.dropDownAlertRef?.showMessage('error', errorCode); logger('unblocking user fails with error', error); }); }; @@ -363,7 +378,7 @@ class CometChatUserListWithMessages extends React.Component { ); } return ( - + {imageView} { + this.dropDownAlertRef?.showMessage(type, message); + }} theme={this.props.theme} loggedInUser={this.loggedInUser} outgoingCall={this.state.outgoingCall} @@ -389,7 +407,8 @@ class CometChatUserListWithMessages extends React.Component { lang={this.state.lang} actionGenerated={this.actionHandler} /> - + (this.dropDownAlertRef = ref)} /> + ); } } diff --git a/src/resources/theme.js b/src/resources/theme.js index 3cac53f..6dad5e8 100644 --- a/src/resources/theme.js +++ b/src/resources/theme.js @@ -7,7 +7,7 @@ export default { darkSecondary: '#eaeaea', grey: 'rgba(20,20,20,0.04)', helpText: 'rgba(20, 20, 20, 0.6)', - blue: '#39f', + blue: '#3399ff', white: '#fff', red: '#ff3b30', listUnderlayColor: 'rgba(0,0,0,0.22)', @@ -21,7 +21,7 @@ export default { white: '#fff', primary: '#E6E6E6', secondary: '#f6f6f6', - blue: '#39f', + blue: '#3399ff', red: '#ff3b30', grey: 'rgba(20,20,20,0.04)', lightGrey: 'rgba(20, 20, 20, 0.08)', diff --git a/src/utils/actions.js b/src/utils/actions.js index d24108b..615fa18 100644 --- a/src/utils/actions.js +++ b/src/utils/actions.js @@ -10,6 +10,9 @@ export const AUDIO_CALL = 'audioCall'; export const VIDEO_CALL = 'videoCall'; export const CALL_ERROR = 'callError'; export const CALL_ENDED = 'callEnded'; +export const JOIN_DIRECT_CALL = 'joinDirectVideoCall'; +export const DIRECT_CALL_ENDED = 'directCallEnded'; +export const ACCEPT_DIRECT_CALL = 'acceptDirectCall'; export const BLOCK_USER = 'blockUser'; export const UNBLOCK_USER = 'unblockUser'; diff --git a/src/utils/enums.js b/src/utils/enums.js index 2be1191..d009e21 100644 --- a/src/utils/enums.js +++ b/src/utils/enums.js @@ -34,6 +34,7 @@ export const CUSTOM_TYPE_POLL = 'extension_poll'; export const CUSTOM_TYPE_STICKER = 'extension_sticker'; export const CUSTOM_TYPE_DOCUMENT = 'extension_document'; export const CUSTOM_TYPE_WHITEBOARD = 'extension_whiteboard'; +export const CUSTOM_TYPE_MEETING = 'meeting'; export const ACTION_TYPE_GROUPMEMBER = 'groupMember'; export const ACTION_TYPE_MESSAGE = 'message';