refactor(speaker-stats): speaker stats as functional component
This commit is contained in:
parent
e7fc9d9973
commit
aa5506e7a6
|
@ -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;
|
||||
|
|
|
@ -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) => {
|
||||
|
|
Loading…
Reference in New Issue