From 1c66ff390759cd5b7e25276aea056a08f5ba75e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Nunes?= <62393923+JoVictorNunes@users.noreply.github.com> Date: Wed, 30 Oct 2024 16:40:55 -0300 Subject: [PATCH] fix(chat): Improved usability, UI fixes, et al. (#21555) * fix(chat): Loading a new message page freezes the client - When the user clicks 'Load more messages' the client freezes for a few seconds before rendering the new page. This was happening because the message component was overheaded with hook calls and data access. In order to fix that, all those hook calls within the message component were placed in the parent component (more stable, doesn't rerender frequently) and passed as props to the message component. * fix(chat): Remove redundant condition * fix(chat): Add some arg validation in the getValueByPointer function * fix(chat): Memoize the onEmojiSelected handler * fix(chat): Memoize reaction mutation functions * fix(chat): Remove duplicated prop comparison * fix(chat): Move comparison prop arrys outside comparison functions * fix(chat): Add logging for edit, delete and reaction mutations * fix(chat): Memoize chat message ref updater * fix(chat): Restore original message input value after editing a message * fix(chat): Messages showing up behind welcome message * fix(chat): Message input focus ring as inset shadow * fix(chat): Tweak toolbar button hover styles * fix(chat): Disable chat roving if all toolbar settings are disabled * fix(chat): Add infinite scroll * fix(chat): Close reply intention button hiding when chat panel in narrowed * fix(chat): Only add top padding to message list if message toolbar is enabled * fix(chat): Add timeout for cleaning up loaded message pages * fix(chat): Focused replied message cleanup * fix(chat): Loading UI when a new page is loaded * fix(chat): Align offline indicator on the left * fix(chat): Revert settings.yml changes * fix(chat): Message input focus style and text alignment - Use border instead of box shadow. - Use 1px border. - Fix bad text alignment. --- .../chat-message-form/component.tsx | 23 ++-- .../chat-graphql/chat-message-form/styles.ts | 9 +- .../chat-message-list/component.tsx | 107 ++++++++++++------ .../chat-message/message-header/component.tsx | 1 + .../chat-message/message-header/styles.ts | 7 +- .../message-replied/component.tsx | 1 - .../message-toolbar/emoji-button/styles.ts | 10 +- .../chat-message/message-toolbar/styles.ts | 6 +- .../chat-message-list/page/component.tsx | 22 +++- .../chat-message-list/page/queries.ts | 7 ++ .../chat-graphql/chat-message-list/styles.ts | 19 +--- .../chat-graphql/chat-popup/component.tsx | 14 ++- .../chat/chat-graphql/chat-popup/styles.ts | 8 +- .../chat-reply-intention/styles.tsx | 1 + 14 files changed, 156 insertions(+), 79 deletions(-) diff --git a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-form/component.tsx b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-form/component.tsx index a665412385c6..e511a77b798f 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-form/component.tsx +++ b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-form/component.tsx @@ -138,11 +138,12 @@ const ChatMessageForm: React.FC = ({ const emojiPickerButtonRef = useRef(null); const [isTextAreaFocused, setIsTextAreaFocused] = React.useState(false); const [repliedMessageId, setRepliedMessageId] = React.useState(null); - const [editingMessage, setEditingMessage] = React.useState(null); + const editingMessage = React.useRef(null); const textAreaRef: RefObject = useRef(null); const { isMobile } = deviceInfo; const prevChatId = usePreviousValue(chatId); const messageRef = useRef(''); + const messageBeforeEditingRef = useRef(null); messageRef.current = message; const updateUnreadMessages = (chatId: string, message: string) => { const storedData = localStorage.getItem('unsentMessages') || '{}'; @@ -302,16 +303,24 @@ const ChatMessageForm: React.FC = ({ const handleEditingMessage = (e: Event) => { if (e instanceof CustomEvent) { if (textAreaRef.current) { + if (messageBeforeEditingRef.current === null) { + messageBeforeEditingRef.current = messageRef.current; + } setMessage(e.detail.message); - setEditingMessage(e.detail); + editingMessage.current = e.detail; } } }; const handleCancelEditingMessage = (e: Event) => { if (e instanceof CustomEvent) { - setMessage(''); - setEditingMessage(null); + if (editingMessage.current) { + if (messageBeforeEditingRef.current !== null) { + setMessage(messageBeforeEditingRef.current); + messageBeforeEditingRef.current = null; + } + editingMessage.current = null; + } } }; @@ -363,11 +372,11 @@ const ChatMessageForm: React.FC = ({ } }; - if (editingMessage && !chatEditMessageLoading) { + if (editingMessage.current && !chatEditMessageLoading) { chatEditMessage({ variables: { - chatId: editingMessage.chatId, - messageId: editingMessage.messageId, + chatId: editingMessage.current.chatId, + messageId: editingMessage.current.messageId, chatMessageInMarkdownFormat: msg, }, }).then(() => { diff --git a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-form/styles.ts b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-form/styles.ts index 7f562d9995bd..ebbfe20bdc30 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-form/styles.ts +++ b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-form/styles.ts @@ -12,7 +12,6 @@ import { smPaddingY, borderRadius, borderSize, - xsPadding, } from '/imports/ui/stylesheets/styled-components/general'; import { fontSizeBase } from '/imports/ui/stylesheets/styled-components/typography'; import TextareaAutosize from 'react-autosize-textarea'; @@ -43,7 +42,6 @@ const Form = styled.form` const Wrapper = styled.div` display: flex; flex-direction: row; - box-shadow: inset 0 0 0 1px ${colorGrayLightest}; border-radius: 0.75rem; `; @@ -51,7 +49,6 @@ const Input = styled(TextareaAutosize)` flex: 1; background: #fff; background-clip: padding-box; - margin: ${xsPadding} 0 ${xsPadding} ${xsPadding}; color: ${colorText}; -webkit-appearance: none; padding: calc(${smPaddingY} * 2.5) calc(${smPaddingX} * 1.25); @@ -171,19 +168,19 @@ const InputWrapper = styled.div` flex-grow: 1; min-width: 0; z-index: 0; + padding: 1px 0 1px 1px; + border: 1px solid ${colorGrayLightest}; [dir='ltr'] & { border-radius: 0.75rem 0 0 0.75rem; - margin-right: ${xsPadding}; } [dir='rtl'] & { border-radius: 0 0.75rem 0.75rem 0; - margin-left: ${xsPadding}; } &:focus-within { - box-shadow: 0 0 0 ${xsPadding} ${colorBlueLight}; + border: 1px solid ${colorBlueLight}; } `; diff --git a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/component.tsx b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/component.tsx index e2eafc905d55..73f86de2bada 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/component.tsx +++ b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/component.tsx @@ -19,7 +19,6 @@ import { Message } from '/imports/ui/Types/message'; import ChatListPage from './page/component'; import LAST_SEEN_MUTATION from './queries'; import { - ButtonLoadMore, MessageList, UnreadButton, } from './styles'; @@ -40,6 +39,7 @@ import { CHAT_DELETE_REACTION_MUTATION, CHAT_SEND_REACTION_MUTATION } from './pa import logger from '/imports/startup/client/logger'; const PAGE_SIZE = 50; +const CLEANUP_TIMEOUT = 3000; const intlMessages = defineMessages({ loadMoreButtonLabel: { @@ -180,21 +180,28 @@ const ChatMessageList: React.FC = ({ const intl = useIntl(); // I used a ref here because I don't want to re-render the component when the last sender changes const lastSenderPerPage = React.useRef>(new Map()); - const sentinelRef = React.useRef(null); + const endSentinelRef = React.useRef(null); + const startSentinelRef = React.useRef(null); const { ref: messageListContainerRef, current: currentMessageListContainer, } = useReactiveRef(null); const messageListRef = React.useRef(null); + const cleanupTimeoutRef = React.useRef | null>(null); const [userLoadedBackUntilPage, setUserLoadedBackUntilPage] = useState(null); const [lastMessageCreatedAt, setLastMessageCreatedAt] = useState(''); const [followingTail, setFollowingTail] = React.useState(true); const [selectedMessage, setSelectedMessage] = React.useState(null); const { - childRefProxy: sentinelRefProxy, - intersecting: isSentinelVisible, - parentRefProxy: messageListContainerRefProxy, - } = useIntersectionObserver(messageListContainerRef, sentinelRef); + childRefProxy: endSentinelRefProxy, + intersecting: isEndSentinelVisible, + parentRefProxy: endSentinelParentRefProxy, + } = useIntersectionObserver(messageListContainerRef, endSentinelRef); + const { + childRefProxy: startSentinelRefProxy, + intersecting: isStartSentinelVisible, + parentRefProxy: startSentinelParentRefProxy, + } = useIntersectionObserver(messageListContainerRef, startSentinelRef); const { startObserving: startObservingStickyScroll, stopObserving: stopObservingStickyScroll, @@ -272,13 +279,27 @@ const ChatMessageList: React.FC = ({ }, [chatDeleteReaction]); useEffect(() => { - if (isSentinelVisible) { + if (isEndSentinelVisible) { startObservingStickyScroll(); } else { stopObservingStickyScroll(); } - toggleFollowingTail(isSentinelVisible); - }, [isSentinelVisible]); + toggleFollowingTail(isEndSentinelVisible); + }, [isEndSentinelVisible]); + + useEffect(() => { + if (isStartSentinelVisible) { + if (followingTail) { + toggleFollowingTail(false); + } + setUserLoadedBackUntilPage((prev) => { + if (typeof prev === 'number' && prev > 0) { + return prev - 1; + } + return prev; + }); + } + }, [isStartSentinelVisible, followingTail]); useEffect(() => { setter({ @@ -330,7 +351,7 @@ const ChatMessageList: React.FC = ({ }, [lastMessageCreatedAt, chatId]); const setScrollToTailEventHandler = () => { - toggleFollowingTail(isSentinelVisible); + toggleFollowingTail(isEndSentinelVisible); }; const toggleFollowingTail = (toggle: boolean) => { @@ -357,8 +378,8 @@ const ChatMessageList: React.FC = ({ key="unread-messages" label={intl.formatMessage(intlMessages.moreMessages)} onClick={() => { - if (sentinelRef.current) { - sentinelRef.current.scrollIntoView({ behavior: 'smooth' }); + if (endSentinelRef.current) { + endSentinelRef.current.scrollIntoView({ behavior: 'smooth' }); } }} /> @@ -369,8 +390,8 @@ const ChatMessageList: React.FC = ({ useEffect(() => { const scrollToTailEventHandler = () => { - if (isElement(sentinelRef.current)) { - sentinelRef.current.scrollIntoView(); + if (isElement(endSentinelRef.current)) { + endSentinelRef.current.scrollIntoView(); } }; @@ -383,13 +404,20 @@ const ChatMessageList: React.FC = ({ useEffect(() => { if (followingTail) { - setUserLoadedBackUntilPage(null); + if (userLoadedBackUntilPage !== null) { + cleanupTimeoutRef.current = setTimeout(() => { + setUserLoadedBackUntilPage(null); + }, CLEANUP_TIMEOUT); + } + } else if (cleanupTimeoutRef.current !== null) { + clearTimeout(cleanupTimeoutRef.current); + cleanupTimeoutRef.current = null; } - }, [followingTail]); + }, [followingTail, userLoadedBackUntilPage]); useEffect(() => { - if (isElement(sentinelRef.current)) { - sentinelRef.current.scrollIntoView(); + if (isElement(endSentinelRef.current)) { + endSentinelRef.current.scrollIntoView(); } }, []); @@ -409,6 +437,17 @@ const ChatMessageList: React.FC = ({ } }; + const hasMessageToolbar = CHAT_DELETE_ENABLED + || CHAT_EDIT_ENABLED + || CHAT_REPLY_ENABLED + || CHAT_REACTIONS_ENABLED; + + const updateRefs = useCallback((el: HTMLDivElement | null) => { + messageListContainerRef.current = el; + startSentinelParentRefProxy.current = el; + endSentinelParentRefProxy.current = el; + }, []); + return ( <> { @@ -424,30 +463,28 @@ const ChatMessageList: React.FC = ({ }} data-test="chatMessages" isRTL={isRTL} - ref={messageListContainerRefProxy} + ref={updateRefs} + $hasMessageToolbar={hasMessageToolbar} >
{ setSelectedMessage(null); }} > - {userLoadedBackUntilPage ? ( - { - if (followingTail) { - toggleFollowingTail(false); - } - setUserLoadedBackUntilPage(userLoadedBackUntilPage - 1); - }} - > - {intl.formatMessage(intlMessages.loadMoreButtonLabel)} - - ) : null} - +
+ {Array.from({ length: pagesToLoad }, (_v, k) => k + (firstPageToLoad)).map((page) => { return ( = ({ lastSenderPreviousPage={page ? lastSenderPerPage.current.get(page - 1) : undefined} chatId={chatId} markMessageAsSeen={markMessageAsSeen} - scrollRef={messageListContainerRefProxy} + scrollRef={messageListContainerRef} focusedId={selectedMessage?.dataset.sequence ? Number.parseInt(selectedMessage?.dataset.sequence, 10) : null} @@ -482,7 +519,7 @@ const ChatMessageList: React.FC = ({ })}
= ({ ) } + {!deleteTime && editTime && ( diff --git a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/chat-message/message-header/styles.ts b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/chat-message/message-header/styles.ts index bb406ce45cac..06abe5971613 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/chat-message/message-header/styles.ts +++ b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/chat-message/message-header/styles.ts @@ -31,7 +31,7 @@ export const ChatUserName = styled.div` white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - flex-grow: 1; + flex-shrink: 1; ${({ currentlyInMeeting }) => currentlyInMeeting && ` color: ${colorHeading}; @@ -102,6 +102,10 @@ export const EditLabel = styled.span` } `; +export const Center = styled.div` + flex-grow: 1; +`; + export default { HeaderContent, ChatTime, @@ -109,4 +113,5 @@ export default { ChatUserName, ChatHeaderText, EditLabel, + Center, }; diff --git a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/chat-message/message-replied/component.tsx b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/chat-message/message-replied/component.tsx index 58b5a4ee716d..3974b15d35f5 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/chat-message/message-replied/component.tsx +++ b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/chat-message/message-replied/component.tsx @@ -37,7 +37,6 @@ const ChatMessageReplied: React.FC = (props) => { }, }), ); - Storage.removeItem(ChatEvents.CHAT_FOCUS_MESSAGE_REQUEST); Storage.setItem(ChatEvents.CHAT_FOCUS_MESSAGE_REQUEST, sequence); }} > diff --git a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/chat-message/message-toolbar/emoji-button/styles.ts b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/chat-message/message-toolbar/emoji-button/styles.ts index ace20831f2dc..924fdd4f0a7d 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/chat-message/message-toolbar/emoji-button/styles.ts +++ b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/chat-message/message-toolbar/emoji-button/styles.ts @@ -1,6 +1,6 @@ import styled from 'styled-components'; -import { colorGray } from '/imports/ui/stylesheets/styled-components/palette'; -import { lgPadding } from '/imports/ui/stylesheets/styled-components/general'; +import { colorGray, colorGrayDark, colorOffWhite } from '/imports/ui/stylesheets/styled-components/palette'; +import { smPadding } from '/imports/ui/stylesheets/styled-components/general'; import { fontSizeSmaller } from '/imports/ui/stylesheets/styled-components/typography'; const EmojiButton = styled.button` @@ -9,13 +9,15 @@ const EmojiButton = styled.button` background: none; border: none; outline: none; - padding: ${lgPadding}; + padding: ${smPadding}; color: ${colorGray}; cursor: pointer; + border-radius: 0.25rem; &:focus, &:hover { - opacity: 0.5; + color: ${colorGrayDark}; + background-color: ${colorOffWhite}; } &:active { diff --git a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/chat-message/message-toolbar/styles.ts b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/chat-message/message-toolbar/styles.ts index 0efd3f838bf1..06ef1c8b318b 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/chat-message/message-toolbar/styles.ts +++ b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/chat-message/message-toolbar/styles.ts @@ -4,7 +4,9 @@ import { colorGrayLightest, colorWhite, } from '/imports/ui/stylesheets/styled-components/palette'; -import { $2xlPadding, borderRadius, smPadding } from '/imports/ui/stylesheets/styled-components/general'; +import { + $2xlPadding, borderRadius, lgPadding, smPadding, +} from '/imports/ui/stylesheets/styled-components/general'; import EmojiPickerComponent from '/imports/ui/components/emoji-picker/component'; import BaseEmojiButton from './emoji-button/component'; @@ -50,6 +52,8 @@ const Container = styled.div` border-radius: 1rem; background-color: ${colorWhite}; box-shadow: 0 0.125rem 0.125rem 0 ${colorGrayLighter}; + padding: ${smPadding} ${lgPadding}; + gap: ${smPadding}; `; const EmojiPickerWrapper = styled.div` diff --git a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/component.tsx b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/component.tsx index aaad8ce99dc2..e50263178953 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/component.tsx +++ b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/component.tsx @@ -17,16 +17,17 @@ import { DomElementManipulationHooks } from 'bigbluebutton-html-plugin-sdk/dist/ import { CHAT_MESSAGE_PUBLIC_SUBSCRIPTION, CHAT_MESSAGE_PRIVATE_SUBSCRIPTION, + ChatMessageSubscriptionResponse, } from './queries'; import { Message } from '/imports/ui/Types/message'; import ChatMessage, { ChatMessageRef } from './chat-message/component'; -import { GraphqlDataHookSubscriptionResponse } from '/imports/ui/Types/hook'; -import { useCreateUseSubscription } from '/imports/ui/core/hooks/createUseSubscription'; import { setLoadedMessageGathering } from '/imports/ui/core/hooks/useLoadedChatMessages'; import { ChatLoading } from '../../component'; import { ChatEvents } from '/imports/ui/core/enums/chat'; import { useStorageKey, STORAGES } from '/imports/ui/services/storage/hooks'; +import Storage from '/imports/ui/services/storage/in-memory'; import { getValueByPointer } from '/imports/utils/object-utils'; +import useDeduplicatedSubscription from '/imports/ui/core/hooks/useDeduplicatedSubscription'; const PAGE_SIZE = 50; @@ -230,6 +231,7 @@ const ChatListPage: React.FC = ({ useEffect(() => { if (typeof chatFocusMessageRequest === 'number') { messageRefs.current[chatFocusMessageRequest]?.requestFocus(); + Storage.removeItem(ChatEvents.CHAT_FOCUS_MESSAGE_REQUEST); } }, []); @@ -320,10 +322,18 @@ const ChatListPageContainer: React.FC = ({ ? defaultVariables : { ...defaultVariables, requestedChatId: chatId }; const isPrivateReadFeedbackEnabled = !isPublicChat && PRIVATE_MESSAGE_READ_FEEDBACK_ENABLED; - const useChatMessageSubscription = useCreateUseSubscription(chatQuery, variables); const { - data: chatMessageData, - } = useChatMessageSubscription((msg) => msg) as GraphqlDataHookSubscriptionResponse; + data, + loading, + } = useDeduplicatedSubscription(chatQuery, { variables }); + let chatMessageData: Message[] | null = null; + if (data) { + if ('chat_message_public' in data) { + chatMessageData = data.chat_message_public; + } else if ('chat_message_private' in data) { + chatMessageData = data.chat_message_private; + } + } useEffect(() => { // component will unmount @@ -332,8 +342,8 @@ const ChatListPageContainer: React.FC = ({ }; }, []); + if (loading) return ; if (!chatMessageData) return null; - if (chatMessageData.length > 0 && chatId !== chatMessageData[0].chatId) return ; if (chatMessageData.length > 0 && chatMessageData[chatMessageData.length - 1].user?.userId) { setLastSender(page, chatMessageData[chatMessageData.length - 1].user?.userId); } diff --git a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/queries.ts b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/queries.ts index af561e6829fe..3896386ef3bf 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/queries.ts +++ b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/queries.ts @@ -1,4 +1,5 @@ import { gql } from '@apollo/client'; +import { Message } from '/imports/ui/Types/message'; export const CHAT_MESSAGE_PUBLIC_SUBSCRIPTION = gql` subscription chatMessages($limit: Int!, $offset: Int!) { @@ -106,3 +107,9 @@ export const CHAT_MESSAGE_PRIVATE_SUBSCRIPTION = gql` } } `; + +export type ChatMessageSubscriptionResponse = { + chat_message_public: Message[] +} | { + chat_message_private: Message[] +} diff --git a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/styles.ts b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/styles.ts index 1f2c0c0619a3..55a49a96ee8c 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/styles.ts +++ b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/styles.ts @@ -1,20 +1,16 @@ import styled from 'styled-components'; -import { - smPaddingX, - borderRadius, -} from '/imports/ui/stylesheets/styled-components/general'; +import { smPaddingX } from '/imports/ui/stylesheets/styled-components/general'; import { ScrollboxVertical } from '/imports/ui/stylesheets/styled-components/scrollable'; -import { colorGrayDark } from '/imports/ui/stylesheets/styled-components/palette'; import { ButtonElipsis } from '/imports/ui/stylesheets/styled-components/placeholders'; interface MessageListProps { isRTL: boolean; + $hasMessageToolbar: boolean; } export const MessageList = styled(ScrollboxVertical)` flex-flow: column; flex-shrink: 1; - padding-top: 2rem; outline-style: none; overflow-x: hidden; user-select: text; @@ -32,15 +28,10 @@ export const MessageList = styled(ScrollboxVertical)` ${({ isRTL }) => !isRTL && ` padding-right: ${smPaddingX}; `} -`; -export const ButtonLoadMore = styled.button` - width: 100%; - min-height: 1.5rem; - margin-bottom: 0.75rem; - background-color: transparent; - border-radius: ${borderRadius}; - border: 1px ridge ${colorGrayDark}; + ${({ $hasMessageToolbar }) => $hasMessageToolbar && ` + padding-top: 2rem; + `} `; export const UnreadButton = styled(ButtonElipsis)` diff --git a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-popup/component.tsx b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-popup/component.tsx index b75de4ccc9bf..7afa29363f12 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-popup/component.tsx +++ b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-popup/component.tsx @@ -8,7 +8,11 @@ import { layoutSelect } from '../../../layout/context'; import { Layout } from '../../../layout/layoutTypes'; import { ChatCommands } from '/imports/ui/core/enums/chat'; -interface ChatPopupProps { +interface ChatPopupCommonProps { + hasMessageToolbar: boolean; +} + +interface ChatPopupProps extends ChatPopupCommonProps { welcomeMessage: string | null; welcomeMsgForModerators: string | null; } @@ -31,6 +35,7 @@ const isBoolean = (v: unknown): boolean => { }; const ChatPopup: React.FC = ({ + hasMessageToolbar, welcomeMessage, welcomeMsgForModerators, }) => { @@ -60,7 +65,7 @@ const ChatPopup: React.FC = ({ }, []); if (!showWelcomeMessage && !showWelcomeMessageForModerators) return null; return ( - + {showWelcomeMessage && welcomeMessage && ( = ({ ); }; -const ChatPopupContainer: React.FC = () => { +const ChatPopupContainer: React.FC = (props) => { + const { hasMessageToolbar } = props; + const { data: welcomeData, loading: welcomeLoading, @@ -104,6 +111,7 @@ const ChatPopupContainer: React.FC = () => { return ( diff --git a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-popup/styles.ts b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-popup/styles.ts index 0037e1cc2392..9214d156ebdd 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-popup/styles.ts +++ b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-popup/styles.ts @@ -1,12 +1,18 @@ import styled from 'styled-components'; import { ScrollboxVertical } from '/imports/ui/stylesheets/styled-components/scrollable'; -export const PopupContainer = styled.div` +export const PopupContainer = styled.div<{ + $hasMessageToolbar: boolean; +}>` position: sticky; top: 0; max-height: 80%; z-index: 3; background-color: white; + + ${({ $hasMessageToolbar }) => $hasMessageToolbar && ` + top: -2rem; + `} `; export const PopupContents = styled(ScrollboxVertical)` diff --git a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-reply-intention/styles.tsx b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-reply-intention/styles.tsx index 5a48197474f4..1dec047a96f2 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-reply-intention/styles.tsx +++ b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-reply-intention/styles.tsx @@ -58,6 +58,7 @@ const Container = styled.div<{ $hidden: boolean; $animations: boolean }>` const Message = styled.div` line-height: 1rlh; flex-grow: 1; + min-width: 0; `; const Markdown = styled(ReactMarkdown)<{