feat(prejoin) Disable join buttons during joining
- use new `Button` component for drop down buttons
This commit is contained in:
parent
82fd465819
commit
0ad52a06ce
|
@ -50,7 +50,7 @@
|
||||||
* Override default InlineDialog behaviour, since it does not play nicely with relative widths
|
* Override default InlineDialog behaviour, since it does not play nicely with relative widths
|
||||||
*/
|
*/
|
||||||
& > div:nth-child(2) {
|
& > div:nth-child(2) {
|
||||||
background: #fff;
|
background: #E0E0E0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
position: absolute !important;
|
position: absolute !important;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
@ -34,6 +34,11 @@ export interface IButtonProps {
|
||||||
*/
|
*/
|
||||||
onClick?: (e?: React.MouseEvent<HTMLButtonElement> | GestureResponderEvent) => void;
|
onClick?: (e?: React.MouseEvent<HTMLButtonElement> | GestureResponderEvent) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key press callback.
|
||||||
|
*/
|
||||||
|
onKeyPress?: (e?: React.KeyboardEvent<HTMLButtonElement>) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of button to be displayed.
|
* The type of button to be displayed.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -187,6 +187,7 @@ const Button = React.forwardRef<any, any>(({
|
||||||
label,
|
label,
|
||||||
labelKey,
|
labelKey,
|
||||||
onClick = () => null,
|
onClick = () => null,
|
||||||
|
onKeyPress = () => null,
|
||||||
size = 'medium',
|
size = 'medium',
|
||||||
testId,
|
testId,
|
||||||
type = BUTTON_TYPES.PRIMARY
|
type = BUTTON_TYPES.PRIMARY
|
||||||
|
@ -206,6 +207,7 @@ const Button = React.forwardRef<any, any>(({
|
||||||
disabled = { disabled }
|
disabled = { disabled }
|
||||||
{ ...(id ? { id } : {}) }
|
{ ...(id ? { id } : {}) }
|
||||||
onClick = { onClick }
|
onClick = { onClick }
|
||||||
|
onKeyPress = { onKeyPress }
|
||||||
ref = { ref }
|
ref = { ref }
|
||||||
title = { accessibilityLabel }
|
title = { accessibilityLabel }
|
||||||
type = { isSubmit ? 'submit' : 'button' }>
|
type = { isSubmit ? 'submit' : 'button' }>
|
||||||
|
|
|
@ -1,95 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import { makeStyles } from 'tss-react/mui';
|
|
||||||
|
|
||||||
import Icon from '../../../base/icons/components/Icon';
|
|
||||||
|
|
||||||
interface IProps {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attribute used in automated testing.
|
|
||||||
*/
|
|
||||||
dataTestId: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The button's icon.
|
|
||||||
*/
|
|
||||||
icon: Function;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The button's label.
|
|
||||||
*/
|
|
||||||
label: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function to be called when button is clicked.
|
|
||||||
*/
|
|
||||||
onButtonClick: (e?: React.MouseEvent) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function to be called on key pressed.
|
|
||||||
*/
|
|
||||||
onKeyPressed: (e?: React.KeyboardEvent) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const useStyles = makeStyles()(theme => {
|
|
||||||
return {
|
|
||||||
prejoinPreviewDropdownBtn: {
|
|
||||||
alignItems: 'center',
|
|
||||||
color: '#1C2025',
|
|
||||||
cursor: 'pointer',
|
|
||||||
display: 'flex',
|
|
||||||
height: 40,
|
|
||||||
fontSize: 15,
|
|
||||||
lineHeight: '24px',
|
|
||||||
padding: '0 16px', // @ts-ignore
|
|
||||||
backgroundColor: theme.palette.field02,
|
|
||||||
|
|
||||||
'&:hover': { // @ts-ignore
|
|
||||||
backgroundColor: theme.palette.field02Hover
|
|
||||||
}
|
|
||||||
},
|
|
||||||
prejoinPreviewDropdownIcon: {
|
|
||||||
display: 'inline-block',
|
|
||||||
marginRight: 16,
|
|
||||||
|
|
||||||
'& > svg': {
|
|
||||||
fill: '#1C2025'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Buttons used for pre meeting actions.
|
|
||||||
*
|
|
||||||
* @returns {ReactElement}
|
|
||||||
*/
|
|
||||||
const DropdownButton = ({
|
|
||||||
dataTestId,
|
|
||||||
icon,
|
|
||||||
onButtonClick,
|
|
||||||
onKeyPressed,
|
|
||||||
label
|
|
||||||
}: IProps) => {
|
|
||||||
const { classes } = useStyles();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className = { classes.prejoinPreviewDropdownBtn }
|
|
||||||
data-testid = { dataTestId }
|
|
||||||
onClick = { onButtonClick }
|
|
||||||
onKeyPress = { onKeyPressed }
|
|
||||||
role = 'button'
|
|
||||||
tabIndex = { 0 }>
|
|
||||||
<Icon
|
|
||||||
className = { classes.prejoinPreviewDropdownIcon }
|
|
||||||
color = '#1C2025'
|
|
||||||
size = { 24 }
|
|
||||||
src = { icon } />
|
|
||||||
{label}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DropdownButton;
|
|
|
@ -13,6 +13,8 @@ import { ActionButton, InputField, PreMeetingScreen } from '../../../base/premee
|
||||||
import { connect } from '../../../base/redux';
|
import { connect } from '../../../base/redux';
|
||||||
import { getDisplayName, updateSettings } from '../../../base/settings';
|
import { getDisplayName, updateSettings } from '../../../base/settings';
|
||||||
import { getLocalJitsiVideoTrack } from '../../../base/tracks';
|
import { getLocalJitsiVideoTrack } from '../../../base/tracks';
|
||||||
|
import Button from '../../../base/ui/components/web/Button';
|
||||||
|
import { BUTTON_TYPES } from '../../../base/ui/constants.any';
|
||||||
import {
|
import {
|
||||||
joinConference as joinConferenceAction,
|
joinConference as joinConferenceAction,
|
||||||
joinConferenceWithoutAudio as joinConferenceWithoutAudioAction,
|
joinConferenceWithoutAudio as joinConferenceWithoutAudioAction,
|
||||||
|
@ -26,7 +28,6 @@ import {
|
||||||
isPrejoinDisplayNameVisible
|
isPrejoinDisplayNameVisible
|
||||||
} from '../../functions';
|
} from '../../functions';
|
||||||
|
|
||||||
import DropdownButton from './DropdownButton';
|
|
||||||
import JoinByPhoneDialog from './dialogs/JoinByPhoneDialog';
|
import JoinByPhoneDialog from './dialogs/JoinByPhoneDialog';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -56,6 +57,11 @@ type Props = {
|
||||||
*/
|
*/
|
||||||
joinConferenceWithoutAudio: Function,
|
joinConferenceWithoutAudio: Function,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether conference join is in progress.
|
||||||
|
*/
|
||||||
|
joiningInProgress: boolean,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the user that is about to join.
|
* The name of the user that is about to join.
|
||||||
*/
|
*/
|
||||||
|
@ -114,11 +120,6 @@ type Props = {
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
|
|
||||||
/**
|
|
||||||
* Flag controlling the visibility of the error label.
|
|
||||||
*/
|
|
||||||
showError: boolean,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag controlling the visibility of the 'join by phone' buttons.
|
* Flag controlling the visibility of the 'join by phone' buttons.
|
||||||
*/
|
*/
|
||||||
|
@ -138,7 +139,6 @@ class Prejoin extends Component<Props, State> {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
showError: false,
|
|
||||||
showJoinByPhoneButtons: false
|
showJoinByPhoneButtons: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -165,14 +165,8 @@ class Prejoin extends Component<Props, State> {
|
||||||
*/
|
*/
|
||||||
_onJoinButtonClick() {
|
_onJoinButtonClick() {
|
||||||
if (this.props.showErrorOnJoin) {
|
if (this.props.showErrorOnJoin) {
|
||||||
this.setState({
|
|
||||||
showError: true
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({ showError: false });
|
|
||||||
this.props.joinConference();
|
this.props.joinConference();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,20 +298,20 @@ class Prejoin extends Component<Props, State> {
|
||||||
|
|
||||||
const noAudio = {
|
const noAudio = {
|
||||||
key: 'no-audio',
|
key: 'no-audio',
|
||||||
dataTestId: 'prejoin.joinWithoutAudio',
|
testId: 'prejoin.joinWithoutAudio',
|
||||||
icon: IconVolumeOff,
|
icon: IconVolumeOff,
|
||||||
label: t('prejoin.joinWithoutAudio'),
|
label: t('prejoin.joinWithoutAudio'),
|
||||||
onButtonClick: joinConferenceWithoutAudio,
|
onClick: joinConferenceWithoutAudio,
|
||||||
onKeyPressed: this._onJoinConferenceWithoutAudioKeyPress
|
onKeyPress: this._onJoinConferenceWithoutAudioKeyPress
|
||||||
};
|
};
|
||||||
|
|
||||||
const byPhone = {
|
const byPhone = {
|
||||||
key: 'by-phone',
|
key: 'by-phone',
|
||||||
dataTestId: 'prejoin.joinByPhone',
|
testId: 'prejoin.joinByPhone',
|
||||||
icon: IconPhoneRinging,
|
icon: IconPhoneRinging,
|
||||||
label: t('prejoin.joinAudioByPhone'),
|
label: t('prejoin.joinAudioByPhone'),
|
||||||
onButtonClick: this._showDialog,
|
onClick: this._showDialog,
|
||||||
onKeyPressed: this._showDialogKeyPress
|
onKeyPress: this._showDialogKeyPress
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -338,12 +332,14 @@ class Prejoin extends Component<Props, State> {
|
||||||
hasJoinByPhoneButton,
|
hasJoinByPhoneButton,
|
||||||
joinConference,
|
joinConference,
|
||||||
joinConferenceWithoutAudio,
|
joinConferenceWithoutAudio,
|
||||||
|
joiningInProgress,
|
||||||
name,
|
name,
|
||||||
participantId,
|
participantId,
|
||||||
prejoinConfig,
|
prejoinConfig,
|
||||||
readOnlyName,
|
readOnlyName,
|
||||||
showCameraPreview,
|
showCameraPreview,
|
||||||
showDialog,
|
showDialog,
|
||||||
|
showErrorOnJoin,
|
||||||
t,
|
t,
|
||||||
videoTrack
|
videoTrack
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
@ -359,7 +355,7 @@ class Prejoin extends Component<Props, State> {
|
||||||
extraButtonsToRender = extraButtonsToRender.filter((btn: Object) => btn.key !== 'by-phone');
|
extraButtonsToRender = extraButtonsToRender.filter((btn: Object) => btn.key !== 'by-phone');
|
||||||
}
|
}
|
||||||
const hasExtraJoinButtons = Boolean(extraButtonsToRender.length);
|
const hasExtraJoinButtons = Boolean(extraButtonsToRender.length);
|
||||||
const { showJoinByPhoneButtons, showError } = this.state;
|
const { showJoinByPhoneButtons } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PreMeetingScreen
|
<PreMeetingScreen
|
||||||
|
@ -373,8 +369,8 @@ class Prejoin extends Component<Props, State> {
|
||||||
{this.showDisplayNameField ? (<InputField
|
{this.showDisplayNameField ? (<InputField
|
||||||
autoComplete = { 'name' }
|
autoComplete = { 'name' }
|
||||||
autoFocus = { true }
|
autoFocus = { true }
|
||||||
className = { showError ? 'error' : '' }
|
className = { showErrorOnJoin ? 'error' : '' }
|
||||||
hasError = { showError }
|
hasError = { showErrorOnJoin }
|
||||||
onChange = { _setName }
|
onChange = { _setName }
|
||||||
onSubmit = { joinConference }
|
onSubmit = { joinConference }
|
||||||
placeHolder = { t('dialog.enterDisplayName') }
|
placeHolder = { t('dialog.enterDisplayName') }
|
||||||
|
@ -391,7 +387,7 @@ class Prejoin extends Component<Props, State> {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{showError && <div
|
{showErrorOnJoin && <div
|
||||||
className = 'prejoin-error'
|
className = 'prejoin-error'
|
||||||
data-testid = 'prejoin.errorMessage'>{t('prejoin.errorMissingName')}</div>}
|
data-testid = 'prejoin.errorMessage'>{t('prejoin.errorMissingName')}</div>}
|
||||||
|
|
||||||
|
@ -399,8 +395,11 @@ class Prejoin extends Component<Props, State> {
|
||||||
<InlineDialog
|
<InlineDialog
|
||||||
content = { hasExtraJoinButtons && <div className = 'prejoin-preview-dropdown-btns'>
|
content = { hasExtraJoinButtons && <div className = 'prejoin-preview-dropdown-btns'>
|
||||||
{extraButtonsToRender.map(({ key, ...rest }: Object) => (
|
{extraButtonsToRender.map(({ key, ...rest }: Object) => (
|
||||||
<DropdownButton
|
<Button
|
||||||
|
disabled = { joiningInProgress }
|
||||||
|
fullWidth = { true }
|
||||||
key = { key }
|
key = { key }
|
||||||
|
type = { BUTTON_TYPES.SECONDARY }
|
||||||
{ ...rest } />
|
{ ...rest } />
|
||||||
))}
|
))}
|
||||||
</div> }
|
</div> }
|
||||||
|
@ -411,6 +410,7 @@ class Prejoin extends Component<Props, State> {
|
||||||
ariaDropDownLabel = { t('prejoin.joinWithoutAudio') }
|
ariaDropDownLabel = { t('prejoin.joinWithoutAudio') }
|
||||||
ariaLabel = { t('prejoin.joinMeeting') }
|
ariaLabel = { t('prejoin.joinMeeting') }
|
||||||
ariaPressed = { showJoinByPhoneButtons }
|
ariaPressed = { showJoinByPhoneButtons }
|
||||||
|
disabled = { joiningInProgress }
|
||||||
hasOptions = { hasExtraJoinButtons }
|
hasOptions = { hasExtraJoinButtons }
|
||||||
onClick = { _onJoinButtonClick }
|
onClick = { _onJoinButtonClick }
|
||||||
onKeyPress = { _onJoinKeyPress }
|
onKeyPress = { _onJoinKeyPress }
|
||||||
|
@ -444,11 +444,13 @@ function mapStateToProps(state): Object {
|
||||||
const name = getDisplayName(state);
|
const name = getDisplayName(state);
|
||||||
const showErrorOnJoin = isDisplayNameRequired(state) && !name;
|
const showErrorOnJoin = isDisplayNameRequired(state) && !name;
|
||||||
const { id: participantId } = getLocalParticipant(state);
|
const { id: participantId } = getLocalParticipant(state);
|
||||||
|
const { joiningInProgress } = state['features/prejoin'];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
canEditDisplayName: isPrejoinDisplayNameVisible(state),
|
canEditDisplayName: isPrejoinDisplayNameVisible(state),
|
||||||
deviceStatusVisible: isDeviceStatusVisible(state),
|
deviceStatusVisible: isDeviceStatusVisible(state),
|
||||||
hasJoinByPhoneButton: isJoinByPhoneButtonVisible(state),
|
hasJoinByPhoneButton: isJoinByPhoneButtonVisible(state),
|
||||||
|
joiningInProgress,
|
||||||
name,
|
name,
|
||||||
participantId,
|
participantId,
|
||||||
prejoinConfig: state['features/base/config'].prejoinConfig,
|
prejoinConfig: state['features/base/config'].prejoinConfig,
|
||||||
|
|
Loading…
Reference in New Issue