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'
},
/**