Add support for disabled chat state in the chat input field. Closes #2761

This commit is contained in:
Gabe Kangas 2023-03-01 16:19:02 -08:00
parent de71984d46
commit 4a0476b237
No known key found for this signature in database
GPG key ID: 4345B2060657F330
9 changed files with 76 additions and 22 deletions

View file

@ -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,
};

View file

@ -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<ChatContainerProps> = ({
isModerator,
showInput,
height,
chatAvailable: chatEnabled,
}) => {
const [showScrollToBottomButton, setShowScrollToBottomButton] = useState(false);
const [isAtBottom, setIsAtBottom] = useState(false);
@ -284,7 +286,7 @@ export const ChatContainer: FC<ChatContainerProps> = ({
{MessagesTable}
{showInput && (
<div className={styles.chatTextField}>
<ChatTextField />
<ChatTextField enabled={chatEnabled} />
</div>
)}
</div>

View file

@ -58,9 +58,13 @@ const Template: ComponentStory<typeof ChatTextField> = 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.',
},
},
};

View file

@ -122,11 +122,12 @@ const getCharacterCount = node => {
export type ChatTextFieldProps = {
defaultText?: string;
enabled: boolean;
};
const characterLimit = 300;
export const ChatTextField: FC<ChatTextFieldProps> = ({ defaultText }) => {
export const ChatTextField: FC<ChatTextFieldProps> = ({ defaultText, enabled }) => {
const [showEmojis, setShowEmojis] = useState(false);
const [characterCount, setCharacterCount] = useState(defaultText?.length);
const websocketService = useRecoilValue<WebsocketService>(websocketServiceAtom);
@ -241,8 +242,10 @@ export const ChatTextField: FC<ChatTextFieldProps> = ({ 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<ChatTextFieldProps> = ({ defaultText }) => {
/>
</Slate>
<div style={{ display: 'flex', paddingLeft: '5px' }}>
<button
type="button"
className={styles.emojiButton}
title="Emoji picker button"
onClick={() => setShowEmojis(!showEmojis)}
>
<SmileOutlined />
</button>
<button
type="button"
className={styles.sendButton}
title="Send message Button"
onClick={sendMessage}
>
<SendOutlined />
</button>
</div>
{enabled && (
<div style={{ display: 'flex', paddingLeft: '5px' }}>
<button
type="button"
className={styles.emojiButton}
title="Emoji picker button"
onClick={() => setShowEmojis(!showEmojis)}
>
<SmileOutlined />
</button>
<button
type="button"
className={styles.sendButton}
title="Send message Button"
onClick={sendMessage}
>
<SendOutlined />
</button>
</div>
)}
</div>
</div>
);

View file

@ -293,6 +293,7 @@ export const Content: FC = () => {
notifyItemSelected={() => setShowNotifyModal(true)}
followItemSelected={() => setShowFollowModal(true)}
externalActionSelected={externalActionSelected}
chatEnabled={isChatAvailable}
/>
) : (
<DesktopContent

View file

@ -25,6 +25,7 @@ export type MobileContentProps = {
messages: ChatMessage[];
currentUser: CurrentUser;
showChat: boolean;
chatEnabled: boolean;
actions: ExternalAction[];
externalActionSelected: (action: ExternalAction) => void;
supportsBrowserNotifications: boolean;
@ -62,6 +63,7 @@ export const MobileContent: FC<MobileContentProps> = ({
messages,
currentUser,
showChat,
chatEnabled,
actions,
setExternalActionToDisplay,
setShowNotifyPopup,
@ -80,6 +82,7 @@ export const MobileContent: FC<MobileContentProps> = ({
usernameToHighlight={displayName}
chatUserId={id}
isModerator={false}
chatAvailable={chatEnabled}
/>
);

View file

@ -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<ChatMessage[]>(visibleChatMessagesSelector);
const isChatAvailable = useRecoilValue(isChatAvailableSelector);
if (!currentUser) {
return <Sider className={styles.root} collapsedWidth={0} width={320} />;
}
@ -30,6 +36,7 @@ export const Sidebar: FC = () => {
usernameToHighlight={displayName}
chatUserId={id}
isModerator={isModerator}
chatAvailable={isChatAvailable}
/>
</Sider>
);

View file

@ -5,11 +5,13 @@ import {
ClientConfigStore,
currentUserAtom,
visibleChatMessagesSelector,
isChatAvailableSelector,
} from '../../../../components/stores/ClientConfigStore';
export default function ReadOnlyChatEmbed() {
const currentUser = useRecoilValue(currentUserAtom);
const messages = useRecoilValue<ChatMessage[]>(visibleChatMessagesSelector);
const isChatAvailable = useRecoilValue(isChatAvailableSelector);
return (
<div>
@ -22,6 +24,7 @@ export default function ReadOnlyChatEmbed() {
isModerator={false}
showInput={false}
height="100vh"
chatAvailable={isChatAvailable}
/>
)}
</div>

View file

@ -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<ServerStatus>(serverStatusState);
const appState = useRecoilValue<AppStateOptions>(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}
/>
</div>
)}