This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
import React from 'react';
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
import { makeStyles } from 'tss-react/mui';
|
||||
|
||||
import Avatar from '../../../../base/avatar/components/Avatar';
|
||||
import { translate } from '../../../../base/i18n/functions';
|
||||
import Icon from '../../../../base/icons/components/Icon';
|
||||
import { IconCloseLarge } from '../../../../base/icons/svg';
|
||||
import Label from '../Label';
|
||||
|
||||
interface IProps extends WithTranslation {
|
||||
|
||||
/**
|
||||
* The phone number that is being called.
|
||||
*/
|
||||
number: string;
|
||||
|
||||
/**
|
||||
* Closes the dialog.
|
||||
*/
|
||||
onClose: (e?: React.MouseEvent) => void;
|
||||
|
||||
/**
|
||||
* The status of the call.
|
||||
*/
|
||||
status: string;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
callingDialog: {
|
||||
padding: theme.spacing(3),
|
||||
textAlign: 'center',
|
||||
|
||||
'& .prejoin-dialog-calling-header': {
|
||||
textAlign: 'right'
|
||||
},
|
||||
|
||||
'& .prejoin-dialog-calling-label': {
|
||||
fontSize: '1rem',
|
||||
margin: `${theme.spacing(2)} 0 ${theme.spacing(3)} 0`
|
||||
},
|
||||
|
||||
'& .prejoin-dialog-calling-number': {
|
||||
fontSize: '1.25rem',
|
||||
lineHeight: '1.75rem',
|
||||
margin: `${theme.spacing(3)} 0`
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Dialog displayed when the user gets called by the meeting.
|
||||
*
|
||||
* @param {IProps} props - The props of the component.
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
function CallingDialog(props: IProps) {
|
||||
const { number, onClose, status, t } = props;
|
||||
const { classes } = useStyles();
|
||||
|
||||
return (
|
||||
<div className = { classes.callingDialog }>
|
||||
<div className = 'prejoin-dialog-calling-header'>
|
||||
<Icon
|
||||
className = 'prejoin-dialog-icon'
|
||||
onClick = { onClose }
|
||||
role = 'button'
|
||||
size = { 24 }
|
||||
src = { IconCloseLarge } />
|
||||
</div>
|
||||
<Label className = 'prejoin-dialog-calling-label'>
|
||||
{t(status)}
|
||||
</Label>
|
||||
<Avatar size = { 72 } />
|
||||
<div className = 'prejoin-dialog-calling-number'>{number}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default translate(CallingDialog);
|
||||
172
react/features/prejoin/components/web/dialogs/DialInDialog.tsx
Normal file
172
react/features/prejoin/components/web/dialogs/DialInDialog.tsx
Normal file
@@ -0,0 +1,172 @@
|
||||
import React from 'react';
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
import { makeStyles } from 'tss-react/mui';
|
||||
|
||||
import { translate } from '../../../../base/i18n/functions';
|
||||
import Icon from '../../../../base/icons/components/Icon';
|
||||
import { IconArrowLeft } from '../../../../base/icons/svg';
|
||||
import Button from '../../../../base/ui/components/web/Button';
|
||||
import { getCountryCodeFromPhone } from '../../../utils';
|
||||
import Label from '../Label';
|
||||
|
||||
interface IProps extends WithTranslation {
|
||||
|
||||
/**
|
||||
* The number to call in order to join the conference.
|
||||
*/
|
||||
number: string | null;
|
||||
|
||||
/**
|
||||
* Handler used when clicking the back button.
|
||||
*/
|
||||
onBack: (e?: React.MouseEvent) => void;
|
||||
|
||||
/**
|
||||
* Click handler for primary button.
|
||||
*/
|
||||
onPrimaryButtonClick: Function;
|
||||
|
||||
/**
|
||||
* Click handler for the small additional text.
|
||||
*/
|
||||
onSmallTextClick: (e?: React.MouseEvent) => void;
|
||||
|
||||
/**
|
||||
* Click handler for the text button.
|
||||
*/
|
||||
onTextButtonClick: (e?: React.MouseEvent) => void;
|
||||
|
||||
/**
|
||||
* The passCode of the conference.
|
||||
*/
|
||||
passCode?: string | number;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
dialInDialog: {
|
||||
textAlign: 'center',
|
||||
|
||||
'& .prejoin-dialog-dialin-header': {
|
||||
alignItems: 'center',
|
||||
margin: `${theme.spacing(3)} 0 ${theme.spacing(5)} ${theme.spacing(3)}`,
|
||||
display: 'flex'
|
||||
},
|
||||
'& .prejoin-dialog-dialin-icon': {
|
||||
marginRight: theme.spacing(3)
|
||||
},
|
||||
'& .prejoin-dialog-dialin-num': {
|
||||
background: '#3e474f',
|
||||
borderRadius: '4px',
|
||||
display: 'inline-block',
|
||||
fontSize: '1rem',
|
||||
lineHeight: '1.5rem',
|
||||
margin: theme.spacing(1),
|
||||
padding: theme.spacing(2),
|
||||
userSelect: 'text',
|
||||
|
||||
'& .prejoin-dialog-dialin-num-container': {
|
||||
minHeight: '48px',
|
||||
margin: `${theme.spacing(2)} 0`
|
||||
},
|
||||
|
||||
'& span': {
|
||||
userSelect: 'text'
|
||||
}
|
||||
},
|
||||
|
||||
'& .prejoin-dialog-dialin-link': {
|
||||
color: '#6FB1EA',
|
||||
cursor: 'pointer',
|
||||
display: 'inline-block',
|
||||
fontSize: '0.875rem',
|
||||
lineHeight: '1.5rem',
|
||||
marginBottom: theme.spacing(4)
|
||||
},
|
||||
'& .prejoin-dialog-dialin-spaced-label': {
|
||||
marginBottom: theme.spacing(3),
|
||||
marginTop: '28px'
|
||||
},
|
||||
'& .prejoin-dialog-dialin-btns > div': {
|
||||
marginBottom: theme.spacing(3)
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* This component displays the dialog with all the information
|
||||
* to join a meeting by calling it.
|
||||
*
|
||||
* @param {IProps} props - The props of the component.
|
||||
* @returns {React$Element}
|
||||
*/
|
||||
function DialinDialog(props: IProps) {
|
||||
const {
|
||||
number,
|
||||
onBack,
|
||||
onPrimaryButtonClick,
|
||||
onSmallTextClick,
|
||||
onTextButtonClick,
|
||||
passCode,
|
||||
t
|
||||
} = props;
|
||||
const { classes } = useStyles();
|
||||
const flagClassName = `prejoin-dialog-flag iti-flag ${getCountryCodeFromPhone(
|
||||
number ?? ''
|
||||
)}`;
|
||||
|
||||
return (
|
||||
<div className = { classes.dialInDialog }>
|
||||
<div className = 'prejoin-dialog-dialin-header'>
|
||||
<Icon
|
||||
className = 'prejoin-dialog-icon prejoin-dialog-dialin-icon'
|
||||
onClick = { onBack }
|
||||
role = 'button'
|
||||
size = { 24 }
|
||||
src = { IconArrowLeft } />
|
||||
<div className = 'prejoin-dialog-title'>
|
||||
{t('prejoin.dialInMeeting')}
|
||||
</div>
|
||||
</div>
|
||||
<Label number = { 1 }>{ t('prejoin.dialInPin') }</Label>
|
||||
|
||||
<div className = 'prejoin-dialog-dialin-num-container'>
|
||||
<div className = 'prejoin-dialog-dialin-num'>
|
||||
<div className = { flagClassName } />
|
||||
<span>{number}</span>
|
||||
</div>
|
||||
<div className = 'prejoin-dialog-dialin-num'>{passCode}</div>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
className = 'prejoin-dialog-dialin-link'
|
||||
onClick = { onSmallTextClick }>
|
||||
{t('prejoin.viewAllNumbers')}
|
||||
</span>
|
||||
</div>
|
||||
<div className = 'prejoin-dialog-delimiter' />
|
||||
<Label
|
||||
className = 'prejoin-dialog-dialin-spaced-label'
|
||||
number = { 2 }>
|
||||
{t('prejoin.connectedWithAudioQ')}
|
||||
</Label>
|
||||
<div className = 'prejoin-dialog-dialin-btns'>
|
||||
<Button
|
||||
className = 'prejoin-dialog-btn'
|
||||
fullWidth = { true }
|
||||
labelKey = 'prejoin.joinMeeting'
|
||||
onClick = { onPrimaryButtonClick }
|
||||
type = 'primary' />
|
||||
<Button
|
||||
className = 'prejoin-dialog-btn'
|
||||
fullWidth = { true }
|
||||
labelKey = 'dialog.Cancel'
|
||||
onClick = { onTextButtonClick }
|
||||
type = 'tertiary' />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default translate(DialinDialog);
|
||||
100
react/features/prejoin/components/web/dialogs/DialOutDialog.tsx
Normal file
100
react/features/prejoin/components/web/dialogs/DialOutDialog.tsx
Normal file
@@ -0,0 +1,100 @@
|
||||
import React from 'react';
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
import { makeStyles } from 'tss-react/mui';
|
||||
|
||||
import { translate } from '../../../../base/i18n/functions';
|
||||
import Icon from '../../../../base/icons/components/Icon';
|
||||
import { IconCloseLarge } from '../../../../base/icons/svg';
|
||||
import Button from '../../../../base/ui/components/web/Button';
|
||||
import Label from '../Label';
|
||||
import CountryPicker from '../country-picker/CountryPicker';
|
||||
|
||||
interface IProps extends WithTranslation {
|
||||
|
||||
/**
|
||||
* Closes a dialog.
|
||||
*/
|
||||
onClose: (e?: React.MouseEvent) => void;
|
||||
|
||||
/**
|
||||
* Submit handler.
|
||||
*/
|
||||
onSubmit: Function;
|
||||
|
||||
/**
|
||||
* Handler for text button.
|
||||
*/
|
||||
onTextButtonClick: Function;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
dialOutDialog: {
|
||||
padding: theme.spacing(3)
|
||||
},
|
||||
header: {
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
marginBottom: theme.spacing(4)
|
||||
},
|
||||
picker: {
|
||||
margin: `${theme.spacing(2)} 0 ${theme.spacing(3)} 0`
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* This component displays the dialog from which the user can enter the
|
||||
* phone number in order to be called by the meeting.
|
||||
*
|
||||
* @param {IProps} props - The props of the component.
|
||||
* @returns {React$Element}
|
||||
*/
|
||||
function DialOutDialog(props: IProps) {
|
||||
const { onClose, onTextButtonClick, onSubmit, t } = props;
|
||||
const { classes } = useStyles();
|
||||
|
||||
return (
|
||||
<div className = { classes.dialOutDialog }>
|
||||
<div className = { classes.header }>
|
||||
<div className = 'prejoin-dialog-title'>
|
||||
{t('prejoin.startWithPhone')}
|
||||
</div>
|
||||
<Icon
|
||||
className = 'prejoin-dialog-icon'
|
||||
onClick = { onClose }
|
||||
role = 'button'
|
||||
size = { 24 }
|
||||
src = { IconCloseLarge } />
|
||||
</div>
|
||||
<Label>{t('prejoin.callMeAtNumber')}</Label>
|
||||
<div className = { classes.picker }>
|
||||
<CountryPicker onSubmit = { onSubmit } />
|
||||
</div>
|
||||
<Button
|
||||
className = 'prejoin-dialog-btn'
|
||||
fullWidth = { true }
|
||||
labelKey = 'prejoin.callMe'
|
||||
onClick = { onSubmit }
|
||||
type = 'primary' />
|
||||
<div className = 'prejoin-dialog-delimiter-container'>
|
||||
<div className = 'prejoin-dialog-delimiter' />
|
||||
<div className = 'prejoin-dialog-delimiter-txt-container'>
|
||||
<span className = 'prejoin-dialog-delimiter-txt'>
|
||||
{t('prejoin.or')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className = 'prejoin-dialog-dialin-container'>
|
||||
<Button
|
||||
className = 'prejoin-dialog-btn'
|
||||
fullWidth = { true }
|
||||
labelKey = 'prejoin.iWantToDialIn'
|
||||
onClick = { onTextButtonClick }
|
||||
type = 'tertiary' />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default translate(DialOutDialog);
|
||||
@@ -0,0 +1,239 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../../app/types';
|
||||
import { updateDialInNumbers } from '../../../../invite/actions.web';
|
||||
import { getConferenceId, getDefaultDialInNumber } from '../../../../invite/functions';
|
||||
import {
|
||||
dialOut as dialOutAction,
|
||||
joinConferenceWithoutAudio as joinConferenceWithoutAudioAction,
|
||||
openDialInPage as openDialInPageAction
|
||||
} from '../../../actions.web';
|
||||
import { getDialOutStatus, getFullDialOutNumber } from '../../../functions';
|
||||
|
||||
import CallingDialog from './CallingDialog';
|
||||
import DialInDialog from './DialInDialog';
|
||||
import DialOutDialog from './DialOutDialog';
|
||||
|
||||
interface IProps {
|
||||
|
||||
/**
|
||||
* The number to call in order to join the conference.
|
||||
*/
|
||||
dialInNumber: string | null;
|
||||
|
||||
/**
|
||||
* The action by which the meeting calls the user.
|
||||
*/
|
||||
dialOut: Function;
|
||||
|
||||
/**
|
||||
* The number the conference should call.
|
||||
*/
|
||||
dialOutNumber: string;
|
||||
|
||||
/**
|
||||
* The status of the call when the meeting calls the user.
|
||||
*/
|
||||
dialOutStatus: string;
|
||||
|
||||
/**
|
||||
* Fetches conference dial in numbers & conference id.
|
||||
*/
|
||||
fetchConferenceDetails: Function;
|
||||
|
||||
/**
|
||||
* Joins the conference without audio.
|
||||
*/
|
||||
joinConferenceWithoutAudio: Function;
|
||||
|
||||
/**
|
||||
* Closes the dialog.
|
||||
*/
|
||||
onClose: (e?: React.MouseEvent) => void;
|
||||
|
||||
/**
|
||||
* Opens a web page with all the dial in numbers.
|
||||
*/
|
||||
openDialInPage: (e?: React.MouseEvent) => void;
|
||||
|
||||
/**
|
||||
* The passCode of the conference used when joining a meeting by phone.
|
||||
*/
|
||||
passCode?: string | number;
|
||||
}
|
||||
|
||||
type State = {
|
||||
|
||||
/**
|
||||
* The dialout call is ongoing, 'CallingDialog' is shown;.
|
||||
*/
|
||||
isCalling: boolean;
|
||||
|
||||
/**
|
||||
* If should show 'DialInDialog'.
|
||||
*/
|
||||
showDialIn: boolean;
|
||||
|
||||
/**
|
||||
* If should show 'DialOutDialog'.
|
||||
*/
|
||||
showDialOut: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is the dialog shown when a user wants to join with phone audio.
|
||||
*/
|
||||
class JoinByPhoneDialog extends PureComponent<IProps, State> {
|
||||
/**
|
||||
* Initializes a new {@code JoinByPhoneDialog} instance.
|
||||
*
|
||||
* @param {IProps} props - The props of the component.
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
isCalling: false,
|
||||
showDialOut: true,
|
||||
showDialIn: false
|
||||
};
|
||||
|
||||
this._dialOut = this._dialOut.bind(this);
|
||||
this._showDialInDialog = this._showDialInDialog.bind(this);
|
||||
this._showDialOutDialog = this._showDialOutDialog.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Meeting calls the user & shows the 'CallingDialog'.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_dialOut() {
|
||||
const { dialOut, joinConferenceWithoutAudio } = this.props;
|
||||
|
||||
this.setState({
|
||||
isCalling: true,
|
||||
showDialOut: false,
|
||||
showDialIn: false
|
||||
});
|
||||
dialOut(joinConferenceWithoutAudio, this._showDialOutDialog);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the 'DialInDialog'.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_showDialInDialog() {
|
||||
this.setState({
|
||||
isCalling: false,
|
||||
showDialOut: false,
|
||||
showDialIn: true
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the 'DialOutDialog'.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_showDialOutDialog() {
|
||||
this.setState({
|
||||
isCalling: false,
|
||||
showDialOut: true,
|
||||
showDialIn: false
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentDidMount()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
override componentDidMount() {
|
||||
this.props.fetchConferenceDetails();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
override render() {
|
||||
const {
|
||||
dialOutStatus,
|
||||
dialInNumber,
|
||||
dialOutNumber,
|
||||
joinConferenceWithoutAudio,
|
||||
passCode,
|
||||
onClose,
|
||||
openDialInPage
|
||||
} = this.props;
|
||||
const {
|
||||
_dialOut,
|
||||
_showDialInDialog,
|
||||
_showDialOutDialog
|
||||
} = this;
|
||||
const { isCalling, showDialOut, showDialIn } = this.state;
|
||||
const className = isCalling
|
||||
? 'prejoin-dialog prejoin-dialog--small'
|
||||
: 'prejoin-dialog';
|
||||
|
||||
return (
|
||||
<div className = 'prejoin-dialog-container'>
|
||||
<div className = { className }>
|
||||
{showDialOut && (
|
||||
<DialOutDialog
|
||||
onClose = { onClose }
|
||||
onSubmit = { _dialOut }
|
||||
onTextButtonClick = { _showDialInDialog } />
|
||||
)}
|
||||
{showDialIn && (
|
||||
<DialInDialog
|
||||
number = { dialInNumber }
|
||||
onBack = { _showDialOutDialog }
|
||||
onPrimaryButtonClick = { joinConferenceWithoutAudio }
|
||||
onSmallTextClick = { openDialInPage }
|
||||
onTextButtonClick = { onClose }
|
||||
passCode = { passCode } />
|
||||
)}
|
||||
{isCalling && (
|
||||
<CallingDialog
|
||||
number = { dialOutNumber }
|
||||
onClose = { onClose }
|
||||
status = { dialOutStatus } />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the redux state to the React {@code Component} props.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @param {Object} _ownProps - Component's own props.
|
||||
* @returns {Object}
|
||||
*/
|
||||
function mapStateToProps(state: IReduxState, _ownProps: any) {
|
||||
return {
|
||||
dialInNumber: getDefaultDialInNumber(state),
|
||||
dialOutNumber: getFullDialOutNumber(state),
|
||||
dialOutStatus: getDialOutStatus(state),
|
||||
passCode: getConferenceId(state)
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
dialOut: dialOutAction,
|
||||
fetchConferenceDetails: updateDialInNumbers,
|
||||
joinConferenceWithoutAudio: joinConferenceWithoutAudioAction,
|
||||
openDialInPage: openDialInPageAction
|
||||
};
|
||||
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(JoinByPhoneDialog);
|
||||
Reference in New Issue
Block a user