From 7de35fd30f0ee313e35beecad17d4b21816b4ec3 Mon Sep 17 00:00:00 2001 From: Priyadarshini Nadar Date: Tue, 26 May 2020 16:49:20 +0530 Subject: [PATCH] v1.0.0 --- CometChat/components/Avatar/index.js | 46 +- CometChat/components/Avatar/style.scss | 81 +- CometChat/components/BadgeCount/index.js | 36 +- CometChat/components/BadgeCount/style.scss | 8 +- CometChat/components/CallMessage/index.js | 61 -- CometChat/components/CallScreen/controller.js | 65 +- CometChat/components/CallScreen/index.js | 449 +++++----- CometChat/components/CallScreen/style.scss | 2 +- CometChat/components/ChatHeader/index.js | 139 --- CometChat/components/ChatWindow/controller.js | 114 --- CometChat/components/ChatWindow/index.js | 237 ----- .../CometChatConversationList/controller.js | 45 +- .../CometChatConversationList/index.js | 188 ++-- .../CometChatConversationListScreen/index.js | 215 ++++- .../CometChatGroupList/controller.js | 81 +- .../components/CometChatGroupList/index.js | 167 ++-- .../CometChatGroupListScreen/index.js | 196 +++- .../ChatHeader/index.js | 57 ++ .../ChatHeader/resources/call-blue-icon.svg | 0 .../resources/details-pane-blue-icon.svg | 0 .../resources/video-call-blue-icon.svg | 0 .../ChatHeader/style.scss | 4 +- .../ChatWindow/CallMessage/index.js | 34 + .../resources/blue-double-tick-icon.png | Bin .../resources/grey-double-tick-icon.png | Bin .../CallMessage/resources/grey-tick-icon.png | Bin .../ChatWindow}/CallMessage/style.scss | 4 +- .../ChatWindow/ReceiverAudioBubble/index.js | 52 ++ .../ReceiverAudioBubble/style.scss | 4 +- .../ChatWindow/ReceiverFileBubble/index.js | 54 ++ .../resources/file-blue.svg | 0 .../ChatWindow}/ReceiverFileBubble/style.scss | 4 +- .../ChatWindow/ReceiverImageBubble/index.js | 49 + .../ReceiverImageBubble/style.scss | 4 +- .../ChatWindow/ReceiverMessageBubble/index.js | 48 + .../ReceiverMessageBubble/style.scss | 4 +- .../ChatWindow/ReceiverVideoBubble/index.js | 52 ++ .../ReceiverVideoBubble/style.scss | 4 +- .../ChatWindow/SenderAudioBubble/index.js | 31 + .../resources/blue-double-tick-icon.png | Bin .../resources/grey-double-tick-icon.png | Bin .../resources/grey-tick-icon.png | Bin .../ChatWindow}/SenderAudioBubble/style.scss | 4 +- .../ChatWindow/SenderFileBubble/index.js | 32 + .../resources/blue-double-tick-icon.png | Bin .../SenderFileBubble}/resources/file-blue.svg | 0 .../resources/grey-double-tick-icon.png | Bin .../resources/grey-tick-icon.png | Bin .../ChatWindow}/SenderFileBubble/style.scss | 4 +- .../ChatWindow/SenderImageBubble/index.js | 30 + .../resources/blue-double-tick-icon.png | Bin .../resources/grey-double-tick-icon.png | Bin .../resources/grey-tick-icon.png | Bin .../ChatWindow}/SenderImageBubble/style.scss | 4 +- .../ChatWindow/SenderMessageBubble/index.js | 31 + .../resources/blue-double-tick-icon.png | Bin .../resources/grey-double-tick-icon.png | Bin .../resources/grey-tick-icon.png | Bin .../SenderMessageBubble/style.scss | 4 +- .../ChatWindow/SenderVideoBubble/index.js | 32 + .../resources/blue-double-tick-icon.png | Bin .../resources/grey-double-tick-icon.png | Bin .../resources/grey-tick-icon.png | Bin .../ChatWindow}/SenderVideoBubble/style.scss | 4 +- .../ChatWindow/controller.js | 57 ++ .../ChatWindow/index.js | 292 ++++++ .../ChatWindow/style.scss | 4 +- .../MessageComposer/index.js | 173 ++++ .../MessageComposer/resources/audio-blue.svg | 0 .../MessageComposer}/resources/file-blue.svg | 0 .../MessageComposer/resources/image-blue.svg | 0 .../resources/rounded-plus-grey-icon.svg | 0 .../resources/send-blue-icon.svg | 0 .../MessageComposer/resources/video-blue.svg | 0 .../MessageComposer/style.scss | 4 +- .../UserProfile/index.js | 38 + .../UserProfile}/resources/call-blue-icon.svg | 0 .../UserProfile}/resources/call-grey-icon.svg | 0 .../UserProfile}/resources/chat-blue-icon.svg | 0 .../UserProfile}/resources/chat-grey-icon.svg | 0 .../resources/group-chat-blue-icon.svg | 0 .../resources/group-chat-grey-icon.svg | 0 .../UserProfile}/resources/more-blue-icon.svg | 0 .../UserProfile}/resources/more-grey-icon.svg | 0 .../resources/people-blue-icon.svg | 0 .../resources/people-grey-icon.svg | 0 .../UserProfile/style.scss | 4 +- .../CometChatMessageScreen/index.js | 102 +-- .../CometChatUnified/NavBar/index.js | 75 ++ .../NavBar}/resources/call-blue-icon.svg | 0 .../NavBar}/resources/call-grey-icon.svg | 0 .../NavBar}/resources/chat-blue-icon.svg | 0 .../NavBar}/resources/chat-grey-icon.svg | 0 .../resources/group-chat-blue-icon.svg | 0 .../resources/group-chat-grey-icon.svg | 0 .../NavBar}/resources/more-blue-icon.svg | 0 .../NavBar}/resources/more-grey-icon.svg | 0 .../NavBar}/resources/people-blue-icon.svg | 0 .../NavBar}/resources/people-grey-icon.svg | 0 .../{ => CometChatUnified}/NavBar/style.scss | 6 +- .../components/CometChatUnified/index.js | 283 +++++- .../CometChatUserInfoScreen/controller.js | 32 - .../CometChatUserInfoScreen/index.js | 188 ++-- .../CometChatUserList/controller.js | 49 +- .../components/CometChatUserList/index.js | 240 +++-- .../CometChatUserListScreen/index.js | 217 ++++- .../components/ConversationView/index.js | 203 +++-- CometChat/components/GroupView/index.js | 61 +- CometChat/components/MessageComposer/index.js | 202 ----- CometChat/components/NavBar/index.js | 85 -- .../components/ReceiverAudioBubble/index.js | 51 -- .../components/ReceiverFileBubble/index.js | 57 -- .../components/ReceiverImageBubble/index.js | 49 - .../components/ReceiverMessageBubble/index.js | 49 - .../components/ReceiverVideoBubble/index.js | 51 -- .../components/SenderAudioBubble/index.js | 51 -- .../components/SenderFileBubble/index.js | 54 -- .../components/SenderImageBubble/index.js | 48 - .../components/SenderMessageBubble/index.js | 52 -- .../components/SenderVideoBubble/index.js | 52 -- CometChat/components/UserProfile/index.js | 95 -- CometChat/components/UserView/index.js | 63 +- CometChat/index.js | 32 +- CometChat/resources/_mixins.scss | 835 ++++++++++++------ CometChat/resources/core.scss | 66 +- CometChat/util/controller.js | 128 +++ CometChat/util/enums.js | 23 + CometChat/util/svgavatar.js | 51 ++ README.md | 3 +- 129 files changed, 3791 insertions(+), 3014 deletions(-) delete mode 100644 CometChat/components/CallMessage/index.js delete mode 100644 CometChat/components/ChatHeader/index.js delete mode 100644 CometChat/components/ChatWindow/controller.js delete mode 100644 CometChat/components/ChatWindow/index.js create mode 100644 CometChat/components/CometChatMessageScreen/ChatHeader/index.js rename CometChat/components/{ => CometChatMessageScreen}/ChatHeader/resources/call-blue-icon.svg (100%) rename CometChat/components/{ => CometChatMessageScreen}/ChatHeader/resources/details-pane-blue-icon.svg (100%) rename CometChat/components/{ => CometChatMessageScreen}/ChatHeader/resources/video-call-blue-icon.svg (100%) rename CometChat/components/{ => CometChatMessageScreen}/ChatHeader/style.scss (94%) create mode 100644 CometChat/components/CometChatMessageScreen/ChatWindow/CallMessage/index.js rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/CallMessage/resources/blue-double-tick-icon.png (100%) rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/CallMessage/resources/grey-double-tick-icon.png (100%) rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/CallMessage/resources/grey-tick-icon.png (100%) rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/CallMessage/style.scss (69%) create mode 100644 CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverAudioBubble/index.js rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/ReceiverAudioBubble/style.scss (88%) create mode 100644 CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverFileBubble/index.js rename CometChat/components/{MessageComposer => CometChatMessageScreen/ChatWindow/ReceiverFileBubble}/resources/file-blue.svg (100%) rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/ReceiverFileBubble/style.scss (91%) create mode 100644 CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverImageBubble/index.js rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/ReceiverImageBubble/style.scss (89%) create mode 100644 CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverMessageBubble/index.js rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/ReceiverMessageBubble/style.scss (89%) create mode 100644 CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverVideoBubble/index.js rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/ReceiverVideoBubble/style.scss (87%) create mode 100644 CometChat/components/CometChatMessageScreen/ChatWindow/SenderAudioBubble/index.js rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/SenderAudioBubble/resources/blue-double-tick-icon.png (100%) rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/SenderAudioBubble/resources/grey-double-tick-icon.png (100%) rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/SenderAudioBubble/resources/grey-tick-icon.png (100%) rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/SenderAudioBubble/style.scss (85%) create mode 100644 CometChat/components/CometChatMessageScreen/ChatWindow/SenderFileBubble/index.js rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/SenderFileBubble/resources/blue-double-tick-icon.png (100%) rename CometChat/components/{ReceiverFileBubble => CometChatMessageScreen/ChatWindow/SenderFileBubble}/resources/file-blue.svg (100%) rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/SenderFileBubble/resources/grey-double-tick-icon.png (100%) rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/SenderFileBubble/resources/grey-tick-icon.png (100%) rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/SenderFileBubble/style.scss (90%) create mode 100644 CometChat/components/CometChatMessageScreen/ChatWindow/SenderImageBubble/index.js rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/SenderImageBubble/resources/blue-double-tick-icon.png (100%) rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/SenderImageBubble/resources/grey-double-tick-icon.png (100%) rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/SenderImageBubble/resources/grey-tick-icon.png (100%) rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/SenderImageBubble/style.scss (87%) create mode 100644 CometChat/components/CometChatMessageScreen/ChatWindow/SenderMessageBubble/index.js rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/SenderMessageBubble/resources/blue-double-tick-icon.png (100%) rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/SenderMessageBubble/resources/grey-double-tick-icon.png (100%) rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/SenderMessageBubble/resources/grey-tick-icon.png (100%) rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/SenderMessageBubble/style.scss (88%) create mode 100644 CometChat/components/CometChatMessageScreen/ChatWindow/SenderVideoBubble/index.js rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/SenderVideoBubble/resources/blue-double-tick-icon.png (100%) rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/SenderVideoBubble/resources/grey-double-tick-icon.png (100%) rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/SenderVideoBubble/resources/grey-tick-icon.png (100%) rename CometChat/components/{ => CometChatMessageScreen/ChatWindow}/SenderVideoBubble/style.scss (87%) create mode 100644 CometChat/components/CometChatMessageScreen/ChatWindow/controller.js create mode 100644 CometChat/components/CometChatMessageScreen/ChatWindow/index.js rename CometChat/components/{ => CometChatMessageScreen}/ChatWindow/style.scss (65%) create mode 100644 CometChat/components/CometChatMessageScreen/MessageComposer/index.js rename CometChat/components/{ => CometChatMessageScreen}/MessageComposer/resources/audio-blue.svg (100%) rename CometChat/components/{SenderFileBubble => CometChatMessageScreen/MessageComposer}/resources/file-blue.svg (100%) rename CometChat/components/{ => CometChatMessageScreen}/MessageComposer/resources/image-blue.svg (100%) rename CometChat/components/{ => CometChatMessageScreen}/MessageComposer/resources/rounded-plus-grey-icon.svg (100%) rename CometChat/components/{ => CometChatMessageScreen}/MessageComposer/resources/send-blue-icon.svg (100%) rename CometChat/components/{ => CometChatMessageScreen}/MessageComposer/resources/video-blue.svg (100%) rename CometChat/components/{ => CometChatMessageScreen}/MessageComposer/style.scss (95%) create mode 100644 CometChat/components/CometChatMessageScreen/UserProfile/index.js rename CometChat/components/{NavBar => CometChatMessageScreen/UserProfile}/resources/call-blue-icon.svg (100%) rename CometChat/components/{NavBar => CometChatMessageScreen/UserProfile}/resources/call-grey-icon.svg (100%) rename CometChat/components/{NavBar => CometChatMessageScreen/UserProfile}/resources/chat-blue-icon.svg (100%) rename CometChat/components/{NavBar => CometChatMessageScreen/UserProfile}/resources/chat-grey-icon.svg (100%) rename CometChat/components/{NavBar => CometChatMessageScreen/UserProfile}/resources/group-chat-blue-icon.svg (100%) rename CometChat/components/{NavBar => CometChatMessageScreen/UserProfile}/resources/group-chat-grey-icon.svg (100%) rename CometChat/components/{NavBar => CometChatMessageScreen/UserProfile}/resources/more-blue-icon.svg (100%) rename CometChat/components/{NavBar => CometChatMessageScreen/UserProfile}/resources/more-grey-icon.svg (100%) rename CometChat/components/{NavBar => CometChatMessageScreen/UserProfile}/resources/people-blue-icon.svg (100%) rename CometChat/components/{NavBar => CometChatMessageScreen/UserProfile}/resources/people-grey-icon.svg (100%) rename CometChat/components/{ => CometChatMessageScreen}/UserProfile/style.scss (94%) create mode 100644 CometChat/components/CometChatUnified/NavBar/index.js rename CometChat/components/{UserProfile => CometChatUnified/NavBar}/resources/call-blue-icon.svg (100%) rename CometChat/components/{UserProfile => CometChatUnified/NavBar}/resources/call-grey-icon.svg (100%) rename CometChat/components/{UserProfile => CometChatUnified/NavBar}/resources/chat-blue-icon.svg (100%) rename CometChat/components/{UserProfile => CometChatUnified/NavBar}/resources/chat-grey-icon.svg (100%) rename CometChat/components/{UserProfile => CometChatUnified/NavBar}/resources/group-chat-blue-icon.svg (100%) rename CometChat/components/{UserProfile => CometChatUnified/NavBar}/resources/group-chat-grey-icon.svg (100%) rename CometChat/components/{UserProfile => CometChatUnified/NavBar}/resources/more-blue-icon.svg (100%) rename CometChat/components/{UserProfile => CometChatUnified/NavBar}/resources/more-grey-icon.svg (100%) rename CometChat/components/{UserProfile => CometChatUnified/NavBar}/resources/people-blue-icon.svg (100%) rename CometChat/components/{UserProfile => CometChatUnified/NavBar}/resources/people-grey-icon.svg (100%) rename CometChat/components/{ => CometChatUnified}/NavBar/style.scss (91%) delete mode 100644 CometChat/components/MessageComposer/index.js delete mode 100644 CometChat/components/NavBar/index.js delete mode 100644 CometChat/components/ReceiverAudioBubble/index.js delete mode 100644 CometChat/components/ReceiverFileBubble/index.js delete mode 100644 CometChat/components/ReceiverImageBubble/index.js delete mode 100644 CometChat/components/ReceiverMessageBubble/index.js delete mode 100644 CometChat/components/ReceiverVideoBubble/index.js delete mode 100644 CometChat/components/SenderAudioBubble/index.js delete mode 100644 CometChat/components/SenderFileBubble/index.js delete mode 100644 CometChat/components/SenderImageBubble/index.js delete mode 100644 CometChat/components/SenderMessageBubble/index.js delete mode 100644 CometChat/components/SenderVideoBubble/index.js delete mode 100644 CometChat/components/UserProfile/index.js create mode 100644 CometChat/util/controller.js create mode 100644 CometChat/util/enums.js create mode 100644 CometChat/util/svgavatar.js diff --git a/CometChat/components/Avatar/index.js b/CometChat/components/Avatar/index.js index 9aed8d7d..3c565590 100644 --- a/CometChat/components/Avatar/index.js +++ b/CometChat/components/Avatar/index.js @@ -1,35 +1,21 @@ import React from "react"; import "./style.scss"; -class Avatar extends React.Component { - constructor(props) { - super(props) - this.state = { - src: "" - } - - } - static getDerivedStateFromProps(props, state) { - return props; - - } - - render() { - return ( - - - {this.state.src.uid ? ((this.state.src.avatar) ? User :
{this.state.src.name.charAt(0)}
) : ((this.state.src.icon) ? Group :
{this.state.src.name.charAt(0)}
)} - -
- - ); - } +const avatar = (props) => { + + const borderWidth = props.borderWidth || '1px'; + const borderColor = props.borderColor || '#AAA'; + const cornerRadius = props.cornerRadius || '50%'; + const image = props.image; + + const getStyle = () => ({borderWidth:borderWidth, borderStyle:'solid',borderColor:borderColor ,'borderRadius': cornerRadius}) + + return ( +
+ Avatar +
+ ); + } - - -export default Avatar; -export const avatar=Avatar; -Avatar.defaultProps = { - src: "" -}; +export default avatar; \ No newline at end of file diff --git a/CometChat/components/Avatar/style.scss b/CometChat/components/Avatar/style.scss index f8384502..94522ea4 100644 --- a/CometChat/components/Avatar/style.scss +++ b/CometChat/components/Avatar/style.scss @@ -1,36 +1,53 @@ -@import '../../resources/mixins'; -@import '../../resources/colors.scss'; +@import "../../resources/mixins"; +@import "../../resources/colors.scss"; -.cp-avatar-wrapper{ - -webkit-box-sizing: border-box; - box-sizing: border-box; - margin: 0; - padding: 0; - list-style: none; - display: inline-block; - text-align: center; - background: #ccc; - color: #fff; - white-space: nowrap; - position: relative; +// .cp-avatar-wrapper { +// -webkit-box-sizing: border-box; +// box-sizing: border-box; +// margin: 0; +// padding: 0; +// list-style: none; +// display: inline-block; +// text-align: center; +// background: #ccc; +// color: #fff; +// white-space: nowrap; +// position: relative; +// overflow: hidden; +// vertical-align: middle; +// width: 32px; +// height: 32px; +// line-height: 32px; +// border-radius: 50%; +// margin-top: 4px; +// } +// .cp-avatar { +// width: 100%; +// height: 100%; +// display: block; + +// background: $gray-lighten; +// } +// .cp-avatar-alternate { +// font-size: 18px; +// font-weight: 600; +// text-transform: capitalize; +// background-color: $blue-background-primary; +// } + +.avatar { + height: 28px; + max-height: 28px; + max-width: 28px; overflow: hidden; - vertical-align: middle; - width: 32px; - height: 32px; - line-height: 32px; - border-radius: 50%; - margin-top: 4px; + min-width: 28px; + min-height: 28px; } -.cp-avatar { - width: 100%; - height: 100%; - display: block; - - background:$gray-lighten; + +.avatar { + img { + max-width: 100%; + max-height: 100%; + min-width: 100%; + } } -.cp-avatar-alternate{ - font-size: 18px; - font-weight: 600; - text-transform: capitalize; - background-color:$blue-background-primary; -} \ No newline at end of file diff --git a/CometChat/components/BadgeCount/index.js b/CometChat/components/BadgeCount/index.js index ee8e9399..6e939069 100644 --- a/CometChat/components/BadgeCount/index.js +++ b/CometChat/components/BadgeCount/index.js @@ -1,36 +1,18 @@ import React from "react"; import "./style.scss"; +const badgecount = (props) => { -class BadgeCount extends React.Component { - constructor(props){ - super(props) - this.state={ - count:"" - } + let count = ""; - } - static getDerivedStateFromProps(props,state){ - return props; - - } - - render() { - return ( - <> - {(this.state.count>0)?
- {((this.state.count)? this.state.count:"")} -
:""} - - + if(props.count) { + count = ( +
+ {props.count} +
); } + return count; } - - -export default BadgeCount; -export const badgeCount=BadgeCount; -BadgeCount.defaultProps = { - src:"" -}; +export default badgecount; \ No newline at end of file diff --git a/CometChat/components/BadgeCount/style.scss b/CometChat/components/BadgeCount/style.scss index ed3a1eb0..8c7b3500 100644 --- a/CometChat/components/BadgeCount/style.scss +++ b/CometChat/components/BadgeCount/style.scss @@ -1,7 +1,7 @@ -@import '../../resources/mixins'; -@import '../../resources/colors.scss'; +@import "../../resources/mixins"; +@import "../../resources/colors.scss"; -.cp-badge-wrapper{ +.cp-badge-wrapper { -webkit-box-sizing: border-box; box-sizing: border-box; margin: 0; @@ -19,7 +19,7 @@ border-radius: 50%; float: right; } -.cp-badge { +.cp-badge { width: 100%; height: 100%; display: block; diff --git a/CometChat/components/CallMessage/index.js b/CometChat/components/CallMessage/index.js deleted file mode 100644 index 792f7d40..00000000 --- a/CometChat/components/CallMessage/index.js +++ /dev/null @@ -1,61 +0,0 @@ -import React from "react"; -import "./style.scss"; -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 { CometChat } from "@cometchat-pro/chat"; - - -class CallMessage extends React.Component { - constructor(props) { - super(props); - this.state = { - } - - } - static getDerivedStateFromProps(props, state) { - return props; - } - printMessage = (message) => { - switch (message.action) { - case CometChat.CALL_STATUS.UNANSWERED: - return

{message.receiver.name + " had missed call from " + message.sender.name}

- break; - case CometChat.CALL_STATUS.REJECTED: - return

{message.sender.name + " had rejected call with " + message.receiver.name}

- break; - case CometChat.CALL_STATUS.ONGOING: - return

{message.sender.name + " had joined the call with " + message.receiver.name}

- break; - case CometChat.CALL_STATUS.INITIATED: - return

{message.sender.name + " had initiated the call with " + message.receiver.name}

- break; - case CometChat.CALL_STATUS.ENDED: - return

{message.sender.name + " ended the call with " + message.receiver.name}

- break; - case CometChat.CALL_STATUS.CANCELLED: - return

{message.sender.name + " rejected the call with " + message.receiver.name}

- break; - - default: - break; - } - } - - render() { - return ( - -
- - {this.printMessage(this.state.message)} - -
- - ); - } -} - - - -export default CallMessage; -export const senderVideoBubble = CallMessage; diff --git a/CometChat/components/CallScreen/controller.js b/CometChat/components/CallScreen/controller.js index 31968bee..8b40f650 100644 --- a/CometChat/components/CallScreen/controller.js +++ b/CometChat/components/CallScreen/controller.js @@ -1,40 +1,37 @@ -import { CometChat } from "@cometchat-pro/chat" +import { CometChat } from "@cometchat-pro/chat"; -export class CometChatManager { +import * as enums from '../../util/enums.js'; - constructor() { +export class CallScreenManager { - } - isUserLogedIn; - logedInUser; - isCometChatUserLogedIn() { - let timerCounter = 10000; - let timer = 0; - return new Promise((resolve, reject) => { - if (timerCounter === timer) reject(); - if (this.logedInUser) { resolve(this.logedInUser); return; } - - this.isUserLogedIn = setInterval(() => { - if (CometChat.isInitialized()) { - CometChat.getLoggedinUser().then(user => { - this.logedInUser = user; - clearInterval(this.isUserLogedIn); - resolve(user); - timer = 0; - }, error => { - console.log(error); - }) - } else { - } - timer = + 100; - }, 100); - }); - } - attachCallListener(callback) { - var listenerID = "UNIQUE_LISTENER_ID"; + callListenerId = new Date().getTime(); + + attachListeners(callback) { + + CometChat.addCallListener( + this.callListenerId, + new CometChat.CallListener({ + onIncomingCallReceived: call => { + callback(enums.INCOMING_CALL_RECEIVED, call); + }, + onOutgoingCallAccepted: call => { + callback(enums.OUTGOING_CALL_ACCEPTED, call); + }, + onOutgoingCallRejected: call => { + console.log("[onOutgoingCallRejected]", call) + callback(enums.OUTGOING_CALL_REJECTED, call); + }, + onIncomingCallCancelled: call => { + callback(enums.INCOMING_CALL_CANCELLED, call); + } + }) + ); } - checkAndSendToCallback(callback, message, isReceipt = false) { - callback(message, isReceipt); - } + + removeListeners() { + + CometChat.removeCallListener(this.callListenerId); + + } } \ No newline at end of file diff --git a/CometChat/components/CallScreen/index.js b/CometChat/components/CallScreen/index.js index c05a1c10..d0e31b1c 100644 --- a/CometChat/components/CallScreen/index.js +++ b/CometChat/components/CallScreen/index.js @@ -1,106 +1,129 @@ import React from "react"; import "./style.scss"; -import SenderMessageBubble from "../SenderMessageBubble"; -import ReceiverMessageBubble from "../ReceiverMessageBubble" -import SenderImageBubble from "../SenderImageBubble" -import ReceiverImageBubble from "../ReceiverImageBubble" -import SenderFileBubble from "../SenderFileBubble" -import ReceiverFileBubble from "../ReceiverFileBubble" -import SenderAudioBubble from "../SenderAudioBubble" -import ReceiverAudioBubble from "../ReceiverAudioBubble" -import SenderVideoBubble from "../SenderVideoBubble" -import ReceiverVideoBubble from "../ReceiverVideoBubble" -import { CometChatManager } from "./controller"; + import { CometChat } from "@cometchat-pro/chat"; -import CallMessage from "../CallMessage"; -import callBlue from "./resources/call-blue-icon.svg"; -import Avatar from "../Avatar"; +import { CometChatManager } from "../../util/controller"; + +import { CallScreenManager } from "./controller"; +import * as enums from '../../util/enums.js'; + +import { SvgAvatar } from '../../util/svgavatar'; + +import Avatar from "../Avatar"; +class CallScreen extends React.PureComponent { -class CallScreen extends React.Component { constructor(props) { super(props); + this.state = { showCallScreen: false, showIncomingScreen: false, showOutgoingScreen: false, - showIframeScreen: false, - actionGenerated: (action, payload) => { - return null; - } + showIframeScreen: false } - this.callScreenElement = React.createRef(); - } + componentDidMount() { - console.log("I am called"); - this.cometChatManager = new CometChatManager(); - - let listenerID = "UNIQUE_LISTENER_ID_CALL_SCREEN"; - - CometChat.addCallListener( - listenerID, - new CometChat.CallListener({ - onIncomingCallReceived: (call) => { - if (!this.state.callIProgress) { - this.setState({ showCallScreen: true, showIncomingScreen: true, callIProgress: call }); - } else { - //TODO reject the call - } - }, - onOutgoingCallAccepted: (call) => { - console.log(call); + this.CallScreenManager = new CallScreenManager(); + this.CallScreenManager.attachListeners(this.callScreenUpdated); + } + + componentDidUpdate(prevProps, prevState) { + + if(prevProps.outgoingCall !== this.props.outgoingCall) { + + this.CallScreenManager.removeListeners(); + this.CallScreenManager = new CallScreenManager(); + this.CallScreenManager.attachListeners(this.callScreenUpdated); + + this.setState({ + showCallScreen: true, + showIncomingScreen: false, + showOutgoingScreen: true, + showIframeScreen: false, + callIProgress: this.props.outgoingCall + }); + } + } + + componentWillUnmount() { + this.CallScreenManager.removeListeners(); + this.CallScreenManager = null; + } + + callScreenUpdated = (key, call) => { + + switch(key) { + + case enums.INCOMING_CALL_RECEIVED://occurs at the callee end + if (!this.state.callIProgress) { this.setState({ - showCallScreen: true, - showIncomingScreen: false, - showOutgoingScreen: false, - showIframeScreen: true, - callIProgress: call + showCallScreen: true, + showIncomingScreen: true, + callIProgress: call }); - CometChat.startCall( - call.getSessionId(), - document.getElementById("cp-call-screen-container"), - new CometChat.OngoingCallListener({ - onUserJoined: user => { - /* Notification received here if another user joins the call. */ - console.log("User joined call:", user); - /* this method can be use to display message or perform any actions if someone joining the call */ - }, - onUserLeft: user => { - /* Notification received here if another user left the call. */ - console.log("User left call:", user); - /* this method can be use to display message or perform any actions if someone leaving the call */ - }, - onCallEnded: call => { - /* Notification received here if current ongoing call is ended. */ - this.setState({ - showCallScreen: false, - showIncomingScreen: false, - showOutgoingScreen: false, - showIframeScreen: false, - callIProgress: undefined - }); - this.props.actionGenerated("callEnded", {}); - /* hiding/closing the call screen can be done here. */ - } - }) - ); + } + this.props.actionGenerated("callStarted", call); + break; + case enums.OUTGOING_CALL_ACCEPTED://occurs at the caller end + this.onCallAccepted(call); + break; + case enums.OUTGOING_CALL_REJECTED://occurs at the caller end, callee rejects the call + this.onCallDismiss(call); + break; + case enums.INCOMING_CALL_CANCELLED://occurs(call dismissed) at the callee end, caller cancels the call + this.onCallDismiss(call); + break; + case enums.CALL_ENDED: + break; + default: + break; + } + + } + + onCallDismiss = (call) => { + this.setState({ + showCallScreen: false, + showIncomingScreen: false, + showOutgoingScreen: false, + showIframeScreen: false, + callIProgress: undefined + }); + this.props.actionGenerated("callEnded", call); + } + + onCallAccepted = (call) => { + + this.setState({ + showCallScreen: true, + showIncomingScreen: false, + showOutgoingScreen: false, + showIframeScreen: true, + callIProgress: call + }); + const el = document.getElementById("cp-call-screen-container"); + CometChat.startCall( + call.getSessionId(), + el, + new CometChat.OngoingCallListener({ + onUserJoined: user => { + /* Notification received here if another user joins the call. */ + //console.log("[CallScreen] onCallAccepted User joined call:", user); + /* this method can be use to display message or perform any actions if someone joining the call */ }, - onOutgoingCallRejected: (call) => { - console.log("here we ate ", call) - this.setState({ - showCallScreen: false, - showIncomingScreen: false, - showOutgoingScreen: false, - showIframeScreen: false, - callIProgress: undefined - }); - this.props.actionGenerated("callEnded", {}); + onUserLeft: user => { + /* Notification received here if another user left the call. */ + //console.log("[CallScreen] onCallAccepted User left call:", user); + /* this method can be use to display message or perform any actions if someone leaving the call */ }, - onIncomingCallCancelled: (call) => { + onCallEnded: call => { + /* Notification received here if current ongoing call is ended. */ + //console.log("[CallScreen] onCallAccepted call ended:", call); this.setState({ showCallScreen: false, showIncomingScreen: false, @@ -108,167 +131,151 @@ class CallScreen extends React.Component { showIframeScreen: false, callIProgress: undefined }); - this.props.actionGenerated("callEnded", {}); + this.props.actionGenerated("callEnded", call); + /* hiding/closing the call screen can be done here. */ } }) - ); + ); } - UNSAFE_componentWillReceiveProps(props) { - if (props.outgoingCall) { - console.log(props, "asfajfhjkaskfaksf aksf kajsf kas "); + //answering incoming call, occurs at the callee end + acceptCall = () => { + + CometChatManager.acceptCall(this.state.callIProgress.sessionId).then(call => { + this.setState({ showCallScreen: true, showIncomingScreen: false, - showOutgoingScreen: true, + showOutgoingScreen: false, + showIframeScreen: true, + }); + + const el = document.getElementById("cp-call-screen-container"); + CometChat.startCall( + call.getSessionId(), + el, + new CometChat.OngoingCallListener({ + onUserJoined: user => { + /* Notification received here if another user joins the call. */ + //console.log("User joined call:", enums.USER_JOINED, user); + /* this method can be use to display message or perform any actions if someone joining the call */ + }, + onUserLeft: user => { + /* Notification received here if another user left the call. */ + //console.log("User left call:", enums.USER_LEFT, user); + /* this method can be use to display message or perform any actions if someone leaving the call */ + }, + onCallEnded: call => { + /* Notification received here if current ongoing call is ended. */ + //console.log("call ended:", enums.CALL_ENDED, call); + this.setState({ + showCallScreen: false, + showIncomingScreen: false, + showOutgoingScreen: false, + showIframeScreen: false, + callIProgress: undefined + }); + this.props.actionGenerated("callEnded", call); + /* hiding/closing the call screen can be done here. */ + } + }) + ); + + }).catch(error => { + console.log("[CallScreen] acceptCall -- error", error); + }); + + } + + //rejecting/cancelling an incoming call, occurs at the callee end + rejectCall = (callStatus) => { + CometChatManager.rejectCall(this.state.callIProgress.sessionId, callStatus).then(call => { + + this.setState({ + showCallScreen: false, + showIncomingScreen: false, + showOutgoingScreen: false, showIframeScreen: false, - callIProgress: props.outgoingCall + callIProgress: undefined }); - } + + this.props.actionGenerated("callEnded", call); + + }).catch(error => { + + this.setState({ + showCallScreen: false, + showIncomingScreen: false, + showOutgoingScreen: false, + showIframeScreen: false, + callIProgress: undefined + }); + + this.props.actionGenerated("callEnded", error); + }); } - // static getDerivedStateFromProps(props, state) { - // if (props.outgoingCall) { - // return { - // showCallScreen: false, - // showIncomingScreen: false, - // showOutgoingScreen: true, - // showIframeScreen: false, - // } - // } - // return null; - // // return props; - - // } + render() { - return (this.state.showCallScreen ?
- {this.state.showIframeScreen ?
-
: null} - {(this.state.showIncomingScreen ?
-
- Calling... -
+ let callScreen = null, iframeScreen, incomingCallScreen, outgoingCallScreen; + if(this.state.showIncomingScreen) { -
- {this.state.callIProgress.sender.name} -
-
- -
+ if(!this.state.callIProgress.sender.getAvatar()) { -
-
{ - CometChat.acceptCall(this.state.callIProgress.sessionId).then(call => { - this.setState({ - showCallScreen: true, - showIncomingScreen: false, - showOutgoingScreen: false, - showIframeScreen: true, - }); - CometChat.startCall( - call.getSessionId(), - document.getElementById("cp-call-screen-container"), - new CometChat.OngoingCallListener({ - onUserJoined: user => { - /* Notification received here if another user joins the call. */ - console.log("User joined call:", user); - /* this method can be use to display message or perform any actions if someone joining the call */ - }, - onUserLeft: user => { - /* Notification received here if another user left the call. */ - console.log("User left call:", user); - /* this method can be use to display message or perform any actions if someone leaving the call */ - }, - onCallEnded: call => { - /* Notification received here if current ongoing call is ended. */ - this.setState({ - showCallScreen: false, - showIncomingScreen: false, - showOutgoingScreen: false, - showIframeScreen: false, - callIProgress: undefined - }); - this.props.actionGenerated("callEnded", {}); - /* hiding/closing the call screen can be done here. */ - } - }) - ); - console.log("callStarted"); - }); - }}> - ACCEPT + const uid = this.state.callIProgress.sender.getUid(); + const char = this.state.callIProgress.sender.getName().charAt(0).toUpperCase(); + + this.state.callIProgress.sender.setAvatar(SvgAvatar.getAvatar(uid, char)); + } + incomingCallScreen = ( +
+
Calling...
+
{this.state.callIProgress.sender.name}
+
+
+
ACCEPT
+
this.rejectCall(CometChat.CALL_STATUS.REJECTED)}>REJECT
-
{ - CometChat.rejectCall(this.state.callIProgress.sessionId, CometChat.CALL_STATUS.REJECTED).then(() => { - this.setState({ - showCallScreen: false, - showIncomingScreen: false, - showOutgoingScreen: false, - showIframeScreen: false, - callIProgress: undefined - - }) - this.props.actionGenerated("callEnded", {}); - }, err => { - this.setState({ - showCallScreen: false, - showIncomingScreen: false, - showOutgoingScreen: false, - showIframeScreen: false, - callIProgress: undefined - }); - this.props.actionGenerated("callEnded", {}); - } - ); - } - }> - REJECT -
+ ); + } -
: null)} - {(this.state.showOutgoingScreen ?
-
- Calling... -
+ if(this.state.showOutgoingScreen) { -
- {this.state.callIProgress.receiver.name} -
-
- -
+ if(!this.state.callIProgress.receiver.getAvatar()) { -
-
{ - CometChat.rejectCall(this.state.callIProgress.sessionId, CometChat.CALL_STATUS.CANCELLED).then(() => { - this.setState({ - showCallScreen: false, - showIncomingScreen: false, - showOutgoingScreen: false, - showIframeScreen: false, - callIProgress: undefined - }); - this.props.actionGenerated("callEnded", {}); - }, err => { - this.setState({ - showCallScreen: false, - showIncomingScreen: false, - showOutgoingScreen: false, - showIframeScreen: false, - callIProgress: undefined - }); - this.props.actionGenerated("callEnded", {}); - }); + const uid = this.state.callIProgress.receiver.getUid(); + const char = this.state.callIProgress.receiver.getName().charAt(0).toUpperCase(); + + this.state.callIProgress.receiver.setAvatar(SvgAvatar.getAvatar(uid, char)); + } - } - }> - CANCEL -
+ outgoingCallScreen = ( +
+
Calling...
+
{this.state.callIProgress.receiver.name}
+
+
+
this.rejectCall(CometChat.CALL_STATUS.CANCELLED)}>CANCEL
+
+ ); + } + + if(this.state.showIframeScreen) { + iframeScreen = (
); + } -
: null)} -
: null) + if(this.state.showCallScreen) { + callScreen = ( +
+ {iframeScreen} + {incomingCallScreen} + {outgoingCallScreen} +
+ ); + } + return callScreen; } } diff --git a/CometChat/components/CallScreen/style.scss b/CometChat/components/CallScreen/style.scss index da8a951e..dcf93413 100644 --- a/CometChat/components/CallScreen/style.scss +++ b/CometChat/components/CallScreen/style.scss @@ -59,4 +59,4 @@ } .m-a { margin: auto; -} +} \ No newline at end of file diff --git a/CometChat/components/ChatHeader/index.js b/CometChat/components/ChatHeader/index.js deleted file mode 100644 index 8ce230da..00000000 --- a/CometChat/components/ChatHeader/index.js +++ /dev/null @@ -1,139 +0,0 @@ -import React from "react"; -import "./style.scss"; -import Avatar from "../Avatar"; -import callBlue from "./resources/call-blue-icon.svg"; -import detailPaneBlue from "./resources/details-pane-blue-icon.svg"; -import videoCallBlue from "./resources/video-call-blue-icon.svg"; -import { CometChat } from "@cometchat-pro/chat"; - -class ChatHeader extends React.Component { - constructor(props) { - super(props); - this.state = { - conversation: {}, - toggleUserProfile: false - } - - } - toggleUserProfile = () => { - this.setState({ - toggleUserProfile: !this.state.toggleUserProfile - }, - this.state.onActionGenerated('toggelProfile', { toggleUserProfile: !this.state.toggleUserProfile }) - ); - - } - makeAudioCall = () => { - - let receiverID; - let callType = CometChat.CALL_TYPE.AUDIO; - let receiverType = CometChat.RECEIVER_TYPE.USER; - - if (this.state.type === 'group') { - receiverID = this.state.item.guid; - receiverType = CometChat.RECEIVER_TYPE.GROUP; - } else { - receiverID = this.state.item.uid; - receiverType = CometChat.RECEIVER_TYPE.USER; - } - - let call = new CometChat.Call(receiverID, callType, receiverType); - - CometChat.initiateCall(call).then( - call => { - console.log("Call initiated successfully:", call); - this.state.onActionGenerated('audioCallInitiated', { call: call }) - }, - error => { - console.log("Call initialization failed with exception:", error); - } - ); - } - makeVideoCall = () => { - let receiverID; - let callType = CometChat.CALL_TYPE.VIDEO; - let receiverType = CometChat.RECEIVER_TYPE.USER; - - if (this.state.type === 'group') { - receiverID = this.state.item.guid; - receiverType = CometChat.RECEIVER_TYPE.GROUP; - } else { - receiverID = this.state.item.uid; - receiverType = CometChat.RECEIVER_TYPE.USER; - } - - let call = new CometChat.Call(receiverID, callType, receiverType); - - CometChat.initiateCall(call).then( - call => { - console.log("Call initiated successfully:", call); - this.state.onActionGenerated('videoCallInitiated', { call }) - }, - error => { - console.log("Call initialization failed with exception:", error); - } - ); - } - static getDerivedStateFromProps(props, state) { - return props; - } - render() { - return ( -
- { - this.state.type === "user" ?
-
- -
-
-
- {(this.state.item ? this.state.item.name : '')}
-
- - - -
-
- {(this.state.item ? this.state.item.status : '')} -
-
-
:
-
- -
-
-
- {(this.state.item ? this.state.item.name : '')}
-
- - - - - -
- - -
- - {(this.state.item ? this.state.item.type : '')} -
-
-
- } - - - - -
- ); - } -} - - - -export default ChatHeader; -export const chatHeader = ChatHeader; - -ChatHeader.defaultProps = { - -}; diff --git a/CometChat/components/ChatWindow/controller.js b/CometChat/components/ChatWindow/controller.js deleted file mode 100644 index 84cc09fd..00000000 --- a/CometChat/components/ChatWindow/controller.js +++ /dev/null @@ -1,114 +0,0 @@ -import { CometChat } from "@cometchat-pro/chat" - -export class CometChatManager { - messagesRequest - item; - type; - constructor(item, type) { - this.item = item; - this.type = type; - if (type === "user") { - const uid = item.uid - this.messagesRequest = new CometChat.MessagesRequestBuilder().setLimit(30).setUID(uid).build(); - } - else if (type === "group") { - const guid = item.guid - this.messagesRequest = new CometChat.MessagesRequestBuilder().setLimit(30).setGUID(guid).build(); - } - } - isUserLogedIn; - logedInUser; - isCometChatUserLogedIn() { - let timerCounter = 10000; - let timer = 0; - return new Promise((resolve, reject) => { - if (timerCounter === timer) reject(); - if (this.logedInUser) { resolve(this.logedInUser); return; } - - this.isUserLogedIn = setInterval(() => { - if (CometChat.isInitialized()) { - CometChat.getLoggedinUser().then(user => { - this.logedInUser = user; - clearInterval(this.isUserLogedIn); - resolve(user); - timer = 0; - }, error => { - console.log(error); - }) - } else { - } - timer = + 100; - }, 100); - }); - } - - fetchPreviousMessages() { - return this.messagesRequest.fetchPrevious(); - } - attachMessageListener(callback) { - var listenerID = "UNIQUE_LISTENER_ID"; - - CometChat.addMessageListener( - listenerID, - new CometChat.MessageListener({ - onTextMessageReceived: textMessage => { - this.checkAndSendToCallback(callback, textMessage); - }, - onMediaMessageReceived: mediaMessage => { - this.checkAndSendToCallback(callback, mediaMessage); - }, - onCustomMessageReceived: customMessage => { - this.checkAndSendToCallback(callback, customMessage); - }, - onMessagesDelivered: messageReceipt => { - this.checkAndSendToCallback(callback, messageReceipt, true); - }, - onMessagesRead: messageReceipt => { - this.checkAndSendToCallback(callback, messageReceipt, true); - } - }) - ); - - CometChat.addCallListener( - listenerID, - new CometChat.CallListener({ - onIncomingCallReceived: (call) => { - console.log(call); - this.checkAndSendToCallback(callback, call); - }, - onOutgoingCallAccepted: (call) => { - this.checkAndSendToCallback(callback, call); - - }, - onOutgoingCallRejected: (call) => { - this.checkAndSendToCallback(callback, call); - - }, - onIncomingCallCancelled: (call) => { - this.checkAndSendToCallback(callback, call); - } - }) - ); - - } - checkAndSendToCallback(callback, message, isReceipt = false) { - if (this.type === 'group') { - if (message.receiver.guid === this.item.guid) { - if (!isReceipt) { - CometChat.markAsRead(message.messageId, message.receiver.guid, 'group'); - } - callback(message, isReceipt); - - } - } else { - if (message.sender.uid === this.item.uid) { - callback(message, isReceipt); - if (!isReceipt) { - CometChat.markAsRead(message.id, message.sender.uid, 'user'); - } - - } - } - - } -} \ No newline at end of file diff --git a/CometChat/components/ChatWindow/index.js b/CometChat/components/ChatWindow/index.js deleted file mode 100644 index 4469ae06..00000000 --- a/CometChat/components/ChatWindow/index.js +++ /dev/null @@ -1,237 +0,0 @@ -import React from "react"; -import "./style.scss"; -import SenderMessageBubble from "../SenderMessageBubble"; -import ReceiverMessageBubble from "../ReceiverMessageBubble" -import SenderImageBubble from "../SenderImageBubble" -import ReceiverImageBubble from "../ReceiverImageBubble" -import SenderFileBubble from "../SenderFileBubble" -import ReceiverFileBubble from "../ReceiverFileBubble" -import SenderAudioBubble from "../SenderAudioBubble" -import ReceiverAudioBubble from "../ReceiverAudioBubble" -import SenderVideoBubble from "../SenderVideoBubble" -import ReceiverVideoBubble from "../ReceiverVideoBubble" -import { CometChatManager } from "./controller"; -import { CometChat } from "@cometchat-pro/chat"; -import CallMessage from "../CallMessage"; - - - -class ChatWindow extends React.Component { - constructor(props) { - super(props); - this.state = { - messageList: [], - onItemClick: null, - item: [], - type: "", - loggedInUser: {} - } - this.getMessagesList = this.getMessagesList.bind(this); - this.handleScroll = this.handleScroll.bind(this); - - this.messagesEnd = React.createRef(); - } - - componentDidMount() { - this.scrollToBottom(); - this.cometChatManager = new CometChatManager(this.props.item, this.props.type); - this.getMessagesList(); - this.cometChatManager.attachMessageListener(this.messageUpdated); - } - scrollToBottom = (scrollHeight = 0) => { - if (this.messagesEnd) { - - this.messagesEnd.scrollTop = (this.messagesEnd.scrollHeight - scrollHeight); - - } - - - } - - componentDidUpdate(prevProps, prevState) { - - if (prevState.inputMessageList !== this.state.inputMessageList) { - this.setState({ messageList: [...this.state.messageList, ...this.state.inputMessageList] }, () => { - this.scrollToBottom(); - }); - - } - - if (prevProps.type === 'user') { - if (prevState.item.uid !== this.state.item.uid) { - this.cometChatManager = new CometChatManager(this.props.item, this.props.type); - this.setState({ messageList: [] }) - this.getMessagesList(); - this.cometChatManager.attachMessageListener(this.messageUpdated); - // this.scrollToBottom(); - } - } else { - if (prevProps.item.guid !== this.props.item.guid) { - - this.cometChatManager = new CometChatManager(this.props.item, this.props.type); - this.setState({ messageList: [] }) - this.getMessagesList(); - this.cometChatManager.attachMessageListener(this.messageUpdated); - } - } - } - static getDerivedStateFromProps(nextProps, prevState) { - - if (nextProps.item !== prevState.item || nextProps.inputMessageList !== prevState.inputMessageList) { - return nextProps; - } else - - return null; - - - } - handleScroll(e) { - const top = Math.round(e.currentTarget.scrollTop) === 0; - if (top) { - this.getMessagesList(); - } - } - - handleClick = (message) => { - this.props.onItemClick(message, 'message'); - } - - messageUpdated = (message, isReceipt) => { - if (isReceipt) { - let messageList = [] - if (message.receiptType === "delivery") { - messageList = this.state.messageList.map(stateMessage => { - if (message.messageId === stateMessage.id) { - stateMessage.deliveredAt = message.deliveredAt; - } - - return stateMessage; - }); - this.setState({ messageList }); - } else { - if (message.receiptType === "read") { - messageList = this.state.messageList.map(stateMessage => { - // if (message.messageId === stateMessage.id) { - if (!stateMessage.readAt) { - stateMessage.readAt = message.readAt; - } - // } - - return stateMessage; - }); - this.setState({ messageList }); - } - } - } - else { - let messageList = [...this.state.messageList, message]; - this.setState({ messageList }); - } - - - this.scrollToBottom(); - } - getMessagesList() { - this.cometChatManager.isCometChatUserLogedIn().then( - user => { - this.cometChatManager.fetchPreviousMessages().then( - (messageList) => { - messageList.map(message => { - if (message.getSender().uid !== user.uid) { - CometChat.markAsRead(message.id, message.getSender().getUid(), 'user'); - } - return true - }); - let scrollHeight = this.messagesEnd.scrollHeight; - this.setState({ messageList: [...messageList, ...this.state.messageList], loggedInUser: user }); - this.scrollToBottom(scrollHeight); - }, - error => { - //TODO Handle the erros in conatct List. - console.error("Handle the erros in conatct List", error); - } - ); - }, - error => { - //TODO Handle the erros in users logedin state. - console.error("Handle the erros in conatct List", error); - } - ); - } - displayMessages() { - if (this.state.messageList.length > 0) { - return this.state.messageList.map((message, key) => { - return ( -
- {this.state.loggedInUser.uid === message.sender.uid ? this.handleSenderMessages(message) : this.handlereceiverMessages(message)} -
- ); - - }); - - } - - - } - handleSenderMessages = (message) => { - switch (message.category) { - case ("message"): { - switch (message.type) { - case ("text"): - return ; - case ("image"): - return ; - case ("file"): - return ; - case ("audio"): - return ; - case ("video"): - return ; - } - } case ("call"): { - - return ; - } - default: - return null; - } - } - handlereceiverMessages = (message) => { - switch (message.category) { - case ("message"): { - switch (message.category, message.type) { - case ("message" && "text"): - return - case ("message" && "image"): - return ; - case ("message" && "file"): - return ; - case ("message" && "audio"): - return ; - case ("message" && "video"): - return ; - default: - return null; - } - } case ("call"): { - return ; - } - } - } - render() { - return ( -
{ this.messagesEnd = el; }} className="cp-chat-window" onScroll={this.handleScroll}> - {this.displayMessages()} -
- ); - } -} - - - -export default ChatWindow; -export const chatWindow = ChatWindow; - -ChatWindow.defaultProps = { - -}; diff --git a/CometChat/components/CometChatConversationList/controller.js b/CometChat/components/CometChatConversationList/controller.js index 4aa0e5b5..a70e9f59 100644 --- a/CometChat/components/CometChatConversationList/controller.js +++ b/CometChat/components/CometChatConversationList/controller.js @@ -1,58 +1,39 @@ import { CometChat } from "@cometchat-pro/chat" -export class CometChatManager { +export class ConversationListManager { + + conversationRequest = null; + conversationListenerId = new Date().getTime(); - conversationRequest constructor() { this.conversationRequest = new CometChat.ConversationsRequestBuilder().setLimit(30).build(); } - isUserLogedIn; - logedInUser; - isCometChatUserLogedIn() { - let timerCounter = 10000; - let timer = 0; - return new Promise((resolve, reject) => { - if (timerCounter === timer) reject(); - this.isUserLogedIn = setInterval(() => { - if (CometChat.isInitialized()) { - CometChat.getLoggedinUser().then(user => { - this.logedInUser = user; - clearInterval(this.isUserLogedIn); - resolve(user); - }, error => { - //TODO do something if user is not loggedIn - }) - } else { - } - timer = + 100; - }, 100); - }); - } fetchNextConversation() { return this.conversationRequest.fetchNext(); } - attachMessageListener(callback) { - var listenerID = "UNIQUE_LISTENER_ID_COVE"; + + attachListeners(callback) { CometChat.addMessageListener( - listenerID, + this.conversationListenerId, new CometChat.MessageListener({ onTextMessageReceived: textMessage => { - this.checkAndSendToCallback(callback, textMessage); + callback(textMessage, false); }, onMediaMessageReceived: mediaMessage => { - this.checkAndSendToCallback(callback, mediaMessage); + callback(mediaMessage, false); }, onCustomMessageReceived: customMessage => { - this.checkAndSendToCallback(callback, customMessage); + callback(customMessage, false); }, }) ); } - checkAndSendToCallback(callback, message, isReceipt = false) { - callback(message, isReceipt); + + removeListeners() { + CometChat.removeMessageListener(this.conversationListenerId); } } \ No newline at end of file diff --git a/CometChat/components/CometChatConversationList/index.js b/CometChat/components/CometChatConversationList/index.js index 649ab143..44660175 100644 --- a/CometChat/components/CometChatConversationList/index.js +++ b/CometChat/components/CometChatConversationList/index.js @@ -1,135 +1,155 @@ import React from "react"; import "./style.scss"; -import ConversationView from "../ConversationView"; -import { CometChatManager } from "./controller"; + import { CometChat } from "@cometchat-pro/chat"; +import { CometChatManager } from "../../util/controller"; +import { ConversationListManager } from "./controller"; +import { SvgAvatar } from '../../util/svgavatar'; + +import ConversationView from "../ConversationView"; class CometChatConversationList extends React.Component { + constructor(props) { + super(props); this.state = { - conversationList: [], + conversationlist: [], onItemClick: null, selectedConversation: undefined } - this.getConversationList = this.getConversationList.bind(this); - this.handleScroll = this.handleScroll.bind(this); - } componentDidMount() { - this.cometChatManager = new CometChatManager(); - this.getConversationList(); - this.cometChatManager.attachMessageListener(this.conversationUpdated); + this.ConversationListManager = new ConversationListManager(); + this.getConversations(); + this.ConversationListManager.attachListeners(this.conversationUpdated); + + } + + componentWillUnmount() { + this.ConversationListManager.removeListeners(); + this.ConversationListManager = null; } + conversationUpdated = (message) => { - let conversationList = this.state.conversationList; - let found = false; - conversationList.map((stateConversation, key) => { - if (stateConversation.conversationId === message.conversationId) { - found = true; - if (this.state.selectedConversation && this.state.selectedConversation.uid === message.sender.uid) { - stateConversation.unreadMessageCount = 0; - } else { - stateConversation.unreadMessageCount++; - } - stateConversation.lastMessage = message; - conversationList.unshift(conversationList.splice(key, 1)[0]); - return true; + + console.log("[CometChatConversationList] conversationUpdated message", message); + let conversationlist = [...this.state.conversationlist]; + let convKey = conversationlist.findIndex((c, k) => c.conversationId === message.conversationId); + let convObj = conversationlist.find((c, k) => c.conversationId === message.conversationId); + console.log("[CometChatConversationList] conversationUpdated convObj", convObj); + if(convObj) { + + if(this.state.selectedConversation && this.state.selectedConversation.getConversationId() === message.getConversationId()) { + convObj.setUnreadMessageCount(0); + } else { + convObj.setUnreadMessageCount(parseInt(convObj.getUnreadMessageCount()) + 1); } - return true; - }); - if (!found) { + + convObj.lastMessage = message; + const conv = conversationlist.splice(convKey, 1); + conversationlist.unshift(conv[0]); + this.setState({ conversationlist: conversationlist}); + + } else { + CometChat.CometChatHelper.getConversationFromMessage(message).then((conv) => { + conv.setUnreadMessageCount(1); - conversationList = [conv, ...conversationList]; - this.setState({ conversationList }); + convObj.lastMessage = message; + conversationlist.unshift(conv); + this.setState({ conversationlist: conversationlist}); + }, error => { console.log('This is an error in converting message to conversation', { error }) - }) - + }); - } else - this.setState({ conversationList }); + } } - handleScroll(e) { + handleScroll = (e) => { + const bottom = Math.round(e.currentTarget.scrollHeight - e.currentTarget.scrollTop) === Math.round(e.currentTarget.clientHeight); - if (bottom) this.getConversationList(); + if (bottom) this.getConversations(); } + + //updating unread message count to zero handleClick = (item, type) => { + + if(!this.props.onItemClick) + return; + this.props.onItemClick(item, type); - let conversationList = this.state.conversationList; + const conversationList = [...this.state.conversationlist]; - conversationList.map((stateConversation, key) => { - if (stateConversation.conversationWith.uid === item.uid) { - stateConversation.unreadMessageCount = 0; - return true; - } - return true; - }); - this.setState({ selectedConversation: item }); + const conversationFound = conversationList.find(conversation => conversation.conversationWith.uid === item.uid); + if(conversationFound) { + conversationFound.unreadMessageCount = 0; + } + + this.setState({ selectedConversation: conversationFound }); } + getConversations = () => { - getConversationList() { - this.cometChatManager.isCometChatUserLogedIn().then( - conversation => { - this.cometChatManager.fetchNextConversation().then( - (conversationList) => { - this.setState({ conversationList: [...this.state.conversationList, ...conversationList] }); - }, - error => { - //TODO Handle the erros in conatct List. - console.error("Handle the erros in conversation List", error); - } - ); - }, - error => { - //TODO Handle the erros in users logedin state. - console.error("Handle the erros in conversation List", error); - } - ); + new CometChatManager().getLoggedInUser().then(conversation => { + + this.ConversationListManager.fetchNextConversation().then(conversationList => { + + conversationList.forEach(conv => conv = this.setAvatar(conv)); + this.setState({ conversationlist: [...this.state.conversationlist, ...conversationList] }); + + }).catch(error => { + console.error("[CometChatConversationList] getConversations fetchNext error", error); + }); + + }).catch(error => { + console.log("[CometChatConversationList] getConversations getLoggedInUser error", error); + }); } - displayConversationList() { - if (this.state.conversationList.length > 0) { - return this.state.conversationList.map((conversation, key) => { - return ( -
this.handleClick(conversation.conversationWith, conversation.conversationType)} key={conversation.conversationId}> - -
+ setAvatar(conversation) { -
- ); + if(conversation.getConversationType() === "user" && !conversation.getConversationWith().getAvatar()) { + + const uid = conversation.getConversationWith().getUid(); + const char = conversation.getConversationWith().getName().charAt(0).toUpperCase(); - }); + conversation.getConversationWith().setAvatar(SvgAvatar.getAvatar(uid, char)); + + } else if(conversation.getConversationType() === "group" && !conversation.getConversationWith().getIcon()) { + + const guid = conversation.getConversationWith().getGuid(); + const char = conversation.getConversationWith().getName().charAt(0).toUpperCase(); + + conversation.getConversationWith().setIcon(SvgAvatar.getAvatar(guid, char)) } } + render() { + + const conversationList = this.state.conversationlist.map((conversation, key) => { + return ( +
this.handleClick(conversation.conversationWith, conversation.conversationType)} key={key}> + +
+
+ ); + + }); + return (

Chats

- {/*

- -

*/}
- - {this.displayConversationList()} + {conversationList}
- ); } } - - -export default CometChatConversationList; -export const cometChatConversationList=CometChatConversationList; - -CometChatConversationList.defaultProps = { - CometChatConversationList: {} -}; +export default CometChatConversationList; \ No newline at end of file diff --git a/CometChat/components/CometChatConversationListScreen/index.js b/CometChat/components/CometChatConversationListScreen/index.js index bf02bb97..a246069f 100644 --- a/CometChat/components/CometChatConversationListScreen/index.js +++ b/CometChat/components/CometChatConversationListScreen/index.js @@ -1,60 +1,219 @@ import React from "react"; import "./style.scss"; -import CometChatMessageScreen from "../CometChatMessageScreen" -import CometChatConversationList from "../CometChatConversationList"; +import { CometChat } from "@cometchat-pro/chat"; + +import { CometChatManager } from "../../util/controller"; +import CometChatConversationList from "../CometChatConversationList"; +import CometChatMessageScreen from "../CometChatMessageScreen"; +import CallScreen from "../CallScreen"; class CometChatConversationListScreen extends React.Component { - constructor(props) { - super(props); - this.state = { - darktheme: false + + state = { + darktheme: false, + item: {}, + type: "", + tab: "conversations", + viewdetail: false, + messageList: [], + outgoingCall: null + } + + changeTheme = (e) => { + + const theme = this.state.darktheme; + this.setState({darktheme: theme}) + } + + onItemClicked = (item, type) => { + + //empty messagelist only if user/group changes + if(type !== this.state.type) { + this.setState({ messageList: [] }); + } + else if(type === "user" && item.uid !== this.state.item.uid) { + this.setState({ messageList: [] }); + } + else if(type === "group" && item.guid !== this.state.item.guid) { + this.setState({ messageList: [] }); + } + + this.setState({ item: {...item}, type, viewdetail: false }) + } + + msgScreenAction = (action, messages) => { + + switch(action) { + case "messageComposed": + case "messageReceived": + this.appendMessage(messages); + break; + case "messageFetched": + this.updateMessageList(messages); + break; + case "audioCall": + this.audioCall(); + break; + case "videoCall": + this.videoCall(); + break; + case "viewDetail": + this.toggleUserDetail( ); + break; + case "blockUser": + this.blockUser( ); + break; + case "unblockUser": + this.unblockUser( ); + break; + default: + break; } } - static getDerivedStateFromProps(props, state) { - return props; + + blockUser = () => { + let usersList = [this.state.item.uid]; + CometChatManager.blockUsers(usersList).then(list => { + + this.setState({item: {...this.state.item, blockedByMe: true}}); + + }).catch(error => { + console.log("Blocking user fails with error", error); + }); } - changeTheme = (e) => { - this.setState({ - darktheme: !this.state.darktheme - }) + unblockUser = () => { + + let usersList = [this.state.item.uid]; + CometChatManager.unblockUsers(usersList).then(list => { + + this.setState({item: {...this.state.item, blockedByMe: false}}); + + }).catch(error => { + console.log("unblocking user fails with error", error); + }); + } + audioCall = () => { + + let receiverID; + let receiverType = CometChat.RECEIVER_TYPE.USER; + let callType = CometChat.CALL_TYPE.AUDIO; + + if (this.state.type === 'group') { + receiverID = this.state.item.guid; + receiverType = CometChat.RECEIVER_TYPE.GROUP; + } else { + receiverID = this.state.item.uid; + receiverType = CometChat.RECEIVER_TYPE.USER; + } + + CometChatManager.audioCall(receiverID, receiverType, callType).then(call => { + + console.log("Call initiated successfully:", call); + this.callScreenAction("callStarted", call); + this.setState({ outgoingCall: call }); + + }).catch(error => { + console.log("Call initialization failed with exception:", error); + }); + + } + + videoCall = () => { + + let receiverID; + let receiverType = CometChat.RECEIVER_TYPE.USER; + let callType = CometChat.CALL_TYPE.VIDEO; + + if (this.state.type === 'group') { + receiverID = this.state.item.guid; + receiverType = CometChat.RECEIVER_TYPE.GROUP; + } else { + receiverID = this.state.item.uid; + receiverType = CometChat.RECEIVER_TYPE.USER; + } + + CometChatManager.videoCall(receiverID, receiverType, callType).then(call => { + + console.log("Call initiated successfully:", call); + this.callScreenAction("callStarted", call); + this.setState({ outgoingCall: call }); + + }).catch(error => { + console.log("Call initialization failed with exception:", error); + }); + + } + + toggleUserDetail = () => { + let viewdetail = !this.state.viewdetail; + this.setState({viewdetail: viewdetail}); + } + + updateMessageList = (message) => { + const messages = [...message, ...this.state.messageList]; + this.setState({ messageList: messages }); + } + + appendMessage = (message) => { + let messages = [...this.state.messageList]; + messages = messages.concat(message); + this.setState({ messageList: messages }); + } + + callScreenAction = (action, call) => { + + switch(action) { + case "callStarted": + case "callEnded": + + if(!call) return; + this.appendMessage(call); + break; + default: + break; + } + } render() { + + let messageScreen = (

Select a chat to start messaging

); + if(Object.keys(this.state.item).length) { + messageScreen = ( + ); + } + return (
- - { - this.setState({ item, type }) - }}> +
- { - this.state.item ? :

Select a chat to start messaging

- - } + {messageScreen}
+
); } } - - -export default CometChatConversationListScreen; -export const cometChatConversationListScreen=CometChatConversationListScreen; - -CometChatConversationListScreen.defaultProps = { - launch: {} -}; +export default CometChatConversationListScreen; \ No newline at end of file diff --git a/CometChat/components/CometChatGroupList/controller.js b/CometChat/components/CometChatGroupList/controller.js index c19b0b10..ba319f0e 100644 --- a/CometChat/components/CometChatGroupList/controller.js +++ b/CometChat/components/CometChatGroupList/controller.js @@ -1,55 +1,58 @@ -import { CometChat } from "@cometchat-pro/chat" +import { CometChat } from "@cometchat-pro/chat"; -export class CometChatManager { +import * as enums from '../../util/enums.js'; + +export class GroupListManager { + + groupRequest = null; + groupListenerId = new Date().getTime(); - groupsRequest constructor(searchKey) { + if (searchKey) { - this.groupsRequest = new CometChat.GroupsRequestBuilder().setLimit(30).setSearchKeyword(searchKey).build(); - } else - this.groupsRequest = new CometChat.GroupsRequestBuilder().setLimit(30).build(); + this.groupRequest = new CometChat.GroupsRequestBuilder().setLimit(30).setSearchKeyword(searchKey).build(); + } else { + this.groupRequest = new CometChat.GroupsRequestBuilder().setLimit(30).build(); + } } - isUserLogedIn; - logedInUser; - isCometChatUserLogedIn() { - let timerCounter = 10000; - let timer = 0; - return new Promise((resolve, reject) => { - if (timerCounter === timer) reject(); - this.isUserLogedIn = setInterval(() => { - if (CometChat.isInitialized()) { - CometChat.getLoggedinUser().then(user => { - this.logedInUser = user; - clearInterval(this.isUserLogedIn); - resolve(user); - }, error => { - //TODO do something if user is not loggedIn - }) - } else { - } - timer = + 100; - }, 100); - }); - } fetchNextGroups() { - return this.groupsRequest.fetchNext(); + return this.groupRequest.fetchNext(); } - attachGroupListener(callback) { - var listenerID = "UNIQUE_LISTENER_ID"; + + attachListeners(callback) { + CometChat.addGroupListener( - listenerID, + this.groupListenerId, new CometChat.GroupListener({ - onUserOnline: onlineUser => { - /* when someuser/friend comes online, user will be received here */ - callback(onlineUser); - }, - onUserOffline: offlineUser => { - /* when someuser/friend went offline, user will be received here */ - callback(offlineUser); + onGroupMemberScopeChanged: (message, changedUser, newScope, oldScope, changedGroup) => { + + }, + onGroupMemberKicked: (message, kickedUser, kickedBy, kickedFrom) => { + + }, + onGroupMemberBanned: (message, bannedUser, bannedBy, bannedFrom) => { + + }, + onGroupMemberUnbanned: (message, unbannedUser, unbannedBy, unbannedFrom) => { + + }, + onMemberAddedToGroup: (message, userAdded, userAddedBy, userAddedIn) => { + + }, + onGroupMemberLeft: (message, leavingUser, group) => { + callback(enums.GROUP_MEMBER_LEFT, message, leavingUser, group); + }, + onGroupMemberJoined: (message, joinedUser, joinedGroup) => { + callback(enums.GROUP_MEMBER_JOINED, message, joinedUser, joinedGroup); } }) ); + + } + + removeListeners() { + CometChat.removeGroupListener(this.groupListenerId); } } \ No newline at end of file diff --git a/CometChat/components/CometChatGroupList/index.js b/CometChat/components/CometChatGroupList/index.js index bfec79c2..f7f102fe 100644 --- a/CometChat/components/CometChatGroupList/index.js +++ b/CometChat/components/CometChatGroupList/index.js @@ -1,38 +1,51 @@ import React from "react"; import "./style.scss"; -import GroupView from "../GroupView"; -import { CometChatManager } from "./controller"; + import { CometChat } from "@cometchat-pro/chat"; +import { CometChatManager } from "../../util/controller"; +import { SvgAvatar } from '../../util/svgavatar'; +import * as enums from '../../util/enums.js'; + +import { GroupListManager } from "./controller"; +import GroupView from "../GroupView"; class CometChatGroupList extends React.Component { timeout; + constructor(props) { + super(props); this.state = { - grouplist: [], - onItemClick: null + grouplist: [] } - this.getGroupsList = this.getGroupsList.bind(this); - this.handleScroll = this.handleScroll.bind(this); } + componentDidMount() { - this.cometChatManager = new CometChatManager(); - this.getGroupsList(); - this.cometChatManager.attachGroupListener(this.groupUpdated); + this.GroupListManager = new GroupListManager(); + this.getGroups(); + this.GroupListManager.attachListeners(this.groupUpdated.bind(this)); + } - // static getDerivedStateFromProps(props,state){ - // return props; - // } - handleScroll(e) { + + componentWillUnmount() { + this.GroupListManager.removeListeners(); + this.GroupListManager = null; + } + + handleScroll = (e) => { const bottom = Math.round(e.currentTarget.scrollHeight - e.currentTarget.scrollTop) === Math.round(e.currentTarget.clientHeight); if (bottom) this.getGroupsList(); } handleClick = (group) => { + + if(!this.props.onItemClick) + return; + if (!group.hasJoined) { let GUID = group.guid; let password = ""; @@ -40,7 +53,7 @@ class CometChatGroupList extends React.Component { CometChat.joinGroup(GUID, groupType, password).then( group => { - + //this.groupUpdated(group); this.props.onItemClick(group, 'group'); }, error => { @@ -53,92 +66,110 @@ class CometChatGroupList extends React.Component { } } + searchGroup = (e) => { + if (this.timeout) { clearTimeout(this.timeout); } + let val = e.target.value; this.timeout = setTimeout(() => { - this.cometChatManager = new CometChatManager(val); - this.setState({ grouplist: [] }, () => { - this.getGroupsList(); - }) + + this.GroupListManager = new GroupListManager(val); + this.setState({ grouplist: [] }, () => this.getGroups()) }, 500) + } + //callback for group listeners + groupUpdated(key, message) { + + //if the group is not the selected group + if(!this.props.item || this.props.item.guid !== message.receiver.guid) + return false; + + switch(key) { + + case enums.GROUP_MEMBER_JOINED: + this.markMessagesRead(message); + this.props.actionGenerated("groupMemberJoined", "group", [message]); + break; + case enums.GROUP_MEMBER_LEFT: + this.markMessagesRead(message); + this.props.actionGenerated("groupMemberLeft", "group", [message]); + break; + default: + break; + } + } - groupUpdated(group) { - let grouplist = this.state.grouplist; - grouplist.map((stateGroup, key) => { - if (stateGroup.uid === group.uid) { - grouplist.splice(key, 1, group); + markMessagesRead = (message) => { - return true; - } - return true; - }); - this.setState({ grouplist }); - } + if (!(message.getReadAt() || message.getReadByMeAt())) { - getGroupsList() { - this.cometChatManager.isCometChatUserLogedIn().then( - group => { - this.cometChatManager.fetchNextGroups().then( - (grouplist) => { - this.setState({ grouplist: [...this.state.grouplist, ...grouplist] }); - }, - error => { - //TODO Handle the erros in conatct List. - console.error("Handle the erros in conatct List", error); - } - ); - }, - error => { - //TODO Handle the erros in users logedin state. - console.error("Handle the erros in conatct List", error); + if (message.getReceiverType() === 'user') { + CometChat.markAsRead(message.getId().toString(), message.getSender().getUid(), message.getReceiverType()); + } else { + CometChat.markAsRead(message.getId().toString(), message.getReceiverId(), message.getReceiverType()); } - ); + } } - displayGroupList() { - if (this.state.grouplist.length > 0) { - return this.state.grouplist.map((group, key) => { + getGroups = () => { + + new CometChatManager().getLoggedInUser().then(group => { + + this.GroupListManager.fetchNextGroups().then(groupList => { - return ( -
this.handleClick(group)} key={group.guid}> - -
+ groupList.forEach(group => group = this.setAvatar(group)); + this.setState({ grouplist: [...this.state.grouplist, ...groupList] }); -
- ); + }).catch(error => { + console.error("[CometChatGroupList] getGroups fetchNextGroups error", error); + }); + + }).catch(error => { + console.log("[CometChatGroupList] getUsers getLoggedInUser error", error); + }); + } - }); + setAvatar(group) { + if(!group.getIcon()) { + + const guid = group.getGuid(); + const char = group.getName().charAt(0).toUpperCase(); + group.setIcon(SvgAvatar.getAvatar(guid, char)) } + } + render() { + + const groups = this.state.grouplist.map((group, key) => { + + return ( +
this.handleClick(group)} key={key}> + +
+
+ ); + + }); + return (

Groups

-
- - {this.displayGroupList()} -
+
{groups}
); } } - - -export default CometChatGroupList; -export const cometChatGroupList=CometChatGroupList; - -CometChatGroupList.defaultProps = { - CometChatGroupList: {} -}; +export default CometChatGroupList; \ No newline at end of file diff --git a/CometChat/components/CometChatGroupListScreen/index.js b/CometChat/components/CometChatGroupListScreen/index.js index df9ba4a6..503be2c0 100644 --- a/CometChat/components/CometChatGroupListScreen/index.js +++ b/CometChat/components/CometChatGroupListScreen/index.js @@ -1,60 +1,192 @@ import React from "react"; import "./style.scss"; -import CometChatMessageScreen from "../CometChatMessageScreen" -import CometChatGroupList from "../CometChatGroupList"; +import { CometChat } from "@cometchat-pro/chat"; + +import { CometChatManager } from "../../util/controller"; + +import CometChatGroupList from "../CometChatGroupList"; +import CometChatMessageScreen from "../CometChatMessageScreen" +import CallScreen from "../CallScreen"; class CometChatGroupListScreen extends React.Component { - constructor(props) { - super(props); - this.state = { - darktheme: false + + state = { + darktheme: false, + item: {}, + type: "group", + tab: "groups", + viewdetail: false, + messageList: [], + outgoingCall: null + } + + changeTheme = (e) => { + + const theme = this.state.darktheme; + this.setState({darktheme: !theme}); + + } + + onItemClicked = (item, type) => { + + //empty messagelist only if user changes + if(item.guid !== this.state.item.guid) { + this.setState({ messageList: [] }); } + this.setState({ item: {...item}, type, viewdetail: false }); } - static getDerivedStateFromProps(props, state) { - return props; + + msgScreenAction = (action, messages) => { + + switch(action) { + case "messageComposed": + case "messageReceived": + this.appendMessage(messages); + break; + case "messageFetched": + this.updateMessageList(messages); + break; + case "audioCall": + this.audioCall(); + break; + case "videoCall": + this.videoCall(); + break; + case "viewDetail": + this.toggleUserDetail(); + break; + default: + break; + } + } - changeTheme = (e) => { - this.setState({ - darktheme: !this.state.darktheme - }) + audioCall = () => { + + let receiverID = this.state.item.guid; + let receiverType = CometChat.RECEIVER_TYPE.GROUP; + let callType = CometChat.CALL_TYPE.AUDIO; + + CometChatManager.audioCall(receiverID, receiverType, callType).then(call => { + + console.log("Call initiated successfully:", call); + this.callScreenAction("callStarted", call); + this.setState({ outgoingCall: call }); + + }).catch(error => { + + console.log("Call initialization failed with exception:", error); + + }); + } + videoCall = () => { + + let receiverID = this.state.item.guid; + let receiverType = CometChat.RECEIVER_TYPE.GROUP; + let callType = CometChat.CALL_TYPE.VIDEO; + + CometChatManager.videoCall(receiverID, receiverType, callType).then(call => { + + console.log("Call initiated successfully:", call); + this.callScreenAction("callStarted", call); + this.setState({ outgoingCall: call }); + + }).catch(error => { + + console.log("Call initialization failed with exception:", error); + + }); + + } + + toggleUserDetail = () => { + let viewdetail = !this.state.viewdetail; + this.setState({viewdetail: viewdetail}); + } + + //listener when messages are fetched from backend + updateMessageList = (message) => { + const messages = [...message, ...this.state.messageList]; + this.setState({ messageList: messages }); + } + + //listener when message is received from composer + appendMessage = (message) => { + let messages = [...this.state.messageList]; + messages = messages.concat(message); + this.setState({ messageList: messages }); + } + + groupScreenAction = (action, type, item) => { + + switch(action) { + case "groupMemberLeft": + this.appendMessage(item); + break; + case "groupMemberJoined": + this.appendMessage(item); + break; + default: + break; + } + } + + callScreenAction = (action, call) => { + + switch(action) { + case "callStarted": + case "callEnded": + + if(!call) return; + this.appendMessage(call); + break; + default: + break; + } + } render() { + + let messageScreen = (

Select a chat to start messaging

); + if(Object.keys(this.state.item).length) { + messageScreen = ( + ); + } + return (
- - { - this.setState({ item, type }) - }}> +
- { - this.state.item ? :

Select a chat to start messaging

- - } - + {messageScreen} +
+
); } } - - -export default CometChatGroupListScreen; -export const cometChatGroupListScreen=CometChatGroupListScreen; - -CometChatGroupListScreen.defaultProps = { - launch: {} -}; +export default CometChatGroupListScreen; \ No newline at end of file diff --git a/CometChat/components/CometChatMessageScreen/ChatHeader/index.js b/CometChat/components/CometChatMessageScreen/ChatHeader/index.js new file mode 100644 index 00000000..017d4e3d --- /dev/null +++ b/CometChat/components/CometChatMessageScreen/ChatHeader/index.js @@ -0,0 +1,57 @@ +import React from "react"; +import "./style.scss"; + +import Avatar from "../../Avatar"; + +import callBlue from "./resources/call-blue-icon.svg"; +import detailPaneBlue from "./resources/details-pane-blue-icon.svg"; +import videoCallBlue from "./resources/video-call-blue-icon.svg"; + +const chatheader = (props) => { + + let status, image; + if(props.type === "user") { + status = props.item.status; + image = props.item.avatar; + } else { + status = props.item.type; + image = props.item.icon; + } + + let callBtns = ( + + + + + ); + + if(props.item.blockedByMe) { + callBtns = ""; + } + + return ( +
+
+
+ +
+
+
{props.item.name}
+
+ {callBtns} + +
+
+ {status} +
+
+
+
+ ) +} + +export default React.memo(chatheader); \ No newline at end of file diff --git a/CometChat/components/ChatHeader/resources/call-blue-icon.svg b/CometChat/components/CometChatMessageScreen/ChatHeader/resources/call-blue-icon.svg similarity index 100% rename from CometChat/components/ChatHeader/resources/call-blue-icon.svg rename to CometChat/components/CometChatMessageScreen/ChatHeader/resources/call-blue-icon.svg diff --git a/CometChat/components/ChatHeader/resources/details-pane-blue-icon.svg b/CometChat/components/CometChatMessageScreen/ChatHeader/resources/details-pane-blue-icon.svg similarity index 100% rename from CometChat/components/ChatHeader/resources/details-pane-blue-icon.svg rename to CometChat/components/CometChatMessageScreen/ChatHeader/resources/details-pane-blue-icon.svg diff --git a/CometChat/components/ChatHeader/resources/video-call-blue-icon.svg b/CometChat/components/CometChatMessageScreen/ChatHeader/resources/video-call-blue-icon.svg similarity index 100% rename from CometChat/components/ChatHeader/resources/video-call-blue-icon.svg rename to CometChat/components/CometChatMessageScreen/ChatHeader/resources/video-call-blue-icon.svg diff --git a/CometChat/components/ChatHeader/style.scss b/CometChat/components/CometChatMessageScreen/ChatHeader/style.scss similarity index 94% rename from CometChat/components/ChatHeader/style.scss rename to CometChat/components/CometChatMessageScreen/ChatHeader/style.scss index 05f24d4c..8f388828 100644 --- a/CometChat/components/ChatHeader/style.scss +++ b/CometChat/components/CometChatMessageScreen/ChatHeader/style.scss @@ -1,5 +1,5 @@ -@import '../../resources/mixins'; -@import '../../resources/colors'; +@import '../../../resources/mixins'; +@import '../../../resources/colors'; .cp-chatheader { padding: 2px; diff --git a/CometChat/components/CometChatMessageScreen/ChatWindow/CallMessage/index.js b/CometChat/components/CometChatMessageScreen/ChatWindow/CallMessage/index.js new file mode 100644 index 00000000..db868fdf --- /dev/null +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/CallMessage/index.js @@ -0,0 +1,34 @@ +import React from "react"; +import "./style.scss"; + +import { CometChat } from "@cometchat-pro/chat"; + +const callmessage = (props) => { + + const getMessage = () => { + + switch (props.message.action) { + + case CometChat.CALL_STATUS.UNANSWERED: + return

{props.message.receiver.name + " had missed call from " + props.message.sender.name}

+ case CometChat.CALL_STATUS.REJECTED: + return

{props.message.sender.name + " had rejected call with " + props.message.receiver.name}

+ case CometChat.CALL_STATUS.ONGOING: + return

{props.message.sender.name + " had joined the call with " + props.message.receiver.name}

+ case CometChat.CALL_STATUS.INITIATED: + return

{props.message.sender.name + " had initiated the call with " + props.message.receiver.name}

+ case CometChat.CALL_STATUS.ENDED: + return

{props.message.sender.name + " ended the call with " + props.message.receiver.name}

+ case CometChat.CALL_STATUS.CANCELLED: + return

{props.message.sender.name + " cancelled the call with " + props.message.receiver.name}

+ default: + break; + } + } + + return ( +
{getMessage()}
+ ) +} + +export default callmessage; \ No newline at end of file diff --git a/CometChat/components/CallMessage/resources/blue-double-tick-icon.png b/CometChat/components/CometChatMessageScreen/ChatWindow/CallMessage/resources/blue-double-tick-icon.png similarity index 100% rename from CometChat/components/CallMessage/resources/blue-double-tick-icon.png rename to CometChat/components/CometChatMessageScreen/ChatWindow/CallMessage/resources/blue-double-tick-icon.png diff --git a/CometChat/components/CallMessage/resources/grey-double-tick-icon.png b/CometChat/components/CometChatMessageScreen/ChatWindow/CallMessage/resources/grey-double-tick-icon.png similarity index 100% rename from CometChat/components/CallMessage/resources/grey-double-tick-icon.png rename to CometChat/components/CometChatMessageScreen/ChatWindow/CallMessage/resources/grey-double-tick-icon.png diff --git a/CometChat/components/CallMessage/resources/grey-tick-icon.png b/CometChat/components/CometChatMessageScreen/ChatWindow/CallMessage/resources/grey-tick-icon.png similarity index 100% rename from CometChat/components/CallMessage/resources/grey-tick-icon.png rename to CometChat/components/CometChatMessageScreen/ChatWindow/CallMessage/resources/grey-tick-icon.png diff --git a/CometChat/components/CallMessage/style.scss b/CometChat/components/CometChatMessageScreen/ChatWindow/CallMessage/style.scss similarity index 69% rename from CometChat/components/CallMessage/style.scss rename to CometChat/components/CometChatMessageScreen/ChatWindow/CallMessage/style.scss index d322e9fc..59a5b4dc 100644 --- a/CometChat/components/CallMessage/style.scss +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/CallMessage/style.scss @@ -1,5 +1,5 @@ -@import "../../resources/mixins"; -@import "../../resources/colors"; +@import "../../../../resources/mixins"; +@import "../../../../resources/colors"; .cp-call-message-container { margin: 10px; diff --git a/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverAudioBubble/index.js b/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverAudioBubble/index.js new file mode 100644 index 00000000..80f154ef --- /dev/null +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverAudioBubble/index.js @@ -0,0 +1,52 @@ +import React from "react"; +import "./style.scss"; + +import { SvgAvatar } from '../../../../util/svgavatar'; + +import Avatar from "../../../Avatar"; + +const receiveraudiobubble = (props) => { + + let avatar = "", name = ""; + if(props.message.receiverType === 'group') { + + if(!props.message.sender.avatar) { + + const uid = props.message.sender.getUid(); + const char = props.message.sender.getName().charAt(0).toUpperCase(); + + props.message.sender.setAvatar(SvgAvatar.getAvatar(uid, char)); + + } + + avatar = ( +
+ +
+ ); + + name = (
{props.message.sender.name}
); + } + + return ( +
+
{avatar}
+
+ {name} +
+ +
+
{new Date(props.message.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })}
+
+
+ ) +} + +export default receiveraudiobubble; \ No newline at end of file diff --git a/CometChat/components/ReceiverAudioBubble/style.scss b/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverAudioBubble/style.scss similarity index 88% rename from CometChat/components/ReceiverAudioBubble/style.scss rename to CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverAudioBubble/style.scss index 5007f073..957296e0 100644 --- a/CometChat/components/ReceiverAudioBubble/style.scss +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverAudioBubble/style.scss @@ -1,5 +1,5 @@ -@import '../../resources/mixins'; -@import '../../resources/colors'; +@import '../../../../resources/mixins'; +@import '../../../../resources/colors'; .cp-receiver-audio-container { diff --git a/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverFileBubble/index.js b/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverFileBubble/index.js new file mode 100644 index 00000000..a89c03e3 --- /dev/null +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverFileBubble/index.js @@ -0,0 +1,54 @@ +import React from "react"; +import "./style.scss"; + +import { SvgAvatar } from '../../../../util/svgavatar'; + +import Avatar from "../../../Avatar"; + +import blueFile from "./resources/file-blue.svg"; + +const receiverfilebubble = (props) => { + + let avatar = "", name = ""; + if(props.message.receiverType === 'group') { + + if(!props.message.sender.avatar) { + + const uid = props.message.sender.getUid(); + const char = props.message.sender.getName().charAt(0).toUpperCase(); + + props.message.sender.setAvatar(SvgAvatar.getAvatar(uid, char)); + + } + + avatar = ( +
+ +
+ ); + + name = (
{props.message.sender.name}
); + } + + return ( +
+
{avatar}
+
+ {name} +
+ +

{props.message.data.attachments[0].extension}

+
+
{new Date(props.message.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })}
+
+
+ ) +} + +export default receiverfilebubble; \ No newline at end of file diff --git a/CometChat/components/MessageComposer/resources/file-blue.svg b/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverFileBubble/resources/file-blue.svg similarity index 100% rename from CometChat/components/MessageComposer/resources/file-blue.svg rename to CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverFileBubble/resources/file-blue.svg diff --git a/CometChat/components/ReceiverFileBubble/style.scss b/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverFileBubble/style.scss similarity index 91% rename from CometChat/components/ReceiverFileBubble/style.scss rename to CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverFileBubble/style.scss index ef22db5f..672a19c8 100644 --- a/CometChat/components/ReceiverFileBubble/style.scss +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverFileBubble/style.scss @@ -1,5 +1,5 @@ -@import '../../resources/mixins'; -@import '../../resources/colors'; +@import '../../../../resources/mixins'; +@import '../../../../resources/colors'; .cp-receiver-file-container { diff --git a/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverImageBubble/index.js b/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverImageBubble/index.js new file mode 100644 index 00000000..ff0edb19 --- /dev/null +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverImageBubble/index.js @@ -0,0 +1,49 @@ +import React from "react"; +import "./style.scss"; + +import { SvgAvatar } from '../../../../util/svgavatar'; + +import Avatar from "../../../Avatar"; + +const revceiverimagebubble = (props) => { + + let avatar = "", name = ""; + if(props.message.receiverType === 'group') { + + if(!props.message.sender.avatar) { + + const uid = props.message.sender.getUid(); + const char = props.message.sender.getName().charAt(0).toUpperCase(); + + props.message.sender.setAvatar(SvgAvatar.getAvatar(uid, char)); + + } + + avatar = ( +
+ +
+ ) + + name = (
{props.message.sender.name}
); + } + + return ( +
+
{avatar}
+
+ {name} +
+ receiver +
+
{new Date(props.message.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })}
+
+
+ ) +} + +export default revceiverimagebubble; \ No newline at end of file diff --git a/CometChat/components/ReceiverImageBubble/style.scss b/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverImageBubble/style.scss similarity index 89% rename from CometChat/components/ReceiverImageBubble/style.scss rename to CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverImageBubble/style.scss index cecb4b07..20badd4a 100644 --- a/CometChat/components/ReceiverImageBubble/style.scss +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverImageBubble/style.scss @@ -1,5 +1,5 @@ -@import '../../resources/mixins'; -@import '../../resources/colors'; +@import '../../../../resources/mixins'; +@import '../../../../resources/colors'; .cp-receiver-image-container { diff --git a/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverMessageBubble/index.js b/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverMessageBubble/index.js new file mode 100644 index 00000000..6a18972e --- /dev/null +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverMessageBubble/index.js @@ -0,0 +1,48 @@ +import React from "react"; +import "./style.scss"; + +import { SvgAvatar } from '../../../../util/svgavatar'; + +import Avatar from "../../../Avatar"; + +const receivermessagebuble = (props) => { + + let avatar = "", name = ""; + if(props.message.receiverType === 'group') { + + if(!props.message.sender.avatar) { + + const uid = props.message.sender.getUid(); + const char = props.message.sender.getName().charAt(0).toUpperCase(); + + props.message.sender.setAvatar(SvgAvatar.getAvatar(uid, char)); + + } + + avatar = ( +
+ +
+ ); + + name = (
{props.message.sender.name}
); + } + + return ( +
+ {avatar} +
+ {name} +
{props.message.text}
+
{new Date(props.message.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })}
+
+
+ ) + +} + +export default receivermessagebuble; \ No newline at end of file diff --git a/CometChat/components/ReceiverMessageBubble/style.scss b/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverMessageBubble/style.scss similarity index 89% rename from CometChat/components/ReceiverMessageBubble/style.scss rename to CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverMessageBubble/style.scss index df2e03ef..8d37407e 100644 --- a/CometChat/components/ReceiverMessageBubble/style.scss +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverMessageBubble/style.scss @@ -1,5 +1,5 @@ -@import '../../resources/mixins'; -@import '../../resources/colors'; +@import '../../../../resources/mixins'; +@import '../../../../resources/colors'; diff --git a/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverVideoBubble/index.js b/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverVideoBubble/index.js new file mode 100644 index 00000000..aca0705c --- /dev/null +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverVideoBubble/index.js @@ -0,0 +1,52 @@ +import React from "react"; +import "./style.scss"; + +import { SvgAvatar } from '../../../../util/svgavatar'; + +import Avatar from "../../../Avatar"; + +const receivervideobubble = (props) => { + + let avatar = "", name = ""; + if(props.message.receiverType === 'group') { + + if(!props.message.sender.avatar) { + + const uid = props.message.sender.getUid(); + const char = props.message.sender.getName().charAt(0).toUpperCase(); + + props.message.sender.setAvatar(SvgAvatar.getAvatar(uid, char)); + + } + + avatar = ( +
+ +
+ ); + + name = (
{props.message.sender.name}
); + } + + return ( +
+
{avatar}
+
+ {name} +
+ +
+
{new Date(props.message.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })}
+
+
+ ) +} + +export default receivervideobubble; \ No newline at end of file diff --git a/CometChat/components/ReceiverVideoBubble/style.scss b/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverVideoBubble/style.scss similarity index 87% rename from CometChat/components/ReceiverVideoBubble/style.scss rename to CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverVideoBubble/style.scss index 98a1c2db..439a0842 100644 --- a/CometChat/components/ReceiverVideoBubble/style.scss +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/ReceiverVideoBubble/style.scss @@ -1,5 +1,5 @@ -@import '../../resources/mixins'; -@import '../../resources/colors'; +@import '../../../../resources/mixins'; +@import '../../../../resources/colors'; .cp-receiver-video-container { diff --git a/CometChat/components/CometChatMessageScreen/ChatWindow/SenderAudioBubble/index.js b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderAudioBubble/index.js new file mode 100644 index 00000000..530c4701 --- /dev/null +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderAudioBubble/index.js @@ -0,0 +1,31 @@ +import React from "react"; +import "./style.scss"; + +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"; + +const senderaudiobubble = (props) => { + + let ticks = blueDoubleTick; + if(props.message.sentAt && !props.message.readAt && !props.message.deliveredAt){ + ticks = greyTick; + }else if(props.message.sentAt && !props.message.readAt && props.message.deliveredAt){ + ticks = greyDoubleTick + } + + return ( +
+
+ +
+
{new Date(props.message.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })} + time +
+
+ ) +} + +export default senderaudiobubble; \ No newline at end of file diff --git a/CometChat/components/SenderAudioBubble/resources/blue-double-tick-icon.png b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderAudioBubble/resources/blue-double-tick-icon.png similarity index 100% rename from CometChat/components/SenderAudioBubble/resources/blue-double-tick-icon.png rename to CometChat/components/CometChatMessageScreen/ChatWindow/SenderAudioBubble/resources/blue-double-tick-icon.png diff --git a/CometChat/components/SenderAudioBubble/resources/grey-double-tick-icon.png b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderAudioBubble/resources/grey-double-tick-icon.png similarity index 100% rename from CometChat/components/SenderAudioBubble/resources/grey-double-tick-icon.png rename to CometChat/components/CometChatMessageScreen/ChatWindow/SenderAudioBubble/resources/grey-double-tick-icon.png diff --git a/CometChat/components/SenderAudioBubble/resources/grey-tick-icon.png b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderAudioBubble/resources/grey-tick-icon.png similarity index 100% rename from CometChat/components/SenderAudioBubble/resources/grey-tick-icon.png rename to CometChat/components/CometChatMessageScreen/ChatWindow/SenderAudioBubble/resources/grey-tick-icon.png diff --git a/CometChat/components/SenderAudioBubble/style.scss b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderAudioBubble/style.scss similarity index 85% rename from CometChat/components/SenderAudioBubble/style.scss rename to CometChat/components/CometChatMessageScreen/ChatWindow/SenderAudioBubble/style.scss index 8cff2c35..bb4a08f3 100644 --- a/CometChat/components/SenderAudioBubble/style.scss +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderAudioBubble/style.scss @@ -1,5 +1,5 @@ -@import '../../resources/mixins'; -@import '../../resources/colors'; +@import '../../../../resources/mixins'; +@import '../../../../resources/colors'; diff --git a/CometChat/components/CometChatMessageScreen/ChatWindow/SenderFileBubble/index.js b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderFileBubble/index.js new file mode 100644 index 00000000..ed24eb5f --- /dev/null +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderFileBubble/index.js @@ -0,0 +1,32 @@ +import React from "react"; +import "./style.scss"; + +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 blueFile from "./resources/file-blue.svg"; + +const senderfilebubble = (props) => { + + let ticks = blueDoubleTick; + if(props.message.sentAt && !props.message.readAt && !props.message.deliveredAt){ + ticks = greyTick; + }else if(props.message.sentAt && !props.message.readAt && props.message.deliveredAt){ + ticks = greyDoubleTick + } + + return ( +
+
+ +

{props.message.data.attachments[0].extension}

+
+
{new Date(props.message.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })} + time
+
+ ) +} + +export default senderfilebubble; \ No newline at end of file diff --git a/CometChat/components/SenderFileBubble/resources/blue-double-tick-icon.png b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderFileBubble/resources/blue-double-tick-icon.png similarity index 100% rename from CometChat/components/SenderFileBubble/resources/blue-double-tick-icon.png rename to CometChat/components/CometChatMessageScreen/ChatWindow/SenderFileBubble/resources/blue-double-tick-icon.png diff --git a/CometChat/components/ReceiverFileBubble/resources/file-blue.svg b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderFileBubble/resources/file-blue.svg similarity index 100% rename from CometChat/components/ReceiverFileBubble/resources/file-blue.svg rename to CometChat/components/CometChatMessageScreen/ChatWindow/SenderFileBubble/resources/file-blue.svg diff --git a/CometChat/components/SenderFileBubble/resources/grey-double-tick-icon.png b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderFileBubble/resources/grey-double-tick-icon.png similarity index 100% rename from CometChat/components/SenderFileBubble/resources/grey-double-tick-icon.png rename to CometChat/components/CometChatMessageScreen/ChatWindow/SenderFileBubble/resources/grey-double-tick-icon.png diff --git a/CometChat/components/SenderFileBubble/resources/grey-tick-icon.png b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderFileBubble/resources/grey-tick-icon.png similarity index 100% rename from CometChat/components/SenderFileBubble/resources/grey-tick-icon.png rename to CometChat/components/CometChatMessageScreen/ChatWindow/SenderFileBubble/resources/grey-tick-icon.png diff --git a/CometChat/components/SenderFileBubble/style.scss b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderFileBubble/style.scss similarity index 90% rename from CometChat/components/SenderFileBubble/style.scss rename to CometChat/components/CometChatMessageScreen/ChatWindow/SenderFileBubble/style.scss index 46e35838..cb0657b9 100644 --- a/CometChat/components/SenderFileBubble/style.scss +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderFileBubble/style.scss @@ -1,5 +1,5 @@ -@import '../../resources/mixins'; -@import '../../resources/colors'; +@import '../../../../resources/mixins'; +@import '../../../../resources/colors'; diff --git a/CometChat/components/CometChatMessageScreen/ChatWindow/SenderImageBubble/index.js b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderImageBubble/index.js new file mode 100644 index 00000000..a3d1023c --- /dev/null +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderImageBubble/index.js @@ -0,0 +1,30 @@ +import React from "react"; +import "./style.scss"; + +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"; + +const senderimagebubble = (props) => { + + let ticks = blueDoubleTick; + if(props.message.sentAt && !props.message.readAt && !props.message.deliveredAt){ + ticks = greyTick; + }else if(props.message.sentAt && !props.message.readAt && props.message.deliveredAt){ + ticks = greyDoubleTick + } + + return ( +
+
+ sender +
+
{new Date(props.message.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })} + time +
+
+ ) + +} + +export default senderimagebubble; \ No newline at end of file diff --git a/CometChat/components/SenderImageBubble/resources/blue-double-tick-icon.png b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderImageBubble/resources/blue-double-tick-icon.png similarity index 100% rename from CometChat/components/SenderImageBubble/resources/blue-double-tick-icon.png rename to CometChat/components/CometChatMessageScreen/ChatWindow/SenderImageBubble/resources/blue-double-tick-icon.png diff --git a/CometChat/components/SenderImageBubble/resources/grey-double-tick-icon.png b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderImageBubble/resources/grey-double-tick-icon.png similarity index 100% rename from CometChat/components/SenderImageBubble/resources/grey-double-tick-icon.png rename to CometChat/components/CometChatMessageScreen/ChatWindow/SenderImageBubble/resources/grey-double-tick-icon.png diff --git a/CometChat/components/SenderImageBubble/resources/grey-tick-icon.png b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderImageBubble/resources/grey-tick-icon.png similarity index 100% rename from CometChat/components/SenderImageBubble/resources/grey-tick-icon.png rename to CometChat/components/CometChatMessageScreen/ChatWindow/SenderImageBubble/resources/grey-tick-icon.png diff --git a/CometChat/components/SenderImageBubble/style.scss b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderImageBubble/style.scss similarity index 87% rename from CometChat/components/SenderImageBubble/style.scss rename to CometChat/components/CometChatMessageScreen/ChatWindow/SenderImageBubble/style.scss index 6295db37..fb4ffcda 100644 --- a/CometChat/components/SenderImageBubble/style.scss +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderImageBubble/style.scss @@ -1,5 +1,5 @@ -@import '../../resources/mixins'; -@import '../../resources/colors'; +@import '../../../../resources/mixins'; +@import '../../../../resources/colors'; diff --git a/CometChat/components/CometChatMessageScreen/ChatWindow/SenderMessageBubble/index.js b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderMessageBubble/index.js new file mode 100644 index 00000000..0ee186bf --- /dev/null +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderMessageBubble/index.js @@ -0,0 +1,31 @@ +import React from "react"; +import "./style.scss"; + +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"; + + +const sendermessagebubble = (props) => { + + let ticks = blueDoubleTick; + if(props.message.sentAt && !props.message.readAt && !props.message.deliveredAt){ + ticks = greyTick; + }else if(props.message.sentAt && !props.message.readAt && props.message.deliveredAt){ + ticks = greyDoubleTick + } + + return ( +
+
{props.message.text}
+
+ {new Date(props.message.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })} + + time + +
+
+ ) +} + +export default sendermessagebubble; \ No newline at end of file diff --git a/CometChat/components/SenderMessageBubble/resources/blue-double-tick-icon.png b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderMessageBubble/resources/blue-double-tick-icon.png similarity index 100% rename from CometChat/components/SenderMessageBubble/resources/blue-double-tick-icon.png rename to CometChat/components/CometChatMessageScreen/ChatWindow/SenderMessageBubble/resources/blue-double-tick-icon.png diff --git a/CometChat/components/SenderMessageBubble/resources/grey-double-tick-icon.png b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderMessageBubble/resources/grey-double-tick-icon.png similarity index 100% rename from CometChat/components/SenderMessageBubble/resources/grey-double-tick-icon.png rename to CometChat/components/CometChatMessageScreen/ChatWindow/SenderMessageBubble/resources/grey-double-tick-icon.png diff --git a/CometChat/components/SenderMessageBubble/resources/grey-tick-icon.png b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderMessageBubble/resources/grey-tick-icon.png similarity index 100% rename from CometChat/components/SenderMessageBubble/resources/grey-tick-icon.png rename to CometChat/components/CometChatMessageScreen/ChatWindow/SenderMessageBubble/resources/grey-tick-icon.png diff --git a/CometChat/components/SenderMessageBubble/style.scss b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderMessageBubble/style.scss similarity index 88% rename from CometChat/components/SenderMessageBubble/style.scss rename to CometChat/components/CometChatMessageScreen/ChatWindow/SenderMessageBubble/style.scss index 3e17d474..2bb9bbb0 100644 --- a/CometChat/components/SenderMessageBubble/style.scss +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderMessageBubble/style.scss @@ -1,5 +1,5 @@ -@import '../../resources/mixins'; -@import '../../resources/colors'; +@import '../../../../resources/mixins'; +@import '../../../../resources/colors'; .cp-sender-message-container{ diff --git a/CometChat/components/CometChatMessageScreen/ChatWindow/SenderVideoBubble/index.js b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderVideoBubble/index.js new file mode 100644 index 00000000..ee15b340 --- /dev/null +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderVideoBubble/index.js @@ -0,0 +1,32 @@ +import React from "react"; +import "./style.scss"; + +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"; + +const sendervideobubble = (props) => { + + let ticks = blueDoubleTick; + if(props.message.sentAt && !props.message.readAt && !props.message.deliveredAt){ + return greyTick; + }else if(props.message.sentAt && !props.message.readAt && props.message.deliveredAt){ + return greyDoubleTick + } + + return ( +
+
+ +
+
{new Date(props.message.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })} + time +
+
+ ) +} + +export default sendervideobubble; \ No newline at end of file diff --git a/CometChat/components/SenderVideoBubble/resources/blue-double-tick-icon.png b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderVideoBubble/resources/blue-double-tick-icon.png similarity index 100% rename from CometChat/components/SenderVideoBubble/resources/blue-double-tick-icon.png rename to CometChat/components/CometChatMessageScreen/ChatWindow/SenderVideoBubble/resources/blue-double-tick-icon.png diff --git a/CometChat/components/SenderVideoBubble/resources/grey-double-tick-icon.png b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderVideoBubble/resources/grey-double-tick-icon.png similarity index 100% rename from CometChat/components/SenderVideoBubble/resources/grey-double-tick-icon.png rename to CometChat/components/CometChatMessageScreen/ChatWindow/SenderVideoBubble/resources/grey-double-tick-icon.png diff --git a/CometChat/components/SenderVideoBubble/resources/grey-tick-icon.png b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderVideoBubble/resources/grey-tick-icon.png similarity index 100% rename from CometChat/components/SenderVideoBubble/resources/grey-tick-icon.png rename to CometChat/components/CometChatMessageScreen/ChatWindow/SenderVideoBubble/resources/grey-tick-icon.png diff --git a/CometChat/components/SenderVideoBubble/style.scss b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderVideoBubble/style.scss similarity index 87% rename from CometChat/components/SenderVideoBubble/style.scss rename to CometChat/components/CometChatMessageScreen/ChatWindow/SenderVideoBubble/style.scss index 26a0d56a..31800846 100644 --- a/CometChat/components/SenderVideoBubble/style.scss +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/SenderVideoBubble/style.scss @@ -1,5 +1,5 @@ -@import '../../resources/mixins'; -@import '../../resources/colors'; +@import '../../../../resources/mixins'; +@import '../../../../resources/colors'; diff --git a/CometChat/components/CometChatMessageScreen/ChatWindow/controller.js b/CometChat/components/CometChatMessageScreen/ChatWindow/controller.js new file mode 100644 index 00000000..f247c479 --- /dev/null +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/controller.js @@ -0,0 +1,57 @@ +import { CometChat } from "@cometchat-pro/chat"; + +import * as enums from '../../../util/enums.js'; + +export class ChatWindowManager { + + item = {}; + type = ""; + messageRequest = null; + msgListenerId = new Date().getTime(); + + constructor(item, type) { + + this.item = item; + this.type = type; + + if (type === "user") { + this.messageRequest = new CometChat.MessagesRequestBuilder().setLimit(30).setUID(item.uid).build(); + } + else if (type === "group") { + this.messageRequest = new CometChat.MessagesRequestBuilder().setLimit(30).setGUID(item.guid).build(); + } + } + + fetchPreviousMessages() { + return this.messageRequest.fetchPrevious(); + } + + attachListeners(callback) { + + CometChat.addMessageListener( + this.msgListenerId, + new CometChat.MessageListener({ + onTextMessageReceived: textMessage => { + callback(enums.TEXT_MESSAGE_RECEIVED, textMessage, false); + }, + onMediaMessageReceived: mediaMessage => { + callback(enums.MEDIA_MESSAGE_RECEIVED, mediaMessage, false); + }, + onCustomMessageReceived: customMessage => { + callback(enums.CUSTOM_MESSAGE_RECEIVED, customMessage, false); + }, + onMessagesDelivered: messageReceipt => { + callback(enums.MESSAGE_DELIVERED, messageReceipt, true); + }, + onMessagesRead: messageReceipt => { + callback(enums.MESSAGE_READ, messageReceipt, true); + } + }) + ); + } + + removeListeners() { + + CometChat.removeMessageListener(this.msgListenerId); + } +} \ No newline at end of file diff --git a/CometChat/components/CometChatMessageScreen/ChatWindow/index.js b/CometChat/components/CometChatMessageScreen/ChatWindow/index.js new file mode 100644 index 00000000..1b567467 --- /dev/null +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/index.js @@ -0,0 +1,292 @@ +import React from "react"; +import "./style.scss"; + +import { CometChat } from "@cometchat-pro/chat"; + +import { CometChatManager } from "../../../util/controller"; +import { ChatWindowManager } from "./controller"; + +import SenderMessageBubble from "./SenderMessageBubble"; +import ReceiverMessageBubble from "./ReceiverMessageBubble"; +import SenderImageBubble from "./SenderImageBubble"; +import ReceiverImageBubble from "./ReceiverImageBubble"; +import SenderFileBubble from "./SenderFileBubble"; +import ReceiverFileBubble from "./ReceiverFileBubble"; +import SenderAudioBubble from "./SenderAudioBubble"; +import ReceiverAudioBubble from "./ReceiverAudioBubble"; +import SenderVideoBubble from "./SenderVideoBubble"; +import ReceiverVideoBubble from "./ReceiverVideoBubble"; + +import CallMessage from "./CallMessage"; + + +class ChatWindow extends React.PureComponent { + loggedInUser = null; + updateScrollBar = true; + lastScrollTop = 0; + + constructor(props) { + + super(props); + this.state = { + onItemClick: null + } + + this.messagesEnd = React.createRef(); + } + + componentDidMount() { + + this.ChatWindowManager = new ChatWindowManager(this.props.item, this.props.type); + this.getMessages(); + this.ChatWindowManager.attachListeners(this.messageUpdated); + + } + + componentDidUpdate(prevProps, prevState) { + + if (this.props.type === 'user' && prevProps.item.uid !== this.props.item.uid) { + + this.updateScrollBar = true; + this.ChatWindowManager.removeListeners(); + this.ChatWindowManager = new ChatWindowManager(this.props.item, this.props.type); + this.getMessages(); + this.ChatWindowManager.attachListeners(this.messageUpdated); + + } else if (this.props.type === 'group' && prevProps.item.guid !== this.props.item.guid){ + + this.updateScrollBar = true; + this.ChatWindowManager.removeListeners(); + this.ChatWindowManager = new ChatWindowManager(this.props.item, this.props.type); + this.getMessages(); + this.ChatWindowManager.attachListeners(this.messageUpdated); + + } else if (prevProps.messages !== this.props.messages) { + + if(this.updateScrollBar) { + this.scrollToBottom(); + } else { + this.scrollToBottom(this.lastScrollTop); + } + + } + } + + scrollToBottom = (scrollHeight = 0) => { + + if (this.messagesEnd) { + this.messagesEnd.scrollTop = (this.messagesEnd.scrollHeight - scrollHeight); + } + } + + getMessages = () => { + + new CometChatManager().getLoggedInUser().then((user) => { + + this.ChatWindowManager.fetchPreviousMessages().then((messageList) => { + + messageList.forEach((message) => { + + //if the sender of the message is not the loggedin user, mark it as read. + if (message.getSender().uid !== user.uid) { + CometChat.markAsRead(message.id, message.getSender().getUid(), 'user'); + } + + }); + + this.loggedInUser = user; + this.lastScrollTop = this.messagesEnd.scrollHeight; + this.props.actionGenerated("messageFetched", messageList); + + }).catch((error) => { + //TODO Handle the erros in contact list. + console.error("[ChatWindow] getMessages fetchPrevious error", error); + }); + + }).catch((error) => { + console.log("[ChatWindow] getMessages getLoggedInUser error", error); + }); + + } + + //callback for listener functions + messageUpdated = (key, message, isReceipt) => { + + if (this.props.type === 'group' + && message.receiverType === 'group' + && message.receiver.guid === this.props.item.guid + && !isReceipt) { + + CometChat.markAsRead(message.messageId, message.receiver.guid, 'group'); + this.props.actionGenerated("messageReceived", [message]); + this.scrollToBottom(); + + } else if (this.props.type === 'user' + && message.receiverType === 'user' + && message.sender.uid === this.props.item.uid + && !isReceipt) { + + CometChat.markAsRead(message.id, message.sender.uid, 'user'); + this.props.actionGenerated("messageReceived", [message]); + this.scrollToBottom(); + } + + if (isReceipt) { + + let messageList = [...this.props.messages]; + if (message.receiptType === "delivery") { + + //search for same message + let msg = messageList.find((m, k) => m.id === message.messageId); + + //if found, update state + if(msg) { + msg.deliveredAt = message.deliveredAt; + this.props.actionGenerated("messageFetched", messageList); + } + + } else if (message.receiptType === "read") { + + //search for same message + let msg = messageList.find((m, k) => m.id === message.messageId); + //if found, update state + if(msg && !msg.readAt) { + msg.readAt = message.readAt; + this.props.actionGenerated("messageFetched", messageList); + } + } + } + } + + handleScroll = (e) => { + + const top = Math.round(e.currentTarget.scrollTop) === 0; + if (top && this.props.messages.length) { + this.updateScrollBar = false; + this.getMessages(); + } + } + + handleClick = (message) => { + this.props.onItemClick(message, 'message'); + } + + messageComponentforSender = (message) => { + + let component; + switch (message.type) { + case CometChat.MESSAGE_TYPE.TEXT: + component = (); + break; + case CometChat.MESSAGE_TYPE.IMAGE: + component = (); + break; + case CometChat.MESSAGE_TYPE.FILE: + component = (); + break; + case CometChat.MESSAGE_TYPE.VIDEO: + component = (); + break; + case CometChat.MESSAGE_TYPE.AUDIO: + component = (); + break; + default: + break; + } + + return component; + } + + messageComponentforReceiver = (message) => { + + let component; + switch (message.type) { + case "message": + case CometChat.MESSAGE_TYPE.TEXT: + component = (); + break; + case CometChat.MESSAGE_TYPE.IMAGE: + component = (); + break; + case CometChat.MESSAGE_TYPE.FILE: + component = (); + break; + case CometChat.MESSAGE_TYPE.AUDIO: + component = (); + break; + case CometChat.MESSAGE_TYPE.VIDEO: + component = (); + break; + default: + break; + } + return component; + } + + getComponent = (message) => { + + let component; + + if(this.loggedInUser.uid === message.sender.uid) { + + switch(message.category) { + case "message": + component = this.messageComponentforSender(message); + break; + case "call": + component = (); + break; + case "action": + component = (

{message.message}

); + break; + default: + break; + } + + } else { + + switch(message.category) { + case "message": + component = this.messageComponentforReceiver(message); + break; + case "call": + component = (); + break; + case "action": + component = (

{message.message}

); + break; + default: + break; + } + + } + + return component; + } + + render() { + + let messages; + messages = this.props.messages.map((message, key) => { + return ( +
+ {this.getComponent(message)} +
+ ); + }); + + return ( +
{ this.messagesEnd = el; }} className="cp-chat-window" onScroll={this.handleScroll}> + {messages} +
+ ); + } + + componentWillUnmount() { + this.ChatWindowManager.removeListeners(); + this.ChatWindowManager = null; + } +} + + +export default ChatWindow; \ No newline at end of file diff --git a/CometChat/components/ChatWindow/style.scss b/CometChat/components/CometChatMessageScreen/ChatWindow/style.scss similarity index 65% rename from CometChat/components/ChatWindow/style.scss rename to CometChat/components/CometChatMessageScreen/ChatWindow/style.scss index 50dc06c4..c85f8840 100644 --- a/CometChat/components/ChatWindow/style.scss +++ b/CometChat/components/CometChatMessageScreen/ChatWindow/style.scss @@ -1,5 +1,5 @@ -@import '../../resources/mixins'; -@import '../../resources/colors'; +@import '../../../resources/mixins'; +@import '../../../resources/colors'; .cp-chat-window { diff --git a/CometChat/components/CometChatMessageScreen/MessageComposer/index.js b/CometChat/components/CometChatMessageScreen/MessageComposer/index.js new file mode 100644 index 00000000..96bff484 --- /dev/null +++ b/CometChat/components/CometChatMessageScreen/MessageComposer/index.js @@ -0,0 +1,173 @@ +import React from "react"; +import "./style.scss"; + +import { CometChat } from "@cometchat-pro/chat" + +import roundedPlus from "./resources/rounded-plus-grey-icon.svg"; +import sendBlue from "./resources/send-blue-icon.svg"; +import imageUpload from "./resources/image-blue.svg"; +import audioUpload from "./resources/audio-blue.svg"; +import videoUpload from "./resources/video-blue.svg"; +import fileUpload from "./resources/file-blue.svg"; + +class MessageComposer extends React.PureComponent { + + state = { + showMediaComposer: false, + messageTxt: "" + } + + changeHandler = (e) => { + this.setState({messageTxt: e.target.value}); + } + + browseMediaMessage = () => { + const currentState = !this.state.showMediaComposer; + this.setState({ showMediaComposer: currentState }); + } + + openFileDialogue = (fileType) => { + + switch (fileType) { + case "image": + this.refs.imageUploader.click(); + break; + case "file": + this.refs.fileUploader.click(); + break; + case "audio": + this.refs.audioUploader.click(); + break; + case "video": + this.refs.videoUploader.click(); + break; + default: + break; + } + } + + onImageChange = (e, messageType) => { + this.sendMediaMessage(e, messageType); + } + + onFileChange = (e, messageType) => { + this.sendMediaMessage(e, messageType) + } + + onAudioChange = (e, messageType) => { + this.sendMediaMessage(e, messageType) + } + + onVideoChange = (e, messageType) => { + this.sendMediaMessage(e, messageType) + } + + sendMediaMessage = (e,messageType) => { + + if(!e.target.files[0]) + return false; + + this.browseMediaMessage(); + + let receiverID = this.props.item.guid; + let receiverType = "group"; + + if (this.props.type === "user") { + receiverID = this.props.item.uid; + receiverType = "user"; + } + + let textMessage = new CometChat.MediaMessage(receiverID, e.target.files[0], messageType, receiverType); + CometChat.sendMessage(textMessage).then( + message => { + + this.props.actionGenerated("messageComposed", [message]) + }, + error => { + console.log("Message sending failed with error:", error); + } + ); + } + + sendMessageOnEnter = (e) => { + + if(e.key !== 'Enter') + return false; + + this.sendTextMessage(); + } + + sendTextMessage = () => { + + if(!this.state.messageTxt.trim().length) { + return false; + } + + let receiverID = this.props.item.guid; + if (this.props.type === "user") { + receiverID = this.props.item.uid; + } + + let receiverType = this.props.type; + let messageText = this.state.messageTxt.trim(); + let textMessage = new CometChat.TextMessage(receiverID, messageText, receiverType); + CometChat.sendMessage(textMessage).then( + message => { + this.setState({messageTxt: ""}) + this.props.actionGenerated("messageComposed", [message]); + }, + error => { + console.log("Message sending failed with error:", error); + } + ); + } + + render() { + + let disabled = false; + if(this.props.item.blockedByMe) { + disabled = true; + } + + return ( +
+
+ +
+
+ + + + +
+ +
+ +
+
+ ); + } +} + +export default MessageComposer; \ No newline at end of file diff --git a/CometChat/components/MessageComposer/resources/audio-blue.svg b/CometChat/components/CometChatMessageScreen/MessageComposer/resources/audio-blue.svg similarity index 100% rename from CometChat/components/MessageComposer/resources/audio-blue.svg rename to CometChat/components/CometChatMessageScreen/MessageComposer/resources/audio-blue.svg diff --git a/CometChat/components/SenderFileBubble/resources/file-blue.svg b/CometChat/components/CometChatMessageScreen/MessageComposer/resources/file-blue.svg similarity index 100% rename from CometChat/components/SenderFileBubble/resources/file-blue.svg rename to CometChat/components/CometChatMessageScreen/MessageComposer/resources/file-blue.svg diff --git a/CometChat/components/MessageComposer/resources/image-blue.svg b/CometChat/components/CometChatMessageScreen/MessageComposer/resources/image-blue.svg similarity index 100% rename from CometChat/components/MessageComposer/resources/image-blue.svg rename to CometChat/components/CometChatMessageScreen/MessageComposer/resources/image-blue.svg diff --git a/CometChat/components/MessageComposer/resources/rounded-plus-grey-icon.svg b/CometChat/components/CometChatMessageScreen/MessageComposer/resources/rounded-plus-grey-icon.svg similarity index 100% rename from CometChat/components/MessageComposer/resources/rounded-plus-grey-icon.svg rename to CometChat/components/CometChatMessageScreen/MessageComposer/resources/rounded-plus-grey-icon.svg diff --git a/CometChat/components/MessageComposer/resources/send-blue-icon.svg b/CometChat/components/CometChatMessageScreen/MessageComposer/resources/send-blue-icon.svg similarity index 100% rename from CometChat/components/MessageComposer/resources/send-blue-icon.svg rename to CometChat/components/CometChatMessageScreen/MessageComposer/resources/send-blue-icon.svg diff --git a/CometChat/components/MessageComposer/resources/video-blue.svg b/CometChat/components/CometChatMessageScreen/MessageComposer/resources/video-blue.svg similarity index 100% rename from CometChat/components/MessageComposer/resources/video-blue.svg rename to CometChat/components/CometChatMessageScreen/MessageComposer/resources/video-blue.svg diff --git a/CometChat/components/MessageComposer/style.scss b/CometChat/components/CometChatMessageScreen/MessageComposer/style.scss similarity index 95% rename from CometChat/components/MessageComposer/style.scss rename to CometChat/components/CometChatMessageScreen/MessageComposer/style.scss index ba26dc29..e093456f 100644 --- a/CometChat/components/MessageComposer/style.scss +++ b/CometChat/components/CometChatMessageScreen/MessageComposer/style.scss @@ -1,5 +1,5 @@ -@import '../../resources/mixins'; -@import '../../resources/colors'; +@import '../../../resources/mixins'; +@import '../../../resources/colors'; .cp-message-composer { .cp-show-media{ diff --git a/CometChat/components/CometChatMessageScreen/UserProfile/index.js b/CometChat/components/CometChatMessageScreen/UserProfile/index.js new file mode 100644 index 00000000..c7e78a6b --- /dev/null +++ b/CometChat/components/CometChatMessageScreen/UserProfile/index.js @@ -0,0 +1,38 @@ +import React from "react"; +import "./style.scss"; + +const userprofile = (props) => { + + let txtDisplay; + + if(props.item.blockedByMe) { + txtDisplay = (); + } else { + txtDisplay = (); + } + + return ( + +
+

Details

+
+
Notifications
+
+ +
+

Privacy and Support

+
+
+ { + props.type === 'user' ?
{txtDisplay}
: "" + } +
+
+
+
+ + ); + +} + +export default React.memo(userprofile); \ No newline at end of file diff --git a/CometChat/components/NavBar/resources/call-blue-icon.svg b/CometChat/components/CometChatMessageScreen/UserProfile/resources/call-blue-icon.svg similarity index 100% rename from CometChat/components/NavBar/resources/call-blue-icon.svg rename to CometChat/components/CometChatMessageScreen/UserProfile/resources/call-blue-icon.svg diff --git a/CometChat/components/NavBar/resources/call-grey-icon.svg b/CometChat/components/CometChatMessageScreen/UserProfile/resources/call-grey-icon.svg similarity index 100% rename from CometChat/components/NavBar/resources/call-grey-icon.svg rename to CometChat/components/CometChatMessageScreen/UserProfile/resources/call-grey-icon.svg diff --git a/CometChat/components/NavBar/resources/chat-blue-icon.svg b/CometChat/components/CometChatMessageScreen/UserProfile/resources/chat-blue-icon.svg similarity index 100% rename from CometChat/components/NavBar/resources/chat-blue-icon.svg rename to CometChat/components/CometChatMessageScreen/UserProfile/resources/chat-blue-icon.svg diff --git a/CometChat/components/NavBar/resources/chat-grey-icon.svg b/CometChat/components/CometChatMessageScreen/UserProfile/resources/chat-grey-icon.svg similarity index 100% rename from CometChat/components/NavBar/resources/chat-grey-icon.svg rename to CometChat/components/CometChatMessageScreen/UserProfile/resources/chat-grey-icon.svg diff --git a/CometChat/components/NavBar/resources/group-chat-blue-icon.svg b/CometChat/components/CometChatMessageScreen/UserProfile/resources/group-chat-blue-icon.svg similarity index 100% rename from CometChat/components/NavBar/resources/group-chat-blue-icon.svg rename to CometChat/components/CometChatMessageScreen/UserProfile/resources/group-chat-blue-icon.svg diff --git a/CometChat/components/NavBar/resources/group-chat-grey-icon.svg b/CometChat/components/CometChatMessageScreen/UserProfile/resources/group-chat-grey-icon.svg similarity index 100% rename from CometChat/components/NavBar/resources/group-chat-grey-icon.svg rename to CometChat/components/CometChatMessageScreen/UserProfile/resources/group-chat-grey-icon.svg diff --git a/CometChat/components/NavBar/resources/more-blue-icon.svg b/CometChat/components/CometChatMessageScreen/UserProfile/resources/more-blue-icon.svg similarity index 100% rename from CometChat/components/NavBar/resources/more-blue-icon.svg rename to CometChat/components/CometChatMessageScreen/UserProfile/resources/more-blue-icon.svg diff --git a/CometChat/components/NavBar/resources/more-grey-icon.svg b/CometChat/components/CometChatMessageScreen/UserProfile/resources/more-grey-icon.svg similarity index 100% rename from CometChat/components/NavBar/resources/more-grey-icon.svg rename to CometChat/components/CometChatMessageScreen/UserProfile/resources/more-grey-icon.svg diff --git a/CometChat/components/NavBar/resources/people-blue-icon.svg b/CometChat/components/CometChatMessageScreen/UserProfile/resources/people-blue-icon.svg similarity index 100% rename from CometChat/components/NavBar/resources/people-blue-icon.svg rename to CometChat/components/CometChatMessageScreen/UserProfile/resources/people-blue-icon.svg diff --git a/CometChat/components/NavBar/resources/people-grey-icon.svg b/CometChat/components/CometChatMessageScreen/UserProfile/resources/people-grey-icon.svg similarity index 100% rename from CometChat/components/NavBar/resources/people-grey-icon.svg rename to CometChat/components/CometChatMessageScreen/UserProfile/resources/people-grey-icon.svg diff --git a/CometChat/components/UserProfile/style.scss b/CometChat/components/CometChatMessageScreen/UserProfile/style.scss similarity index 94% rename from CometChat/components/UserProfile/style.scss rename to CometChat/components/CometChatMessageScreen/UserProfile/style.scss index 3d0a9be9..77b1455b 100644 --- a/CometChat/components/UserProfile/style.scss +++ b/CometChat/components/CometChatMessageScreen/UserProfile/style.scss @@ -1,5 +1,5 @@ -@import '../../resources/mixins'; -@import '../../resources/colors'; +@import '../../../resources/mixins'; +@import '../../../resources/colors'; //dark .dark { diff --git a/CometChat/components/CometChatMessageScreen/index.js b/CometChat/components/CometChatMessageScreen/index.js index c7acef32..06b39c80 100644 --- a/CometChat/components/CometChatMessageScreen/index.js +++ b/CometChat/components/CometChatMessageScreen/index.js @@ -1,79 +1,45 @@ import React from "react"; import "./style.scss"; -import ChatHeader from "../ChatHeader"; -import MessageComposer from "../MessageComposer"; -import ChatWindow from "../ChatWindow"; -import UserProfile from "../UserProfile" - -class CometChatMessageScreen extends React.Component { - constructor(props) { - super(props); - this.state = { - chatList: [], - onItemClick: null, - messages: undefined, - actionGenerated: () => { - return null; - } +import ChatHeader from "./ChatHeader"; +import ChatWindow from "./ChatWindow"; +import MessageComposer from "./MessageComposer"; +import UserProfile from "./UserProfile"; + +const messagescreen = (props) => { + + let detail; + if(props.viewdetail) { + detail = (
+ +
); } - } - - static getDerivedStateFromProps(props, state) { - return props; - - } - render() { return ( -
-
- { - this.state.actionGenerated(action, payload); - switch (action) { - case 'audioCallInitiated': - console.log("AUDIO calll started", payload); - - this.setState({ messages: [payload.call] }); - break; - case 'videoCallInitiated': - console.log("VIDEOP calll started", payload); - this.setState({ messages: [payload.call] }); - - break; - case 'toggelProfile': - this.setState({ - ...payload - }) - break; - } - - }}> -
- +
+
+ +
+
- - { - this.setState({ messages: [message] }); - }} item={this.state.item} type={this.state.type}> +
- {this.state.toggleUserProfile ?
- - -
: ""} - - + {detail}
- - ); - } + ) } - - -export default CometChatMessageScreen; -export const cometChatMessageScreen = CometChatMessageScreen; - -CometChatMessageScreen.defaultProps = { - CometChatMessageScreen: {} -}; +export default React.memo(messagescreen); \ No newline at end of file diff --git a/CometChat/components/CometChatUnified/NavBar/index.js b/CometChat/components/CometChatUnified/NavBar/index.js new file mode 100644 index 00000000..b8da5fa2 --- /dev/null +++ b/CometChat/components/CometChatUnified/NavBar/index.js @@ -0,0 +1,75 @@ +import React from "react"; +import "./style.scss"; + +import CometChatUserList from "../../CometChatUserList"; +import CometChatGroupList from "../../CometChatGroupList"; +import CometChatConversationList from "../../CometChatConversationList"; +import CometChatUserInfoScreen from "../../CometChatUserInfoScreen"; + +import peopleGrey from "./resources/people-grey-icon.svg"; +import peopleBlue from "./resources/people-blue-icon.svg"; +import callGrey from "./resources/call-grey-icon.svg"; +import callBlue from "./resources/call-blue-icon.svg"; +import chatGrey from "./resources/chat-grey-icon.svg"; +import chatBlue from "./resources/chat-blue-icon.svg"; +import groupGrey from "./resources/group-chat-grey-icon.svg"; +import groupBlue from "./resources/group-chat-blue-icon.svg"; +import moreGrey from "./resources/more-grey-icon.svg"; +import moreBlue from "./resources/more-blue-icon.svg"; + +const navbar = (props) => { + + const switchComponent = () => { + + switch (props.tab) { + case "contacts": + return props.actionGenerated("userStatusChanged", "user", item)} + onItemClick={(item, type) => props.actionGenerated("itemClicked", type, item)}>; + case "calls": + return "calls"; + case "conversations": + return props.actionGenerated("itemClicked", type, item)}>; + case "groups": + return props.actionGenerated("itemClicked", type, item)}>; + case "info": + return props.actionGenerated("itemClicked", type, item)}>; + default: + return null; + } + + } + + return ( + +
+
{switchComponent()}
+
+ + + + + +
+
+ + ) +} + +export default React.memo(navbar); \ No newline at end of file diff --git a/CometChat/components/UserProfile/resources/call-blue-icon.svg b/CometChat/components/CometChatUnified/NavBar/resources/call-blue-icon.svg similarity index 100% rename from CometChat/components/UserProfile/resources/call-blue-icon.svg rename to CometChat/components/CometChatUnified/NavBar/resources/call-blue-icon.svg diff --git a/CometChat/components/UserProfile/resources/call-grey-icon.svg b/CometChat/components/CometChatUnified/NavBar/resources/call-grey-icon.svg similarity index 100% rename from CometChat/components/UserProfile/resources/call-grey-icon.svg rename to CometChat/components/CometChatUnified/NavBar/resources/call-grey-icon.svg diff --git a/CometChat/components/UserProfile/resources/chat-blue-icon.svg b/CometChat/components/CometChatUnified/NavBar/resources/chat-blue-icon.svg similarity index 100% rename from CometChat/components/UserProfile/resources/chat-blue-icon.svg rename to CometChat/components/CometChatUnified/NavBar/resources/chat-blue-icon.svg diff --git a/CometChat/components/UserProfile/resources/chat-grey-icon.svg b/CometChat/components/CometChatUnified/NavBar/resources/chat-grey-icon.svg similarity index 100% rename from CometChat/components/UserProfile/resources/chat-grey-icon.svg rename to CometChat/components/CometChatUnified/NavBar/resources/chat-grey-icon.svg diff --git a/CometChat/components/UserProfile/resources/group-chat-blue-icon.svg b/CometChat/components/CometChatUnified/NavBar/resources/group-chat-blue-icon.svg similarity index 100% rename from CometChat/components/UserProfile/resources/group-chat-blue-icon.svg rename to CometChat/components/CometChatUnified/NavBar/resources/group-chat-blue-icon.svg diff --git a/CometChat/components/UserProfile/resources/group-chat-grey-icon.svg b/CometChat/components/CometChatUnified/NavBar/resources/group-chat-grey-icon.svg similarity index 100% rename from CometChat/components/UserProfile/resources/group-chat-grey-icon.svg rename to CometChat/components/CometChatUnified/NavBar/resources/group-chat-grey-icon.svg diff --git a/CometChat/components/UserProfile/resources/more-blue-icon.svg b/CometChat/components/CometChatUnified/NavBar/resources/more-blue-icon.svg similarity index 100% rename from CometChat/components/UserProfile/resources/more-blue-icon.svg rename to CometChat/components/CometChatUnified/NavBar/resources/more-blue-icon.svg diff --git a/CometChat/components/UserProfile/resources/more-grey-icon.svg b/CometChat/components/CometChatUnified/NavBar/resources/more-grey-icon.svg similarity index 100% rename from CometChat/components/UserProfile/resources/more-grey-icon.svg rename to CometChat/components/CometChatUnified/NavBar/resources/more-grey-icon.svg diff --git a/CometChat/components/UserProfile/resources/people-blue-icon.svg b/CometChat/components/CometChatUnified/NavBar/resources/people-blue-icon.svg similarity index 100% rename from CometChat/components/UserProfile/resources/people-blue-icon.svg rename to CometChat/components/CometChatUnified/NavBar/resources/people-blue-icon.svg diff --git a/CometChat/components/UserProfile/resources/people-grey-icon.svg b/CometChat/components/CometChatUnified/NavBar/resources/people-grey-icon.svg similarity index 100% rename from CometChat/components/UserProfile/resources/people-grey-icon.svg rename to CometChat/components/CometChatUnified/NavBar/resources/people-grey-icon.svg diff --git a/CometChat/components/NavBar/style.scss b/CometChat/components/CometChatUnified/NavBar/style.scss similarity index 91% rename from CometChat/components/NavBar/style.scss rename to CometChat/components/CometChatUnified/NavBar/style.scss index 5681f2c7..b1316b5c 100644 --- a/CometChat/components/NavBar/style.scss +++ b/CometChat/components/CometChatUnified/NavBar/style.scss @@ -1,5 +1,5 @@ -@import '../../resources/mixins'; -@import '../../resources/colors.scss'; +@import '../../../resources/mixins'; +@import '../../../resources/colors.scss'; @@ -38,7 +38,7 @@ left: 0; bottom: 15px; background-color: #fff; - z-index: 1; + // z-index: 1; } /* Style the buttons inside the tab */ diff --git a/CometChat/components/CometChatUnified/index.js b/CometChat/components/CometChatUnified/index.js index a5db5265..57b52a45 100644 --- a/CometChat/components/CometChatUnified/index.js +++ b/CometChat/components/CometChatUnified/index.js @@ -1,21 +1,24 @@ import React from "react"; import "./style.scss"; -import NavBar from "../NavBar"; -import CallScreen from "../CallScreen"; -import CometChatMessageScreen from "../CometChatMessageScreen" +import { CometChat } from "@cometchat-pro/chat"; +import { CometChatManager } from "../../util/controller"; -class CometChatUnified extends React.Component { - constructor(props) { - super(props); - this.state = { - darktheme: false - } +import NavBar from "./NavBar"; +import CometChatMessageScreen from "../CometChatMessageScreen" +import CallScreen from "../CallScreen"; - } - static getDerivedStateFromProps(props, state) { - return props; +class CometChatUnified extends React.Component { + + state = { + darktheme: false, + outgoingCall: undefined, + item: {}, + type: "user", + tab: "contacts", + viewdetail: false, + messageList: [] } changeTheme = (e) => { @@ -24,47 +27,241 @@ class CometChatUnified extends React.Component { }) } + msgScreenAction = (action, msgArr) => { + + switch(action) { + case "messageComposed": + case "messageReceived": + this.appendMessage(msgArr); + break; + case "messageFetched": + this.updateMessageList(msgArr); + break; + case "audioCall": + this.audioCall(); + break; + case "videoCall": + this.videoCall(); + break; + case "viewDetail": + this.toggleUserDetail( ); + break; + case "blockUser": + this.blockUser( ); + break; + case "unblockUser": + this.unblockUser( ); + break; + default: + break; + } + + } + + blockUser = () => { + + console.log("[CometChatUnified] blockUser", {...this.state.item}); + + let usersList = [this.state.item.uid]; + CometChatManager.blockUsers(usersList).then(list => { + + console.log(list);console.log("[blockUser success]", this.state.item); + + this.setState({item: {...this.state.item, blockedByMe: true}}); + + }).catch(error => { + console.log("Blocking user fails with error", error); + }); + } + + unblockUser = () => { + + console.log("[CometChatUnified] unblockUser", {...this.state.item}); + + let usersList = [this.state.item.uid]; + CometChatManager.unblockUsers(usersList).then(list => { + + console.log(list);console.log("[unblockUser success]", this.state.item); + + this.setState({item: {...this.state.item, blockedByMe: false}}); + + }).catch(error => { + console.log("unblocking user fails with error", error); + }); + } + + audioCall = () => { + + let receiverID; + let receiverType = CometChat.RECEIVER_TYPE.USER; + let callType = CometChat.CALL_TYPE.AUDIO; + + if (this.state.type === 'group') { + receiverID = this.state.item.guid; + receiverType = CometChat.RECEIVER_TYPE.GROUP; + } else { + receiverID = this.state.item.uid; + receiverType = CometChat.RECEIVER_TYPE.USER; + } + + CometChatManager.audioCall(receiverID, receiverType, callType).then(call => { + + this.callScreenAction("callStarted", call); + this.setState({ outgoingCall: call }); + + }).catch(error => { + + console.log("Call initialization failed with exception:", error); + + }); + + } + + videoCall = () => { + + let receiverID; + let receiverType = CometChat.RECEIVER_TYPE.USER; + let callType = CometChat.CALL_TYPE.VIDEO; + + if (this.state.type === 'group') { + receiverID = this.state.item.guid; + receiverType = CometChat.RECEIVER_TYPE.GROUP; + } else { + receiverID = this.state.item.uid; + receiverType = CometChat.RECEIVER_TYPE.USER; + } + + CometChatManager.videoCall(receiverID, receiverType, callType).then(call => { + + this.callScreenAction("callStarted", call); + this.setState({ outgoingCall: call }); + + }).catch(error => { + + console.log("Call initialization failed with exception:", error); + + }); + } + + toggleUserDetail = () => { + let viewdetail = !this.state.viewdetail; + this.setState({viewdetail: viewdetail}); + } + + //listener when messages are fetched from backend + updateMessageList = (message) => { + + const messages = [...message, ...this.state.messageList]; + this.setState({ messageList: messages }); + + } + + //listener when message is received from composer + appendMessage = (message) => { + + let messages = [...this.state.messageList]; + messages = messages.concat(message); + this.setState({ messageList: messages }); + } + + + navBarAction = (action, type, item) => { + + switch(action) { + case "itemClicked": + this.itemClicked(item, type); + break; + case "tabChanged": + this.tabChanged(type); + break; + case "groupMemberLeft": + this.appendMessage(item); + break; + case "groupMemberJoined": + this.appendMessage(item); + break; + case "userStatusChanged": + this.updateSelectedUser(item); + break; + default: + break; + } + } + + updateSelectedUser = (item) => { + + this.setState({ item: {...item}}); + } + + itemClicked = (item, type) => { + + //empty messagelist only if the user/group changes + if(this.state.type === type) { + + if((type === "user" && item.uid !== this.state.item.uid) || + (type === "group" && item.guid !== this.state.item.guid)) { + this.setState({ messageList: []}); + } + } + else { + this.setState({ messageList: []}); + } + + this.setState({ item: {...item}, type }); + this.setState({viewdetail: false}); + + } + + tabChanged = (tab) => { + this.setState({tab}); + this.setState({viewdetail: false}); + } + + callScreenAction = (action, call) => { + + switch(action) { + case "callStarted": + case "callEnded": + + if(!call) return; + this.appendMessage(call); + break; + default: + break; + } + } render() { + + let messageScreen = (

Select a chat to start messaging

); + if(Object.keys(this.state.item).length) { + messageScreen = ( + ); + } + return (
- { - this.setState({ item, type }) - }}> +
-
- { - this.state.item ? { - switch (action) { - case 'audioCallInitiated': - this.setState({ outgoingCall: payload.call }); - break; - case 'videoCallInitiated': - this.setState({ outgoingCall: payload.call }); - - break; - } - }}> :

Select a chat to start messaging

- - } - -
- { - this.setState({ outgoingCall: undefined }); - }} outgoingCall={this.state.outgoingCall}> +
{messageScreen}
+
); } } - - -export default CometChatUnified; -export const cometChatUnified = CometChatUnified; - -CometChatUnified.defaultProps = { - launch: {} -}; +export default CometChatUnified; \ No newline at end of file diff --git a/CometChat/components/CometChatUserInfoScreen/controller.js b/CometChat/components/CometChatUserInfoScreen/controller.js index 5a1da790..e69de29b 100644 --- a/CometChat/components/CometChatUserInfoScreen/controller.js +++ b/CometChat/components/CometChatUserInfoScreen/controller.js @@ -1,32 +0,0 @@ -import { CometChat } from "@cometchat-pro/chat" - -export class CometChatManager { - - usersRequest - constructor() { - this.usersRequest = new CometChat.UsersRequestBuilder().setLimit(30).build(); - } - isUserLogedIn; - logedInUser; - isCometChatUserLogedIn() { - let timerCounter = 10000; - let timer = 0; - return new Promise((resolve, reject) => { - if (timerCounter === timer) reject(); - this.isUserLogedIn = setInterval(() => { - if (CometChat.isInitialized()) { - CometChat.getLoggedinUser().then(user => { - this.logedInUser = user; - clearInterval(this.isUserLogedIn); - resolve(user); - }, error => { - //TODO do something if user is not loggedIn - }) - } else { - } - timer = + 100; - }, 100); - }); - } - -} \ No newline at end of file diff --git a/CometChat/components/CometChatUserInfoScreen/index.js b/CometChat/components/CometChatUserInfoScreen/index.js index 2bd2fe50..f9ff6c7e 100644 --- a/CometChat/components/CometChatUserInfoScreen/index.js +++ b/CometChat/components/CometChatUserInfoScreen/index.js @@ -1,147 +1,105 @@ import React from "react"; import "./style.scss"; + +import { CometChatManager } from "../../util/controller"; + import Avatar from "../Avatar"; -import { CometChatManager } from "./controller"; + import notificationBlack from "./resources/notification-black-icon.svg"; -// import notificationWhite from "./resources/notification-white-icon.svg"; import privacyBlack from "./resources/privacy-black-icon.svg"; -// import privacyWhite from "./resources/privacy-white-icon.svg"; import chatBlack from "./resources/chat-black-icon.svg"; -// import chatWhite from "./resources/chat-light-grey-icon.svg"; import helpBlack from "./resources/help-black-icon.svg"; -// import helpWhite from "./resources/help-white-icon.svg"; import reportBlack from "./resources/report-black-icon.svg"; -// import reportWhite from "./resources/report-white-icon.svg"; - - class CometChatUserInfoScreen extends React.Component { - constructor(props) { - super(props); - this.state = { - user: {}, - } + state = { + user: {}, } componentDidMount() { - this.cometChatManager = new CometChatManager(); this.getProfile(); } - static getDerivedStateFromProps(props, state) { - return props; - } + getProfile() { - this.cometChatManager.isCometChatUserLogedIn().then( - user => { + + new CometChatManager().getLoggedInUser().then(user => { this.setState({ user: user }); - }, - error => { - //TODO Handle the erros in users logedin state. - console.error("Handle the erros in conatct List", error); - } - ); + }).catch(error => { + console.log("[CometChatUserInfoScreen] getProfile getLoggedInUser error", error); + }); + } + render() { - return ( -
-

More

-
-
-
- - - {(Object.keys(this.state.user).length>0?:'')} -
-
-
- {this.state.user.name} -
-
- - Online -
-
+ let avatar = ""; + if(Object.keys(this.state.user).length) { + avatar = (); + } + + return ( +
+

More

+
+
+
{avatar}
+
+
{this.state.user.name}
+
Online
-
-

PREFERENCES

-
-
- notification -
-
-
- Notifications -
-
- -
-
-
-
- privacy -
-
-
- Privacy and Security -
-
- -
-
-
-
- chat -
-
-
- Chats -
-
- -
-
- +
+
+

PREFERENCES

+
+
notification
+
+
Notifications
+
-
-

OTHERS

-
-
- help -
-
-
- Help -
-
- -
-
-
-
- report -
-
-
- Report a Problem -
-
- -
-
+
+
+
privacy
+
+
Privacy and Security
+
+
+
+
chat
+
+
Chats
+
+
+
+
+
+

OTHERS

+
+
help
+
+
Help
+
+
+
+
+
report
+
+
Report a Problem
+
+
+
- ); +
); } } -export default CometChatUserInfoScreen; -export const cometChatUserInfoScreen=CometChatUserInfoScreen; -CometChatUserInfoScreen.defaultProps = { - CometChatUserInfoScreen: {} -}; +export default CometChatUserInfoScreen; \ No newline at end of file diff --git a/CometChat/components/CometChatUserList/controller.js b/CometChat/components/CometChatUserList/controller.js index 82a2a712..8be38c0a 100644 --- a/CometChat/components/CometChatUserList/controller.js +++ b/CometChat/components/CometChatUserList/controller.js @@ -1,45 +1,27 @@ -import { CometChat } from "@cometchat-pro/chat" +import { CometChat } from "@cometchat-pro/chat"; -export class CometChatManager { +export class UserListManager { + + userRequest = null; + userListenerId = new Date().getTime(); - usersRequest constructor(searchKey) { + if (searchKey) { this.usersRequest = new CometChat.UsersRequestBuilder().setLimit(30).setSearchKeyword(searchKey).build(); - } else + } else { this.usersRequest = new CometChat.UsersRequestBuilder().setLimit(30).build(); - - } - isUserLogedIn; - logedInUser; - isCometChatUserLogedIn() { - let timerCounter = 10000; - let timer = 0; - return new Promise((resolve, reject) => { - if (timerCounter === timer) reject(); - this.isUserLogedIn = setInterval(() => { - if (CometChat.isInitialized()) { - CometChat.getLoggedinUser().then(user => { - this.logedInUser = user; - clearInterval(this.isUserLogedIn); - resolve(user); - }, error => { - //TODO do something if user is not loggedIn - }) - } else { - } - timer = + 100; - }, 100); - }); + } } - fetchNextContacts() { + fetchNextUsers() { return this.usersRequest.fetchNext(); } - attachUserListener(callback) { - var listenerID = "UNIQUE_LISTENER_ID"; + + attachListeners(callback) { + CometChat.addUserListener( - listenerID, + this.userListenerId, new CometChat.UserListener({ onUserOnline: onlineUser => { /* when someuser/friend comes online, user will be received here */ @@ -52,4 +34,9 @@ export class CometChatManager { }) ); } + + removeListeners() { + + CometChat.removeUserListener(this.userListenerId); + } } \ No newline at end of file diff --git a/CometChat/components/CometChatUserList/index.js b/CometChat/components/CometChatUserList/index.js index c422bcf5..b057ac58 100644 --- a/CometChat/components/CometChatUserList/index.js +++ b/CometChat/components/CometChatUserList/index.js @@ -1,146 +1,194 @@ import React from "react"; import "./style.scss"; + +import { CometChatManager } from "../../util/controller"; +import { SvgAvatar } from '../../util/svgavatar'; +import { UserListManager } from "./controller"; + import UserView from "../UserView"; -import { CometChatManager } from "./controller"; -class CometChatUserList extends React.Component { +class CometChatUserList extends React.PureComponent { timeout; + constructor(props) { super(props); this.state = { - userlist: [], - onItemClick: null + userlist: [] } - this.getUsersList = this.getUsersList.bind(this); - this.handleScroll = this.handleScroll.bind(this); - } + componentDidMount() { - this.cometChatManager = new CometChatManager(); - this.getUsersList(); - this.cometChatManager.attachUserListener(this.userUpdated); - } - // static getDerivedStateFromProps(props,state){ - // return props; - // } - handleScroll(e) { - const bottom = - Math.round(e.currentTarget.scrollHeight - e.currentTarget.scrollTop) === Math.round(e.currentTarget.clientHeight); - if (bottom) this.getUsersList(); + + this.UserListManager = new UserListManager(); + this.getUsers(); + this.UserListManager.attachListeners(this.userUpdated); + } + componentDidUpdate(prevProps, prevState) { - handleClick = (user) => { - this.props.onItemClick(user, 'user'); + //if user is blocked/unblocked, update userlist in state + if(prevProps.item + && Object.keys(prevProps.item).length + && prevProps.item.uid === this.props.item.uid + && prevProps.item.blockedByMe !== this.props.item.blockedByMe) { + + let userlist = [...this.state.userlist]; + let userObj = userlist.find((u, k) => u.uid === this.props.item.uid); + + if(userObj) { + userObj = Object.assign(userObj, {blockedByMe: this.props.item.blockedByMe}); + } + + this.setState({ userlist }); + } } + componentWillUnmount() { + + console.log("[CometChatUserList] componentWillUnmount") + this.UserListManager.removeListeners(); + this.UserListManager = null; + } userUpdated = (user) => { - if (this.state.userlist) { - let userlist = this.state.userlist; + + let userlist = [...this.state.userlist]; - userlist.map((stateUser, key) => { - if (stateUser.uid === user.uid) { - userlist.splice(key, 1, user); + //search for user + let index = userlist.findIndex((u, k) => u.uid === user.uid); + let userObj = userlist.find((u, k) => u.uid === user.uid); + + //if found in the list, update user object + if(userObj) { - return true; - } - return true; - }); - this.setState({ userlist }); + userObj = Object.assign(userObj, user); + userlist.splice(index, 1, userObj); + + this.setState({ userlist: userlist }); + + if(this.props.userStatusChanged && this.props.item.uid === user.uid) { + this.props.userStatusChanged(userObj); + } } + } + handleScroll = (e) => { + const bottom = + Math.round(e.currentTarget.scrollHeight - e.currentTarget.scrollTop) === Math.round(e.currentTarget.clientHeight); + if (bottom) this.getUsers(); } + + handleClick = (user) => { + + if(!this.props.onItemClick) + return; + + this.props.onItemClick(user, 'user'); + } + searchUsers = (e) => { + if (this.timeout) { clearTimeout(this.timeout); } - let val=e.target.value; + + let val = e.target.value; this.timeout = setTimeout(() => { - this.cometChatManager = new CometChatManager(val); - this.setState({ userlist: [] }, () => { - this.getUsersList(); - }) - }, 500) + this.UserListManager = new UserListManager(val); + this.setState({ userlist: [] }, () => this.getUsers()) + }, 500) } - getUsersList() { - this.cometChatManager.isCometChatUserLogedIn().then( - user => { - this.cometChatManager.fetchNextContacts().then( - (userlist) => { - this.setState({ userlist: [...this.state.userlist, ...userlist] }); - }, - error => { - //TODO Handle the erros in conatct List. - console.error("Handle the erros in conatct List", error); - } - ); - }, - error => { - //TODO Handle the erros in users logedin state. - console.error("Handle the erros in conatct List", error); - } - ); - } + getUsers = () => { - displayUserList() { - let currentLetter = ""; - if (this.state.userlist.length > 0) { - return this.state.userlist.map((user, key) => { - if (user.name.substring(0, 1).toUpperCase() !== currentLetter) { - currentLetter = user.name.substring(0, 1).toUpperCase(); - return ( -
this.handleClick(user)} key={user.uid}> -
{currentLetter}
- -
-
- ); - } else { - return ( -
this.handleClick(user)} key={user.uid}> - -
- -
- ); - } - - // return - //
- // - // - //
- // return true; + new CometChatManager().getLoggedInUser().then((user) => { + + this.UserListManager.fetchNextUsers().then((userList) => { + + userList.forEach(user => user = this.setAvatar(user)); + this.setState({ userlist: [...this.state.userlist, ...userList] }); + + }).catch((error) => { + console.error("[CometChatUserList] getUsers fetchNext error", error); }); + }).catch((error) => { + console.log("[CometChatUserList] getUsers getLoggedInUser error", error); + }); + } + + setAvatar(user) { + + if(!user.getAvatar()) { + + const uid = user.getUid(); + const char = user.getName().charAt(0).toUpperCase(); + user.setAvatar(SvgAvatar.getAvatar(uid, char)) } + + } + + transformUserList = () => { + + const users = [...this.state.userlist]; + + //sort alphabetically by name + users.sort(function(a, b){ + + if(a.name < b.name) { return -1; } + if(a.name > b.name) { return 1; } + return 0; + + }); + + return users; } + render() { + + const userList = this.transformUserList(); + let currentLetter = ""; + const users = userList.map((user, key) => { + + const chr = user.name[0].toUpperCase(); + if (chr !== currentLetter) { + + currentLetter = chr; + return ( +
this.handleClick(user)} key={key}> +
{currentLetter}
+ +
+
+ ); + + } else { + + return ( +
this.handleClick(user)} key={key}> + +
+
+ ); + } + + }); + return ( +

Contacts

-
- - {this.displayUserList()} -
+
{users}
); } } - - -export default CometChatUserList; -export const cometChatUserList=CometChatUserList; - -CometChatUserList.defaultProps = { - CometChatUserList: {} -}; +export default CometChatUserList; \ No newline at end of file diff --git a/CometChat/components/CometChatUserListScreen/index.js b/CometChat/components/CometChatUserListScreen/index.js index f3af99b8..b39d8f17 100644 --- a/CometChat/components/CometChatUserListScreen/index.js +++ b/CometChat/components/CometChatUserListScreen/index.js @@ -1,60 +1,219 @@ import React from "react"; import "./style.scss"; -import CometChatMessageScreen from "../CometChatMessageScreen" -import CometChatUserList from "../CometChatUserList"; +import { CometChat } from "@cometchat-pro/chat"; +import { CometChatManager } from "../../util/controller"; + +import CometChatUserList from "../CometChatUserList"; +import CometChatMessageScreen from "../CometChatMessageScreen" +import CallScreen from "../CallScreen"; class CometChatUserListScreen extends React.Component { - constructor(props) { - super(props); - this.state = { - darktheme: false + + state = { + darktheme: false, + item: {}, + type: "user", + tab: "contacts", + viewdetail: false, + messageList: [], + outgoingCall: null + } + + changeTheme = (e) => { + + const theme = this.state.darktheme; + this.setState({darktheme: !theme}); + } + + onItemClicked = (item, type) => { + + //empty messagelist only if user changes + if(item.uid !== this.state.item.uid) { + this.setState({ messageList: [] }); } + this.setState({ item: {...item}, type, viewdetail: false }); } - static getDerivedStateFromProps(props, state) { - return props; + + updateSelectedUser = (item) => { + this.setState({ item: {...item}}); } - changeTheme = (e) => { - this.setState({ - darktheme: !this.state.darktheme - }) + msgScreenAction = (action, msgArr) => { + + switch(action) { + case "messageComposed": + case "messageReceived": + this.appendMessage(msgArr); + break; + case "messageFetched": + this.updateMessageList(msgArr); + break; + case "audioCall": + this.audioCall(); + break; + case "videoCall": + this.videoCall(); + break; + case "viewDetail": + this.toggleUserDetail( ); + break; + case "blockUser": + this.blockUser( ); + break; + case "unblockUser": + this.unblockUser( ); + break; + default: + break; + } + + } + + blockUser = () => { + + console.log("[CometChatUserListScreen] blockUser", {...this.state.item}); + + let usersList = [this.state.item.uid]; + CometChatManager.blockUsers(usersList).then(list => { + + console.log(list);console.log("[blockUser success]", this.state.item); + this.setState({item: {...this.state.item, blockedByMe: true}}); + + }).catch(error => { + console.log("Blocking user fails with error", error); + }); + + } + + unblockUser = () => { + + console.log("[CometChatUserListScreen] unblockUser", {...this.state.item}); + + let usersList = [this.state.item.uid]; + CometChatManager.unblockUsers(usersList).then(list => { + + console.log(list);console.log("[unblockUser success]", this.state.item) + this.setState({item: {...this.state.item, blockedByMe: false}}); + + }).catch(error => { + console.log("unblocking user fails with error", error); + }); + + } + + audioCall = () => { + + let receiverID = this.state.item.uid; + let receiverType = CometChat.RECEIVER_TYPE.USER; + let callType = CometChat.CALL_TYPE.AUDIO; + + CometChatManager.audioCall(receiverID, receiverType, callType).then(call => { + + console.log("Call initiated successfully:", call); + this.callScreenAction("callStarted", call); + this.setState({ outgoingCall: call }); + + }).catch(error => { + + console.log("Call initialization failed with exception:", error); + + }); + + } + + videoCall = () => { + + let receiverID = this.state.item.uid; + let receiverType = CometChat.RECEIVER_TYPE.USER; + let callType = CometChat.CALL_TYPE.VIDEO; + + CometChatManager.videoCall(receiverID, receiverType, callType).then(call => { + + console.log("Call initiated successfully:", call); + this.callScreenAction("callStarted", call); + this.setState({ outgoingCall: call }); + + }).catch(error => { + + console.log("Call initialization failed with exception:", error); + + }); + } + toggleUserDetail = () => { + let viewdetail = !this.state.viewdetail; + this.setState({viewdetail: viewdetail}); + } + + //listener when messages are fetched from backend + updateMessageList = (message) => { + const messages = [...message, ...this.state.messageList]; + this.setState({ messageList: messages }); + } + + //listener when message is received from composer + appendMessage = (message) => { + let messages = [...this.state.messageList]; + messages = messages.concat(message); + this.setState({ messageList: messages }); + } + + callScreenAction = (action, call) => { + + switch(action) { + case "callStarted": + case "callEnded": + if(!call) return; + this.appendMessage(call); + break; + default: + break; + } + } + render() { + + let messageScreen = (

Select a chat to start messaging

); + if(Object.keys(this.state.item).length) { + messageScreen = ( + ); + } + return ( +
-
+
- - { - this.setState({ item, type }) - }}> +
- { - this.state.item ? :

Select a chat to start messaging

- - } + {messageScreen}
+
); } } - - -export default CometChatUserListScreen; -export const cometChatUserListScreen=CometChatUserListScreen; - -CometChatUserListScreen.defaultProps = { - launch: {} -}; +export default CometChatUserListScreen; \ No newline at end of file diff --git a/CometChat/components/ConversationView/index.js b/CometChat/components/ConversationView/index.js index c80feb7e..17b1bb6b 100644 --- a/CometChat/components/ConversationView/index.js +++ b/CometChat/components/ConversationView/index.js @@ -1,108 +1,133 @@ import React from "react"; + +import { CometChat } from '@cometchat-pro/chat'; + import "./style.scss"; + import Avatar from "../Avatar"; import BadgeCount from "../BadgeCount"; -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"; +const conversationview = (props) => { -class ConversationView extends React.Component { - constructor(props) { - super(props); - this.state = { - conversation: {}, + const getMessage = () => { + + let message = ""; + const type = props.conversation.lastMessage.type; + + switch(type) { + case CometChat.MESSAGE_TYPE.TEXT: + message = props.conversation.lastMessage.text; + break; + case CometChat.MESSAGE_TYPE.MEDIA: + message = "Media message"; + break; + case CometChat.MESSAGE_TYPE.IMAGE: + message = "Image message"; + break; + case CometChat.MESSAGE_TYPE.FILE: + message = "File message"; + break; + case CometChat.MESSAGE_TYPE.VIDEO: + message = "Video message"; + break; + case CometChat.MESSAGE_TYPE.AUDIO: + message = "Audio message"; + break; + case CometChat.MESSAGE_TYPE.CUSTOM: + message = "Custom message"; + break; + default: + break; } + + return message; } - static getDerivedStateFromProps(props, state) { - return props; - } - displayTicks=(message)=>{ - if(message.sentAt && !message.readAt && !message.deliveredAt){ - return greyTick; - }else if(message.sentAt && !message.readAt && message.deliveredAt){ - return greyDoubleTick - }else{ - return blueDoubleTick + const getCallMessage = () => { + + let message = ""; + const type = props.conversation.lastMessage.type; + + if(type === CometChat.MESSAGE_TYPE.VIDEO) { + message = "Video call"; + } else if(type === CometChat.MESSAGE_TYPE.AUDIO) { + message = "Audio call"; } + return message; } - displayLastMessage=(lastMessage)=>{ - if (lastMessage.text) { - return lastMessage.text - }else if(lastMessage.type === 'image'){ - return 'Image' - }else if(lastMessage.type === 'file'){ - return 'File' - }else if(lastMessage.type === 'audio'){ - return 'Audio' - }else if(lastMessage.type === 'video'){ - return 'Video' + + const getLastMessage = () => { + + if(!props.conversation.lastMessage) + return false; + + let message = ""; + + switch(props.conversation.lastMessage.category) { + case "message": + message = getMessage(); + break; + case "call": + message = getCallMessage(); + break; + case "action": + message = props.conversation.lastMessage.message; + break; + case "custom": + message = "Some Custom Message"; + break; + default: + break; } + + return message; + } + + const getAvatar = () => { + let avatar = ""; + if(props.conversation.getConversationType() === "user") { + avatar = props.conversation.getConversationWith().getAvatar(); + } else if (props.conversation.getConversationType() === "group") { + avatar = props.conversation.getConversationWith().getIcon(); + } + return avatar; } - render() { - return ( -
{ if (this.props.onClick) this.props.onClick(this.state.conversation) }}> - {(() => { - switch (this.state.conversation.conversationType) { - case "user": return (
-
- -
-
-
-
- {this.state.conversation.conversationWith.name}
-
{new Date(this.state.conversation.lastMessage.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })}
-
-
-
- - {this.state.conversation.lastMessage ?
{this.displayLastMessage(this.state.conversation.lastMessage.data)}
:
Tap to start a conversation.
- } -
-
- -
-
-
-
); - case "group": return (
-
- -
-
-
-
-
{this.state.conversation.conversationWith.name}
-
-
-
{new Date(this.state.conversation.lastMessage.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })}
-
-
-
-
- {this.state.conversation.lastMessage ?
{this.displayLastMessage(this.state.conversation.lastMessage.data)}
:
Tap to start a conversation.
- } -
-
- -
-
+ + return ( +
+
+
+ +
+
+
+
+
{props.conversation.conversationWith.name}
+
+
+
{new Date(props.conversation.lastMessage.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })}
+
+
+
+
+
+ {getLastMessage()}
-
); - default: return null; - } - })()} +
+
+ +
+
+
- ); - } +
+ ) } -export default ConversationView; -export const conversationView=ConversationView; -ConversationView.defaultProps = { - conversation: {} -}; +export default conversationview; \ No newline at end of file diff --git a/CometChat/components/GroupView/index.js b/CometChat/components/GroupView/index.js index ece63cdd..1a1a8192 100644 --- a/CometChat/components/GroupView/index.js +++ b/CometChat/components/GroupView/index.js @@ -1,51 +1,26 @@ import React from "react"; import "./style.scss"; -import Avatar from "../Avatar"; +import Avatar from "../Avatar"; -class GroupView extends React.Component { - constructor(props){ - super(props); - this.state={ - group:{}, - } +const groupview = (props) => { - } - static getDerivedStateFromProps(props,state){ - return props; - } - render() { - return ( -
{ if(this.props.onClick)this.props.onClick(this.state.group)}}> -
-
- -
-
-
- {this.state.group.name} -
- {/* - - {this.state.user.status} - */} -
- -
- - - - + return ( +
+
+
+ +
+
+
{props.group.name}
+
- ); - } +
+ ) } - - -export default GroupView; -export const groupView=GroupView; - -GroupView.defaultProps = { - group:{} -}; +export default groupview; \ No newline at end of file diff --git a/CometChat/components/MessageComposer/index.js b/CometChat/components/MessageComposer/index.js deleted file mode 100644 index 24cf6ccd..00000000 --- a/CometChat/components/MessageComposer/index.js +++ /dev/null @@ -1,202 +0,0 @@ -import React from "react"; -import "./style.scss"; -import roundedPlus from "./resources/rounded-plus-grey-icon.svg"; -import sendBlue from "./resources/send-blue-icon.svg"; -import imageUpload from "./resources/image-blue.svg"; -import audioUpload from "./resources/audio-blue.svg"; -import videoUpload from "./resources/video-blue.svg"; -import fileUpload from "./resources/file-blue.svg"; -import { CometChat } from "@cometchat-pro/chat" - - -class MessageComposer extends React.Component { - constructor(props) { - super(props); - this.state = { - conversation: {}, - showMediaComposer: false, - fileList: [] - } - - - } - static getDerivedStateFromProps(props, state) { - return props; - } - handleSendMessageOnEnter = (e) => { - if (e.key === 'Enter' && e.target.value) { - var receiverID; - if (this.state.type === "user") { - receiverID = this.state.item.uid; - } else { - receiverID = this.state.item.guid; - } - var messageText = e.target.value; - var receiverType = this.state.type; - var textMessage = new CometChat.TextMessage( - receiverID, - messageText, - receiverType - ); - - CometChat.sendMessage(textMessage).then( - message => { - document.getElementById("messageInput").value = ''; - if (this.state.onMessageSent) { - this.state.onMessageSent(message); - } - }, - error => { - console.log("Message sending failed with error:", error); - } - ); - } - - } - onImageChange = (e, messageType) => { - this.sendMediaMessage(e,messageType) - } - onFileChange = (e, messageType) => { - this.sendMediaMessage(e,messageType) - - } - onAudioChange = (e, messageType) => { - this.sendMediaMessage(e,messageType) - - } - onVideoChange = (e, messageType) => { - this.sendMediaMessage(e,messageType) - - } - sendMediaMessage=(e,messageType)=>{ - if (e.target.files[0]) { - var receiverID; - var receiverType; - if (this.state.type === "user") { - receiverID = this.state.item.uid; - receiverType="user"; - } else { - receiverID = this.state.item.guid; - receiverType="group"; - } - var textMessage = new CometChat.MediaMessage( - receiverID, - e.target.files[0], - messageType, - receiverType - ); - - CometChat.sendMessage(textMessage).then( - message => { - if (this.state.onMessageSent) { - this.state.onMessageSent(message); - } - this.setState({ fileList: [] }) - }, - error => { - console.log("Message sending failed with error:", error); - } - ); - } - } - openFileDialouge = (fileType) => { - switch (fileType) { - case "image": - this.refs.imageUploader.click(); - break; - case "file": - this.refs.fileUploader.click(); - break; - case "audio": - this.refs.audioUploader.click(); - break; - case "video": - this.refs.videoUploader.click(); - break; - - default: - break; - } - } - browseMediaMessage = () => { - const currentState = this.state.showMediaComposer; - this.setState({ showMediaComposer: !currentState }); - } - handleSendMessage = () => { - let message = document.getElementById("messageInput").value - document.getElementById("messageInput").value = ''; - if (message) { - var receiverID; - if (this.state.type === "user") { - receiverID = this.state.item.uid; - } else { - receiverID = this.state.item.guid; - } - var messageText = message; - var receiverType = this.state.type; - var textMessage = new CometChat.TextMessage( - receiverID, - messageText, - receiverType - ); - - CometChat.sendMessage(textMessage).then( - message => { - if (this.state.onMessageSent) { - this.state.onMessageSent(message); - } - - }, - error => { - console.log("Message sending failed with error:", error); - } - ); - } - - } - render() { - return ( -
-
- -
-
- - - - - -
- -
-
- -
- ); - } -} - - - -export default MessageComposer; -export const messageComposer=MessageComposer; - -MessageComposer.defaultProps = { - -}; diff --git a/CometChat/components/NavBar/index.js b/CometChat/components/NavBar/index.js deleted file mode 100644 index a44997b6..00000000 --- a/CometChat/components/NavBar/index.js +++ /dev/null @@ -1,85 +0,0 @@ -import React from "react"; -import "./style.scss"; -import CometChatUserList from "../CometChatUserList"; -import CometChatGroupList from "../CometChatGroupList"; -import CometChatConversationList from "../CometChatConversationList"; -import CometChatUserInfoScreen from "../CometChatUserInfoScreen"; -import peopleGrey from "./resources/people-grey-icon.svg"; -import peopleBlue from "./resources/people-blue-icon.svg"; -import callGrey from "./resources/call-grey-icon.svg"; -import callBlue from "./resources/call-blue-icon.svg"; -import chatGrey from "./resources/chat-grey-icon.svg"; -import chatBlue from "./resources/chat-blue-icon.svg"; -import groupGrey from "./resources/group-chat-grey-icon.svg"; -import groupBlue from "./resources/group-chat-blue-icon.svg"; -import moreGrey from "./resources/more-grey-icon.svg"; -import moreBlue from "./resources/more-blue-icon.svg"; - -class NavBar extends React.Component { - constructor(props) { - super(props) - this.state = { - src: "", - activeTab: 'contacts' - } - - - } - - onTabChange(tab) { - this.setState({ - activeTab: tab - }) - - } - static getDerivedStateFromProps(props, state) { - return props; - - - } - render() { - return ( -
- -
- - {(() => { - switch (this.state.activeTab) { - case "contacts": - return - case "calls": - return "calls" - case "conversations": - return - case "groups": - return - case "info": - return - - default: - break; - } - })()} -
-
- - - - - - -
-
- ) - } -} - - - -export default NavBar; -export const navBar=NavBar; - -NavBar.defaultProps = { - src: "" -}; - diff --git a/CometChat/components/ReceiverAudioBubble/index.js b/CometChat/components/ReceiverAudioBubble/index.js deleted file mode 100644 index de4d6720..00000000 --- a/CometChat/components/ReceiverAudioBubble/index.js +++ /dev/null @@ -1,51 +0,0 @@ -import React from "react"; -import "./style.scss"; -import Avatar from "../Avatar"; - - - -class ReceiverAudioBubble extends React.Component { - constructor(props) { - super(props); - this.state = { - } - - } - static getDerivedStateFromProps(props, state) { - return props; - } - render() { - return ( - -
-
- {this.state.message.receiverType === 'group' ?
- - -
: ""} -
-
- {this.state.message.receiverType === 'group' ?
{this.state.message.sender.name}
: ""} -
- -
-
{new Date(this.state.message.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })}
- -
-
- - ); - } -} - - - -export default ReceiverAudioBubble; -export const receiverAudioBubble=ReceiverAudioBubble; - -ReceiverAudioBubble.defaultProps = { - -}; diff --git a/CometChat/components/ReceiverFileBubble/index.js b/CometChat/components/ReceiverFileBubble/index.js deleted file mode 100644 index 1a0e2240..00000000 --- a/CometChat/components/ReceiverFileBubble/index.js +++ /dev/null @@ -1,57 +0,0 @@ -import React from "react"; -import "./style.scss"; -import Avatar from "../Avatar"; -import blueFile from "./resources/file-blue.svg"; - - - - -class ReceiverFileBubble extends React.Component { - constructor(props) { - super(props); - this.state = { - } - - } - static getDerivedStateFromProps(props, state) { - return props; - } - render() { - return ( - -
-
- {this.state.message.receiverType === 'group' ?
- - -
: ""} -
-
- {this.state.message.receiverType === 'group' ?
{this.state.message.sender.name}
: ""} -
- -

{this.state.message.data.attachments[0].extension}

- - -
-
{new Date(this.state.message.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })}
- -
- -
- - ); - } -} - - - -export default ReceiverFileBubble; -export const receiverFileBubble=ReceiverFileBubble; - -ReceiverFileBubble.defaultProps = { - -}; diff --git a/CometChat/components/ReceiverImageBubble/index.js b/CometChat/components/ReceiverImageBubble/index.js deleted file mode 100644 index 108306d8..00000000 --- a/CometChat/components/ReceiverImageBubble/index.js +++ /dev/null @@ -1,49 +0,0 @@ -import React from "react"; -import "./style.scss"; -import Avatar from "../Avatar"; - - - -class ReceiverImageBubble extends React.Component { - constructor(props) { - super(props); - this.state = { - } - - } - static getDerivedStateFromProps(props, state) { - return props; - } - render() { - return ( - -
-
- {this.state.message.receiverType === 'group' ?
- - -
: ""} -
-
- {this.state.message.receiverType === 'group' ?
{this.state.message.sender.name}
: ""} -
- receiver -
-
{new Date(this.state.message.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })}
- -
- -
- - ); - } -} - - - -export default ReceiverImageBubble; -export const receiverImageBubble=ReceiverImageBubble; - -ReceiverImageBubble.defaultProps = { - -}; diff --git a/CometChat/components/ReceiverMessageBubble/index.js b/CometChat/components/ReceiverMessageBubble/index.js deleted file mode 100644 index b6b150ad..00000000 --- a/CometChat/components/ReceiverMessageBubble/index.js +++ /dev/null @@ -1,49 +0,0 @@ -import React from "react"; -import "./style.scss"; -import Avatar from "../Avatar"; - - - - -class ReceiverMessageBubble extends React.Component { - constructor(props) { - super(props); - this.state = { - } - - } - static getDerivedStateFromProps(props, state) { - return props; - } - render() { - return ( - -
- {this.state.message.receiverType === 'group'?
- - -
:""} -
- {this.state.message.receiverType === 'group'?
{this.state.message.sender.name}
:""} - -
- {this.state.message.text} -
-
{new Date(this.state.message.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })}
- -
- -
- - ); - } -} - - - -export default ReceiverMessageBubble; -export const receiverMessageBubble=ReceiverMessageBubble; - -ReceiverMessageBubble.defaultProps = { - -}; diff --git a/CometChat/components/ReceiverVideoBubble/index.js b/CometChat/components/ReceiverVideoBubble/index.js deleted file mode 100644 index d5e12faf..00000000 --- a/CometChat/components/ReceiverVideoBubble/index.js +++ /dev/null @@ -1,51 +0,0 @@ -import React from "react"; -import "./style.scss"; -import Avatar from "../Avatar"; - - -class ReceiverVideoBubble extends React.Component { - constructor(props) { - super(props); - this.state = { - } - - } - static getDerivedStateFromProps(props, state) { - return props; - } - render() { - return ( - -
-
- {this.state.message.receiverType === 'group' ?
- - -
: ""} -
-
- {this.state.message.receiverType === 'group' ?
{this.state.message.sender.name}
: ""} -
- -
-
{new Date(this.state.message.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })}
- -
- -
- - ); - } -} - - - -export default ReceiverVideoBubble; -export const receiverVideoBubble=ReceiverVideoBubble; - -ReceiverVideoBubble.defaultProps = { - -}; diff --git a/CometChat/components/SenderAudioBubble/index.js b/CometChat/components/SenderAudioBubble/index.js deleted file mode 100644 index 34d574eb..00000000 --- a/CometChat/components/SenderAudioBubble/index.js +++ /dev/null @@ -1,51 +0,0 @@ -import React from "react"; -import "./style.scss"; -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"; - - -class SenderAudioBubble extends React.Component { - constructor(props) { - super(props); - this.state = { - } - - } - static getDerivedStateFromProps(props, state) { - return props; - } - displayTicks=(message)=>{ - if(message.sentAt && !message.readAt && !message.deliveredAt){ - return greyTick; - }else if(message.sentAt && !message.readAt && message.deliveredAt){ - return greyDoubleTick - }else{ - return blueDoubleTick - } - - } - render() { - return ( - -
-
- -
-
{new Date(this.state.message.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })}time
-
- - ); - } -} - - - -export default SenderAudioBubble; -export const senderAudioBubble=SenderAudioBubble; - -SenderAudioBubble.defaultProps = { - -}; diff --git a/CometChat/components/SenderFileBubble/index.js b/CometChat/components/SenderFileBubble/index.js deleted file mode 100644 index f81b02ab..00000000 --- a/CometChat/components/SenderFileBubble/index.js +++ /dev/null @@ -1,54 +0,0 @@ -import React from "react"; -import "./style.scss"; -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 blueFile from "./resources/file-blue.svg"; - - - -class SenderFileBubble extends React.Component { - constructor(props) { - super(props); - this.state = { - } - - } - static getDerivedStateFromProps(props, state) { - return props; - } - displayTicks=(message)=>{ - if(message.sentAt && !message.readAt && !message.deliveredAt){ - return greyTick; - }else if(message.sentAt && !message.readAt && message.deliveredAt){ - return greyDoubleTick - }else{ - return blueDoubleTick - } - - } - render() { - return ( - -
-
- -

{this.state.message.data.attachments[0].extension}

- -
-
{new Date(this.state.message.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })}time
-
- - ); - } -} - - - -export default SenderFileBubble; -export const senderFileBubble=SenderFileBubble; -SenderFileBubble.defaultProps = { - -}; diff --git a/CometChat/components/SenderImageBubble/index.js b/CometChat/components/SenderImageBubble/index.js deleted file mode 100644 index 97d08ad9..00000000 --- a/CometChat/components/SenderImageBubble/index.js +++ /dev/null @@ -1,48 +0,0 @@ -import React from "react"; -import "./style.scss"; -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"; - -class SenderImageBubble extends React.Component { - constructor(props) { - super(props); - this.state = { - } - - } - static getDerivedStateFromProps(props, state) { - return props; - } - displayTicks=(message)=>{ - if(message.sentAt && !message.readAt && !message.deliveredAt){ - return greyTick; - }else if(message.sentAt && !message.readAt && message.deliveredAt){ - return greyDoubleTick - }else{ - return blueDoubleTick - } - - } - render() { - return ( - -
-
- sender -
-
{new Date(this.state.message.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })}time
-
- - ); - } -} - - - -export default SenderImageBubble; -export const senderImageBubble=SenderImageBubble; - -SenderImageBubble.defaultProps = { - -}; diff --git a/CometChat/components/SenderMessageBubble/index.js b/CometChat/components/SenderMessageBubble/index.js deleted file mode 100644 index 3b0abf91..00000000 --- a/CometChat/components/SenderMessageBubble/index.js +++ /dev/null @@ -1,52 +0,0 @@ -import React from "react"; -import "./style.scss"; -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"; - - - - -class SenderMessageBubble extends React.Component { - constructor(props) { - super(props); - this.state = { - } - - } - static getDerivedStateFromProps(props, state) { - return props; - } - displayTicks=(message)=>{ - if(message.sentAt && !message.readAt && !message.deliveredAt){ - return greyTick; - }else if(message.sentAt && !message.readAt && message.deliveredAt){ - return greyDoubleTick - }else{ - return blueDoubleTick - } - - } - render() { - return ( -
- -
- {this.state.message.text} -
-
{new Date(this.state.message.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })}time
- -
- - ); - } -} - - - -export default SenderMessageBubble; -export const senderMessageBubble=SenderMessageBubble; - -SenderMessageBubble.defaultProps = { - -}; diff --git a/CometChat/components/SenderVideoBubble/index.js b/CometChat/components/SenderVideoBubble/index.js deleted file mode 100644 index 02d30d63..00000000 --- a/CometChat/components/SenderVideoBubble/index.js +++ /dev/null @@ -1,52 +0,0 @@ -import React from "react"; -import "./style.scss"; -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"; - - -class SenderVideoBubble extends React.Component { - constructor(props) { - super(props); - this.state = { - } - - } - static getDerivedStateFromProps(props, state) { - return props; - } - displayTicks=(message)=>{ - if(message.sentAt && !message.readAt && !message.deliveredAt){ - return greyTick; - }else if(message.sentAt && !message.readAt && message.deliveredAt){ - return greyDoubleTick - }else{ - return blueDoubleTick - } - - } - render() { - return ( - -
-
- -
-
{new Date(this.state.message.sentAt * 1000).toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true })}time
-
- - ); - } -} - - - -export default SenderVideoBubble; -export const senderVideoBubble=SenderVideoBubble; - -SenderVideoBubble.defaultProps = { - -}; diff --git a/CometChat/components/UserProfile/index.js b/CometChat/components/UserProfile/index.js deleted file mode 100644 index 41559a5d..00000000 --- a/CometChat/components/UserProfile/index.js +++ /dev/null @@ -1,95 +0,0 @@ -import React from "react"; -import "./style.scss"; -import { CometChat } from "@cometchat-pro/chat"; - - - -class UserProfile extends React.Component { - constructor(props) { - super(props) - this.state = { - src: "", - activeTab: 'contacts' - } - } - - onTabChange(tab) { - this.setState({ - activeTab: tab - }) - - } - blockUser=()=>{ - let usersList = [this.state.item.uid]; - CometChat.blockUsers(usersList).then( - list => { - this.setState(prevState => ({ - item: { - ...prevState.item, - blockedByMe: true - } - })) - }, - error => { - console.log("Blocking user fails with error", error); - } -); - - } - unblockUser=()=>{ - let usersList = [this.state.item.uid]; -CometChat.unblockUsers(usersList).then( - list => { - this.setState(prevState => ({ - item: { - ...prevState.item, - blockedByMe: false - } - })) - }, - error => { - console.log("unblocking user fails with error", error); - } -); - } - static getDerivedStateFromProps(props, state) { - return {...props,...state}; - - } - render() { - return ( -
-

Details

-
-
- Notifications -
-
- -
-

Privacy and Support

-
-
- {this.state.type ==='user'?
- {!this.state.item.blockedByMe?:""} - {this.state.item.blockedByMe?:""} -
:""} -
- -
-
- -
- ) - } -} - - - -export default UserProfile; -export const userProfile=UserProfile; - -UserProfile.defaultProps = { - src: "" -}; - diff --git a/CometChat/components/UserView/index.js b/CometChat/components/UserView/index.js index 6a1d7d37..91e0f0a7 100644 --- a/CometChat/components/UserView/index.js +++ b/CometChat/components/UserView/index.js @@ -1,51 +1,26 @@ import React from "react"; import "./style.scss"; -import Avatar from "../Avatar"; - -class UserView extends React.Component { - constructor(props){ - super(props); - this.state={ - user:{}, - } +import Avatar from "../Avatar"; - } - static getDerivedStateFromProps(props,state){ - return props; - } - render() { - return ( -
{ if(this.props.onClick)this.props.onClick(this.state.user)}}> -
-
- -
-
-
- {this.state.user.name} -
- {/* - - {this.state.user.status} - */} -
- -
- - - - +const userview = (props) => { + + return ( +
+
+
+ +
+
+
{props.user.name}
+
- ); - } +
+ ) } - - -export default UserView; -export const userView=UserView; - -UserView.defaultProps = { - user:{} -}; +export default userview; \ No newline at end of file diff --git a/CometChat/index.js b/CometChat/index.js index 981a52c5..ffd13778 100644 --- a/CometChat/index.js +++ b/CometChat/index.js @@ -1,21 +1,13 @@ -import { cometChatConversationList } from "./components/CometChatConversationList"; -import { cometChatConversationListScreen } from "./components/CometChatConversationListScreen"; -import { cometChatGroupList } from "./components/CometChatGroupList"; -import { cometChatGroupListScreen } from "./components/CometChatGroupListScreen"; -import { cometChatUserList } from "./components/CometChatUserList"; -import { cometChatUserListScreen } from "./components/CometChatUserListScreen"; -import { cometChatMessageScreen } from "./components/CometChatMessageScreen"; -import { avatar } from "./components/Avatar"; -import { badgeCount } from "./components/BadgeCount"; -import { cometChatUnified } from "./components/CometChatUnified"; +export { default as Avatar } from "./components/Avatar"; +export { default as BadgeCount } from "./components/BadgeCount"; -export const CometChatConversationList = cometChatConversationList; -export const CometChatConversationListScreen = cometChatConversationListScreen; -export const CometChatGroupList = cometChatGroupList; -export const CometChatGroupListScreen = cometChatGroupListScreen; -export const CometChatUserList = cometChatUserList; -export const CometChatUserListScreen = cometChatUserListScreen; -export const CometChatMessageScreen = cometChatMessageScreen; -export const Avatar = avatar; -export const BadgeCount = badgeCount; -export const CometChatUnified = cometChatUnified; \ No newline at end of file +export { default as CometChatUserList } from "./components/CometChatUserList"; +export { default as CometChatUserListScreen } from "./components/CometChatUserListScreen"; + +export { default as CometChatGroupList } from "./components/CometChatGroupList"; +export { default as CometChatGroupListScreen } from "./components/CometChatGroupListScreen"; + +export { default as CometChatConversationList } from "./components/CometChatConversationList"; +export { default as CometChatConversationListScreen } from "./components/CometChatConversationListScreen"; + +export { default as CometChatUnified } from "./components/CometChatUnified"; \ No newline at end of file diff --git a/CometChat/resources/_mixins.scss b/CometChat/resources/_mixins.scss index cbc8198e..52bf2041 100644 --- a/CometChat/resources/_mixins.scss +++ b/CometChat/resources/_mixins.scss @@ -1,12 +1,12 @@ // Font Family -$base__font-family: 'Inter', sans-serif !important; +$base__font-family: "Inter", sans-serif !important; // Font Size $base__font-size: 17 !default; // Convert value rem() sass mixin @function rem($px, $base: $base__font-size) { - @return #{floor( ($px/$base) * 100 ) / 100}rem; // to REMs + @return #{floor(($px/$base) * 100) / 100}rem; // to REMs // comment code above and uncomment below for change REMs to PXs //@return #{$px}px; } @@ -63,7 +63,6 @@ $xs-max-width: 575px; background: #e8e8e8; } - //Bootstrap /*! * Bootstrap v4.3.1 (https://getbootstrap.com/) @@ -71,7 +70,7 @@ $xs-max-width: 575px; * Copyright 2011-2019 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) */ - :root { +:root { --blue: #007bff; --indigo: #6610f2; --purple: #6f42c1; @@ -98,7 +97,8 @@ $xs-max-width: 575px; --breakpoint-md: 768px; --breakpoint-lg: 992px; --breakpoint-xl: 1200px; - --font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", + sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; --font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; } @@ -115,13 +115,23 @@ html { -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } -article, aside, figcaption, figure, footer, header, hgroup, main, nav, section { +article, +aside, +figcaption, +figure, +footer, +header, +hgroup, +main, +nav, +section { display: block; } body { margin: 0; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, + "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 1rem; font-weight: 400; line-height: 1.5; @@ -140,7 +150,12 @@ hr { overflow: visible; } -h1, h2, h3, h4, h5, h6 { +h1, +h2, +h3, +h4, +h5, +h6 { margin-top: 0; margin-bottom: 0.5rem; } @@ -186,7 +201,7 @@ dt { } dd { - margin-bottom: .5rem; + margin-bottom: 0.5rem; margin-left: 0; } @@ -212,11 +227,11 @@ sup { } sub { - bottom: -.25em; + bottom: -0.25em; } sup { - top: -.5em; + top: -0.5em; } a { @@ -235,7 +250,8 @@ a:not([href]):not([tabindex]) { text-decoration: none; } -a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus { +a:not([href]):not([tabindex]):hover, +a:not([href]):not([tabindex]):focus { color: inherit; text-decoration: none; } @@ -379,7 +395,7 @@ legend { width: 100%; max-width: 100%; padding: 0; - margin-bottom: .5rem; + margin-bottom: 0.5rem; font-size: 1.5rem; line-height: inherit; color: inherit; @@ -426,34 +442,50 @@ template { display: none !important; } -h1, h2, h3, h4, h5, h6, -.h1, .h2, .h3, .h4, .h5, .h6 { +h1, +h2, +h3, +h4, +h5, +h6, +.h1, +.h2, +.h3, +.h4, +.h5, +.h6 { margin-bottom: 0.5rem; font-weight: 500; line-height: 1.2; } -h1, .h1 { +h1, +.h1 { font-size: 2.5rem; } -h2, .h2 { +h2, +.h2 { font-size: 2rem; } -h3, .h3 { +h3, +.h3 { font-size: 1.75rem; } -h4, .h4 { +h4, +.h4 { font-size: 1.5rem; } -h5, .h5 { +h5, +.h5 { font-size: 1.25rem; } -h6, .h6 { +h6, +.h6 { font-size: 1rem; } @@ -672,11 +704,75 @@ pre code { padding-left: 0; } -.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12, .col, -.col-auto, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm, -.col-sm-auto, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-md, -.col-md-auto, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg, -.col-lg-auto, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl, +.col-1, +.col-2, +.col-3, +.col-4, +.col-5, +.col-6, +.col-7, +.col-8, +.col-9, +.col-10, +.col-11, +.col-12, +.col, +.col-auto, +.col-sm-1, +.col-sm-2, +.col-sm-3, +.col-sm-4, +.col-sm-5, +.col-sm-6, +.col-sm-7, +.col-sm-8, +.col-sm-9, +.col-sm-10, +.col-sm-11, +.col-sm-12, +.col-sm, +.col-sm-auto, +.col-md-1, +.col-md-2, +.col-md-3, +.col-md-4, +.col-md-5, +.col-md-6, +.col-md-7, +.col-md-8, +.col-md-9, +.col-md-10, +.col-md-11, +.col-md-12, +.col-md, +.col-md-auto, +.col-lg-1, +.col-lg-2, +.col-lg-3, +.col-lg-4, +.col-lg-5, +.col-lg-6, +.col-lg-7, +.col-lg-8, +.col-lg-9, +.col-lg-10, +.col-lg-11, +.col-lg-12, +.col-lg, +.col-lg-auto, +.col-xl-1, +.col-xl-2, +.col-xl-3, +.col-xl-4, +.col-xl-5, +.col-xl-6, +.col-xl-7, +.col-xl-8, +.col-xl-9, +.col-xl-10, +.col-xl-11, +.col-xl-12, +.col-xl, .col-xl-auto { position: relative; width: 100%; @@ -1981,7 +2077,8 @@ pre code { opacity: 1; } -.form-control:disabled, .form-control[readonly] { +.form-control:disabled, +.form-control[readonly] { background-color: #e9ecef; opacity: 1; } @@ -2032,7 +2129,8 @@ select.form-control:focus::-ms-value { border-width: 1px 0; } -.form-control-plaintext.form-control-sm, .form-control-plaintext.form-control-lg { +.form-control-plaintext.form-control-sm, +.form-control-plaintext.form-control-lg { padding-right: 0; padding-left: 0; } @@ -2053,7 +2151,8 @@ select.form-control:focus::-ms-value { border-radius: 0.3rem; } -select.form-control[size], select.form-control[multiple] { +select.form-control[size], +select.form-control[multiple] { height: auto; } @@ -2136,7 +2235,7 @@ textarea.form-control { display: none; max-width: 100%; padding: 0.25rem 0.5rem; - margin-top: .1rem; + margin-top: 0.1rem; font-size: 0.875rem; line-height: 1.5; color: #fff; @@ -2144,7 +2243,8 @@ textarea.form-control { border-radius: 0.25rem; } -.was-validated .form-control:valid, .form-control.is-valid { +.was-validated .form-control:valid, +.form-control.is-valid { border-color: #28a745; padding-right: calc(1.5em + 0.75rem); background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e"); @@ -2153,93 +2253,114 @@ textarea.form-control { background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); } -.was-validated .form-control:valid:focus, .form-control.is-valid:focus { +.was-validated .form-control:valid:focus, +.form-control.is-valid:focus { border-color: #28a745; box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); } .was-validated .form-control:valid ~ .valid-feedback, -.was-validated .form-control:valid ~ .valid-tooltip, .form-control.is-valid ~ .valid-feedback, +.was-validated .form-control:valid ~ .valid-tooltip, +.form-control.is-valid ~ .valid-feedback, .form-control.is-valid ~ .valid-tooltip { display: block; } -.was-validated textarea.form-control:valid, textarea.form-control.is-valid { +.was-validated textarea.form-control:valid, +textarea.form-control.is-valid { padding-right: calc(1.5em + 0.75rem); background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem); } -.was-validated .custom-select:valid, .custom-select.is-valid { +.was-validated .custom-select:valid, +.custom-select.is-valid { border-color: #28a745; padding-right: calc((1em + 0.75rem) * 3 / 4 + 1.75rem); - background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right 0.75rem center/8px 10px, url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e") #fff no-repeat center right 1.75rem/calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); + background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") + no-repeat right 0.75rem center/8px 10px, + url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e") + #fff no-repeat center right 1.75rem / calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); } -.was-validated .custom-select:valid:focus, .custom-select.is-valid:focus { +.was-validated .custom-select:valid:focus, +.custom-select.is-valid:focus { border-color: #28a745; box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); } .was-validated .custom-select:valid ~ .valid-feedback, -.was-validated .custom-select:valid ~ .valid-tooltip, .custom-select.is-valid ~ .valid-feedback, +.was-validated .custom-select:valid ~ .valid-tooltip, +.custom-select.is-valid ~ .valid-feedback, .custom-select.is-valid ~ .valid-tooltip { display: block; } .was-validated .form-control-file:valid ~ .valid-feedback, -.was-validated .form-control-file:valid ~ .valid-tooltip, .form-control-file.is-valid ~ .valid-feedback, +.was-validated .form-control-file:valid ~ .valid-tooltip, +.form-control-file.is-valid ~ .valid-feedback, .form-control-file.is-valid ~ .valid-tooltip { display: block; } -.was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label { +.was-validated .form-check-input:valid ~ .form-check-label, +.form-check-input.is-valid ~ .form-check-label { color: #28a745; } .was-validated .form-check-input:valid ~ .valid-feedback, -.was-validated .form-check-input:valid ~ .valid-tooltip, .form-check-input.is-valid ~ .valid-feedback, +.was-validated .form-check-input:valid ~ .valid-tooltip, +.form-check-input.is-valid ~ .valid-feedback, .form-check-input.is-valid ~ .valid-tooltip { display: block; } -.was-validated .custom-control-input:valid ~ .custom-control-label, .custom-control-input.is-valid ~ .custom-control-label { +.was-validated .custom-control-input:valid ~ .custom-control-label, +.custom-control-input.is-valid ~ .custom-control-label { color: #28a745; } -.was-validated .custom-control-input:valid ~ .custom-control-label::before, .custom-control-input.is-valid ~ .custom-control-label::before { +.was-validated .custom-control-input:valid ~ .custom-control-label::before, +.custom-control-input.is-valid ~ .custom-control-label::before { border-color: #28a745; } .was-validated .custom-control-input:valid ~ .valid-feedback, -.was-validated .custom-control-input:valid ~ .valid-tooltip, .custom-control-input.is-valid ~ .valid-feedback, +.was-validated .custom-control-input:valid ~ .valid-tooltip, +.custom-control-input.is-valid ~ .valid-feedback, .custom-control-input.is-valid ~ .valid-tooltip { display: block; } -.was-validated .custom-control-input:valid:checked ~ .custom-control-label::before, .custom-control-input.is-valid:checked ~ .custom-control-label::before { +.was-validated .custom-control-input:valid:checked ~ .custom-control-label::before, +.custom-control-input.is-valid:checked ~ .custom-control-label::before { border-color: #34ce57; background-color: #34ce57; } -.was-validated .custom-control-input:valid:focus ~ .custom-control-label::before, .custom-control-input.is-valid:focus ~ .custom-control-label::before { +.was-validated .custom-control-input:valid:focus ~ .custom-control-label::before, +.custom-control-input.is-valid:focus ~ .custom-control-label::before { box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); } -.was-validated .custom-control-input:valid:focus:not(:checked) ~ .custom-control-label::before, .custom-control-input.is-valid:focus:not(:checked) ~ .custom-control-label::before { +.was-validated .custom-control-input:valid:focus:not(:checked) ~ .custom-control-label::before, +.custom-control-input.is-valid:focus:not(:checked) ~ .custom-control-label::before { border-color: #28a745; } -.was-validated .custom-file-input:valid ~ .custom-file-label, .custom-file-input.is-valid ~ .custom-file-label { +.was-validated .custom-file-input:valid ~ .custom-file-label, +.custom-file-input.is-valid ~ .custom-file-label { border-color: #28a745; } .was-validated .custom-file-input:valid ~ .valid-feedback, -.was-validated .custom-file-input:valid ~ .valid-tooltip, .custom-file-input.is-valid ~ .valid-feedback, +.was-validated .custom-file-input:valid ~ .valid-tooltip, +.custom-file-input.is-valid ~ .valid-feedback, .custom-file-input.is-valid ~ .valid-tooltip { display: block; } -.was-validated .custom-file-input:valid:focus ~ .custom-file-label, .custom-file-input.is-valid:focus ~ .custom-file-label { +.was-validated .custom-file-input:valid:focus ~ .custom-file-label, +.custom-file-input.is-valid:focus ~ .custom-file-label { border-color: #28a745; box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); } @@ -2259,7 +2380,7 @@ textarea.form-control { display: none; max-width: 100%; padding: 0.25rem 0.5rem; - margin-top: .1rem; + margin-top: 0.1rem; font-size: 0.875rem; line-height: 1.5; color: #fff; @@ -2267,7 +2388,8 @@ textarea.form-control { border-radius: 0.25rem; } -.was-validated .form-control:invalid, .form-control.is-invalid { +.was-validated .form-control:invalid, +.form-control.is-invalid { border-color: #dc3545; padding-right: calc(1.5em + 0.75rem); background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E"); @@ -2276,93 +2398,114 @@ textarea.form-control { background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); } -.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus { +.was-validated .form-control:invalid:focus, +.form-control.is-invalid:focus { border-color: #dc3545; box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); } .was-validated .form-control:invalid ~ .invalid-feedback, -.was-validated .form-control:invalid ~ .invalid-tooltip, .form-control.is-invalid ~ .invalid-feedback, +.was-validated .form-control:invalid ~ .invalid-tooltip, +.form-control.is-invalid ~ .invalid-feedback, .form-control.is-invalid ~ .invalid-tooltip { display: block; } -.was-validated textarea.form-control:invalid, textarea.form-control.is-invalid { +.was-validated textarea.form-control:invalid, +textarea.form-control.is-invalid { padding-right: calc(1.5em + 0.75rem); background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem); } -.was-validated .custom-select:invalid, .custom-select.is-invalid { +.was-validated .custom-select:invalid, +.custom-select.is-invalid { border-color: #dc3545; padding-right: calc((1em + 0.75rem) * 3 / 4 + 1.75rem); - background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right 0.75rem center/8px 10px, url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E") #fff no-repeat center right 1.75rem/calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); + background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") + no-repeat right 0.75rem center/8px 10px, + url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E") + #fff no-repeat center right 1.75rem / calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); } -.was-validated .custom-select:invalid:focus, .custom-select.is-invalid:focus { +.was-validated .custom-select:invalid:focus, +.custom-select.is-invalid:focus { border-color: #dc3545; box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); } .was-validated .custom-select:invalid ~ .invalid-feedback, -.was-validated .custom-select:invalid ~ .invalid-tooltip, .custom-select.is-invalid ~ .invalid-feedback, +.was-validated .custom-select:invalid ~ .invalid-tooltip, +.custom-select.is-invalid ~ .invalid-feedback, .custom-select.is-invalid ~ .invalid-tooltip { display: block; } .was-validated .form-control-file:invalid ~ .invalid-feedback, -.was-validated .form-control-file:invalid ~ .invalid-tooltip, .form-control-file.is-invalid ~ .invalid-feedback, +.was-validated .form-control-file:invalid ~ .invalid-tooltip, +.form-control-file.is-invalid ~ .invalid-feedback, .form-control-file.is-invalid ~ .invalid-tooltip { display: block; } -.was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label { +.was-validated .form-check-input:invalid ~ .form-check-label, +.form-check-input.is-invalid ~ .form-check-label { color: #dc3545; } .was-validated .form-check-input:invalid ~ .invalid-feedback, -.was-validated .form-check-input:invalid ~ .invalid-tooltip, .form-check-input.is-invalid ~ .invalid-feedback, +.was-validated .form-check-input:invalid ~ .invalid-tooltip, +.form-check-input.is-invalid ~ .invalid-feedback, .form-check-input.is-invalid ~ .invalid-tooltip { display: block; } -.was-validated .custom-control-input:invalid ~ .custom-control-label, .custom-control-input.is-invalid ~ .custom-control-label { +.was-validated .custom-control-input:invalid ~ .custom-control-label, +.custom-control-input.is-invalid ~ .custom-control-label { color: #dc3545; } -.was-validated .custom-control-input:invalid ~ .custom-control-label::before, .custom-control-input.is-invalid ~ .custom-control-label::before { +.was-validated .custom-control-input:invalid ~ .custom-control-label::before, +.custom-control-input.is-invalid ~ .custom-control-label::before { border-color: #dc3545; } .was-validated .custom-control-input:invalid ~ .invalid-feedback, -.was-validated .custom-control-input:invalid ~ .invalid-tooltip, .custom-control-input.is-invalid ~ .invalid-feedback, +.was-validated .custom-control-input:invalid ~ .invalid-tooltip, +.custom-control-input.is-invalid ~ .invalid-feedback, .custom-control-input.is-invalid ~ .invalid-tooltip { display: block; } -.was-validated .custom-control-input:invalid:checked ~ .custom-control-label::before, .custom-control-input.is-invalid:checked ~ .custom-control-label::before { +.was-validated .custom-control-input:invalid:checked ~ .custom-control-label::before, +.custom-control-input.is-invalid:checked ~ .custom-control-label::before { border-color: #e4606d; background-color: #e4606d; } -.was-validated .custom-control-input:invalid:focus ~ .custom-control-label::before, .custom-control-input.is-invalid:focus ~ .custom-control-label::before { +.was-validated .custom-control-input:invalid:focus ~ .custom-control-label::before, +.custom-control-input.is-invalid:focus ~ .custom-control-label::before { box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); } -.was-validated .custom-control-input:invalid:focus:not(:checked) ~ .custom-control-label::before, .custom-control-input.is-invalid:focus:not(:checked) ~ .custom-control-label::before { +.was-validated .custom-control-input:invalid:focus:not(:checked) ~ .custom-control-label::before, +.custom-control-input.is-invalid:focus:not(:checked) ~ .custom-control-label::before { border-color: #dc3545; } -.was-validated .custom-file-input:invalid ~ .custom-file-label, .custom-file-input.is-invalid ~ .custom-file-label { +.was-validated .custom-file-input:invalid ~ .custom-file-label, +.custom-file-input.is-invalid ~ .custom-file-label { border-color: #dc3545; } .was-validated .custom-file-input:invalid ~ .invalid-feedback, -.was-validated .custom-file-input:invalid ~ .invalid-tooltip, .custom-file-input.is-invalid ~ .invalid-feedback, +.was-validated .custom-file-input:invalid ~ .invalid-tooltip, +.custom-file-input.is-invalid ~ .invalid-feedback, .custom-file-input.is-invalid ~ .invalid-tooltip { display: block; } -.was-validated .custom-file-input:invalid:focus ~ .custom-file-label, .custom-file-input.is-invalid:focus ~ .custom-file-label { +.was-validated .custom-file-input:invalid:focus ~ .custom-file-label, +.custom-file-input.is-invalid:focus ~ .custom-file-label { border-color: #dc3545; box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); } @@ -2458,7 +2601,8 @@ textarea.form-control { font-size: 1rem; line-height: 1.5; border-radius: 0.25rem; - transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, + box-shadow 0.15s ease-in-out; } @media (prefers-reduced-motion: reduce) { @@ -2472,12 +2616,14 @@ textarea.form-control { text-decoration: none; } -.btn:focus, .btn.focus { +.btn:focus, +.btn.focus { outline: 0; box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); } -.btn.disabled, .btn:disabled { +.btn.disabled, +.btn:disabled { opacity: 0.65; } @@ -2498,24 +2644,28 @@ fieldset:disabled a.btn { border-color: #0062cc; } -.btn-primary:focus, .btn-primary.focus { +.btn-primary:focus, +.btn-primary.focus { box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5); } -.btn-primary.disabled, .btn-primary:disabled { +.btn-primary.disabled, +.btn-primary:disabled { color: #fff; background-color: #007bff; border-color: #007bff; } -.btn-primary:not(:disabled):not(.disabled):active, .btn-primary:not(:disabled):not(.disabled).active, +.btn-primary:not(:disabled):not(.disabled):active, +.btn-primary:not(:disabled):not(.disabled).active, .show > .btn-primary.dropdown-toggle { color: #fff; background-color: #0062cc; border-color: #005cbf; } -.btn-primary:not(:disabled):not(.disabled):active:focus, .btn-primary:not(:disabled):not(.disabled).active:focus, +.btn-primary:not(:disabled):not(.disabled):active:focus, +.btn-primary:not(:disabled):not(.disabled).active:focus, .show > .btn-primary.dropdown-toggle:focus { box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5); } @@ -2532,24 +2682,28 @@ fieldset:disabled a.btn { border-color: #545b62; } -.btn-secondary:focus, .btn-secondary.focus { +.btn-secondary:focus, +.btn-secondary.focus { box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5); } -.btn-secondary.disabled, .btn-secondary:disabled { +.btn-secondary.disabled, +.btn-secondary:disabled { color: #fff; background-color: #6c757d; border-color: #6c757d; } -.btn-secondary:not(:disabled):not(.disabled):active, .btn-secondary:not(:disabled):not(.disabled).active, +.btn-secondary:not(:disabled):not(.disabled):active, +.btn-secondary:not(:disabled):not(.disabled).active, .show > .btn-secondary.dropdown-toggle { color: #fff; background-color: #545b62; border-color: #4e555b; } -.btn-secondary:not(:disabled):not(.disabled):active:focus, .btn-secondary:not(:disabled):not(.disabled).active:focus, +.btn-secondary:not(:disabled):not(.disabled):active:focus, +.btn-secondary:not(:disabled):not(.disabled).active:focus, .show > .btn-secondary.dropdown-toggle:focus { box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5); } @@ -2566,24 +2720,28 @@ fieldset:disabled a.btn { border-color: #1e7e34; } -.btn-success:focus, .btn-success.focus { +.btn-success:focus, +.btn-success.focus { box-shadow: 0 0 0 0.2rem rgba(72, 180, 97, 0.5); } -.btn-success.disabled, .btn-success:disabled { +.btn-success.disabled, +.btn-success:disabled { color: #fff; background-color: #28a745; border-color: #28a745; } -.btn-success:not(:disabled):not(.disabled):active, .btn-success:not(:disabled):not(.disabled).active, +.btn-success:not(:disabled):not(.disabled):active, +.btn-success:not(:disabled):not(.disabled).active, .show > .btn-success.dropdown-toggle { color: #fff; background-color: #1e7e34; border-color: #1c7430; } -.btn-success:not(:disabled):not(.disabled):active:focus, .btn-success:not(:disabled):not(.disabled).active:focus, +.btn-success:not(:disabled):not(.disabled):active:focus, +.btn-success:not(:disabled):not(.disabled).active:focus, .show > .btn-success.dropdown-toggle:focus { box-shadow: 0 0 0 0.2rem rgba(72, 180, 97, 0.5); } @@ -2600,24 +2758,28 @@ fieldset:disabled a.btn { border-color: #117a8b; } -.btn-info:focus, .btn-info.focus { +.btn-info:focus, +.btn-info.focus { box-shadow: 0 0 0 0.2rem rgba(58, 176, 195, 0.5); } -.btn-info.disabled, .btn-info:disabled { +.btn-info.disabled, +.btn-info:disabled { color: #fff; background-color: #17a2b8; border-color: #17a2b8; } -.btn-info:not(:disabled):not(.disabled):active, .btn-info:not(:disabled):not(.disabled).active, +.btn-info:not(:disabled):not(.disabled):active, +.btn-info:not(:disabled):not(.disabled).active, .show > .btn-info.dropdown-toggle { color: #fff; background-color: #117a8b; border-color: #10707f; } -.btn-info:not(:disabled):not(.disabled):active:focus, .btn-info:not(:disabled):not(.disabled).active:focus, +.btn-info:not(:disabled):not(.disabled):active:focus, +.btn-info:not(:disabled):not(.disabled).active:focus, .show > .btn-info.dropdown-toggle:focus { box-shadow: 0 0 0 0.2rem rgba(58, 176, 195, 0.5); } @@ -2634,24 +2796,28 @@ fieldset:disabled a.btn { border-color: #d39e00; } -.btn-warning:focus, .btn-warning.focus { +.btn-warning:focus, +.btn-warning.focus { box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5); } -.btn-warning.disabled, .btn-warning:disabled { +.btn-warning.disabled, +.btn-warning:disabled { color: #212529; background-color: #ffc107; border-color: #ffc107; } -.btn-warning:not(:disabled):not(.disabled):active, .btn-warning:not(:disabled):not(.disabled).active, +.btn-warning:not(:disabled):not(.disabled):active, +.btn-warning:not(:disabled):not(.disabled).active, .show > .btn-warning.dropdown-toggle { color: #212529; background-color: #d39e00; border-color: #c69500; } -.btn-warning:not(:disabled):not(.disabled):active:focus, .btn-warning:not(:disabled):not(.disabled).active:focus, +.btn-warning:not(:disabled):not(.disabled):active:focus, +.btn-warning:not(:disabled):not(.disabled).active:focus, .show > .btn-warning.dropdown-toggle:focus { box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5); } @@ -2668,24 +2834,28 @@ fieldset:disabled a.btn { border-color: #bd2130; } -.btn-danger:focus, .btn-danger.focus { +.btn-danger:focus, +.btn-danger.focus { box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5); } -.btn-danger.disabled, .btn-danger:disabled { +.btn-danger.disabled, +.btn-danger:disabled { color: #fff; background-color: #dc3545; border-color: #dc3545; } -.btn-danger:not(:disabled):not(.disabled):active, .btn-danger:not(:disabled):not(.disabled).active, +.btn-danger:not(:disabled):not(.disabled):active, +.btn-danger:not(:disabled):not(.disabled).active, .show > .btn-danger.dropdown-toggle { color: #fff; background-color: #bd2130; border-color: #b21f2d; } -.btn-danger:not(:disabled):not(.disabled):active:focus, .btn-danger:not(:disabled):not(.disabled).active:focus, +.btn-danger:not(:disabled):not(.disabled):active:focus, +.btn-danger:not(:disabled):not(.disabled).active:focus, .show > .btn-danger.dropdown-toggle:focus { box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5); } @@ -2702,24 +2872,28 @@ fieldset:disabled a.btn { border-color: #dae0e5; } -.btn-light:focus, .btn-light.focus { +.btn-light:focus, +.btn-light.focus { box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5); } -.btn-light.disabled, .btn-light:disabled { +.btn-light.disabled, +.btn-light:disabled { color: #212529; background-color: #f8f9fa; border-color: #f8f9fa; } -.btn-light:not(:disabled):not(.disabled):active, .btn-light:not(:disabled):not(.disabled).active, +.btn-light:not(:disabled):not(.disabled):active, +.btn-light:not(:disabled):not(.disabled).active, .show > .btn-light.dropdown-toggle { color: #212529; background-color: #dae0e5; border-color: #d3d9df; } -.btn-light:not(:disabled):not(.disabled):active:focus, .btn-light:not(:disabled):not(.disabled).active:focus, +.btn-light:not(:disabled):not(.disabled):active:focus, +.btn-light:not(:disabled):not(.disabled).active:focus, .show > .btn-light.dropdown-toggle:focus { box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5); } @@ -2736,24 +2910,28 @@ fieldset:disabled a.btn { border-color: #1d2124; } -.btn-dark:focus, .btn-dark.focus { +.btn-dark:focus, +.btn-dark.focus { box-shadow: 0 0 0 0.2rem rgba(82, 88, 93, 0.5); } -.btn-dark.disabled, .btn-dark:disabled { +.btn-dark.disabled, +.btn-dark:disabled { color: #fff; background-color: #343a40; border-color: #343a40; } -.btn-dark:not(:disabled):not(.disabled):active, .btn-dark:not(:disabled):not(.disabled).active, +.btn-dark:not(:disabled):not(.disabled):active, +.btn-dark:not(:disabled):not(.disabled).active, .show > .btn-dark.dropdown-toggle { color: #fff; background-color: #1d2124; border-color: #171a1d; } -.btn-dark:not(:disabled):not(.disabled):active:focus, .btn-dark:not(:disabled):not(.disabled).active:focus, +.btn-dark:not(:disabled):not(.disabled):active:focus, +.btn-dark:not(:disabled):not(.disabled).active:focus, .show > .btn-dark.dropdown-toggle:focus { box-shadow: 0 0 0 0.2rem rgba(82, 88, 93, 0.5); } @@ -2769,23 +2947,27 @@ fieldset:disabled a.btn { border-color: #007bff; } -.btn-outline-primary:focus, .btn-outline-primary.focus { +.btn-outline-primary:focus, +.btn-outline-primary.focus { box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5); } -.btn-outline-primary.disabled, .btn-outline-primary:disabled { +.btn-outline-primary.disabled, +.btn-outline-primary:disabled { color: #007bff; background-color: transparent; } -.btn-outline-primary:not(:disabled):not(.disabled):active, .btn-outline-primary:not(:disabled):not(.disabled).active, +.btn-outline-primary:not(:disabled):not(.disabled):active, +.btn-outline-primary:not(:disabled):not(.disabled).active, .show > .btn-outline-primary.dropdown-toggle { color: #fff; background-color: #007bff; border-color: #007bff; } -.btn-outline-primary:not(:disabled):not(.disabled):active:focus, .btn-outline-primary:not(:disabled):not(.disabled).active:focus, +.btn-outline-primary:not(:disabled):not(.disabled):active:focus, +.btn-outline-primary:not(:disabled):not(.disabled).active:focus, .show > .btn-outline-primary.dropdown-toggle:focus { box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5); } @@ -2801,23 +2983,27 @@ fieldset:disabled a.btn { border-color: #6c757d; } -.btn-outline-secondary:focus, .btn-outline-secondary.focus { +.btn-outline-secondary:focus, +.btn-outline-secondary.focus { box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); } -.btn-outline-secondary.disabled, .btn-outline-secondary:disabled { +.btn-outline-secondary.disabled, +.btn-outline-secondary:disabled { color: #6c757d; background-color: transparent; } -.btn-outline-secondary:not(:disabled):not(.disabled):active, .btn-outline-secondary:not(:disabled):not(.disabled).active, +.btn-outline-secondary:not(:disabled):not(.disabled):active, +.btn-outline-secondary:not(:disabled):not(.disabled).active, .show > .btn-outline-secondary.dropdown-toggle { color: #fff; background-color: #6c757d; border-color: #6c757d; } -.btn-outline-secondary:not(:disabled):not(.disabled):active:focus, .btn-outline-secondary:not(:disabled):not(.disabled).active:focus, +.btn-outline-secondary:not(:disabled):not(.disabled):active:focus, +.btn-outline-secondary:not(:disabled):not(.disabled).active:focus, .show > .btn-outline-secondary.dropdown-toggle:focus { box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); } @@ -2833,23 +3019,27 @@ fieldset:disabled a.btn { border-color: #28a745; } -.btn-outline-success:focus, .btn-outline-success.focus { +.btn-outline-success:focus, +.btn-outline-success.focus { box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); } -.btn-outline-success.disabled, .btn-outline-success:disabled { +.btn-outline-success.disabled, +.btn-outline-success:disabled { color: #28a745; background-color: transparent; } -.btn-outline-success:not(:disabled):not(.disabled):active, .btn-outline-success:not(:disabled):not(.disabled).active, +.btn-outline-success:not(:disabled):not(.disabled):active, +.btn-outline-success:not(:disabled):not(.disabled).active, .show > .btn-outline-success.dropdown-toggle { color: #fff; background-color: #28a745; border-color: #28a745; } -.btn-outline-success:not(:disabled):not(.disabled):active:focus, .btn-outline-success:not(:disabled):not(.disabled).active:focus, +.btn-outline-success:not(:disabled):not(.disabled):active:focus, +.btn-outline-success:not(:disabled):not(.disabled).active:focus, .show > .btn-outline-success.dropdown-toggle:focus { box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); } @@ -2865,23 +3055,27 @@ fieldset:disabled a.btn { border-color: #17a2b8; } -.btn-outline-info:focus, .btn-outline-info.focus { +.btn-outline-info:focus, +.btn-outline-info.focus { box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); } -.btn-outline-info.disabled, .btn-outline-info:disabled { +.btn-outline-info.disabled, +.btn-outline-info:disabled { color: #17a2b8; background-color: transparent; } -.btn-outline-info:not(:disabled):not(.disabled):active, .btn-outline-info:not(:disabled):not(.disabled).active, +.btn-outline-info:not(:disabled):not(.disabled):active, +.btn-outline-info:not(:disabled):not(.disabled).active, .show > .btn-outline-info.dropdown-toggle { color: #fff; background-color: #17a2b8; border-color: #17a2b8; } -.btn-outline-info:not(:disabled):not(.disabled):active:focus, .btn-outline-info:not(:disabled):not(.disabled).active:focus, +.btn-outline-info:not(:disabled):not(.disabled):active:focus, +.btn-outline-info:not(:disabled):not(.disabled).active:focus, .show > .btn-outline-info.dropdown-toggle:focus { box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); } @@ -2897,23 +3091,27 @@ fieldset:disabled a.btn { border-color: #ffc107; } -.btn-outline-warning:focus, .btn-outline-warning.focus { +.btn-outline-warning:focus, +.btn-outline-warning.focus { box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); } -.btn-outline-warning.disabled, .btn-outline-warning:disabled { +.btn-outline-warning.disabled, +.btn-outline-warning:disabled { color: #ffc107; background-color: transparent; } -.btn-outline-warning:not(:disabled):not(.disabled):active, .btn-outline-warning:not(:disabled):not(.disabled).active, +.btn-outline-warning:not(:disabled):not(.disabled):active, +.btn-outline-warning:not(:disabled):not(.disabled).active, .show > .btn-outline-warning.dropdown-toggle { color: #212529; background-color: #ffc107; border-color: #ffc107; } -.btn-outline-warning:not(:disabled):not(.disabled):active:focus, .btn-outline-warning:not(:disabled):not(.disabled).active:focus, +.btn-outline-warning:not(:disabled):not(.disabled):active:focus, +.btn-outline-warning:not(:disabled):not(.disabled).active:focus, .show > .btn-outline-warning.dropdown-toggle:focus { box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); } @@ -2929,23 +3127,27 @@ fieldset:disabled a.btn { border-color: #dc3545; } -.btn-outline-danger:focus, .btn-outline-danger.focus { +.btn-outline-danger:focus, +.btn-outline-danger.focus { box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); } -.btn-outline-danger.disabled, .btn-outline-danger:disabled { +.btn-outline-danger.disabled, +.btn-outline-danger:disabled { color: #dc3545; background-color: transparent; } -.btn-outline-danger:not(:disabled):not(.disabled):active, .btn-outline-danger:not(:disabled):not(.disabled).active, +.btn-outline-danger:not(:disabled):not(.disabled):active, +.btn-outline-danger:not(:disabled):not(.disabled).active, .show > .btn-outline-danger.dropdown-toggle { color: #fff; background-color: #dc3545; border-color: #dc3545; } -.btn-outline-danger:not(:disabled):not(.disabled):active:focus, .btn-outline-danger:not(:disabled):not(.disabled).active:focus, +.btn-outline-danger:not(:disabled):not(.disabled):active:focus, +.btn-outline-danger:not(:disabled):not(.disabled).active:focus, .show > .btn-outline-danger.dropdown-toggle:focus { box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); } @@ -2961,23 +3163,27 @@ fieldset:disabled a.btn { border-color: #f8f9fa; } -.btn-outline-light:focus, .btn-outline-light.focus { +.btn-outline-light:focus, +.btn-outline-light.focus { box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); } -.btn-outline-light.disabled, .btn-outline-light:disabled { +.btn-outline-light.disabled, +.btn-outline-light:disabled { color: #f8f9fa; background-color: transparent; } -.btn-outline-light:not(:disabled):not(.disabled):active, .btn-outline-light:not(:disabled):not(.disabled).active, +.btn-outline-light:not(:disabled):not(.disabled):active, +.btn-outline-light:not(:disabled):not(.disabled).active, .show > .btn-outline-light.dropdown-toggle { color: #212529; background-color: #f8f9fa; border-color: #f8f9fa; } -.btn-outline-light:not(:disabled):not(.disabled):active:focus, .btn-outline-light:not(:disabled):not(.disabled).active:focus, +.btn-outline-light:not(:disabled):not(.disabled):active:focus, +.btn-outline-light:not(:disabled):not(.disabled).active:focus, .show > .btn-outline-light.dropdown-toggle:focus { box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); } @@ -2993,23 +3199,27 @@ fieldset:disabled a.btn { border-color: #343a40; } -.btn-outline-dark:focus, .btn-outline-dark.focus { +.btn-outline-dark:focus, +.btn-outline-dark.focus { box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5); } -.btn-outline-dark.disabled, .btn-outline-dark:disabled { +.btn-outline-dark.disabled, +.btn-outline-dark:disabled { color: #343a40; background-color: transparent; } -.btn-outline-dark:not(:disabled):not(.disabled):active, .btn-outline-dark:not(:disabled):not(.disabled).active, +.btn-outline-dark:not(:disabled):not(.disabled):active, +.btn-outline-dark:not(:disabled):not(.disabled).active, .show > .btn-outline-dark.dropdown-toggle { color: #fff; background-color: #343a40; border-color: #343a40; } -.btn-outline-dark:not(:disabled):not(.disabled):active:focus, .btn-outline-dark:not(:disabled):not(.disabled).active:focus, +.btn-outline-dark:not(:disabled):not(.disabled):active:focus, +.btn-outline-dark:not(:disabled):not(.disabled).active:focus, .show > .btn-outline-dark.dropdown-toggle:focus { box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5); } @@ -3025,24 +3235,28 @@ fieldset:disabled a.btn { text-decoration: underline; } -.btn-link:focus, .btn-link.focus { +.btn-link:focus, +.btn-link.focus { text-decoration: underline; box-shadow: none; } -.btn-link:disabled, .btn-link.disabled { +.btn-link:disabled, +.btn-link.disabled { color: #6c757d; pointer-events: none; } -.btn-lg, .btn-group-lg > .btn { +.btn-lg, +.btn-group-lg > .btn { padding: 0.5rem 1rem; font-size: 1.25rem; line-height: 1.5; border-radius: 0.3rem; } -.btn-sm, .btn-group-sm > .btn { +.btn-sm, +.btn-group-sm > .btn { padding: 0.25rem 0.5rem; font-size: 0.875rem; line-height: 1.5; @@ -3281,7 +3495,10 @@ input[type="button"].btn-block { vertical-align: 0; } -.dropdown-menu[x-placement^="top"], .dropdown-menu[x-placement^="right"], .dropdown-menu[x-placement^="bottom"], .dropdown-menu[x-placement^="left"] { +.dropdown-menu[x-placement^="top"], +.dropdown-menu[x-placement^="right"], +.dropdown-menu[x-placement^="bottom"], +.dropdown-menu[x-placement^="left"] { right: auto; bottom: auto; } @@ -3306,19 +3523,22 @@ input[type="button"].btn-block { border: 0; } -.dropdown-item:hover, .dropdown-item:focus { +.dropdown-item:hover, +.dropdown-item:focus { color: #16181b; text-decoration: none; background-color: #f8f9fa; } -.dropdown-item.active, .dropdown-item:active { +.dropdown-item.active, +.dropdown-item:active { color: #fff; text-decoration: none; background-color: #007bff; } -.dropdown-item.disabled, .dropdown-item:disabled { +.dropdown-item.disabled, +.dropdown-item:disabled { color: #6c757d; pointer-events: none; background-color: transparent; @@ -3363,7 +3583,9 @@ input[type="button"].btn-block { z-index: 1; } -.btn-group > .btn:focus, .btn-group > .btn:active, .btn-group > .btn.active, +.btn-group > .btn:focus, +.btn-group > .btn:active, +.btn-group > .btn.active, .btn-group-vertical > .btn:focus, .btn-group-vertical > .btn:active, .btn-group-vertical > .btn.active { @@ -3415,12 +3637,14 @@ input[type="button"].btn-block { margin-right: 0; } -.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split { +.btn-sm + .dropdown-toggle-split, +.btn-group-sm > .btn + .dropdown-toggle-split { padding-right: 0.375rem; padding-left: 0.375rem; } -.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split { +.btn-lg + .dropdown-toggle-split, +.btn-group-lg > .btn + .dropdown-toggle-split { padding-right: 0.75rem; padding-left: 0.75rem; } @@ -3797,9 +4021,12 @@ input[type="button"].btn-block { height: calc(1rem - 4px); background-color: #adb5bd; border-radius: 0.5rem; - transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-transform 0.15s ease-in-out; - transition: transform 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; - transition: transform 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-transform 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, + -webkit-transform 0.15s ease-in-out; + transition: transform 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, + box-shadow 0.15s ease-in-out; + transition: transform 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, + box-shadow 0.15s ease-in-out, -webkit-transform 0.15s ease-in-out; } @media (prefers-reduced-motion: reduce) { @@ -3828,7 +4055,8 @@ input[type="button"].btn-block { line-height: 1.5; color: #495057; vertical-align: middle; - background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right 0.75rem center/8px 10px; + background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") + no-repeat right 0.75rem center/8px 10px; background-color: #fff; border: 1px solid #ced4da; border-radius: 0.25rem; @@ -3848,7 +4076,8 @@ input[type="button"].btn-block { background-color: #fff; } -.custom-select[multiple], .custom-select[size]:not([size="1"]) { +.custom-select[multiple], +.custom-select[size]:not([size="1"]) { height: auto; padding-right: 0.75rem; background-image: none; @@ -4132,7 +4361,8 @@ input[type="button"].btn-block { padding: 0.5rem 1rem; } -.nav-link:hover, .nav-link:focus { +.nav-link:hover, +.nav-link:focus { text-decoration: none; } @@ -4156,7 +4386,8 @@ input[type="button"].btn-block { border-top-right-radius: 0.25rem; } -.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus { +.nav-tabs .nav-link:hover, +.nav-tabs .nav-link:focus { border-color: #e9ecef #e9ecef #dee2e6; } @@ -4246,7 +4477,8 @@ input[type="button"].btn-block { white-space: nowrap; } -.navbar-brand:hover, .navbar-brand:focus { +.navbar-brand:hover, +.navbar-brand:focus { text-decoration: none; } @@ -4294,7 +4526,8 @@ input[type="button"].btn-block { border-radius: 0.25rem; } -.navbar-toggler:hover, .navbar-toggler:focus { +.navbar-toggler:hover, +.navbar-toggler:focus { text-decoration: none; } @@ -4524,7 +4757,8 @@ input[type="button"].btn-block { color: rgba(0, 0, 0, 0.9); } -.navbar-light .navbar-brand:hover, .navbar-light .navbar-brand:focus { +.navbar-light .navbar-brand:hover, +.navbar-light .navbar-brand:focus { color: rgba(0, 0, 0, 0.9); } @@ -4532,7 +4766,8 @@ input[type="button"].btn-block { color: rgba(0, 0, 0, 0.5); } -.navbar-light .navbar-nav .nav-link:hover, .navbar-light .navbar-nav .nav-link:focus { +.navbar-light .navbar-nav .nav-link:hover, +.navbar-light .navbar-nav .nav-link:focus { color: rgba(0, 0, 0, 0.7); } @@ -4564,7 +4799,8 @@ input[type="button"].btn-block { color: rgba(0, 0, 0, 0.9); } -.navbar-light .navbar-text a:hover, .navbar-light .navbar-text a:focus { +.navbar-light .navbar-text a:hover, +.navbar-light .navbar-text a:focus { color: rgba(0, 0, 0, 0.9); } @@ -4572,7 +4808,8 @@ input[type="button"].btn-block { color: #fff; } -.navbar-dark .navbar-brand:hover, .navbar-dark .navbar-brand:focus { +.navbar-dark .navbar-brand:hover, +.navbar-dark .navbar-brand:focus { color: #fff; } @@ -4580,7 +4817,8 @@ input[type="button"].btn-block { color: rgba(255, 255, 255, 0.5); } -.navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-nav .nav-link:focus { +.navbar-dark .navbar-nav .nav-link:hover, +.navbar-dark .navbar-nav .nav-link:focus { color: rgba(255, 255, 255, 0.75); } @@ -4612,7 +4850,8 @@ input[type="button"].btn-block { color: #fff; } -.navbar-dark .navbar-text a:hover, .navbar-dark .navbar-text a:focus { +.navbar-dark .navbar-text a:hover, +.navbar-dark .navbar-text a:focus { color: #fff; } @@ -5002,7 +5241,8 @@ input[type="button"].btn-block { white-space: nowrap; vertical-align: baseline; border-radius: 0.25rem; - transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, + box-shadow 0.15s ease-in-out; } @media (prefers-reduced-motion: reduce) { @@ -5011,7 +5251,8 @@ input[type="button"].btn-block { } } -a.badge:hover, a.badge:focus { +a.badge:hover, +a.badge:focus { text-decoration: none; } @@ -5035,12 +5276,14 @@ a.badge:hover, a.badge:focus { background-color: #007bff; } -a.badge-primary:hover, a.badge-primary:focus { +a.badge-primary:hover, +a.badge-primary:focus { color: #fff; background-color: #0062cc; } -a.badge-primary:focus, a.badge-primary.focus { +a.badge-primary:focus, +a.badge-primary.focus { outline: 0; box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5); } @@ -5050,12 +5293,14 @@ a.badge-primary:focus, a.badge-primary.focus { background-color: #6c757d; } -a.badge-secondary:hover, a.badge-secondary:focus { +a.badge-secondary:hover, +a.badge-secondary:focus { color: #fff; background-color: #545b62; } -a.badge-secondary:focus, a.badge-secondary.focus { +a.badge-secondary:focus, +a.badge-secondary.focus { outline: 0; box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); } @@ -5065,12 +5310,14 @@ a.badge-secondary:focus, a.badge-secondary.focus { background-color: #28a745; } -a.badge-success:hover, a.badge-success:focus { +a.badge-success:hover, +a.badge-success:focus { color: #fff; background-color: #1e7e34; } -a.badge-success:focus, a.badge-success.focus { +a.badge-success:focus, +a.badge-success.focus { outline: 0; box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); } @@ -5080,12 +5327,14 @@ a.badge-success:focus, a.badge-success.focus { background-color: #17a2b8; } -a.badge-info:hover, a.badge-info:focus { +a.badge-info:hover, +a.badge-info:focus { color: #fff; background-color: #117a8b; } -a.badge-info:focus, a.badge-info.focus { +a.badge-info:focus, +a.badge-info.focus { outline: 0; box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); } @@ -5095,12 +5344,14 @@ a.badge-info:focus, a.badge-info.focus { background-color: #ffc107; } -a.badge-warning:hover, a.badge-warning:focus { +a.badge-warning:hover, +a.badge-warning:focus { color: #212529; background-color: #d39e00; } -a.badge-warning:focus, a.badge-warning.focus { +a.badge-warning:focus, +a.badge-warning.focus { outline: 0; box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); } @@ -5110,12 +5361,14 @@ a.badge-warning:focus, a.badge-warning.focus { background-color: #dc3545; } -a.badge-danger:hover, a.badge-danger:focus { +a.badge-danger:hover, +a.badge-danger:focus { color: #fff; background-color: #bd2130; } -a.badge-danger:focus, a.badge-danger.focus { +a.badge-danger:focus, +a.badge-danger.focus { outline: 0; box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); } @@ -5125,12 +5378,14 @@ a.badge-danger:focus, a.badge-danger.focus { background-color: #f8f9fa; } -a.badge-light:hover, a.badge-light:focus { +a.badge-light:hover, +a.badge-light:focus { color: #212529; background-color: #dae0e5; } -a.badge-light:focus, a.badge-light.focus { +a.badge-light:focus, +a.badge-light.focus { outline: 0; box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); } @@ -5140,12 +5395,14 @@ a.badge-light:focus, a.badge-light.focus { background-color: #343a40; } -a.badge-dark:hover, a.badge-dark:focus { +a.badge-dark:hover, +a.badge-dark:focus { color: #fff; background-color: #1d2124; } -a.badge-dark:focus, a.badge-dark.focus { +a.badge-dark:focus, +a.badge-dark.focus { outline: 0; box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5); } @@ -5358,7 +5615,16 @@ a.badge-dark:focus, a.badge-dark.focus { } .progress-bar-striped { - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient( + 45deg, + rgba(255, 255, 255, 0.15) 25%, + transparent 25%, + transparent 50%, + rgba(255, 255, 255, 0.15) 50%, + rgba(255, 255, 255, 0.15) 75%, + transparent 75%, + transparent + ); background-size: 1rem 1rem; } @@ -5401,7 +5667,8 @@ a.badge-dark:focus, a.badge-dark.focus { text-align: inherit; } -.list-group-item-action:hover, .list-group-item-action:focus { +.list-group-item-action:hover, +.list-group-item-action:focus { z-index: 1; color: #495057; text-decoration: none; @@ -5433,7 +5700,8 @@ a.badge-dark:focus, a.badge-dark.focus { border-bottom-left-radius: 0.25rem; } -.list-group-item.disabled, .list-group-item:disabled { +.list-group-item.disabled, +.list-group-item:disabled { color: #6c757d; pointer-events: none; background-color: #fff; @@ -5581,7 +5849,8 @@ a.badge-dark:focus, a.badge-dark.focus { background-color: #b8daff; } -.list-group-item-primary.list-group-item-action:hover, .list-group-item-primary.list-group-item-action:focus { +.list-group-item-primary.list-group-item-action:hover, +.list-group-item-primary.list-group-item-action:focus { color: #004085; background-color: #9fcdff; } @@ -5597,7 +5866,8 @@ a.badge-dark:focus, a.badge-dark.focus { background-color: #d6d8db; } -.list-group-item-secondary.list-group-item-action:hover, .list-group-item-secondary.list-group-item-action:focus { +.list-group-item-secondary.list-group-item-action:hover, +.list-group-item-secondary.list-group-item-action:focus { color: #383d41; background-color: #c8cbcf; } @@ -5613,7 +5883,8 @@ a.badge-dark:focus, a.badge-dark.focus { background-color: #c3e6cb; } -.list-group-item-success.list-group-item-action:hover, .list-group-item-success.list-group-item-action:focus { +.list-group-item-success.list-group-item-action:hover, +.list-group-item-success.list-group-item-action:focus { color: #155724; background-color: #b1dfbb; } @@ -5629,7 +5900,8 @@ a.badge-dark:focus, a.badge-dark.focus { background-color: #bee5eb; } -.list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus { +.list-group-item-info.list-group-item-action:hover, +.list-group-item-info.list-group-item-action:focus { color: #0c5460; background-color: #abdde5; } @@ -5645,7 +5917,8 @@ a.badge-dark:focus, a.badge-dark.focus { background-color: #ffeeba; } -.list-group-item-warning.list-group-item-action:hover, .list-group-item-warning.list-group-item-action:focus { +.list-group-item-warning.list-group-item-action:hover, +.list-group-item-warning.list-group-item-action:focus { color: #856404; background-color: #ffe8a1; } @@ -5661,7 +5934,8 @@ a.badge-dark:focus, a.badge-dark.focus { background-color: #f5c6cb; } -.list-group-item-danger.list-group-item-action:hover, .list-group-item-danger.list-group-item-action:focus { +.list-group-item-danger.list-group-item-action:hover, +.list-group-item-danger.list-group-item-action:focus { color: #721c24; background-color: #f1b0b7; } @@ -5677,7 +5951,8 @@ a.badge-dark:focus, a.badge-dark.focus { background-color: #fdfdfe; } -.list-group-item-light.list-group-item-action:hover, .list-group-item-light.list-group-item-action:focus { +.list-group-item-light.list-group-item-action:hover, +.list-group-item-light.list-group-item-action:focus { color: #818182; background-color: #ececf6; } @@ -5693,7 +5968,8 @@ a.badge-dark:focus, a.badge-dark.focus { background-color: #c6c8ca; } -.list-group-item-dark.list-group-item-action:hover, .list-group-item-dark.list-group-item-action:focus { +.list-group-item-dark.list-group-item-action:hover, +.list-group-item-dark.list-group-item-action:focus { color: #1b1e21; background-color: #b9bbbe; } @@ -5711,7 +5987,7 @@ a.badge-dark:focus, a.badge-dark.focus { line-height: 1; color: #000; text-shadow: 0 1px 0 #fff; - opacity: .5; + opacity: 0.5; } .close:hover { @@ -5719,8 +5995,9 @@ a.badge-dark:focus, a.badge-dark.focus { text-decoration: none; } -.close:not(:disabled):not(.disabled):hover, .close:not(:disabled):not(.disabled):focus { - opacity: .75; +.close:not(:disabled):not(.disabled):hover, +.close:not(:disabled):not(.disabled):focus { + opacity: 0.75; } button.close { @@ -5958,11 +6235,11 @@ a.close.disabled { } .modal-footer > :not(:first-child) { - margin-left: .25rem; + margin-left: 0.25rem; } .modal-footer > :not(:last-child) { - margin-right: .25rem; + margin-right: 0.25rem; } .modal-scrollbar-measure { @@ -6013,7 +6290,8 @@ a.close.disabled { z-index: 1070; display: block; margin: 0; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, + "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-style: normal; font-weight: 400; line-height: 1.5; @@ -6050,61 +6328,73 @@ a.close.disabled { border-style: solid; } -.bs-tooltip-top, .bs-tooltip-auto[x-placement^="top"] { +.bs-tooltip-top, +.bs-tooltip-auto[x-placement^="top"] { padding: 0.4rem 0; } -.bs-tooltip-top .arrow, .bs-tooltip-auto[x-placement^="top"] .arrow { +.bs-tooltip-top .arrow, +.bs-tooltip-auto[x-placement^="top"] .arrow { bottom: 0; } -.bs-tooltip-top .arrow::before, .bs-tooltip-auto[x-placement^="top"] .arrow::before { +.bs-tooltip-top .arrow::before, +.bs-tooltip-auto[x-placement^="top"] .arrow::before { top: 0; border-width: 0.4rem 0.4rem 0; border-top-color: #000; } -.bs-tooltip-right, .bs-tooltip-auto[x-placement^="right"] { +.bs-tooltip-right, +.bs-tooltip-auto[x-placement^="right"] { padding: 0 0.4rem; } -.bs-tooltip-right .arrow, .bs-tooltip-auto[x-placement^="right"] .arrow { +.bs-tooltip-right .arrow, +.bs-tooltip-auto[x-placement^="right"] .arrow { left: 0; width: 0.4rem; height: 0.8rem; } -.bs-tooltip-right .arrow::before, .bs-tooltip-auto[x-placement^="right"] .arrow::before { +.bs-tooltip-right .arrow::before, +.bs-tooltip-auto[x-placement^="right"] .arrow::before { right: 0; border-width: 0.4rem 0.4rem 0.4rem 0; border-right-color: #000; } -.bs-tooltip-bottom, .bs-tooltip-auto[x-placement^="bottom"] { +.bs-tooltip-bottom, +.bs-tooltip-auto[x-placement^="bottom"] { padding: 0.4rem 0; } -.bs-tooltip-bottom .arrow, .bs-tooltip-auto[x-placement^="bottom"] .arrow { +.bs-tooltip-bottom .arrow, +.bs-tooltip-auto[x-placement^="bottom"] .arrow { top: 0; } -.bs-tooltip-bottom .arrow::before, .bs-tooltip-auto[x-placement^="bottom"] .arrow::before { +.bs-tooltip-bottom .arrow::before, +.bs-tooltip-auto[x-placement^="bottom"] .arrow::before { bottom: 0; border-width: 0 0.4rem 0.4rem; border-bottom-color: #000; } -.bs-tooltip-left, .bs-tooltip-auto[x-placement^="left"] { +.bs-tooltip-left, +.bs-tooltip-auto[x-placement^="left"] { padding: 0 0.4rem; } -.bs-tooltip-left .arrow, .bs-tooltip-auto[x-placement^="left"] .arrow { +.bs-tooltip-left .arrow, +.bs-tooltip-auto[x-placement^="left"] .arrow { right: 0; width: 0.4rem; height: 0.8rem; } -.bs-tooltip-left .arrow::before, .bs-tooltip-auto[x-placement^="left"] .arrow::before { +.bs-tooltip-left .arrow::before, +.bs-tooltip-auto[x-placement^="left"] .arrow::before { left: 0; border-width: 0.4rem 0 0.4rem 0.4rem; border-left-color: #000; @@ -6126,7 +6416,8 @@ a.close.disabled { z-index: 1060; display: block; max-width: 276px; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, + "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-style: normal; font-weight: 400; line-height: 1.5; @@ -6156,7 +6447,8 @@ a.close.disabled { margin: 0 0.3rem; } -.popover .arrow::before, .popover .arrow::after { +.popover .arrow::before, +.popover .arrow::after { position: absolute; display: block; content: ""; @@ -6164,70 +6456,83 @@ a.close.disabled { border-style: solid; } -.bs-popover-top, .bs-popover-auto[x-placement^="top"] { +.bs-popover-top, +.bs-popover-auto[x-placement^="top"] { margin-bottom: 0.5rem; } -.bs-popover-top > .arrow, .bs-popover-auto[x-placement^="top"] > .arrow { +.bs-popover-top > .arrow, +.bs-popover-auto[x-placement^="top"] > .arrow { bottom: calc((0.5rem + 1px) * -1); } -.bs-popover-top > .arrow::before, .bs-popover-auto[x-placement^="top"] > .arrow::before { +.bs-popover-top > .arrow::before, +.bs-popover-auto[x-placement^="top"] > .arrow::before { bottom: 0; border-width: 0.5rem 0.5rem 0; border-top-color: rgba(0, 0, 0, 0.25); } -.bs-popover-top > .arrow::after, .bs-popover-auto[x-placement^="top"] > .arrow::after { +.bs-popover-top > .arrow::after, +.bs-popover-auto[x-placement^="top"] > .arrow::after { bottom: 1px; border-width: 0.5rem 0.5rem 0; border-top-color: #fff; } -.bs-popover-right, .bs-popover-auto[x-placement^="right"] { +.bs-popover-right, +.bs-popover-auto[x-placement^="right"] { margin-left: 0.5rem; } -.bs-popover-right > .arrow, .bs-popover-auto[x-placement^="right"] > .arrow { +.bs-popover-right > .arrow, +.bs-popover-auto[x-placement^="right"] > .arrow { left: calc((0.5rem + 1px) * -1); width: 0.5rem; height: 1rem; margin: 0.3rem 0; } -.bs-popover-right > .arrow::before, .bs-popover-auto[x-placement^="right"] > .arrow::before { +.bs-popover-right > .arrow::before, +.bs-popover-auto[x-placement^="right"] > .arrow::before { left: 0; border-width: 0.5rem 0.5rem 0.5rem 0; border-right-color: rgba(0, 0, 0, 0.25); } -.bs-popover-right > .arrow::after, .bs-popover-auto[x-placement^="right"] > .arrow::after { +.bs-popover-right > .arrow::after, +.bs-popover-auto[x-placement^="right"] > .arrow::after { left: 1px; border-width: 0.5rem 0.5rem 0.5rem 0; border-right-color: #fff; } -.bs-popover-bottom, .bs-popover-auto[x-placement^="bottom"] { +.bs-popover-bottom, +.bs-popover-auto[x-placement^="bottom"] { margin-top: 0.5rem; } -.bs-popover-bottom > .arrow, .bs-popover-auto[x-placement^="bottom"] > .arrow { +.bs-popover-bottom > .arrow, +.bs-popover-auto[x-placement^="bottom"] > .arrow { top: calc((0.5rem + 1px) * -1); } -.bs-popover-bottom > .arrow::before, .bs-popover-auto[x-placement^="bottom"] > .arrow::before { +.bs-popover-bottom > .arrow::before, +.bs-popover-auto[x-placement^="bottom"] > .arrow::before { top: 0; border-width: 0 0.5rem 0.5rem 0.5rem; border-bottom-color: rgba(0, 0, 0, 0.25); } -.bs-popover-bottom > .arrow::after, .bs-popover-auto[x-placement^="bottom"] > .arrow::after { +.bs-popover-bottom > .arrow::after, +.bs-popover-auto[x-placement^="bottom"] > .arrow::after { top: 1px; border-width: 0 0.5rem 0.5rem 0.5rem; border-bottom-color: #fff; } -.bs-popover-bottom .popover-header::before, .bs-popover-auto[x-placement^="bottom"] .popover-header::before { +.bs-popover-bottom .popover-header::before, +.bs-popover-auto[x-placement^="bottom"] .popover-header::before { position: absolute; top: 0; left: 50%; @@ -6238,24 +6543,28 @@ a.close.disabled { border-bottom: 1px solid #f7f7f7; } -.bs-popover-left, .bs-popover-auto[x-placement^="left"] { +.bs-popover-left, +.bs-popover-auto[x-placement^="left"] { margin-right: 0.5rem; } -.bs-popover-left > .arrow, .bs-popover-auto[x-placement^="left"] > .arrow { +.bs-popover-left > .arrow, +.bs-popover-auto[x-placement^="left"] > .arrow { right: calc((0.5rem + 1px) * -1); width: 0.5rem; height: 1rem; margin: 0.3rem 0; } -.bs-popover-left > .arrow::before, .bs-popover-auto[x-placement^="left"] > .arrow::before { +.bs-popover-left > .arrow::before, +.bs-popover-auto[x-placement^="left"] > .arrow::before { right: 0; border-width: 0.5rem 0 0.5rem 0.5rem; border-left-color: rgba(0, 0, 0, 0.25); } -.bs-popover-left > .arrow::after, .bs-popover-auto[x-placement^="left"] > .arrow::after { +.bs-popover-left > .arrow::after, +.bs-popover-auto[x-placement^="left"] > .arrow::after { right: 1px; border-width: 0.5rem 0 0.5rem 0.5rem; border-left-color: #fff; @@ -6392,7 +6701,8 @@ a.close.disabled { } } -.carousel-control-prev:hover, .carousel-control-prev:focus, +.carousel-control-prev:hover, +.carousel-control-prev:focus, .carousel-control-next:hover, .carousel-control-next:focus { color: #fff; @@ -6455,7 +6765,7 @@ a.close.disabled { background-clip: padding-box; border-top: 10px solid transparent; border-bottom: 10px solid transparent; - opacity: .5; + opacity: 0.5; transition: opacity 0.6s ease; } @@ -6503,8 +6813,8 @@ a.close.disabled { border: 0.25em solid currentColor; border-right-color: transparent; border-radius: 50%; - -webkit-animation: spinner-border .75s linear infinite; - animation: spinner-border .75s linear infinite; + -webkit-animation: spinner-border 0.75s linear infinite; + animation: spinner-border 0.75s linear infinite; } .spinner-border-sm { @@ -6541,8 +6851,8 @@ a.close.disabled { background-color: currentColor; border-radius: 50%; opacity: 0; - -webkit-animation: spinner-grow .75s linear infinite; - animation: spinner-grow .75s linear infinite; + -webkit-animation: spinner-grow 0.75s linear infinite; + animation: spinner-grow 0.75s linear infinite; } .spinner-grow-sm { @@ -6578,7 +6888,8 @@ a.close.disabled { background-color: #007bff !important; } -a.bg-primary:hover, a.bg-primary:focus, +a.bg-primary:hover, +a.bg-primary:focus, button.bg-primary:hover, button.bg-primary:focus { background-color: #0062cc !important; @@ -6588,7 +6899,8 @@ button.bg-primary:focus { background-color: #6c757d !important; } -a.bg-secondary:hover, a.bg-secondary:focus, +a.bg-secondary:hover, +a.bg-secondary:focus, button.bg-secondary:hover, button.bg-secondary:focus { background-color: #545b62 !important; @@ -6598,7 +6910,8 @@ button.bg-secondary:focus { background-color: #28a745 !important; } -a.bg-success:hover, a.bg-success:focus, +a.bg-success:hover, +a.bg-success:focus, button.bg-success:hover, button.bg-success:focus { background-color: #1e7e34 !important; @@ -6608,7 +6921,8 @@ button.bg-success:focus { background-color: #17a2b8 !important; } -a.bg-info:hover, a.bg-info:focus, +a.bg-info:hover, +a.bg-info:focus, button.bg-info:hover, button.bg-info:focus { background-color: #117a8b !important; @@ -6618,7 +6932,8 @@ button.bg-info:focus { background-color: #ffc107 !important; } -a.bg-warning:hover, a.bg-warning:focus, +a.bg-warning:hover, +a.bg-warning:focus, button.bg-warning:hover, button.bg-warning:focus { background-color: #d39e00 !important; @@ -6628,7 +6943,8 @@ button.bg-warning:focus { background-color: #dc3545 !important; } -a.bg-danger:hover, a.bg-danger:focus, +a.bg-danger:hover, +a.bg-danger:focus, button.bg-danger:hover, button.bg-danger:focus { background-color: #bd2130 !important; @@ -6638,7 +6954,8 @@ button.bg-danger:focus { background-color: #f8f9fa !important; } -a.bg-light:hover, a.bg-light:focus, +a.bg-light:hover, +a.bg-light:focus, button.bg-light:hover, button.bg-light:focus { background-color: #dae0e5 !important; @@ -6648,7 +6965,8 @@ button.bg-light:focus { background-color: #343a40 !important; } -a.bg-dark:hover, a.bg-dark:focus, +a.bg-dark:hover, +a.bg-dark:focus, button.bg-dark:hover, button.bg-dark:focus { background-color: #1d2124 !important; @@ -7880,7 +8198,8 @@ button.bg-dark:focus { border: 0; } -.sr-only-focusable:active, .sr-only-focusable:focus { +.sr-only-focusable:active, +.sr-only-focusable:focus { position: static; width: auto; height: auto; @@ -9919,7 +10238,8 @@ button.bg-dark:focus { color: #007bff !important; } -a.text-primary:hover, a.text-primary:focus { +a.text-primary:hover, +a.text-primary:focus { color: #0056b3 !important; } @@ -9927,7 +10247,8 @@ a.text-primary:hover, a.text-primary:focus { color: #6c757d !important; } -a.text-secondary:hover, a.text-secondary:focus { +a.text-secondary:hover, +a.text-secondary:focus { color: #494f54 !important; } @@ -9935,7 +10256,8 @@ a.text-secondary:hover, a.text-secondary:focus { color: #28a745 !important; } -a.text-success:hover, a.text-success:focus { +a.text-success:hover, +a.text-success:focus { color: #19692c !important; } @@ -9943,7 +10265,8 @@ a.text-success:hover, a.text-success:focus { color: #17a2b8 !important; } -a.text-info:hover, a.text-info:focus { +a.text-info:hover, +a.text-info:focus { color: #0f6674 !important; } @@ -9951,7 +10274,8 @@ a.text-info:hover, a.text-info:focus { color: #ffc107 !important; } -a.text-warning:hover, a.text-warning:focus { +a.text-warning:hover, +a.text-warning:focus { color: #ba8b00 !important; } @@ -9959,7 +10283,8 @@ a.text-warning:hover, a.text-warning:focus { color: #dc3545 !important; } -a.text-danger:hover, a.text-danger:focus { +a.text-danger:hover, +a.text-danger:focus { color: #a71d2a !important; } @@ -9967,7 +10292,8 @@ a.text-danger:hover, a.text-danger:focus { color: #f8f9fa !important; } -a.text-light:hover, a.text-light:focus { +a.text-light:hover, +a.text-light:focus { color: #cbd3da !important; } @@ -9975,7 +10301,8 @@ a.text-light:hover, a.text-light:focus { color: #343a40 !important; } -a.text-dark:hover, a.text-dark:focus { +a.text-dark:hover, +a.text-dark:focus { color: #121416 !important; } @@ -10103,4 +10430,4 @@ a.text-dark:hover, a.text-dark:focus { border-color: #dee2e6; } } -/*# sourceMappingURL=bootstrap.css.map */ \ No newline at end of file +/*# sourceMappingURL=bootstrap.css.map */ diff --git a/CometChat/resources/core.scss b/CometChat/resources/core.scss index 987c8206..c3a32cb4 100644 --- a/CometChat/resources/core.scss +++ b/CometChat/resources/core.scss @@ -1,6 +1,5 @@ -@import './mixins'; -@import './colors'; - +@import "./mixins"; +@import "./colors"; ///////////////////////////////////////////////////////////////////////////////////////// /* CORE MODULE STYLES */ @@ -13,7 +12,6 @@ html { } } - body { font-family: $base__font-family; color: $text-darken-more; @@ -22,7 +20,6 @@ body { height: 100vh; overflow: hidden; - @media (max-width: $sm-max-width) { font-size: 12px; } @@ -79,9 +76,9 @@ input { box-shadow: none !important; } -input[type=text], -input[type=password], -input[type=email], +input[type="text"], +input[type="password"], +input[type="email"], textarea { appearance: none !important; } @@ -117,12 +114,10 @@ textarea { font-family: inherit; } - ///////////////////////////////////////////////////////////////////////////////////////// /* CORE COMPONENTS & UTILITIES */ .utils { - // main container &__content { padding: rem(30); @@ -132,7 +127,6 @@ textarea { overflow-x: hidden; } - @media (max-width: $sm-max-width) { padding: rem(30) rem(10); overflow-x: hidden; @@ -156,67 +150,67 @@ textarea { // font size @at-root { .font-size-0 { - font-size: rem(0) + font-size: rem(0); } .font-size-10 { - font-size: rem(10) + font-size: rem(10); } .font-size-12 { - font-size: rem(12) + font-size: rem(12); } .font-size-14 { - font-size: rem(14) + font-size: rem(14); } .font-size-16 { - font-size: rem(16) + font-size: rem(16); } .font-size-18 { - font-size: rem(18) + font-size: rem(18); } .font-size-20 { - font-size: rem(20) + font-size: rem(20); } .font-size-24 { - font-size: rem(24) + font-size: rem(24); } .font-size-26 { - font-size: rem(26) + font-size: rem(26); } .font-size-30 { - font-size: rem(30) + font-size: rem(30); } .font-size-36 { - font-size: rem(36) + font-size: rem(36); } .font-size-40 { - font-size: rem(40) + font-size: rem(40); } .font-size-50 { - font-size: rem(50) + font-size: rem(50); } .font-size-60 { - font-size: rem(60) + font-size: rem(60); } .font-size-70 { - font-size: rem(70) + font-size: rem(70); } .font-size-80 { - font-size: rem(80) + font-size: rem(80); } } @@ -406,7 +400,7 @@ textarea { border: 1px solid $gray-border; &:before { - content: 'EXAMPLE'; + content: "EXAMPLE"; display: block; margin-bottom: rem(15); color: $text; @@ -416,10 +410,10 @@ textarea { // links &__link { &--underlined { - border-bottom: 1px solid rgba($black-lighten-more, .25); + border-bottom: 1px solid rgba($black-lighten-more, 0.25); &:hover { - border-bottom-color: rgba($blue, .2); + border-bottom-color: rgba($blue, 0.2); } } @@ -431,10 +425,10 @@ textarea { } &.link-underlined { - border-bottom: 1px solid rgba($blue, .25); + border-bottom: 1px solid rgba($blue, 0.25); &:hover { - border-bottom-color: rgba($blue, .2); + border-bottom-color: rgba($blue, 0.2); } } } @@ -498,12 +492,12 @@ textarea { // ant design example blocks &__codeCollapse { - .ant-collapse>.ant-collapse-item.ant-collapse-no-arrow>.ant-collapse-header { + .ant-collapse > .ant-collapse-item.ant-collapse-no-arrow > .ant-collapse-header { padding-left: rem(30); padding-right: rem(30); } - .ant-collapse-borderless>.ant-collapse-item { + .ant-collapse-borderless > .ant-collapse-item { margin-top: rem(17); border-top: 1px solid $gray-border; border-bottom: none; @@ -511,7 +505,6 @@ textarea { } } - ///////////////////////////////////////////////////////////////////////////////////////// /* CORE ANIMATIONS */ @@ -546,7 +539,6 @@ textarea { } } - body { height: 100vh !important; overflow: hidden !important; @@ -560,4 +552,4 @@ body { height: 100% !important; overflow: hidden !important; } -} \ No newline at end of file +} diff --git a/CometChat/util/controller.js b/CometChat/util/controller.js new file mode 100644 index 00000000..9fb03cb1 --- /dev/null +++ b/CometChat/util/controller.js @@ -0,0 +1,128 @@ +import { CometChat } from "@cometchat-pro/chat" + +export class CometChatManager { + + loggedInUser; + isUserLoggedIn; + + getLoggedInUser() { + + let timerCounter = 10000; + let timer = 0; + + return new Promise((resolve, reject) => { + + if(timerCounter === timer) reject(`timer reached ${timerCounter}`); + + if(this.loggedInUser) resolve(this.loggedInUser); + + if(!CometChat.isInitialized()) reject("CometChat not initialized"); + + this.isUserLoggedIn = setInterval(() => { + + CometChat.getLoggedinUser().then(user => { + + this.loggedInUser = user; + clearInterval(this.isUserLoggedIn); + resolve(user); + + }, error => { + console.log(error); + reject(error); + }); + + timer += 100; + }, 100); + + }); + } + + static blockUsers = (userList) => { + + let promise = new Promise((resolve, reject) => { + + CometChat.blockUsers(userList).then( + list => resolve(list), + error => reject(error) + ); + + }); + + return promise; + } + + static unblockUsers = (userList) => { + + let promise = new Promise((resolve, reject) => { + + CometChat.unblockUsers(userList).then( + list => resolve(list), + error => reject(error) + ); + + }); + + return promise; + } + + static audioCall = (receiverID, receiverType, callType) => { + + let promise = new Promise((resolve, reject) => { + + const call = new CometChat.Call(receiverID, callType, receiverType); + CometChat.initiateCall(call).then( + call => resolve(call), + error => reject(error) + ); + + }); + + return promise; + + } + + static videoCall = (receiverID, receiverType, callType) => { + + let promise = new Promise((resolve, reject) => { + + const call = new CometChat.Call(receiverID, callType, receiverType); + CometChat.initiateCall(call).then( + call => resolve(call), + error => reject(error) + ); + + }); + + return promise; + } + + static acceptCall = (sessionId) => { + + let promise = new Promise((resolve, reject) => { + + CometChat.acceptCall(sessionId).then( + call => resolve(call), + error => reject(error) + ); + + }); + + return promise; + } + + static rejectCall = (sessionId, rejectStatus) => { + + let promise = new Promise((resolve, reject) => { + + CometChat.rejectCall(sessionId, rejectStatus).then( + call => resolve(call), + error => reject(error) + ); + + }); + + return promise; + } +} + +export default CometChatManager; \ No newline at end of file diff --git a/CometChat/util/enums.js b/CometChat/util/enums.js new file mode 100644 index 00000000..7198ea8b --- /dev/null +++ b/CometChat/util/enums.js @@ -0,0 +1,23 @@ +export const USER_JOINED = 'onUserJoined'; +export const USER_LEFT = 'onUserLeft'; + +export const TEXT_MESSAGE_RECEIVED = 'onTextMessageReceived'; +export const MEDIA_MESSAGE_RECEIVED = 'onMediaMessageReceived'; +export const CUSTOM_MESSAGE_RECEIVED = 'onCustomMessageReceived'; +export const MESSAGE_DELIVERED = 'onMessagesDelivered'; +export const MESSAGE_READ = 'onMessagesRead'; + +export const INCOMING_CALL_RECEIVED = 'onIncomingCallReceived'; +export const OUTGOING_CALL_ACCEPTED = 'onOutgoingCallAccepted'; +export const OUTGOING_CALL_REJECTED = 'onOutgoingCallRejected'; +export const INCOMING_CALL_CANCELLED = 'onIncomingCallCancelled'; + +export const CALL_ENDED = 'onCallEnded'; + +export const GROUP_MEMBER_SCOPE_CHANGED = "onGroupMemberScopeChanged"; +export const GROUP_MEMBER_KICKED = "onGroupMemberKicked"; +export const GROUP_MEMBER_BANNED = "onGroupMemberBanned"; +export const GROUP_MEMBER_UNBANNED = "onGroupMemberUnbanned"; +export const GROUP_MEMBER_ADDED = "onMemberAddedToGroup"; +export const GROUP_MEMBER_LEFT = "onGroupMemberLeft"; +export const GROUP_MEMBER_JOINED = "onGroupMemberJoined"; \ No newline at end of file diff --git a/CometChat/util/svgavatar.js b/CometChat/util/svgavatar.js new file mode 100644 index 00000000..e4e7f5b1 --- /dev/null +++ b/CometChat/util/svgavatar.js @@ -0,0 +1,51 @@ +export class SvgAvatar { + + static getAvatar = (generator, data) => { + + const svg1 = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + svg1.setAttribute("width", "200"); + svg1.setAttribute("height", "200"); + + const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + rect.setAttribute('x', '0'); + rect.setAttribute('y', '0'); + rect.setAttribute('width', '200'); + rect.setAttribute('height', '200'); + rect.setAttribute('fill', SvgAvatar.stringToColour(generator)); + const text = document.createElementNS("http://www.w3.org/2000/svg", "text"); + text.setAttribute('x', '50%'); + text.setAttribute('y', '54%'); + text.setAttribute('dominant-baseline', 'middle'); + text.setAttribute('text-anchor', 'middle'); + text.setAttribute('fill', 'white'); + text.setAttribute('font-size', '120'); + text.setAttribute('font-family', "'Inter', sans-serif"); + text.setAttribute('font-wight', "600"); + text.textContent = data; + svg1.appendChild(rect); + svg1.appendChild(text); + let svgString = new XMLSerializer().serializeToString(svg1); + + + let decoded = unescape(encodeURIComponent(svgString)); + let base64 = btoa(decoded); + + let imgSource = `data:image/svg+xml;base64,${base64}`; + return imgSource; + } + + static stringToColour = function (str) { + let hash = 0; + for (let i = 0; i < str.length; i++) { + hash = str.charCodeAt(i) + ((hash << 5) - hash); + } + let colour = '#'; + for (let i = 0; i < 3; i++) { + let value = (hash >> (i * 8)) & 0xFF; + colour += ('00' + value.toString(16)).substr(-2); + } + return colour; + } +} + +export default SvgAvatar; \ No newline at end of file diff --git a/README.md b/README.md index dfad0a26..139c54eb 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,8 @@ After adding necessary dependancies inside you app to integrate UI Kit inside yo 1. Simply clone the UI Kit Library from react-chat-uikit repository. 2. Copy the CometChat folder to your project lib folder -3. Start using CometChat Components by following the exmple code. +3. npm install node-sass +4. Start using CometChat Components by following the example code.