refactor(speaker-stats): speaker stats as functional component

This commit is contained in:
Gabriel Borlea 2022-01-13 11:58:01 +02:00 committed by Calinteodor
parent e7fc9d9973
commit aa5506e7a6
2 changed files with 42 additions and 169 deletions

View File

@ -1,169 +1,52 @@
// @flow
import React, { Component } from 'react';
import type { Dispatch } from 'redux';
import React, { useCallback, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { Dialog } from '../../../base/dialog';
import { translate } from '../../../base/i18n';
import { connect } from '../../../base/redux';
import { escapeRegexp } from '../../../base/util';
import { initSearch, resetSearchCriteria, toggleFacialExpressions } from '../../actions';
import { resetSearchCriteria, toggleFacialExpressions } from '../../actions';
import { REDUCE_EXPRESSIONS_THRESHOLD } from '../../constants';
import FacialExpressionsSwitch from './FacialExpressionsSwitch';
import SpeakerStatsLabels from './SpeakerStatsLabels';
import SpeakerStatsList from './SpeakerStatsList';
import SpeakerStatsSearch from './SpeakerStatsSearch';
/**
* The type of the React {@code Component} props of {@link SpeakerStats}.
*/
type Props = {
const SpeakerStats = () => {
const { enableFacialRecognition } = useSelector(state => state['features/base/config']);
const { showFacialExpressions } = useSelector(state => state['features/speaker-stats']);
const { clientWidth } = useSelector(state => state['features/base/responsive-ui']);
const reduceExpressions = clientWidth < REDUCE_EXPRESSIONS_THRESHOLD;
const dispatch = useDispatch();
/**
* The flag which shows if the facial recognition is enabled, obtained from the redux store.
* If enabled facial expressions can be expanded.
*/
_enableFacialRecognition: boolean,
const onToggleFacialExpressions = useCallback(() =>
dispatch(toggleFacialExpressions())
, [ dispatch ]);
/**
* The flag which shows if the facial expressions are displayed or not.
*/
_showFacialExpressions: boolean,
useEffect(() => () => dispatch(resetSearchCriteria()), []);
/**
* True if the client width is less than 750.
*/
_reduceExpressions: boolean,
return (
<Dialog
cancelKey = 'dialog.close'
submitDisabled = { true }
titleKey = 'speakerStats.speakerStats'
width = { showFacialExpressions ? 'large' : 'small' }>
<div className = 'speaker-stats'>
<SpeakerStatsSearch />
{ enableFacialRecognition
&& <FacialExpressionsSwitch
onChange = { onToggleFacialExpressions }
showFacialExpressions = { showFacialExpressions } />
}
<SpeakerStatsLabels
reduceExpressions = { reduceExpressions }
showFacialExpressions = { showFacialExpressions ?? false } />
<div className = 'separator-line' />
<SpeakerStatsList />
</div>
</Dialog>
/**
* The search criteria.
*/
_criteria: string | null,
/**
* Redux store dispatch method.
*/
dispatch: Dispatch<any>,
/**
* The function to translate human-readable text.
*/
t: Function
);
};
/**
* React component for displaying a list of speaker stats.
*
* @augments Component
*/
class SpeakerStats extends Component<Props> {
/**
* Initializes a new SpeakerStats instance.
*
* @param {Object} props - The read-only React Component props with which
* the new instance is to be initialized.
*/
constructor(props) {
super(props);
// Bind event handlers so they are only bound once per instance.
this._onSearch = this._onSearch.bind(this);
this._onToggleFacialExpressions = this._onToggleFacialExpressions.bind(this);
}
/**
* Resets the search criteria when component will unmount.
*
* @private
* @returns {void}
*/
componentWillUnmount() {
this.props.dispatch(resetSearchCriteria());
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
return (
<Dialog
cancelKey = 'dialog.close'
submitDisabled = { true }
titleKey = 'speakerStats.speakerStats'
width = { this.props._showFacialExpressions ? 'large' : 'small' }>
<div className = 'speaker-stats'>
<SpeakerStatsSearch onSearch = { this._onSearch } />
{ this.props._enableFacialRecognition
&& <FacialExpressionsSwitch
onChange = { this._onToggleFacialExpressions }
showFacialExpressions = { this.props._showFacialExpressions } />
}
<SpeakerStatsLabels
reduceExpressions = { this.props._reduceExpressions }
showFacialExpressions = { this.props._showFacialExpressions ?? false } />
<div className = 'separator-line' />
<SpeakerStatsList />
</div>
</Dialog>
);
}
_onSearch: () => void;
/**
* Search the existing participants by name.
*
* @returns {void}
* @param {string} criteria - The search parameter.
* @protected
*/
_onSearch(criteria = '') {
this.props.dispatch(initSearch(escapeRegexp(criteria)));
}
_onToggleFacialExpressions: () => void;
/**
* Toggle the facial expressions grid from speaker stats.
*
* @returns {void}
* @protected
*/
_onToggleFacialExpressions() {
this.props.dispatch(toggleFacialExpressions());
}
}
/**
* Maps (parts of) the redux state to the associated SpeakerStats's props.
*
* @param {Object} state - The redux state.
* @private
* @returns {{
* _showFacialExpressions: ?boolean,
* _reduceExpressions: boolean,
* }}
*/
function _mapStateToProps(state) {
const { enableFacialRecognition } = state['features/base/config'];
const { showFacialExpressions } = state['features/speaker-stats'];
const { clientWidth } = state['features/base/responsive-ui'];
return {
/**
* The local display name.
*
* @private
* @type {string|undefined}
*/
_enableFacialRecognition: enableFacialRecognition,
_showFacialExpressions: showFacialExpressions,
_reduceExpressions: clientWidth < 750
};
}
export default translate(connect(_mapStateToProps)(SpeakerStats));
export default SpeakerStats;

View File

@ -4,9 +4,11 @@ import { FieldTextStateless as TextField } from '@atlaskit/field-text';
import { makeStyles } from '@material-ui/core/styles';
import React, { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import { useSelector, useDispatch } from 'react-redux';
import { getFieldValue } from '../../../base/react';
import { escapeRegexp } from '../../../base/util';
import { initSearch } from '../../actions';
import { isSpeakerStatsSearchDisabled } from '../../functions';
const useStyles = makeStyles(() => {
@ -25,33 +27,21 @@ const useStyles = makeStyles(() => {
};
});
/**
* The type of the React {@code Component} props of {@link SpeakerStatsSearch}.
*/
type Props = {
/**
* The function to initiate the change in the speaker stats table.
*/
onSearch: Function,
};
/**
* React component for display an individual user's speaker stats.
*
* @returns {React$Element<any>}
*/
function SpeakerStatsSearch({ onSearch }: Props) {
function SpeakerStatsSearch() {
const classes = useStyles();
const { t } = useTranslation();
const [ searchValue, setSearchValue ] = useState<string>('');
const dispatch = useDispatch();
const onChange = useCallback((evt: Event) => {
const value = getFieldValue(evt);
setSearchValue(value);
onSearch && onSearch(value);
dispatch(initSearch(escapeRegexp(value)));
}, []);
const disableSpeakerStatsSearch = useSelector(isSpeakerStatsSearchDisabled);
const preventDismiss = useCallback((evt: KeyboardEvent) => {