From 66da77bcf525facc1772a265860f09ab63165ea3 Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Fri, 22 Sep 2017 17:02:34 -0500 Subject: [PATCH] fix(profile_button): unclickable --- modules/UI/UI.js | 6 +- react/features/toolbox/actions.web.js | 34 +---- .../components/ProfileButton.native.js | 0 .../toolbox/components/ProfileButton.web.js | 126 ++++++++++++++++++ .../components/StatelessToolbarButton.js | 44 +----- .../toolbox/components/Toolbar.web.js | 14 +- .../toolbox/components/ToolbarButton.web.js | 36 +---- .../toolbox/defaultToolbarButtons.web.js | 21 +-- 8 files changed, 154 insertions(+), 127 deletions(-) create mode 100644 react/features/toolbox/components/ProfileButton.native.js create mode 100644 react/features/toolbox/components/ProfileButton.web.js diff --git a/modules/UI/UI.js b/modules/UI/UI.js index 9423bccef..5cc5385f0 100644 --- a/modules/UI/UI.js +++ b/modules/UI/UI.js @@ -1248,11 +1248,7 @@ const UIListeners = new Map([ ], [ UIEvents.TOGGLE_PROFILE, () => { - const { - isGuest - } = APP.store.getState()['features/jwt']; - - isGuest && UI.toggleSidePanel('profile_container'); + UI.toggleSidePanel('profile_container'); } ], [ UIEvents.TOGGLE_FILMSTRIP, diff --git a/react/features/toolbox/actions.web.js b/react/features/toolbox/actions.web.js index d0913b55f..dcbc413b3 100644 --- a/react/features/toolbox/actions.web.js +++ b/react/features/toolbox/actions.web.js @@ -100,11 +100,10 @@ export function dockToolbox(dock: boolean): Function { * closure. * * @param {Function} dispatch - Redux action dispatcher. - * @param {Function} getState - The function fetching the Redux state. * @returns {Object} Button on mount/unmount handlers. * @private */ -function _getButtonHandlers(dispatch, getState) { +function _getButtonHandlers(dispatch) { const localRaiseHandHandler = (...args) => dispatch(changeLocalRaiseHand(...args)); const toggleFullScreenHandler @@ -136,17 +135,6 @@ function _getButtonHandlers(dispatch, getState) { toggleFullScreenHandler) }, - /** - * Mount handler for profile button. - * - * @type {Object} - */ - profile: { - onMount: () => - getState()['features/jwt'] - || dispatch(setProfileButtonUnclickable(true)) - }, - /** * Mount/Unmount handlers for raisehand button. * @@ -246,9 +234,9 @@ export function setButtonPopupTimeout(buttonName, popupName, timeout) { * @returns {Function} */ export function setDefaultToolboxButtons(): Function { - return (dispatch: Dispatch, getState: Function) => { + return (dispatch: Dispatch) => { // Save dispatch function in closure. - const buttonHandlers = _getButtonHandlers(dispatch, getState); + const buttonHandlers = _getButtonHandlers(dispatch); const toolboxButtons = getDefaultToolboxButtons(buttonHandlers); dispatch({ @@ -258,22 +246,6 @@ export function setDefaultToolboxButtons(): Function { }; } -/** - * Signals that unclickable property of profile button should change its value. - * - * @param {boolean} unclickable - Shows whether button is unclickable. - * @returns {Function} - */ -export function setProfileButtonUnclickable(unclickable: boolean): Function { - return (dispatch: Dispatch<*>) => { - const buttonName = 'profile'; - - dispatch(setToolbarButton(buttonName, { - unclickable - })); - }; -} - /** * Shows desktop sharing button. * diff --git a/react/features/toolbox/components/ProfileButton.native.js b/react/features/toolbox/components/ProfileButton.native.js new file mode 100644 index 000000000..e69de29bb diff --git a/react/features/toolbox/components/ProfileButton.web.js b/react/features/toolbox/components/ProfileButton.web.js new file mode 100644 index 000000000..17d2a9df4 --- /dev/null +++ b/react/features/toolbox/components/ProfileButton.web.js @@ -0,0 +1,126 @@ +/* @flow */ + +import React, { Component } from 'react'; +import { connect } from 'react-redux'; + +import { DEFAULT_AVATAR_RELATIVE_PATH } from '../../base/participants'; +import UIEvents from '../../../../service/UI/UIEvents'; + +import ToolbarButton from './ToolbarButton'; + +declare var APP: Object; +declare var JitsiMeetJS: Object; + +/** + * The default configuration for the button. + * + * @type {Object} + */ +const DEFAULT_BUTTON_CONFIGURATION = { + buttonName: 'profile', + classNames: [ 'button' ], + enabled: true, + id: 'toolbar_button_profile', + tooltipKey: 'profile.setDisplayNameLabel' +}; + +/** + * React {@code Component} for the profile button. + * + * @extends Component + */ +class ProfileButton extends Component { + _onClick: Function; + + /** + * {@code ProfileButton}'s property types. + * + * @static + */ + static propTypes = { + /** + * Whether the button support clicking or not. + */ + _unclickable: React.PropTypes.bool, + + /** + * Whether the side panel is opened or not. + */ + toggled: React.PropTypes.bool, + + /** + * From which side tooltips should display. Will be re-used for + * displaying the inline dialog for video quality adjustment. + */ + tooltipPosition: React.PropTypes.string + }; + + /** + * Initializes a new {@code ProfileButton} instance. + * + * @param {Object} props - The read-only properties with which the new + * instance is to be initialized. + */ + constructor(props) { + super(props); + + // Bind event handlers so they are only bound once for every instance. + this._onClick = this._onClick.bind(this); + } + + /** + * Implements React's {@link Component#render()}. + * + * @inheritdoc + * @returns {ReactElement} + */ + render() { + const { _unclickable, tooltipPosition, toggled } = this.props; + const buttonConfiguration = { + ...DEFAULT_BUTTON_CONFIGURATION, + unclickable: _unclickable, + toggled + }; + + return ( + + + + ); + } + + /** + * Click handler for the button. + * + * @returns {void} + */ + _onClick() { + if (!this.props._unclickable) { + JitsiMeetJS.analytics.sendEvent('toolbar.profile.toggled'); + APP.UI.emitEvent(UIEvents.TOGGLE_PROFILE); + } + } +} + +/** + * Maps (parts of) the Redux state to the associated {@code ProfileButton} + * component's props. + * + * @param {Object} state - The Redux state. + * @private + * @returns {{ + * _unclickable: boolean + * }} + */ +function _mapStateToProps(state) { + return { + _unclickable: !state['features/jwt'].isGuest + }; +} + +export default connect(_mapStateToProps)(ProfileButton); diff --git a/react/features/toolbox/components/StatelessToolbarButton.js b/react/features/toolbox/components/StatelessToolbarButton.js index 417cadec5..3751ed992 100644 --- a/react/features/toolbox/components/StatelessToolbarButton.js +++ b/react/features/toolbox/components/StatelessToolbarButton.js @@ -68,12 +68,7 @@ export default class StatelessToolbarButton extends AbstractToolbarButton { /** * Object describing button. */ - button: React.PropTypes.object.isRequired, - - /** - * Handler for button's reference. - */ - createRefToButton: React.PropTypes.func + button: React.PropTypes.object.isRequired }; /** @@ -102,10 +97,8 @@ export default class StatelessToolbarButton extends AbstractToolbarButton { return ( - { this._renderInnerElementsIfRequired() } - { this._renderChildComponentIfRequired() } + onClick = { this._onClick }> + { this.props.children } ); } @@ -131,35 +124,4 @@ export default class StatelessToolbarButton extends AbstractToolbarButton { onClick(event); } } - - /** - * Render any configured child component for the toolbar button. - * - * @returns {ReactElement|null} - * @private - */ - _renderChildComponentIfRequired(): ReactElement<*> | null { - if (this.props.button.childComponent) { - const Child = this.props.button.childComponent; - - return ; - } - - return null; - } - - /** - * If toolbar button should contain children elements - * renders them. - * - * @returns {ReactElement|null} - * @private - */ - _renderInnerElementsIfRequired(): ReactElement<*> | null { - if (this.props.button.html) { - return this.props.button.html; - } - - return null; - } } diff --git a/react/features/toolbox/components/Toolbar.web.js b/react/features/toolbox/components/Toolbar.web.js index 3437319da..3c6ff4674 100644 --- a/react/features/toolbox/components/Toolbar.web.js +++ b/react/features/toolbox/components/Toolbar.web.js @@ -128,15 +128,22 @@ class Toolbar extends Component { const [ key, button ] = keyValuePair; if (button.component) { + return ( ); } const { tooltipPosition } = this.props; - const { onClick, onMount, onUnmount } = button; + const { + childComponent: ChildComponent, + onClick, + onMount, + onUnmount + } = button; const onClickWithDispatch = (...args) => onClick && onClick(this.props.dispatch, ...args); @@ -147,7 +154,10 @@ class Toolbar extends Component { onClick = { onClickWithDispatch } onMount = { onMount } onUnmount = { onUnmount } - tooltipPosition = { tooltipPosition } /> + tooltipPosition = { tooltipPosition }> + { button.html || null } + { ChildComponent ? : null } + ); } } diff --git a/react/features/toolbox/components/ToolbarButton.web.js b/react/features/toolbox/components/ToolbarButton.web.js index 90ad79151..605c3c604 100644 --- a/react/features/toolbox/components/ToolbarButton.web.js +++ b/react/features/toolbox/components/ToolbarButton.web.js @@ -32,7 +32,6 @@ const TOOLTIP_TO_POPUP_POSITION = { */ class ToolbarButton extends Component { button: Object; - _createRefToButton: Function; _onClick: Function; @@ -99,7 +98,6 @@ class ToolbarButton extends Component { }; // Bind methods to save the context - this._createRefToButton = this._createRefToButton.bind(this); this._onClick = this._onClick.bind(this); this._onMouseOut = this._onMouseOut.bind(this); this._onMouseOver = this._onMouseOver.bind(this); @@ -142,8 +140,7 @@ class ToolbarButton extends Component { const { button, t, tooltipPosition } = this.props; const props = { ...this.props, - onClick: this._onClick, - createRefToButton: this._createRefToButton + onClick: this._onClick }; const buttonComponent = ( // eslint-disable-line no-extra-parens @@ -153,7 +150,9 @@ class ToolbarButton extends Component { onMouseOver = { this._onMouseOver } position = { tooltipPosition } visible = { this.state.showTooltip }> - + + { this.props.children } + ); let children = buttonComponent; @@ -192,18 +191,6 @@ class ToolbarButton extends Component { this.setState({ showTooltip: false }); } - /** - * Creates reference to current toolbar button. - * - * @param {HTMLElement} element - HTMLElement representing the toolbar - * button. - * @returns {void} - * @private - */ - _createRefToButton(element: HTMLElement): void { - this.button = element; - } - /** * Parses the props and state to find any popup that should be displayed * and returns an object describing how the popup should display. @@ -230,21 +217,6 @@ class ToolbarButton extends Component { }); } - /** - * If toolbar button should contain children elements - * renders them. - * - * @returns {ReactElement|null} - * @private - */ - _renderInnerElementsIfRequired(): ReactElement<*> | null { - if (this.props.button.html) { - return this.props.button.html; - } - - return null; - } - /** * Hides any displayed tooltip. * diff --git a/react/features/toolbox/defaultToolbarButtons.web.js b/react/features/toolbox/defaultToolbarButtons.web.js index d611a331f..147232719 100644 --- a/react/features/toolbox/defaultToolbarButtons.web.js +++ b/react/features/toolbox/defaultToolbarButtons.web.js @@ -2,15 +2,14 @@ import React from 'react'; -import { DEFAULT_AVATAR_RELATIVE_PATH } from '../base/participants'; +import { ParticipantCounter } from '../contact-list'; import { openDeviceSelectionDialog } from '../device-selection'; import { openDialOutDialog } from '../dial-out'; import { openAddPeopleDialog, openInviteDialog } from '../invite'; +import UIEvents from '../../../service/UI/UIEvents'; import { VideoQualityButton } from '../video-quality'; -import UIEvents from '../../../service/UI/UIEvents'; - -import { ParticipantCounter } from '../contact-list'; +import ProfileButton from './components/ProfileButton'; declare var APP: Object; declare var interfaceConfig: Object; @@ -328,18 +327,8 @@ const buttons: Object = { * The descriptor of the profile toolbar button. */ profile: { - classNames: [ 'button' ], - enabled: true, - html: , - id: 'toolbar_button_profile', - onClick() { - JitsiMeetJS.analytics.sendEvent('toolbar.profile.toggled'); - APP.UI.emitEvent(UIEvents.TOGGLE_PROFILE); - }, - sideContainerId: 'profile_container', - tooltipKey: 'profile.setDisplayNameLabel' + component: ProfileButton, + sideContainerId: 'profile_container' }, /**