diff --git a/react/features/participants-pane/components/web/ParticipantsPane.tsx b/react/features/participants-pane/components/web/ParticipantsPane.tsx index 3aaaea1b8..f1d63069d 100644 --- a/react/features/participants-pane/components/web/ParticipantsPane.tsx +++ b/react/features/participants-pane/components/web/ParticipantsPane.tsx @@ -1,16 +1,15 @@ /* eslint-disable lines-around-comment */ import { Theme } from '@mui/material'; -import { withStyles } from '@mui/styles'; -import React, { Component } from 'react'; -import { WithTranslation } from 'react-i18next'; +import React, { useCallback, useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useDispatch, useSelector } from 'react-redux'; +import { makeStyles } from 'tss-react/mui'; import { IState } from '../../../app/types'; import participantsPaneTheme from '../../../base/components/themes/participantsPaneTheme.json'; import { openDialog } from '../../../base/dialog/actions'; -import { translate } from '../../../base/i18n/functions'; import { IconClose, IconHorizontalPoints } from '../../../base/icons/svg'; import { isLocalParticipantModerator } from '../../../base/participants/functions'; -import { connect } from '../../../base/redux/functions'; import Button from '../../../base/ui/components/web/Button'; import ClickableIcon from '../../../base/ui/components/web/ClickableIcon'; import { BUTTON_TYPES } from '../../../base/ui/constants'; @@ -32,74 +31,8 @@ import { FooterContextMenu } from './FooterContextMenu'; import LobbyParticipants from './LobbyParticipants'; import MeetingParticipants from './MeetingParticipants'; -/** - * The type of the React {@code Component} props of {@link ParticipantsPane}. - */ -interface Props extends WithTranslation { - /** - * Whether there is backend support for Breakout Rooms. - */ - _isBreakoutRoomsSupported: Boolean; - - /** - * Whether to display the context menu as a drawer. - */ - _overflowDrawer: boolean; - - /** - * Is the participants pane open. - */ - _paneOpen: boolean; - - /** - * Should the add breakout room button be displayed? - */ - _showAddRoomButton: boolean; - - /** - * Whether to show the footer menu. - */ - _showFooter: boolean; - - /** - * Whether to show the more actions button. - */ - _showMoreActionsButton: boolean; - - /** - * Whether to show the mute all button. - */ - _showMuteAllButton: boolean; - - /** - * An object containing the CSS classes. - */ - classes: any; - - /** - * The Redux dispatch function. - */ - dispatch: Function; -} - -/** - * The type of the React {@code Component} state of {@link ParticipantsPane}. - */ -type State = { - - /** - * Indicates if the footer context menu is open. - */ - contextOpen: boolean; - - /** - * Participants search string. - */ - searchString: string; -}; - -const styles = (theme: Theme) => { +const useStyles = makeStyles()((theme: Theme) => { return { container: { boxSizing: 'border-box' as const, @@ -159,217 +92,104 @@ const styles = (theme: Theme) => { position: 'relative' as const } }; +}); + +const ParticipantsPane = () => { + const { classes } = useStyles(); + const paneOpen = useSelector(getParticipantsPaneOpen); + const isBreakoutRoomsSupported = useSelector((state: IState) => state['features/base/conference']) + .conference?.getBreakoutRooms()?.isSupported(); + const showAddRoomButton = useSelector(isAddBreakoutRoomButtonVisible); + const showFooter = useSelector(isLocalParticipantModerator); + const showMuteAllButton = useSelector(isMuteAllVisible); + const showMoreActionsButton = useSelector(isMoreActionsVisible); + const dispatch = useDispatch(); + const { t } = useTranslation(); + + const [ contextOpen, setContextOpen ] = useState(false); + const [ searchString, setSearchString ] = useState(''); + + const onWindowClickListener = useCallback((e: any) => { + if (contextOpen && !findAncestorByClass(e.target, classes.footerMoreContainer)) { + setContextOpen(false); + } + }, [ contextOpen ]); + + useEffect(() => { + window.addEventListener('click', onWindowClickListener); + + return () => { + window.removeEventListener('click', onWindowClickListener); + }; + }, []); + + const onClosePane = useCallback(() => { + dispatch(close()); + }, []); + + const onDrawerClose = useCallback(() => { + setContextOpen(false); + }, []); + + const onMuteAll = useCallback(() => { + dispatch(openDialog(MuteEveryoneDialog)); + }, []); + + const onToggleContext = useCallback(() => { + setContextOpen(open => !open); + }, []); + + if (!paneOpen) { + return null; + } + + return ( +
+
+
+ +
+
+ +
+ + {isBreakoutRoomsSupported && } + {showAddRoomButton && } +
+ {showFooter && ( +
+ {showMuteAllButton && ( +
+ )} +
+ )} +
+ + ); }; -/** - * Implements the participants list. - */ -class ParticipantsPane extends Component { - /** - * Initializes a new {@code ParticipantsPane} instance. - * - * @inheritdoc - */ - constructor(props: Props) { - super(props); - this.state = { - contextOpen: false, - searchString: '' - }; - - // Bind event handlers so they are only bound once per instance. - this._onClosePane = this._onClosePane.bind(this); - this._onDrawerClose = this._onDrawerClose.bind(this); - this._onMuteAll = this._onMuteAll.bind(this); - this._onToggleContext = this._onToggleContext.bind(this); - this._onWindowClickListener = this._onWindowClickListener.bind(this); - this.setSearchString = this.setSearchString.bind(this); - } - - - /** - * Implements React's {@link Component#componentDidMount()}. - * - * @inheritdoc - */ - componentDidMount() { - window.addEventListener('click', this._onWindowClickListener); - } - - /** - * Implements React's {@link Component#componentWillUnmount()}. - * - * @inheritdoc - */ - componentWillUnmount() { - window.removeEventListener('click', this._onWindowClickListener); - } - - /** - * Implements React's {@link Component#render}. - * - * @inheritdoc - */ - render() { - const { - _isBreakoutRoomsSupported, - _paneOpen, - _showAddRoomButton, - _showFooter, - _showMoreActionsButton, - _showMuteAllButton, - classes, - t - } = this.props; - const { contextOpen, searchString } = this.state; - - // when the pane is not open optimize to not - // execute the MeetingParticipantList render for large list of participants - if (!_paneOpen) { - return null; - } - - return ( -
-
-
- -
-
- -
- - {_isBreakoutRoomsSupported && } - {_showAddRoomButton && } -
- {_showFooter && ( -
- {_showMuteAllButton && ( -
- )} -
- )} -
- - ); - } - - /** - * Sets the search string. - * - * @param {string} newSearchString - The new search string. - * @returns {void} - */ - setSearchString(newSearchString: string) { - this.setState({ - searchString: newSearchString - }); - } - - /** - * Callback for closing the participant pane. - * - * @private - * @returns {void} - */ - _onClosePane() { - this.props.dispatch(close()); - } - - /** - * Callback for closing the drawer. - * - * @private - * @returns {void} - */ - _onDrawerClose() { - this.setState({ - contextOpen: false - }); - } - - /** - * The handler for clicking mute all button. - * - * @returns {void} - */ - _onMuteAll() { - this.props.dispatch(openDialog(MuteEveryoneDialog)); - } - - /** - * Handler for toggling open/close of the footer context menu. - * - * @returns {void} - */ - _onToggleContext() { - this.setState({ - contextOpen: !this.state.contextOpen - }); - } - - /** - * Window click event listener. - * - * @param {Event} e - The click event. - * @returns {void} - */ - _onWindowClickListener(e: any) { - if (this.state.contextOpen && !findAncestorByClass(e.target, this.props.classes.footerMoreContainer)) { - this.setState({ - contextOpen: false - }); - } - } - - -} - -/** - * Maps (parts of) the redux state to the React {@code Component} props of - * {@code ParticipantsPane}. - * - * @param {Object} state - The redux state. - * @protected - * @returns {Props} - */ -function _mapStateToProps(state: IState) { - const isPaneOpen = getParticipantsPaneOpen(state); - const { conference } = state['features/base/conference']; - const _isBreakoutRoomsSupported = conference?.getBreakoutRooms()?.isSupported(); - - return { - _isBreakoutRoomsSupported, - _paneOpen: isPaneOpen, - _showAddRoomButton: isAddBreakoutRoomButtonVisible(state), - _showFooter: isLocalParticipantModerator(state), - _showMuteAllButton: isMuteAllVisible(state), - _showMoreActionsButton: isMoreActionsVisible(state) - }; -} - -export default translate(connect(_mapStateToProps)(withStyles(styles)(ParticipantsPane))); +export default ParticipantsPane;