Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 37 additions & 15 deletions samples/Chat/src/app/ConfigurationScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ const CONFIGURATIONSCREEN_SHOWING_JOIN_CHAT = 2;
const CONFIGURATIONSCREEN_SHOWING_INVALID_THREAD = 3;
const CONFIGURATIONSCREEN_SHOWING_SPINNER_INITIALIZE_CHAT = 4;

const ALERT_TEXT_TRY_AGAIN = "You can't be added at this moment. Please wait at least 60 seconds to try again.";
const AVATAR_LABEL = 'Avatar';
const ERROR_TEXT_THREAD_INVALID = 'Thread Id is not valid, please revisit home page to create a new thread';
const ERROR_TEXT_THREAD_NOT_RECORDED = 'Thread id is not recorded in server';
const ERROR_TEXT_THREAD_NULL = 'Thread id is null';
const INITIALIZE_CHAT_SPINNER_LABEL = 'Initializing chat client...';
const JOIN_BUTTON_TEXT = 'Join chat';
const LOADING_SPINNER_LABEL = 'Loading...';
const NAME_DEFAULT = 'Name';

/**
* There are four states of ConfigurationScreen.
* 1. Loading configuration screen state. This will show 'loading' spinner on the screen.
Expand All @@ -64,8 +74,6 @@ const CONFIGURATIONSCREEN_SHOWING_SPINNER_INITIALIZE_CHAT = 4;
*/
export default (props: ConfigurationScreenProps): JSX.Element => {
const avatarsList = [CAT, MOUSE, KOALA, OCTOPUS, MONKEY, FOX];
const loadingSpinnerLabel = 'Loading...';
const initializeChatSpinnerLabel = 'Initializing chat client...';
const [name, setName] = useState('');
const [emptyWarning, setEmptyWarning] = useState(false);
const [selectedAvatar, setSelectedAvatar] = useState(CAT);
Expand All @@ -84,7 +92,7 @@ export default (props: ConfigurationScreenProps): JSX.Element => {
const endpointUrl = await getEndpointUrl();

if (!threadId) {
throw new Error('Thread id is null');
throw new Error(ERROR_TEXT_THREAD_NULL);
}

setToken(token.token);
Expand All @@ -97,7 +105,7 @@ export default (props: ConfigurationScreenProps): JSX.Element => {

const result = await joinThread(threadId, token.identity, name);
if (!result) {
alert("You can't be added at this moment. Please wait at least 60 seconds to try again.");
alert(ALERT_TEXT_TRY_AGAIN);
setDisableJoinChatButton(false);
return;
}
Expand All @@ -114,7 +122,7 @@ export default (props: ConfigurationScreenProps): JSX.Element => {
try {
const threadId = getThreadId();
if (!(await checkThreadValid(threadId))) {
throw new Error('Thread id is not recorded in server');
throw new Error(ERROR_TEXT_THREAD_NOT_RECORDED);
}
} catch (error) {
setConfigurationScreenState(CONFIGURATIONSCREEN_SHOWING_INVALID_THREAD);
Expand Down Expand Up @@ -162,22 +170,36 @@ export default (props: ConfigurationScreenProps): JSX.Element => {
tokens={responsiveLayoutStackTokens}
className={responsiveLayoutStyle}
>
<Stack className={leftPreviewContainerStyle} tokens={leftPreviewContainerStackTokens}>
<Stack
role={'heading'}
aria-level={1}
className={leftPreviewContainerStyle}
tokens={leftPreviewContainerStackTokens}
>
<div className={largeAvatarContainerStyle(selectedAvatar)}>
<div className={largeAvatarStyle}>{selectedAvatar}</div>
<div aria-label={`${selectedAvatar} avatar`} className={largeAvatarStyle}>
{selectedAvatar}
</div>
</div>
<Text className={namePreviewStyle(name !== '')}>{name !== '' ? name : 'Name'}</Text>
<Text className={namePreviewStyle(name !== '')}>{name !== '' ? name : NAME_DEFAULT}</Text>
</Stack>
<Stack className={rightInputContainerStyle} tokens={rightInputContainerStackTokens}>
<Text className={labelFontStyle}>Avatar</Text>
<Text id={'avatar-list-label'} className={labelFontStyle}>
{AVATAR_LABEL}
</Text>
<FocusZone direction={FocusZoneDirection.horizontal}>
<Stack role="list" horizontal className={avatarListContainerStyle} tokens={avatarListContainerStackTokens}>
<Stack
horizontal
className={avatarListContainerStyle}
tokens={avatarListContainerStackTokens}
role="list"
aria-labelledby={'avatar-list-label'}
>
{avatarsList.map((avatar, index) => (
<div
role="listitem"
id={avatar}
key={index}
tabIndex={0}
data-is-focusable={true}
className={smallAvatarContainerClassName(avatar)}
onClick={() => onAvatarChange(avatar)}
Expand All @@ -197,7 +219,7 @@ export default (props: ConfigurationScreenProps): JSX.Element => {
disabled={disableJoinChatButton}
className={buttonStyle}
styles={buttonWithIconStyles}
text={'Join chat'}
text={JOIN_BUTTON_TEXT}
onClick={validateName}
onRenderIcon={() => <Chat20Filled className={chatIconStyle} />}
/>
Expand All @@ -209,7 +231,7 @@ export default (props: ConfigurationScreenProps): JSX.Element => {
const displayInvalidThreadError = (): JSX.Element => {
return (
<div>
<p>Thread Id is not valid, please revisit home page to create a new thread</p>
<p>{ERROR_TEXT_THREAD_INVALID}</p>
</div>
);
};
Expand All @@ -223,13 +245,13 @@ export default (props: ConfigurationScreenProps): JSX.Element => {
};

if (configurationScreenState === CONFIGURATIONSCREEN_SHOWING_SPINNER_LOADING) {
return displaySpinner(loadingSpinnerLabel);
return displaySpinner(LOADING_SPINNER_LABEL);
} else if (configurationScreenState === CONFIGURATIONSCREEN_SHOWING_JOIN_CHAT) {
return displayWithStack(displayJoinChatArea());
} else if (configurationScreenState === CONFIGURATIONSCREEN_SHOWING_INVALID_THREAD) {
return displayWithStack(displayInvalidThreadError());
} else if (configurationScreenState === CONFIGURATIONSCREEN_SHOWING_SPINNER_INITIALIZE_CHAT) {
return displaySpinner(initializeChatSpinnerLabel);
return displaySpinner(INITIALIZE_CHAT_SPINNER_LABEL);
} else {
throw new Error('configuration screen state ' + configurationScreenState.toString() + ' is invalid');
}
Expand Down
56 changes: 22 additions & 34 deletions samples/Chat/src/app/DisplayNameField.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import {
TextFieldStyleProps,
inputBoxStyle,
inputBoxTextStyle,
inputBoxWarningStyle,
labelFontStyle,
warningStyle
} from './styles/DisplayNameField.styles';
import { TextFieldStyleProps, inputBoxStyle, inputBoxTextStyle } from './styles/DisplayNameField.styles';
import { ENTER_KEY } from './utils/constants';

import React from 'react';
Expand All @@ -22,6 +15,11 @@ interface DisplayNameFieldProps {
validateName?(): void;
}

const TEXTFIELD_LABEL = 'Name';
const TEXTFIELD_ID = 'displayName';
const TEXTFIELD_PLACEHOLDER = 'Enter your name';
const TEXTFIELD_EMPTY_ERROR_MSG = 'Name cannot be empty';

const DisplayNameFieldComponent = (props: DisplayNameFieldProps): JSX.Element => {
const { setName, setEmptyWarning, isEmpty, defaultName, validateName } = props;

Expand All @@ -40,33 +38,23 @@ const DisplayNameFieldComponent = (props: DisplayNameFieldProps): JSX.Element =>
};

return (
<div>
<div className={labelFontStyle}>Name</div>
<TextField
autoComplete="off"
defaultValue={defaultName}
inputClassName={inputBoxTextStyle}
ariaLabel="Choose your name"
className={isEmpty ? inputBoxWarningStyle : inputBoxStyle}
onChange={onNameTextChange}
id="displayName"
placeholder="Enter your name"
onKeyDown={(ev) => {
if (ev.which === ENTER_KEY) {
validateName && validateName();
}
}}
styles={TextFieldStyleProps}
errorMessage={
isEmpty ? (
<div role="alert" className={warningStyle}>
{' '}
Name cannot be empty{' '}
</div>
) : undefined
<TextField
autoComplete="off"
defaultValue={defaultName}
inputClassName={inputBoxTextStyle}
label={TEXTFIELD_LABEL}
className={inputBoxStyle}
onChange={onNameTextChange}
id={TEXTFIELD_ID}
placeholder={TEXTFIELD_PLACEHOLDER}
onKeyDown={(ev) => {
if (ev.which === ENTER_KEY) {
validateName && validateName();
}
/>
</div>
}}
styles={TextFieldStyleProps}
errorMessage={isEmpty ? TEXTFIELD_EMPTY_ERROR_MSG : undefined}
/>
);
};

Expand Down
34 changes: 0 additions & 34 deletions samples/Chat/src/app/styles/DisplayNameField.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,13 @@
import { mergeStyles } from '@fluentui/react';

export const TextFieldStyleProps = {
wrapper: {
height: '2.3rem'
},
fieldGroup: {
height: '2.3rem'
}
};

export const inputBoxStyle = mergeStyles({
boxSizing: 'border-box',
height: '2.5rem',
width: '18.75rem',
borderRadius: '0.125rem'
});
Expand All @@ -36,33 +32,3 @@ export const inputBoxTextStyle = mergeStyles({
fontWeight: 600
}
});

export const inputBoxWarningStyle = mergeStyles({
boxSizing: 'border-box',
height: '2.5rem',
width: '18.75rem',
borderRadius: '2px',
fontSize: '0.875rem'
});

export const labelFontStyle = mergeStyles({
fontSize: '0.875rem',
fontWeight: 600,
boxSizing: 'border-box',
boxShadow: 'none',
margin: 0,
display: 'inline-block',
padding: '5px 0px',
overflowWrap: 'break-word'
});

export const warningStyle = mergeStyles({
width: '18.75rem',
marginTop: '0.188rem',
marginBottom: '0.188rem',
marginLeft: '0.188rem',
color: '#e81123',
fontSize: '.7375rem',
fontWeight: '400',
position: 'absolute'
});