From 346176a7a0365d81608420ad6a02f448b0d3da62 Mon Sep 17 00:00:00 2001 From: abirc8010 Date: Wed, 25 Dec 2024 23:11:54 +0530 Subject: [PATCH 1/8] Added room announcement feature , display avatar and make room name clickable --- packages/react/src/views/ChatBody/ChatBody.js | 72 +++++++++++++++++-- .../src/views/ChatBody/ChatBody.styles.js | 20 +++++- .../react/src/views/ChatHeader/ChatHeader.js | 51 +++++++++---- .../src/views/ChatHeader/ChatHeader.styles.js | 11 ++- packages/react/src/views/EmbeddedChat.js | 4 ++ .../views/RoomInformation/RoomInformation.js | 52 +++++++------- .../RoomInformation/RoomInformation.styles.js | 25 +++++++ 7 files changed, 191 insertions(+), 44 deletions(-) create mode 100644 packages/react/src/views/RoomInformation/RoomInformation.styles.js diff --git a/packages/react/src/views/ChatBody/ChatBody.js b/packages/react/src/views/ChatBody/ChatBody.js index a582244d0..9903d51c8 100644 --- a/packages/react/src/views/ChatBody/ChatBody.js +++ b/packages/react/src/views/ChatBody/ChatBody.js @@ -1,11 +1,19 @@ /* eslint-disable no-shadow */ -import React, { useCallback, useContext, useEffect, useState } from 'react'; +import React, { + useCallback, + useContext, + useEffect, + useState, + useRef, +} from 'react'; import PropTypes from 'prop-types'; import { css } from '@emotion/react'; import { Box, Throbber, useComponentOverrides, + Modal, + useTheme, } from '@embeddedchat/ui-elements'; import RCContext from '../../context/RCInstance'; import { @@ -33,21 +41,23 @@ const ChatBody = ({ scrollToBottom, }) => { const { classNames, styleOverrides } = useComponentOverrides('ChatBody'); - - const styles = getChatbodyStyles(); + const { theme, mode } = useTheme(); + const styles = getChatbodyStyles(theme, mode); const [scrollPosition, setScrollPosition] = useState(0); const [popupVisible, setPopupVisible] = useState(false); const [, setIsUserScrolledUp] = useState(false); const [otherUserMessage, setOtherUserMessage] = useState(false); - + const [isOverflowing, setIsOverflowing] = useState(false); const { RCInstance, ECOptions } = useContext(RCContext); + const showAnnouncement = ECOptions?.showAnnouncement; const messages = useMessageStore((state) => state.messages); const threadMessages = useMessageStore((state) => state.threadMessages); - + const [isModalOpen, setModalOpen] = useState(false); const setThreadMessages = useMessageStore((state) => state.setThreadMessages); const upsertMessage = useMessageStore((state) => state.upsertMessage); const removeMessage = useMessageStore((state) => state.removeMessage); const isChannelPrivate = useChannelStore((state) => state.isChannelPrivate); + const channelInfo = useChannelStore((state) => state.channelInfo); const isLoginIn = useLoginStore((state) => state.isLoginIn); const [isThreadOpen, threadMainMessage] = useMessageStore((state) => [ @@ -182,7 +192,24 @@ const ChatBody = ({ const showNewMessagesPopup = () => { setPopupVisible(true); }; + const announcementRef = useRef(null); + + const toggleModal = () => { + setModalOpen(!isModalOpen); + }; + + const checkOverflow = () => { + if (announcementRef.current) { + setIsOverflowing( + announcementRef.current.scrollWidth > + announcementRef.current.clientWidth + ); + } + }; + useEffect(() => { + checkOverflow(); + }, [channelInfo.announcement]); useEffect(() => { const currentRef = messageListRef.current; currentRef.addEventListener('scroll', handleScroll); @@ -204,6 +231,41 @@ const ChatBody = ({ return ( <> + {channelInfo.announcement && showAnnouncement && ( + + + {channelInfo.announcement} + + + )} + {isModalOpen && ( + + + Announcement + + + + {channelInfo.announcement} + + + )} { +export const getChatbodyStyles = (theme, mode) => { const styles = { chatbodyContainer: css` flex: 1; @@ -14,6 +15,23 @@ export const getChatbodyStyles = () => { padding-top: 70px; margin-top: 0.25rem; `, + announcementStyles: css` + display: flex; + justify-content: center; + padding: 7px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + background-color: ${mode === 'light' + ? lighten(theme.colors.info, 0.78) + : darken(theme.colors.primary, 0.7)}; + `, + announcementTextBox: css` + max-width: 80%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + `, }; return styles; diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js index 010739977..9e80d0e15 100644 --- a/packages/react/src/views/ChatHeader/ChatHeader.js +++ b/packages/react/src/views/ChatHeader/ChatHeader.js @@ -1,4 +1,5 @@ import React, { useCallback, useEffect, useMemo } from 'react'; +import { css } from '@emotion/react'; import PropTypes from 'prop-types'; import { Box, @@ -8,6 +9,7 @@ import { useToastBarDispatch, useComponentOverrides, useTheme, + Avatar, } from '@embeddedchat/ui-elements'; import { useRCContext } from '../../context/RCInstance'; import { @@ -78,7 +80,7 @@ const ChatHeader = ({ const { RCInstance, ECOptions } = useRCContext(); const { channelName, anonymousMode, showRoles } = ECOptions ?? {}; - + const showChannelAvatar = ECOptions?.showChannelAvatar; const isUserAuthenticated = useUserStore( (state) => state.isUserAuthenticated ); @@ -115,7 +117,10 @@ const ChatHeader = ({ ); const setShowAllFiles = useFileStore((state) => state.setShowAllFiles); const setShowMentions = useMentionsStore((state) => state.setShowMentions); - + const getChannelAvatarURL = (channelname) => { + const host = RCInstance.getHost(); + return `${host}/avatar/${channelname}`; + }; const handleGoBack = async () => { if (isUserAuthenticated) { getMessagesAndRoles(); @@ -347,7 +352,6 @@ const ChatHeader = ({ > - {isUserAuthenticated ? ( <> @@ -355,17 +359,40 @@ const ChatHeader = ({ level={3} className="ec-chat-header--channelName" css={styles.clearSpacing} + style={{ + display: 'flex', + alignItems: 'center', + gap: '0.2rem', + }} > - {channelInfo.name || channelName || 'channelName'} + + + setExclusiveState(setShowChannelinfo)} + > + +
+ {channelInfo.name || channelName || 'channelName'} +
+
+ {fullScreen && ( + + {channelInfo.topic || ''} + + )} +
- {fullScreen && ( -

- {channelInfo.description || ''} -

- )} ) : ( { margin: 0; padding: 0; `, - chatHeaderChild: css` ${rowCentreAlign} padding: 0 0.75rem; @@ -43,6 +42,16 @@ const getChatHeaderStyles = ({ theme, mode }) => { position:relative; gap: 0.5rem; `, + channelName: css` + display: flex; + align-items: center; + gap: 0.1rem; + cursor: pointer; + `, + channelTopic: css` + opacity: 0.8rem; + font-size: 1rem; + `, }; return styles; }; diff --git a/packages/react/src/views/EmbeddedChat.js b/packages/react/src/views/EmbeddedChat.js index 00557f289..17b1ff1a4 100644 --- a/packages/react/src/views/EmbeddedChat.js +++ b/packages/react/src/views/EmbeddedChat.js @@ -44,6 +44,7 @@ const EmbeddedChat = (props) => { toastBarPosition = 'bottom right', showRoles = false, showAvatar = true, + showAnnouncement = true, showUsername = false, showName = true, enableThreads = false, @@ -204,6 +205,7 @@ const EmbeddedChat = (props) => { showName, showRoles, showAvatar, + showAnnouncement, showUsername, hideHeader, anonymousMode, @@ -219,6 +221,7 @@ const EmbeddedChat = (props) => { showName, showRoles, showAvatar, + showAnnouncement, showUsername, hideHeader, anonymousMode, @@ -281,6 +284,7 @@ EmbeddedChat.propTypes = { toastBarPosition: PropTypes.string, showRoles: PropTypes.bool, showAvatar: PropTypes.bool, + showAnnouncement: PropTypes.bool, enableThreads: PropTypes.bool, theme: PropTypes.object, auth: PropTypes.oneOfType([ diff --git a/packages/react/src/views/RoomInformation/RoomInformation.js b/packages/react/src/views/RoomInformation/RoomInformation.js index 3cfdefad0..5fba686b4 100644 --- a/packages/react/src/views/RoomInformation/RoomInformation.js +++ b/packages/react/src/views/RoomInformation/RoomInformation.js @@ -9,11 +9,12 @@ import { } from '@embeddedchat/ui-elements'; import RCContext from '../../context/RCInstance'; import { useChannelStore } from '../../store'; +import getRoomInformationStyles from './RoomInformation.styles'; import useSetExclusiveState from '../../hooks/useSetExclusiveState'; const Roominfo = () => { const { RCInstance } = useContext(RCContext); - + const styles = getRoomInformationStyles(); const channelInfo = useChannelStore((state) => state.channelInfo); const { variantOverrides } = useComponentOverrides('RoomMember'); const viewType = variantOverrides.viewType || 'Sidebar'; @@ -44,34 +45,35 @@ const Roominfo = () => { overflow: auto; `} > - - - # {channelInfo.name} - - - Description - - - {channelInfo.description} - + + + + # {channelInfo.name} + {channelInfo.description && ( + <> + Description + {channelInfo.description} + + )} + {channelInfo.description && ( + <> + Topic + {channelInfo.topic} + + )} + {channelInfo.description && ( + <> + Announcement + {channelInfo.announcement} + + )}
diff --git a/packages/react/src/views/RoomInformation/RoomInformation.styles.js b/packages/react/src/views/RoomInformation/RoomInformation.styles.js new file mode 100644 index 000000000..9ab039b94 --- /dev/null +++ b/packages/react/src/views/RoomInformation/RoomInformation.styles.js @@ -0,0 +1,25 @@ +import { css } from '@emotion/react'; + +const getRoomInformationStyles = () => { + const styles = { + infoContainer: css` + margin: 16px; + display: flex; + flex-direction: column; + gap: 0.1rem; + `, + infoHeader: css` + margin-block: 5px; + font-weight: 900; + `, + info: css` + word-wrap: break-word; + overflow-wrap: anywhere; + white-space: normal; + `, + }; + + return styles; +}; + +export default getRoomInformationStyles; From 8d92d91dd92ae81e253de8c76e9f443e96ce7d0c Mon Sep 17 00:00:00 2001 From: abirc8010 Date: Wed, 25 Dec 2024 23:16:12 +0530 Subject: [PATCH 2/8] remove showChannelAvatar from ECOptions --- packages/react/src/views/ChatHeader/ChatHeader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js index 9e80d0e15..817ff4097 100644 --- a/packages/react/src/views/ChatHeader/ChatHeader.js +++ b/packages/react/src/views/ChatHeader/ChatHeader.js @@ -80,7 +80,7 @@ const ChatHeader = ({ const { RCInstance, ECOptions } = useRCContext(); const { channelName, anonymousMode, showRoles } = ECOptions ?? {}; - const showChannelAvatar = ECOptions?.showChannelAvatar; + const isUserAuthenticated = useUserStore( (state) => state.isUserAuthenticated ); From b4a35142ed8e7291f21867f450cfdf155be4c214 Mon Sep 17 00:00:00 2001 From: abirc8010 Date: Wed, 25 Dec 2024 23:38:41 +0530 Subject: [PATCH 3/8] Add padding --- packages/react/src/views/ChatBody/ChatBody.styles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/src/views/ChatBody/ChatBody.styles.js b/packages/react/src/views/ChatBody/ChatBody.styles.js index f7824d924..9710f213b 100644 --- a/packages/react/src/views/ChatBody/ChatBody.styles.js +++ b/packages/react/src/views/ChatBody/ChatBody.styles.js @@ -18,7 +18,7 @@ export const getChatbodyStyles = (theme, mode) => { announcementStyles: css` display: flex; justify-content: center; - padding: 7px; + padding: 10px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; From 895f6c634b203dd8292545babb4c8506691177cd Mon Sep 17 00:00:00 2001 From: abirc8010 Date: Wed, 25 Dec 2024 23:51:35 +0530 Subject: [PATCH 4/8] Add padding to modal --- packages/react/src/views/ChatBody/ChatBody.js | 3 ++- packages/react/src/views/ChatBody/ChatBody.styles.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/react/src/views/ChatBody/ChatBody.js b/packages/react/src/views/ChatBody/ChatBody.js index 9903d51c8..1546ae357 100644 --- a/packages/react/src/views/ChatBody/ChatBody.js +++ b/packages/react/src/views/ChatBody/ChatBody.js @@ -256,10 +256,11 @@ const ChatBody = ({ {channelInfo.announcement} diff --git a/packages/react/src/views/ChatBody/ChatBody.styles.js b/packages/react/src/views/ChatBody/ChatBody.styles.js index 9710f213b..f7824d924 100644 --- a/packages/react/src/views/ChatBody/ChatBody.styles.js +++ b/packages/react/src/views/ChatBody/ChatBody.styles.js @@ -18,7 +18,7 @@ export const getChatbodyStyles = (theme, mode) => { announcementStyles: css` display: flex; justify-content: center; - padding: 10px; + padding: 7px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; From 075e374cc4dcdc03b290b4ca46c5cba1c50230b9 Mon Sep 17 00:00:00 2001 From: abirc8010 Date: Thu, 26 Dec 2024 00:27:07 +0530 Subject: [PATCH 5/8] Remove text underline in announcement in normal view --- packages/react/src/views/ChatBody/ChatBody.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/react/src/views/ChatBody/ChatBody.js b/packages/react/src/views/ChatBody/ChatBody.js index 1546ae357..1c29b8d8c 100644 --- a/packages/react/src/views/ChatBody/ChatBody.js +++ b/packages/react/src/views/ChatBody/ChatBody.js @@ -238,8 +238,10 @@ const ChatBody = ({ css={[ styles.announcementTextBox, css` - text-decoration: ${isOverflowing ? 'underline' : 'none'}; - cursor: ${isOverflowing ? 'pointer' : 'default'}; + &:hover { + text-decoration: ${isOverflowing ? 'underline' : 'none'}; + cursor: ${isOverflowing ? 'pointer' : 'default'}; + } `, ]} onClick={isOverflowing ? toggleModal : undefined} From c91e394a8082e273c7a991d491928bfd300d60c5 Mon Sep 17 00:00:00 2001 From: abirc8010 Date: Thu, 26 Dec 2024 01:56:46 +0530 Subject: [PATCH 6/8] add showAnnouncement dependency to useEffect --- packages/react/src/views/ChatBody/ChatBody.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react/src/views/ChatBody/ChatBody.js b/packages/react/src/views/ChatBody/ChatBody.js index 1c29b8d8c..23d70a785 100644 --- a/packages/react/src/views/ChatBody/ChatBody.js +++ b/packages/react/src/views/ChatBody/ChatBody.js @@ -171,7 +171,7 @@ const ChatBody = ({ setScrollPosition(messageListRef.current.scrollTop); setIsUserScrolledUp( messageListRef.current.scrollTop + messageListRef.current.clientHeight < - messageListRef.current.scrollHeight + messageListRef.current.scrollHeight ); } @@ -202,14 +202,14 @@ const ChatBody = ({ if (announcementRef.current) { setIsOverflowing( announcementRef.current.scrollWidth > - announcementRef.current.clientWidth + announcementRef.current.clientWidth ); } }; useEffect(() => { checkOverflow(); - }, [channelInfo.announcement]); + }, [channelInfo.announcement, showAnnouncement]); useEffect(() => { const currentRef = messageListRef.current; currentRef.addEventListener('scroll', handleScroll); From 216c06211c347e739d55b68ac30b9c232772b3b1 Mon Sep 17 00:00:00 2001 From: abirc8010 Date: Thu, 26 Dec 2024 02:00:18 +0530 Subject: [PATCH 7/8] Run prettier --- packages/react/src/views/ChatBody/ChatBody.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react/src/views/ChatBody/ChatBody.js b/packages/react/src/views/ChatBody/ChatBody.js index 23d70a785..721c2d2dc 100644 --- a/packages/react/src/views/ChatBody/ChatBody.js +++ b/packages/react/src/views/ChatBody/ChatBody.js @@ -171,7 +171,7 @@ const ChatBody = ({ setScrollPosition(messageListRef.current.scrollTop); setIsUserScrolledUp( messageListRef.current.scrollTop + messageListRef.current.clientHeight < - messageListRef.current.scrollHeight + messageListRef.current.scrollHeight ); } @@ -202,7 +202,7 @@ const ChatBody = ({ if (announcementRef.current) { setIsOverflowing( announcementRef.current.scrollWidth > - announcementRef.current.clientWidth + announcementRef.current.clientWidth ); } }; From 9563deb858eb287142558c0066de7e5bfd28ab6a Mon Sep 17 00:00:00 2001 From: abirc8010 Date: Sun, 29 Dec 2024 18:27:40 +0530 Subject: [PATCH 8/8] replace channelInfo.description --- packages/react/src/views/RoomInformation/RoomInformation.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react/src/views/RoomInformation/RoomInformation.js b/packages/react/src/views/RoomInformation/RoomInformation.js index 5fba686b4..b4e26764c 100644 --- a/packages/react/src/views/RoomInformation/RoomInformation.js +++ b/packages/react/src/views/RoomInformation/RoomInformation.js @@ -62,13 +62,13 @@ const Roominfo = () => { {channelInfo.description} )} - {channelInfo.description && ( + {channelInfo.topic && ( <> Topic {channelInfo.topic} )} - {channelInfo.description && ( + {channelInfo.announcement && ( <> Announcement {channelInfo.announcement}