From 4a0476b237e339e85e3bf46951f32aea0c20208b Mon Sep 17 00:00:00 2001 From: Gabe Kangas Date: Wed, 1 Mar 2023 16:19:02 -0800 Subject: [PATCH] Add support for disabled chat state in the chat input field. Closes #2761 --- .../ChatContainer/ChatContainer.stories.tsx | 13 ++++++ .../chat/ChatContainer/ChatContainer.tsx | 4 +- .../ChatTextField/ChatTextField.stories.tsx | 17 +++++++ .../chat/ChatTextField/ChatTextField.tsx | 45 ++++++++++--------- web/components/ui/Content/Content.tsx | 1 + web/components/ui/Content/MobileContent.tsx | 3 ++ web/components/ui/Sidebar/Sidebar.tsx | 9 +++- web/pages/embed/chat/readonly/index.tsx | 3 ++ web/pages/embed/chat/readwrite/index.tsx | 3 ++ 9 files changed, 76 insertions(+), 22 deletions(-) diff --git a/web/components/chat/ChatContainer/ChatContainer.stories.tsx b/web/components/chat/ChatContainer/ChatContainer.stories.tsx index 3ca706472..dac0713b7 100644 --- a/web/components/chat/ChatContainer/ChatContainer.stories.tsx +++ b/web/components/chat/ChatContainer/ChatContainer.stories.tsx @@ -593,6 +593,18 @@ Example.args = { chatUserId: 'testuser', isModerator: true, showInput: true, + chatAvailable: true, +}; + +export const ChatDisabled = Template.bind({}); +ChatDisabled.args = { + loading: false, + messages, + usernameToHighlight: 'testuser', + chatUserId: 'testuser', + isModerator: true, + showInput: true, + chatAvailable: false, }; export const SingleMessage = Template.bind({}); @@ -603,4 +615,5 @@ SingleMessage.args = { chatUserId: 'testuser', isModerator: true, showInput: true, + chatAvailable: true, }; diff --git a/web/components/chat/ChatContainer/ChatContainer.tsx b/web/components/chat/ChatContainer/ChatContainer.tsx index 4a7e8d039..bbc40dc1c 100644 --- a/web/components/chat/ChatContainer/ChatContainer.tsx +++ b/web/components/chat/ChatContainer/ChatContainer.tsx @@ -25,6 +25,7 @@ export type ChatContainerProps = { isModerator: boolean; showInput?: boolean; height?: string; + chatAvailable: boolean; }; function shouldCollapseMessages( @@ -92,6 +93,7 @@ export const ChatContainer: FC = ({ isModerator, showInput, height, + chatAvailable: chatEnabled, }) => { const [showScrollToBottomButton, setShowScrollToBottomButton] = useState(false); const [isAtBottom, setIsAtBottom] = useState(false); @@ -284,7 +286,7 @@ export const ChatContainer: FC = ({ {MessagesTable} {showInput && (
- +
)} diff --git a/web/components/chat/ChatTextField/ChatTextField.stories.tsx b/web/components/chat/ChatTextField/ChatTextField.stories.tsx index b0f2ea4a9..138274e2f 100644 --- a/web/components/chat/ChatTextField/ChatTextField.stories.tsx +++ b/web/components/chat/ChatTextField/ChatTextField.stories.tsx @@ -58,9 +58,13 @@ const Template: ComponentStory = args => ( ); export const Example = Template.bind({}); +Example.args = { + enabled: true, +}; export const LongerMessage = Template.bind({}); LongerMessage.args = { + enabled: true, defaultText: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', }; @@ -72,3 +76,16 @@ LongerMessage.parameters = { }, }, }; + +export const DisabledChat = Template.bind({}); +DisabledChat.args = { + enabled: false, +}; + +DisabledChat.parameters = { + docs: { + description: { + story: 'Should not allow you to type anything and should state that chat is disabled.', + }, + }, +}; diff --git a/web/components/chat/ChatTextField/ChatTextField.tsx b/web/components/chat/ChatTextField/ChatTextField.tsx index 5e3e857b6..44fae7ca8 100644 --- a/web/components/chat/ChatTextField/ChatTextField.tsx +++ b/web/components/chat/ChatTextField/ChatTextField.tsx @@ -122,11 +122,12 @@ const getCharacterCount = node => { export type ChatTextFieldProps = { defaultText?: string; + enabled: boolean; }; const characterLimit = 300; -export const ChatTextField: FC = ({ defaultText }) => { +export const ChatTextField: FC = ({ defaultText, enabled }) => { const [showEmojis, setShowEmojis] = useState(false); const [characterCount, setCharacterCount] = useState(defaultText?.length); const websocketService = useRecoilValue(websocketServiceAtom); @@ -241,8 +242,10 @@ export const ChatTextField: FC = ({ defaultText }) => { className="chat-text-input" onKeyDown={onKeyDown} onPaste={onPaste} + disabled={!enabled} + readOnly={!enabled} renderElement={renderElement} - placeholder="Send a message to chat" + placeholder={enabled ? 'Send a message to chat' : 'Chat is currently unavailable.'} style={{ width: '100%' }} role="textbox" aria-label="Chat text input" @@ -262,24 +265,26 @@ export const ChatTextField: FC = ({ defaultText }) => { /> -
- - -
+ {enabled && ( +
+ + +
+ )} ); diff --git a/web/components/ui/Content/Content.tsx b/web/components/ui/Content/Content.tsx index bcacb6825..8f8b3c3b4 100644 --- a/web/components/ui/Content/Content.tsx +++ b/web/components/ui/Content/Content.tsx @@ -293,6 +293,7 @@ export const Content: FC = () => { notifyItemSelected={() => setShowNotifyModal(true)} followItemSelected={() => setShowFollowModal(true)} externalActionSelected={externalActionSelected} + chatEnabled={isChatAvailable} /> ) : ( void; supportsBrowserNotifications: boolean; @@ -62,6 +63,7 @@ export const MobileContent: FC = ({ messages, currentUser, showChat, + chatEnabled, actions, setExternalActionToDisplay, setShowNotifyPopup, @@ -80,6 +82,7 @@ export const MobileContent: FC = ({ usernameToHighlight={displayName} chatUserId={id} isModerator={false} + chatAvailable={chatEnabled} /> ); diff --git a/web/components/ui/Sidebar/Sidebar.tsx b/web/components/ui/Sidebar/Sidebar.tsx index 68971a8ab..1e492aa50 100644 --- a/web/components/ui/Sidebar/Sidebar.tsx +++ b/web/components/ui/Sidebar/Sidebar.tsx @@ -5,7 +5,11 @@ import dynamic from 'next/dynamic'; import { ChatMessage } from '../../../interfaces/chat-message.model'; import styles from './Sidebar.module.scss'; -import { currentUserAtom, visibleChatMessagesSelector } from '../../stores/ClientConfigStore'; +import { + currentUserAtom, + visibleChatMessagesSelector, + isChatAvailableSelector, +} from '../../stores/ClientConfigStore'; // Lazy loaded components const ChatContainer = dynamic( @@ -18,6 +22,8 @@ const ChatContainer = dynamic( export const Sidebar: FC = () => { const currentUser = useRecoilValue(currentUserAtom); const messages = useRecoilValue(visibleChatMessagesSelector); + const isChatAvailable = useRecoilValue(isChatAvailableSelector); + if (!currentUser) { return ; } @@ -30,6 +36,7 @@ export const Sidebar: FC = () => { usernameToHighlight={displayName} chatUserId={id} isModerator={isModerator} + chatAvailable={isChatAvailable} /> ); diff --git a/web/pages/embed/chat/readonly/index.tsx b/web/pages/embed/chat/readonly/index.tsx index 65600c294..c2c3f1a6a 100644 --- a/web/pages/embed/chat/readonly/index.tsx +++ b/web/pages/embed/chat/readonly/index.tsx @@ -5,11 +5,13 @@ import { ClientConfigStore, currentUserAtom, visibleChatMessagesSelector, + isChatAvailableSelector, } from '../../../../components/stores/ClientConfigStore'; export default function ReadOnlyChatEmbed() { const currentUser = useRecoilValue(currentUserAtom); const messages = useRecoilValue(visibleChatMessagesSelector); + const isChatAvailable = useRecoilValue(isChatAvailableSelector); return (
@@ -22,6 +24,7 @@ export default function ReadOnlyChatEmbed() { isModerator={false} showInput={false} height="100vh" + chatAvailable={isChatAvailable} /> )}
diff --git a/web/pages/embed/chat/readwrite/index.tsx b/web/pages/embed/chat/readwrite/index.tsx index 35fc51820..3c43d5dce 100644 --- a/web/pages/embed/chat/readwrite/index.tsx +++ b/web/pages/embed/chat/readwrite/index.tsx @@ -8,6 +8,7 @@ import { clientConfigStateAtom, appStateAtom, serverStatusState, + isChatAvailableSelector, } from '../../../../components/stores/ClientConfigStore'; import Header from '../../../../components/ui/Header/Header'; import { ClientConfig } from '../../../../interfaces/client-config.model'; @@ -21,6 +22,7 @@ export default function ReadWriteChatEmbed() { const clientStatus = useRecoilValue(serverStatusState); const appState = useRecoilValue(appStateAtom); + const isChatAvailable = useRecoilValue(isChatAvailableSelector); const { name, chatDisabled } = clientConfig; const { videoAvailable } = appState; @@ -41,6 +43,7 @@ export default function ReadWriteChatEmbed() { isModerator={currentUser.isModerator} showInput height="80vh" + chatAvailable={isChatAvailable} /> )}