2019-11-02 03:29:33 +08:00
|
|
|
import React, { PureComponent } from 'react';
|
|
|
|
import cx from 'classnames';
|
|
|
|
import _ from 'lodash';
|
2019-11-15 23:54:07 +08:00
|
|
|
import { defineMessages, injectIntl } from 'react-intl';
|
2019-11-23 06:25:05 +08:00
|
|
|
import Button from '/imports/ui/components/button/component';
|
2019-11-02 03:29:33 +08:00
|
|
|
import { styles } from './styles';
|
2021-10-08 03:00:39 +08:00
|
|
|
import Service from './service';
|
2019-11-02 03:29:33 +08:00
|
|
|
|
2019-11-15 23:54:07 +08:00
|
|
|
const intlMessages = defineMessages({
|
|
|
|
wasTalking: {
|
|
|
|
id: 'app.talkingIndicator.wasTalking',
|
|
|
|
description: 'aria label for user who is not talking but still visible',
|
|
|
|
},
|
|
|
|
isTalking: {
|
|
|
|
id: 'app.talkingIndicator.isTalking',
|
|
|
|
description: 'aria label for user currently talking',
|
|
|
|
},
|
|
|
|
ariaMuteDesc: {
|
|
|
|
id: 'app.talkingIndicator.ariaMuteDesc',
|
|
|
|
description: 'aria description for muting a user',
|
|
|
|
},
|
2019-12-04 02:49:09 +08:00
|
|
|
muteLabel: {
|
|
|
|
id: 'app.actionsBar.muteLabel',
|
|
|
|
description: 'indicator mute label for moderators',
|
|
|
|
},
|
2021-10-08 22:13:37 +08:00
|
|
|
moreThanMaxIndicatorsTalking: {
|
|
|
|
id: 'app.talkingIndicator.moreThanMaxIndicatorsTalking',
|
|
|
|
description: 'indicator label for all users who is talking but not visible',
|
|
|
|
},
|
|
|
|
moreThanMaxIndicatorsWereTalking: {
|
|
|
|
id: 'app.talkingIndicator.moreThanMaxIndicatorsWereTalking',
|
|
|
|
description: 'indicator label for all users who is not talking but not visible',
|
2021-10-08 03:00:39 +08:00
|
|
|
},
|
2019-11-15 23:54:07 +08:00
|
|
|
});
|
|
|
|
|
2019-11-02 03:29:33 +08:00
|
|
|
class TalkingIndicator extends PureComponent {
|
2019-11-15 23:54:07 +08:00
|
|
|
handleMuteUser(id) {
|
2020-11-20 03:12:05 +08:00
|
|
|
const { muteUser, amIModerator, isBreakoutRoom } = this.props;
|
|
|
|
// only allow moderator muting anyone in non-breakout
|
|
|
|
if (!amIModerator || isBreakoutRoom) return;
|
2019-11-15 23:54:07 +08:00
|
|
|
muteUser(id);
|
|
|
|
}
|
|
|
|
|
2019-11-02 03:29:33 +08:00
|
|
|
render() {
|
2019-12-04 02:49:09 +08:00
|
|
|
const {
|
2021-05-18 04:25:07 +08:00
|
|
|
intl,
|
|
|
|
talkers,
|
|
|
|
amIModerator,
|
|
|
|
sidebarNavigationIsOpen,
|
|
|
|
sidebarContentIsOpen,
|
2021-10-08 03:00:39 +08:00
|
|
|
moreThanMaxIndicators,
|
2019-12-04 02:49:09 +08:00
|
|
|
} = this.props;
|
2019-11-02 03:29:33 +08:00
|
|
|
if (!talkers) return null;
|
|
|
|
|
2019-11-27 00:44:58 +08:00
|
|
|
const talkingUserElements = Object.keys(talkers).map((id) => {
|
2019-11-02 03:29:33 +08:00
|
|
|
const {
|
|
|
|
talking,
|
|
|
|
color,
|
2019-11-14 01:56:26 +08:00
|
|
|
muted,
|
2019-11-27 00:44:58 +08:00
|
|
|
callerName,
|
|
|
|
} = talkers[`${id}`];
|
2019-11-02 03:29:33 +08:00
|
|
|
|
|
|
|
const style = {
|
|
|
|
[styles.talker]: true,
|
|
|
|
[styles.spoke]: !talking,
|
2019-11-14 01:56:26 +08:00
|
|
|
[styles.muted]: muted,
|
2021-05-18 04:25:07 +08:00
|
|
|
[styles.mobileHide]: sidebarNavigationIsOpen
|
|
|
|
&& sidebarContentIsOpen,
|
2019-12-04 02:49:09 +08:00
|
|
|
[styles.isViewer]: !amIModerator,
|
2019-11-02 03:29:33 +08:00
|
|
|
};
|
|
|
|
|
2019-11-23 06:25:05 +08:00
|
|
|
const ariaLabel = intl.formatMessage(talking
|
|
|
|
? intlMessages.isTalking : intlMessages.wasTalking, {
|
2019-11-27 00:44:58 +08:00
|
|
|
0: callerName,
|
2019-11-15 23:54:07 +08:00
|
|
|
});
|
|
|
|
|
2019-11-23 06:25:05 +08:00
|
|
|
let icon = talking ? 'unmute' : 'blank';
|
|
|
|
icon = muted ? 'mute' : icon;
|
|
|
|
|
2019-11-02 03:29:33 +08:00
|
|
|
return (
|
2019-11-23 06:25:05 +08:00
|
|
|
<Button
|
2019-11-27 00:44:58 +08:00
|
|
|
key={_.uniqueId(`${callerName}-`)}
|
2019-11-02 03:29:33 +08:00
|
|
|
className={cx(style)}
|
2021-10-22 20:13:33 +08:00
|
|
|
onClick={() => this.handleMuteUser(id)}
|
2019-11-27 00:44:58 +08:00
|
|
|
label={callerName}
|
2019-12-04 02:49:09 +08:00
|
|
|
tooltipLabel={!muted && amIModerator
|
|
|
|
? `${intl.formatMessage(intlMessages.muteLabel)} ${callerName}`
|
2021-10-08 03:00:39 +08:00
|
|
|
: null}
|
2020-03-04 22:50:56 +08:00
|
|
|
data-test={talking ? 'isTalking' : 'wasTalking'}
|
2019-11-15 23:54:07 +08:00
|
|
|
aria-label={ariaLabel}
|
|
|
|
aria-describedby={talking ? 'description' : null}
|
2019-11-23 06:25:05 +08:00
|
|
|
color="primary"
|
|
|
|
icon={icon}
|
|
|
|
size="sm"
|
2019-11-02 03:29:33 +08:00
|
|
|
style={{
|
|
|
|
backgroundColor: color,
|
2019-11-23 06:25:05 +08:00
|
|
|
border: `solid 2px ${color}`,
|
2019-11-02 03:29:33 +08:00
|
|
|
}}
|
|
|
|
>
|
2019-11-23 06:25:05 +08:00
|
|
|
{talking ? (
|
|
|
|
<div id="description" className={styles.hidden}>
|
|
|
|
{`${intl.formatMessage(intlMessages.ariaMuteDesc)}`}
|
|
|
|
</div>
|
2021-10-08 03:00:39 +08:00
|
|
|
) : null}
|
2019-11-23 06:25:05 +08:00
|
|
|
</Button>
|
2019-11-02 03:29:33 +08:00
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2021-10-08 03:00:39 +08:00
|
|
|
const maxIndicator = () => {
|
|
|
|
if (!moreThanMaxIndicators) return null;
|
|
|
|
|
2021-10-08 22:57:26 +08:00
|
|
|
const nobodyTalking = Service.nobodyTalking(talkers);
|
2021-10-08 22:13:37 +08:00
|
|
|
|
2021-10-08 03:00:39 +08:00
|
|
|
const style = {
|
|
|
|
[styles.talker]: true,
|
2021-10-08 22:57:26 +08:00
|
|
|
[styles.spoke]: nobodyTalking,
|
|
|
|
// [styles.muted]: false,
|
2021-10-08 03:00:39 +08:00
|
|
|
[styles.mobileHide]: sidebarNavigationIsOpen
|
|
|
|
&& sidebarContentIsOpen,
|
|
|
|
};
|
|
|
|
|
2021-10-08 22:13:37 +08:00
|
|
|
const { moreThanMaxIndicatorsTalking, moreThanMaxIndicatorsWereTalking } = intlMessages;
|
|
|
|
|
2021-10-08 22:57:26 +08:00
|
|
|
const ariaLabel = intl.formatMessage(nobodyTalking
|
2021-10-08 22:13:37 +08:00
|
|
|
? moreThanMaxIndicatorsWereTalking : moreThanMaxIndicatorsTalking, {
|
2021-10-08 03:00:39 +08:00
|
|
|
0: Object.keys(talkers).length,
|
|
|
|
});
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Button
|
|
|
|
key={_.uniqueId('_has__More_')}
|
|
|
|
className={cx(style)}
|
|
|
|
onClick={() => {}} // maybe add a dropdown to show the rest of the users
|
|
|
|
label="..."
|
|
|
|
tooltipLabel={ariaLabel}
|
|
|
|
aria-label={ariaLabel}
|
|
|
|
color="primary"
|
|
|
|
size="sm"
|
|
|
|
style={{
|
|
|
|
backgroundColor: '#4a148c',
|
|
|
|
border: 'solid 2px #4a148c',
|
|
|
|
cursor: 'default',
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2019-11-02 03:29:33 +08:00
|
|
|
return (
|
|
|
|
<div className={styles.isTalkingWrapper}>
|
|
|
|
<div className={styles.speaking}>
|
|
|
|
{talkingUserElements}
|
2021-10-08 03:00:39 +08:00
|
|
|
{maxIndicator()}
|
2019-11-02 03:29:33 +08:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-15 23:54:07 +08:00
|
|
|
export default injectIntl(TalkingIndicator);
|