feat(profile-tab) Update Profile tab in Settings Dialog (#12992)

Implement redesign
Move some options from More to this tab
This commit is contained in:
Robert Pintilii 2023-03-03 10:42:59 +02:00 committed by GitHub
parent 17ed45799c
commit b1a71d55d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 193 additions and 199 deletions

View File

@ -886,9 +886,9 @@
},
"profile": {
"avatar": "avatar",
"setDisplayNameLabel": "Set your display name",
"setDisplayNameLabel": "Name",
"setEmailInput": "Enter email",
"setEmailLabel": "Set your gravatar email",
"setEmailLabel": "Gravatar email",
"title": "Profile"
},
"raisedHand": "Would like to speak",

View File

@ -107,20 +107,12 @@ export function submitMoreTab(newState: any) {
}));
}
if (newState.currentLanguage !== currentState.currentLanguage) {
i18next.changeLanguage(newState.currentLanguage);
}
if (newState.currentFramerate !== currentState.currentFramerate) {
const frameRate = parseInt(newState.currentFramerate, 10);
dispatch(setScreenshareFramerate(frameRate));
}
if (newState.hideSelfView !== currentState.hideSelfView) {
dispatch(updateSettings({ disableSelfView: newState.hideSelfView }));
}
if (newState.maxStageParticipants !== currentState.maxStageParticipants) {
dispatch(updateSettings({ maxStageParticipants: Number(newState.maxStageParticipants) }));
}
@ -174,6 +166,14 @@ export function submitProfileTab(newState: any) {
if (newState.email !== currentState.email) {
APP.conference.changeLocalEmail(newState.email);
}
if (newState.hideSelfView !== currentState.hideSelfView) {
dispatch(updateSettings({ disableSelfView: newState.hideSelfView }));
}
if (newState.currentLanguage !== currentState.currentLanguage) {
i18next.changeLanguage(newState.currentLanguage);
}
};
}

View File

@ -22,22 +22,11 @@ export type Props = AbstractDialogTabProps & WithTranslation & {
*/
currentFramerate: string;
/**
* The currently selected language to display in the language select
* dropdown.
*/
currentLanguage: string;
/**
* All available desktop capture frame rates.
*/
desktopShareFramerates: Array<number>;
/**
* Whether to show hide self view setting.
*/
disableHideSelfView: boolean;
/**
* The types of enabled notifications that can be configured and their specific visibility.
*/
@ -48,26 +37,11 @@ export type Props = AbstractDialogTabProps & WithTranslation & {
*/
followMeActive: boolean;
/**
* Whether or not to hide self-view screen.
*/
hideSelfView: boolean;
/**
* All available languages to display in the language select dropdown.
*/
languages: Array<string>;
/**
* The number of max participants to display on stage.
*/
maxStageParticipants: number;
/**
* Whether or not to display the language select dropdown.
*/
showLanguageSettings: boolean;
/**
* Whether or not to display moderator-only settings.
*/
@ -116,11 +90,9 @@ class MoreTab extends AbstractDialogTab<Props, any> {
// Bind event handler so it is only bound once for every instance.
this._onFramerateItemSelect = this._onFramerateItemSelect.bind(this);
this._onLanguageItemSelect = this._onLanguageItemSelect.bind(this);
this._onEnabledNotificationsChanged = this._onEnabledNotificationsChanged.bind(this);
this._onShowPrejoinPageChanged = this._onShowPrejoinPageChanged.bind(this);
this._onKeyboardShortcutEnableChanged = this._onKeyboardShortcutEnableChanged.bind(this);
this._onHideSelfViewChanged = this._onHideSelfViewChanged.bind(this);
this._renderMaxStageParticipantsSelect = this._renderMaxStageParticipantsSelect.bind(this);
this._onMaxStageParticipantsSelect = this._onMaxStageParticipantsSelect.bind(this);
}
@ -159,19 +131,6 @@ class MoreTab extends AbstractDialogTab<Props, any> {
super._onChange({ currentFramerate: frameRate });
}
/**
* Callback invoked to select a language from select dropdown.
*
* @param {Object} e - The key event to handle.
*
* @returns {void}
*/
_onLanguageItemSelect(e: React.ChangeEvent<HTMLSelectElement>) {
const language = e.target.value;
super._onChange({ currentLanguage: language });
}
/**
* Callback invoked to select if the lobby
* should be shown.
@ -215,17 +174,6 @@ class MoreTab extends AbstractDialogTab<Props, any> {
super._onChange({ keyboardShortcutEnable: checked });
}
/**
* Callback invoked to select if hide self view should be enabled.
*
* @param {Object} e - The key event to handle.
*
* @returns {void}
*/
_onHideSelfViewChanged({ target: { checked } }: React.ChangeEvent<HTMLInputElement>) {
super._onChange({ hideSelfView: checked });
}
/**
* Callback invoked to select a max number of stage participants from the select dropdown.
*
@ -296,67 +244,6 @@ class MoreTab extends AbstractDialogTab<Props, any> {
);
}
/**
* Returns the React Element for self view setting.
*
* @private
* @returns {ReactElement}
*/
_renderSelfViewCheckbox() {
const { hideSelfView, t } = this.props;
return (
<div
className = 'settings-sub-pane-element'
key = 'selfview'>
<span className = 'checkbox-label'>
{ t('settings.selfView') }
</span>
<Checkbox
checked = { hideSelfView }
label = { t('videothumbnail.hideSelfView') }
name = 'hide-self-view'
onChange = { this._onHideSelfViewChanged } />
</div>
);
}
/**
* Returns the menu item for changing displayed language.
*
* @private
* @returns {ReactElement}
*/
_renderLanguageSelect() {
const {
currentLanguage,
languages,
t
} = this.props;
const languageItems
= languages.map((language: string) => {
return {
value: language,
label: t(`languages:${language}`)
};
});
return (
<div
className = 'settings-sub-pane-element'
key = 'language'>
<div className = 'dropdown-menu'>
<Select
label = { t('settings.language') }
onChange = { this._onLanguageItemSelect }
options = { languageItems }
value = { currentLanguage } />
</div>
</div>
);
}
/**
* Returns the React Element for modifying prejoin screen settings.
*
@ -454,13 +341,10 @@ class MoreTab extends AbstractDialogTab<Props, any> {
* @returns {ReactElement}
*/
_renderSettingsRight() {
const { showLanguageSettings } = this.props;
return (
<div
className = 'settings-sub-pane right'
key = 'settings-sub-pane-right'>
{ showLanguageSettings && this._renderLanguageSelect() }
{ this._renderFramerateSelect() }
{ this._renderMaxStageParticipantsSelect() }
</div>
@ -473,7 +357,7 @@ class MoreTab extends AbstractDialogTab<Props, any> {
* @returns {ReactElement}
*/
_renderSettingsLeft() {
const { disableHideSelfView, showNotificationsSettings, showPrejoinSettings } = this.props;
const { showNotificationsSettings, showPrejoinSettings } = this.props;
return (
<div
@ -482,7 +366,6 @@ class MoreTab extends AbstractDialogTab<Props, any> {
{ showPrejoinSettings && this._renderPrejoinScreenSettings() }
{ showNotificationsSettings && this._renderNotificationsSettings() }
{ this._renderKeyboardShortcutCheckbox() }
{ !disableHideSelfView && this._renderSelfViewCheckbox() }
</div>
);
}

View File

@ -1,4 +1,5 @@
/* eslint-disable lines-around-comment */
import { Theme } from '@mui/material';
import { withStyles } from '@mui/styles';
import React from 'react';
import { WithTranslation } from 'react-i18next';
@ -6,20 +7,22 @@ import { WithTranslation } from 'react-i18next';
import UIEvents from '../../../../../service/UI/UIEvents';
import { createProfilePanelButtonEvent } from '../../../analytics/AnalyticsEvents';
import { sendAnalytics } from '../../../analytics/functions';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { AbstractDialogTab } from '../../../base/dialog';
// @ts-ignore
import type { Props as AbstractDialogTabProps } from '../../../base/dialog';
import Avatar from '../../../base/avatar/components/Avatar';
import AbstractDialogTab, {
IProps as AbstractDialogTabProps } from '../../../base/dialog/components/web/AbstractDialogTab';
import { translate } from '../../../base/i18n/functions';
import Button from '../../../base/ui/components/web/Button';
import Checkbox from '../../../base/ui/components/web/Checkbox';
import Input from '../../../base/ui/components/web/Input';
import Select from '../../../base/ui/components/web/Select';
import { openLogoutDialog } from '../../actions';
/* eslint-enable lines-around-comment */
/**
* The type of the React {@code Component} props of {@link ProfileTab}.
*/
export type Props = AbstractDialogTabProps & WithTranslation & {
export interface IProps extends AbstractDialogTabProps, WithTranslation {
/**
* Whether or not server-side authentication is available.
@ -31,6 +34,22 @@ export type Props = AbstractDialogTabProps & WithTranslation & {
*/
authLogin: string;
/**
* CSS classes object.
*/
classes: any;
/**
* The currently selected language to display in the language select
* dropdown.
*/
currentLanguage: string;
/**
* Whether to show hide self view setting.
*/
disableHideSelfView: boolean;
/**
* The display name to display for the local participant.
*/
@ -46,15 +65,52 @@ export type Props = AbstractDialogTabProps & WithTranslation & {
*/
hideEmailInSettings?: boolean;
/**
* Whether or not to hide self-view screen.
*/
hideSelfView: boolean;
/**
* The id of the local participant.
*/
id: string;
/**
* All available languages to display in the language select dropdown.
*/
languages: Array<string>;
/**
* If the display name is read only.
*/
readOnlyName: boolean;
/**
* Invoked to obtain translated strings.
* Whether or not to display the language select dropdown.
*/
t: Function;
showLanguageSettings: boolean;
}
const styles = (theme: Theme) => {
return {
container: {
display: 'flex',
flexDirection: 'column' as const,
width: '100%',
padding: '0 2px'
},
avatarContainer: {
display: 'flex',
width: '100%',
justifyContent: 'center',
marginBottom: theme.spacing(4)
},
bottomMargin: {
marginBottom: theme.spacing(4)
}
};
};
/**
@ -62,7 +118,7 @@ export type Props = AbstractDialogTabProps & WithTranslation & {
*
* @augments Component
*/
class ProfileTab extends AbstractDialogTab<Props> {
class ProfileTab extends AbstractDialogTab<IProps, any> {
static defaultProps = {
displayName: '',
email: ''
@ -71,16 +127,18 @@ class ProfileTab extends AbstractDialogTab<Props> {
/**
* Initializes a new {@code ConnectedSettingsDialog} instance.
*
* @param {Props} props - The React {@code Component} props to initialize
* @param {IProps} props - The React {@code Component} props to initialize
* the new {@code ConnectedSettingsDialog} instance with.
*/
constructor(props: Props) {
constructor(props: IProps) {
super(props);
// Bind event handlers so they are only bound once for every instance.
this._onAuthToggle = this._onAuthToggle.bind(this);
this._onDisplayNameChange = this._onDisplayNameChange.bind(this);
this._onEmailChange = this._onEmailChange.bind(this);
this._onHideSelfViewChanged = this._onHideSelfViewChanged.bind(this);
this._onLanguageItemSelect = this._onLanguageItemSelect.bind(this);
}
/**
@ -105,6 +163,62 @@ class ProfileTab extends AbstractDialogTab<Props> {
super._onChange({ email: value });
}
/**
* Callback invoked to select if hide self view should be enabled.
*
* @param {Object} e - The key event to handle.
*
* @returns {void}
*/
_onHideSelfViewChanged({ target: { checked } }: React.ChangeEvent<HTMLInputElement>) {
super._onChange({ hideSelfView: checked });
}
/**
* Callback invoked to select a language from select dropdown.
*
* @param {Object} e - The key event to handle.
*
* @returns {void}
*/
_onLanguageItemSelect(e: React.ChangeEvent<HTMLSelectElement>) {
const language = e.target.value;
super._onChange({ currentLanguage: language });
}
/**
* Returns the menu item for changing displayed language.
*
* @private
* @returns {ReactElement}
*/
_renderLanguageSelect() {
const {
classes,
currentLanguage,
languages,
t
} = this.props;
const languageItems
= languages.map((language: string) => {
return {
value: language,
label: t(`languages:${language}`)
};
});
return (
<Select
className = { classes.bottomMargin }
label = { t('settings.language') }
onChange = { this._onLanguageItemSelect }
options = { languageItems }
value = { currentLanguage } />
);
}
/**
* Implements React's {@link Component#render()}.
*
@ -114,38 +228,55 @@ class ProfileTab extends AbstractDialogTab<Props> {
render() {
const {
authEnabled,
classes,
disableHideSelfView,
displayName,
email,
hideEmailInSettings,
hideSelfView,
id,
readOnlyName,
t // @ts-ignore
showLanguageSettings,
t
} = this.props;
return (
<div>
<div className = 'profile-edit'>
<div className = 'profile-edit-field'>
<Input
disabled = { readOnlyName }
id = 'setDisplayName'
label = { t('profile.setDisplayNameLabel') }
name = 'name'
onChange = { this._onDisplayNameChange }
placeholder = { t('settings.name') }
type = 'text'
value = { displayName } />
</div>
{!hideEmailInSettings && <div className = 'profile-edit-field'>
<Input
id = 'setEmail'
label = { t('profile.setEmailLabel') }
name = 'email'
onChange = { this._onEmailChange }
placeholder = { t('profile.setEmailInput') }
type = 'text'
value = { email } />
</div>}
<div className = { classes.container } >
<div className = { classes.avatarContainer }>
<Avatar
participantId = { id }
size = { 60 } />
</div>
<Input
className = { classes.bottomMargin }
disabled = { readOnlyName }
id = 'setDisplayName'
label = { t('profile.setDisplayNameLabel') }
name = 'name'
onChange = { this._onDisplayNameChange }
placeholder = { t('settings.name') }
type = 'text'
value = { displayName } />
{!hideEmailInSettings && <div className = 'profile-edit-field'>
<Input
className = { classes.bottomMargin }
id = 'setEmail'
label = { t('profile.setEmailLabel') }
name = 'email'
onChange = { this._onEmailChange }
placeholder = { t('profile.setEmailInput') }
type = 'text'
value = { email } />
</div>}
{!disableHideSelfView && (
<Checkbox
checked = { hideSelfView }
className = { classes.bottomMargin }
label = { t('videothumbnail.hideSelfView') }
name = 'hide-self-view'
onChange = { this._onHideSelfViewChanged } />
)}
{showLanguageSettings && this._renderLanguageSelect()}
{ authEnabled && this._renderAuth() }
</div>
);
@ -159,7 +290,6 @@ class ProfileTab extends AbstractDialogTab<Props> {
* @returns {void}
*/
_onAuthToggle() {
// @ts-ignore
if (this.props.authLogin) {
sendAnalytics(createProfilePanelButtonEvent('logout.button'));
@ -183,8 +313,6 @@ class ProfileTab extends AbstractDialogTab<Props> {
const {
authLogin,
t
// @ts-ignore
} = this.props;
return (
@ -206,5 +334,4 @@ class ProfileTab extends AbstractDialogTab<Props> {
}
}
// @ts-ignore
export default translate(ProfileTab);
export default withStyles(styles)(translate(ProfileTab));

View File

@ -84,10 +84,6 @@ const styles = (theme: Theme) => {
display: 'flex',
width: '100%',
'&.profile-pane': {
flexDirection: 'column'
},
'& .auth-name': {
marginBottom: theme.spacing(1)
},
@ -130,19 +126,6 @@ const styles = (theme: Theme) => {
width: '100%'
},
'& .profile-edit': {
display: 'flex',
width: '100%',
padding: '0 2px',
boxSizing: 'border-box'
},
'& .profile-edit-field': {
flex: 0.5,
marginRight: '20px',
marginTop: theme.spacing(3)
},
'& .settings-sub-pane': {
flex: 1
},
@ -303,7 +286,7 @@ function _mapStateToProps(state: IReduxState, ownProps: any) {
component: ProfileTab,
labelKey: 'profile.title',
props: getProfileTabProps(state),
className: `settings-pane ${classes.settingsDialog} profile-pane`,
className: `settings-pane ${classes.settingsDialog}`,
submit: submitProfileTab,
icon: IconUser
});

View File

@ -116,22 +116,12 @@ export function getNotificationsMap(stateful: IStateful) {
export function getMoreTabProps(stateful: IStateful) {
const state = toState(stateful);
const framerate = state['features/screen-share'].captureFrameRate ?? SS_DEFAULT_FRAME_RATE;
const language = i18next.language || DEFAULT_LANGUAGE;
const configuredTabs: string[] = interfaceConfig.SETTINGS_SECTIONS || [];
const enabledNotifications = getNotificationsMap(stateful);
const stageFilmstripEnabled = isStageFilmstripEnabled(state);
// when self view is controlled by the config we hide the settings
const { disableSelfView, disableSelfViewSettings } = state['features/base/config'];
return {
currentFramerate: framerate,
currentLanguage: language,
desktopShareFramerates: SS_SUPPORTED_FRAMERATES,
disableHideSelfView: disableSelfViewSettings || disableSelfView,
hideSelfView: getHideSelfView(state),
languages: LANGUAGES,
showLanguageSettings: configuredTabs.includes('language'),
enabledNotifications,
showNotificationsSettings: Object.keys(enabledNotifications).length > 0,
showPrejoinPage: !state['features/base/settings'].userSelectedSkipPrejoin,
@ -207,14 +197,25 @@ export function getProfileTabProps(stateful: IStateful) {
} = state['features/base/conference'];
const { hideEmailInSettings } = state['features/base/config'];
const localParticipant = getLocalParticipant(state);
const language = i18next.language || DEFAULT_LANGUAGE;
const configuredTabs: string[] = interfaceConfig.SETTINGS_SECTIONS || [];
// when self view is controlled by the config we hide the settings
const { disableSelfView, disableSelfViewSettings } = state['features/base/config'];
return {
authEnabled: Boolean(conference && authEnabled),
authLogin,
disableHideSelfView: disableSelfViewSettings || disableSelfView,
currentLanguage: language,
displayName: localParticipant?.name,
email: localParticipant?.email,
hideEmailInSettings,
hideSelfView: getHideSelfView(state),
id: localParticipant?.id,
languages: LANGUAGES,
readOnlyName: isNameReadOnly(state),
hideEmailInSettings
showLanguageSettings: configuredTabs.includes('language')
};
}

View File

@ -22,7 +22,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
titleKey: 'notify.selfViewTitle',
customActionNameKey: [ 'settings.title' ],
customActionHandler: [ () =>
dispatch(openSettingsDialog(SETTINGS_TABS.MORE))
dispatch(openSettingsDialog(SETTINGS_TABS.PROFILE))
]
}, NOTIFICATION_TIMEOUT_TYPE.STICKY));
}

View File

@ -92,7 +92,7 @@ const LanguageSelectorDialog = ({
}, [ _language ]);
const onSourceLanguageClick = useCallback(() => {
dispatch(openSettingsDialog(SETTINGS_TABS.MORE, false));
dispatch(openSettingsDialog(SETTINGS_TABS.PROFILE, false));
}, []);
return (