From dd6478b3cf2635db67f78c9eb3a9bde2fcd52da2 Mon Sep 17 00:00:00 2001 From: Robert Pintilii Date: Mon, 17 Oct 2022 14:27:48 +0300 Subject: [PATCH] ref(ui-components) Use new Dialog (#12363) Convert some files to TS Improve Dialog component --- .../components/web/LoginDialog.tsx | 25 +++-- ...rOwnerDialog.js => WaitForOwnerDialog.tsx} | 39 +++----- react/features/base/dialog/middleware.web.ts | 9 +- .../base/ui/components/web/Dialog.tsx | 41 +++++--- .../{DesktopPicker.js => DesktopPicker.tsx} | 97 ++++++++----------- .../RemoteControlAuthorizationDialog.js | 8 +- .../components/web/SalesforceLinkDialog.tsx | 6 +- .../settings/components/web/LogoutDialog.js | 48 --------- .../settings/components/web/LogoutDialog.tsx | 38 ++++++++ 9 files changed, 148 insertions(+), 163 deletions(-) rename react/features/authentication/components/web/{WaitForOwnerDialog.js => WaitForOwnerDialog.tsx} (71%) rename react/features/desktop-picker/components/{DesktopPicker.js => DesktopPicker.tsx} (83%) delete mode 100644 react/features/settings/components/web/LogoutDialog.js create mode 100644 react/features/settings/components/web/LogoutDialog.tsx diff --git a/react/features/authentication/components/web/LoginDialog.tsx b/react/features/authentication/components/web/LoginDialog.tsx index 7178d8bdf..61d6eee47 100644 --- a/react/features/authentication/components/web/LoginDialog.tsx +++ b/react/features/authentication/components/web/LoginDialog.tsx @@ -7,11 +7,10 @@ import { connect } from '../../../../../connection'; import { IState, IStore } from '../../../app/types'; import { IConfig } from '../../../base/config/configType'; import { toJid } from '../../../base/connection/functions'; -// @ts-ignore -import { Dialog } from '../../../base/dialog'; import { translate, translateToHTML } from '../../../base/i18n/functions'; import { JitsiConnectionErrors } from '../../../base/lib-jitsi-meet'; import { connect as reduxConnect } from '../../../base/redux/functions'; +import Dialog from '../../../base/ui/components/web/Dialog'; import Input from '../../../base/ui/components/web/Input'; import { authenticateAndUpgradeRole, @@ -255,19 +254,18 @@ class LoginDialog extends Component { return ( + titleKey = { t('dialog.authenticationRequired') }> { value = { username } />
, + dispatch: IStore['dispatch']; /** * Function to be invoked after click. */ - onAuthNow: ?Function, - - /** - * Invoked to obtain translated strings. - */ - t: Function + onAuthNow?: Function; } /** @@ -48,8 +44,6 @@ class WaitForOwnerDialog extends PureComponent { this._onIAmHost = this._onIAmHost.bind(this); } - _onCancelWaitForOwner: () => void; - /** * Called when the cancel button is clicked. * @@ -62,8 +56,6 @@ class WaitForOwnerDialog extends PureComponent { dispatch(cancelWaitForOwner()); } - _onIAmHost: () => void; - /** * Called when the OK button is clicked. * @@ -73,7 +65,7 @@ class WaitForOwnerDialog extends PureComponent { _onIAmHost() { const { onAuthNow } = this.props; - onAuthNow && onAuthNow(); + onAuthNow?.(); } /** @@ -88,13 +80,12 @@ class WaitForOwnerDialog extends PureComponent { return ( + titleKey = { t('dialog.WaitingForHostTitle') }> { t('dialog.WaitForHostMsg') } diff --git a/react/features/base/dialog/middleware.web.ts b/react/features/base/dialog/middleware.web.ts index c5a23881b..e56d2a449 100644 --- a/react/features/base/dialog/middleware.web.ts +++ b/react/features/base/dialog/middleware.web.ts @@ -1,5 +1,8 @@ /* eslint-disable lines-around-comment */ +import LoginDialog from '../../authentication/components/web/LoginDialog'; +import WaitForOwnerDialog from '../../authentication/components/web/WaitForOwnerDialog'; import ChatPrivacyDialog from '../../chat/components/web/ChatPrivacyDialog'; +import DesktopPicker from '../../desktop-picker/components/DesktopPicker'; import DisplayNamePrompt from '../../display-name/components/web/DisplayNamePrompt'; import EmbedMeetingDialog from '../../embed-meeting/components/EmbedMeetingDialog'; // @ts-ignore @@ -15,9 +18,12 @@ import StopLiveStreamDialog from '../../recording/components/LiveStream/web/Stop import StartRecordingDialog from '../../recording/components/Recording/web/StartRecordingDialog'; // @ts-ignore import StopRecordingDialog from '../../recording/components/Recording/web/StopRecordingDialog'; +// @ts-ignore +import RemoteControlAuthorizationDialog from '../../remote-control/components/RemoteControlAuthorizationDialog'; import ShareAudioDialog from '../../screen-share/components/ShareAudioDialog'; import ShareScreenWarningDialog from '../../screen-share/components/ShareScreenWarningDialog'; import SecurityDialog from '../../security/components/security-dialog/web/SecurityDialog'; +import LogoutDialog from '../../settings/components/web/LogoutDialog'; import SharedVideoDialog from '../../shared-video/components/web/SharedVideoDialog'; import SpeakerStats from '../../speaker-stats/components/web/SpeakerStats'; import LanguageSelectorDialog from '../../subtitles/components/LanguageSelectorDialog.web'; @@ -41,7 +47,8 @@ const NEW_DIALOG_LIST = [ KeyboardShortcutsDialog, ChatPrivacyDialog, DisplayNam StartRecordingDialog, StopRecordingDialog, ShareAudioDialog, ShareScreenWarningDialog, SecurityDialog, SharedVideoDialog, SpeakerStats, LanguageSelectorDialog, MuteEveryoneDialog, MuteEveryonesVideoDialog, GrantModeratorDialog, KickRemoteParticipantDialog, MuteRemoteParticipantsVideoDialog, VideoQualityDialog, - VirtualBackgroundDialog ]; + VirtualBackgroundDialog, LoginDialog, WaitForOwnerDialog, DesktopPicker, RemoteControlAuthorizationDialog, + LogoutDialog ]; // This function is necessary while the transition from @atlaskit dialog to our component is ongoing. const isNewDialog = (component: any) => NEW_DIALOG_LIST.some(comp => comp === component); diff --git a/react/features/base/ui/components/web/Dialog.tsx b/react/features/base/ui/components/web/Dialog.tsx index 5223164e3..1172a9118 100644 --- a/react/features/base/ui/components/web/Dialog.tsx +++ b/react/features/base/ui/components/web/Dialog.tsx @@ -1,5 +1,5 @@ import { Theme } from '@mui/material'; -import React, { ReactElement, useCallback, useContext, useEffect } from 'react'; +import React, { useCallback, useContext, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { useDispatch } from 'react-redux'; import { keyframes } from 'tss-react'; @@ -177,9 +177,11 @@ interface DialogProps { hidden?: boolean; translationKey?: string; }; - children?: ReactElement | ReactElement[]; + children?: React.ReactNode; className?: string; description?: string; + disableBackdropClose?: boolean; + hideCloseButton?: boolean; ok?: { disabled?: boolean; hidden?: boolean; @@ -197,6 +199,8 @@ const Dialog = ({ children, className, description, + disableBackdropClose, + hideCloseButton, ok = { translationKey: 'dialog.Ok' }, onCancel, onSubmit, @@ -214,17 +218,24 @@ const Dialog = ({ dispatch(hideDialog()); }, [ onCancel ]); - const handleKeyDown = useCallback((e: KeyboardEvent) => { - if (e.key === 'Escape') { - onClose(); - } - }, []); - const submit = useCallback(() => { onSubmit?.(); dispatch(hideDialog()); }, [ onSubmit ]); + const handleKeyDown = useCallback((e: KeyboardEvent) => { + if (e.key === 'Escape') { + onClose(); + } + if (e.key === 'Enter') { + submit(); + } + }, []); + + const onBackdropClick = useCallback(() => { + !disableBackdropClose && onClose(); + }, [ disableBackdropClose, onClose ]); + useEffect(() => { window.addEventListener('keydown', handleKeyDown); @@ -235,7 +246,7 @@ const Dialog = ({
+ onClick = { onBackdropClick } />
{title ?? t(titleKey ?? '')}

- + {!hideCloseButton && ( + + )}
{children}
diff --git a/react/features/desktop-picker/components/DesktopPicker.js b/react/features/desktop-picker/components/DesktopPicker.tsx similarity index 83% rename from react/features/desktop-picker/components/DesktopPicker.js rename to react/features/desktop-picker/components/DesktopPicker.tsx index a89f10e37..3df19c583 100644 --- a/react/features/desktop-picker/components/DesktopPicker.js +++ b/react/features/desktop-picker/components/DesktopPicker.tsx @@ -1,14 +1,17 @@ -// @flow - +/* eslint-disable lines-around-comment */ import Tabs from '@atlaskit/tabs'; import React, { PureComponent } from 'react'; -import type { Dispatch } from 'redux'; +import { WithTranslation } from 'react-i18next'; -import { Dialog, hideDialog } from '../../base/dialog'; -import { translate } from '../../base/i18n'; -import { connect } from '../../base/redux'; +import { IStore } from '../../app/types'; +import { hideDialog } from '../../base/dialog/actions'; +import { translate } from '../../base/i18n/functions'; +import { connect } from '../../base/redux/functions'; +import Dialog from '../../base/ui/components/web/Dialog'; +// @ts-ignore import { obtainDesktopSources } from '../functions'; +// @ts-ignore import DesktopPickerPane from './DesktopPickerPane'; /** @@ -45,29 +48,24 @@ const VALID_TYPES = Object.keys(TAB_LABELS); /** * The type of the React {@code Component} props of {@link DesktopPicker}. */ -type Props = { +interface Props extends WithTranslation { /** * An array with desktop sharing sources to be displayed. */ - desktopSharingSources: Array, + desktopSharingSources: Array; /** * Used to request DesktopCapturerSources. */ - dispatch: Dispatch, + dispatch: IStore['dispatch']; /** * The callback to be invoked when the component is closed or when a * DesktopCapturerSource has been chosen. */ - onSourceChoose: Function, - - /** - * Used to obtain translations. - */ - t: Function -}; + onSourceChoose: Function; +} /** * The type of the React {@code Component} state of {@link DesktopPicker}. @@ -77,27 +75,27 @@ type State = { /** * The state of the audio screen share checkbox. */ - screenShareAudio: boolean, + screenShareAudio: boolean; /** * The currently highlighted DesktopCapturerSource. */ - selectedSource: Object, + selectedSource: any; /** * The desktop source type currently being displayed. */ - selectedTab: number, + selectedTab: number; /** * An object containing all the DesktopCapturerSources. */ - sources: Object, + sources: Object; /** * The desktop source types to fetch previews for. */ - types: Array + types: Array; }; @@ -112,7 +110,7 @@ class DesktopPicker extends PureComponent { * * @inheritdoc */ - static getDerivedStateFromProps(props) { + static getDerivedStateFromProps(props: Props) { return { types: DesktopPicker._getValidTypes(props.desktopSharingSources) }; @@ -125,14 +123,14 @@ class DesktopPicker extends PureComponent { * @private * @returns {Array} The filtered types. */ - static _getValidTypes(types = []) { + static _getValidTypes(types: string[] = []) { return types.filter( type => VALID_TYPES.includes(type)); } - _poller = null; + _poller: any = null; - state = { + state: State = { screenShareAudio: false, selectedSource: {}, selectedTab: 0, @@ -195,33 +193,34 @@ class DesktopPicker extends PureComponent { render() { return ( + size = 'large' + titleKey = 'dialog.shareYourScreen'> { this._renderTabs() } ); } /** - * Computates the selected source. + * Computes the selected source. * * @param {Object} sources - The available sources. * @returns {Object} The selectedSource value. */ - _getSelectedSource(sources = {}) { + _getSelectedSource(sources: any = {}) { const { selectedSource } = this.state; /** * If there are no sources for this type (or no sources for any type) * we can't select anything. */ - if (!Array.isArray(sources[this._selectedTabType]) - || sources[this._selectedTabType].length <= 0) { + if (!Array.isArray(sources[this._selectedTabType as keyof typeof sources]) + || sources[this._selectedTabType as keyof typeof sources].length <= 0) { return {}; } @@ -235,7 +234,7 @@ class DesktopPicker extends PureComponent { if (!selectedSource // scenario 1) || selectedSource.type !== this._selectedTabType // scenario 2) || !sources[this._selectedTabType].some( // scenario 3) - source => source.id === selectedSource.id)) { + (source: any) => source.id === selectedSource.id)) { return { id: sources[this._selectedTabType][0].id, type: this._selectedTabType @@ -248,8 +247,6 @@ class DesktopPicker extends PureComponent { return selectedSource; } - _onCloseModal: (?string, string, ?boolean) => void; - /** * Dispatches an action to hide the DesktopPicker and invokes the passed in * callback with a selectedSource, if any. @@ -262,13 +259,11 @@ class DesktopPicker extends PureComponent { * screen sharing session. * @returns {void} */ - _onCloseModal(id = '', type, screenShareAudio = false) { + _onCloseModal(id = '', type?: string, screenShareAudio = false) { this.props.onSourceChoose(id, type, screenShareAudio); this.props.dispatch(hideDialog()); } - _onPreviewClick: (string, string) => void; - /** * Sets the currently selected DesktopCapturerSource. * @@ -276,7 +271,7 @@ class DesktopPicker extends PureComponent { * @param {string} type - The type of DesktopCapturerSource. * @returns {void} */ - _onPreviewClick(id, type) { + _onPreviewClick(id: string, type: string) { this.setState({ selectedSource: { id, @@ -285,8 +280,6 @@ class DesktopPicker extends PureComponent { }); } - _onSubmit: () => void; - /** * Request to close the modal and execute callbacks with the selected source * id. @@ -299,19 +292,17 @@ class DesktopPicker extends PureComponent { this._onCloseModal(id, type, screenShareAudio); } - _onTabSelected: () => void; - /** * Stores the selected tab and updates the selected source via * {@code _getSelectedSource}. * - * @param {Object} tab - The configuration passed into atlaskit tabs to + * @param {Object} _tab - The configuration passed into atlaskit tabs to * describe how to display the selected tab. * @param {number} tabIndex - The index of the tab within the array of * displayed tabs. * @returns {void} */ - _onTabSelected(tab, tabIndex) { // eslint-disable-line no-unused-vars + _onTabSelected(_tab: Object, tabIndex: number) { const { types, sources } = this.state; this._selectedTabType = types[tabIndex]; @@ -325,8 +316,6 @@ class DesktopPicker extends PureComponent { }); } - _onShareAudioChecked: (boolean) => void; - /** * Set the screenSharingAudio state indicating whether or not to also share * system audio. @@ -334,7 +323,7 @@ class DesktopPicker extends PureComponent { * @param {boolean} checked - Share audio or not. * @returns {void} */ - _onShareAudioChecked(checked) { + _onShareAudioChecked(checked: boolean) { this.setState({ screenShareAudio: checked }); } @@ -357,9 +346,9 @@ class DesktopPicker extends PureComponent { onDoubleClick = { this._onSubmit } onShareAudioChecked = { this._onShareAudioChecked } selectedSourceId = { selectedSource.id } - sources = { sources[type] } + sources = { sources[type as keyof typeof sources] } type = { type } />, - label: t(TAB_LABELS[type]) + label: t(TAB_LABELS[type as keyof typeof TAB_LABELS]) }; }); @@ -393,8 +382,6 @@ class DesktopPicker extends PureComponent { this._poller = null; } - _updateSources: () => void; - /** * Obtains the desktop sources and updates state with them. * @@ -409,7 +396,7 @@ class DesktopPicker extends PureComponent { this.state.types, { thumbnailSize: THUMBNAIL_SIZE } ) - .then(sources => { + .then((sources: any) => { const selectedSource = this._getSelectedSource(sources); // TODO: Maybe check if we have stopped the timer and unmounted diff --git a/react/features/remote-control/components/RemoteControlAuthorizationDialog.js b/react/features/remote-control/components/RemoteControlAuthorizationDialog.js index e7aaa2a32..8fa42b1e6 100644 --- a/react/features/remote-control/components/RemoteControlAuthorizationDialog.js +++ b/react/features/remote-control/components/RemoteControlAuthorizationDialog.js @@ -2,11 +2,12 @@ import React, { Component } from 'react'; -import { Dialog, hideDialog } from '../../base/dialog'; +import { hideDialog } from '../../base/dialog/actions'; import { translate } from '../../base/i18n'; import { getParticipantById } from '../../base/participants'; import { connect } from '../../base/redux'; import { getLocalVideoTrack } from '../../base/tracks'; +import Dialog from '../../base/ui/components/web/Dialog'; import { deny, grant } from '../actions'; declare var APP: Object; @@ -68,11 +69,10 @@ class RemoteControlAuthorizationDialog extends Component { render() { return ( + titleKey = 'dialog.remoteControlTitle'> { this.props.t( 'dialog.remoteControlRequestMessage', diff --git a/react/features/salesforce/components/web/SalesforceLinkDialog.tsx b/react/features/salesforce/components/web/SalesforceLinkDialog.tsx index 288e2db13..0b21b1f22 100644 --- a/react/features/salesforce/components/web/SalesforceLinkDialog.tsx +++ b/react/features/salesforce/components/web/SalesforceLinkDialog.tsx @@ -11,8 +11,7 @@ import { Dialog } from '../../../base/dialog'; import { hideDialog } from '../../../base/dialog/actions'; import Icon from '../../../base/icons/components/Icon'; import { IconSearch } from '../../../base/icons/svg'; -// @ts-ignore -import { getFieldValue } from '../../../base/react'; +import { getFieldValue } from '../../../base/react/functions'; import { withPixelLineHeight } from '../../../base/styles/functions.web'; import { NOTES_MAX_LENGTH } from '../../constants'; // @ts-ignore @@ -20,7 +19,6 @@ import { useSalesforceLinkDialog } from '../../useSalesforceLinkDialog'; import { RecordItem } from './RecordItem'; -// @ts-ignore const useStyles = makeStyles()((theme: Theme) => { return { container: { @@ -102,7 +100,7 @@ const useStyles = makeStyles()((theme: Theme) => { minHeight: '130px', resize: 'vertical', width: '100%', - boxSizing: 'borderBox', + boxSizing: 'border-box', overflow: 'hidden', border: '1px solid', borderColor: theme.palette.ui05, diff --git a/react/features/settings/components/web/LogoutDialog.js b/react/features/settings/components/web/LogoutDialog.js deleted file mode 100644 index 7659dfbb7..000000000 --- a/react/features/settings/components/web/LogoutDialog.js +++ /dev/null @@ -1,48 +0,0 @@ -// @flow - -import React from 'react'; - -import { Dialog } from '../../../base/dialog'; -import { translate } from '../../../base/i18n'; -import { connect } from '../../../base/redux'; - -/** - * The type of {@link LogoutDialog}'s React {@code Component} props. - */ -type Props = { - - /** - * Logout handler. - */ - onLogout: Function, - - /** - * Function to be used to translate i18n labels. - */ - t: Function -}; - -/** - * Implements the Logout dialog. - * - * @param {Object} props - The props of the component. - * @returns {React$Element}. - */ -function LogoutDialog(props: Props) { - const { onLogout, t } = props; - - return ( - -
- { t('dialog.logoutQuestion') } -
-
- ); -} - -export default translate(connect()(LogoutDialog)); diff --git a/react/features/settings/components/web/LogoutDialog.tsx b/react/features/settings/components/web/LogoutDialog.tsx new file mode 100644 index 000000000..f223a6d32 --- /dev/null +++ b/react/features/settings/components/web/LogoutDialog.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { WithTranslation } from 'react-i18next'; + +import { translate } from '../../../base/i18n/functions'; +import { connect } from '../../../base/redux/functions'; +import Dialog from '../../../base/ui/components/web/Dialog'; + +/** + * The type of {@link LogoutDialog}'s React {@code Component} props. + */ +interface Props extends WithTranslation { + + /** + * Logout handler. + */ + onLogout: () => void; +} + +/** + * Implements the Logout dialog. + * + * @param {Object} props - The props of the component. + * @returns {React$Element}. + */ +function LogoutDialog({ onLogout, t }: Props) { + return ( + +
+ { t('dialog.logoutQuestion') } +
+
+ ); +} + +export default translate(connect()(LogoutDialog));