2019-11-02 03:29:33 +08:00
|
|
|
import React, { PureComponent } from 'react';
|
2019-11-15 23:54:07 +08:00
|
|
|
import { defineMessages, injectIntl } from 'react-intl';
|
2021-11-03 00:25:39 +08:00
|
|
|
import Styled from './styles';
|
2021-10-08 03:00:39 +08:00
|
|
|
import Service from './service';
|
2023-02-23 22:23:51 +08:00
|
|
|
import { uniqueId } from '/imports/utils/string-utils';
|
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,
|
2021-10-08 03:00:39 +08:00
|
|
|
moreThanMaxIndicators,
|
2022-12-08 03:47:31 +08:00
|
|
|
users,
|
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,
|
2022-04-14 21:59:54 +08:00
|
|
|
transcribing,
|
2022-04-18 21:38:52 +08:00
|
|
|
floor,
|
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
|
|
|
|
2022-12-08 03:47:31 +08:00
|
|
|
const user = users[id];
|
|
|
|
|
|
|
|
const name = user?.name ?? callerName;
|
|
|
|
|
2019-11-23 06:25:05 +08:00
|
|
|
const ariaLabel = intl.formatMessage(talking
|
|
|
|
? intlMessages.isTalking : intlMessages.wasTalking, {
|
2022-12-08 03:47:31 +08:00
|
|
|
0: name,
|
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 (
|
2022-04-14 21:59:54 +08:00
|
|
|
<Styled.TalkingIndicatorWrapper
|
2023-02-23 22:23:51 +08:00
|
|
|
key={uniqueId(`${name}-`)}
|
2022-04-14 21:59:54 +08:00
|
|
|
muted={muted}
|
|
|
|
talking={talking}
|
2022-04-18 21:38:52 +08:00
|
|
|
floor={floor}
|
2019-11-02 03:29:33 +08:00
|
|
|
>
|
2022-04-14 21:59:54 +08:00
|
|
|
{transcribing && (
|
|
|
|
<Styled.CCIcon
|
|
|
|
iconName={muted ? 'closed_caption_stop' : 'closed_caption'}
|
|
|
|
muted={muted}
|
|
|
|
talking={talking}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
<Styled.TalkingIndicatorButton
|
|
|
|
$spoke={!talking || undefined}
|
|
|
|
$muted={muted}
|
|
|
|
$isViewer={!amIModerator || undefined}
|
2023-02-23 22:23:51 +08:00
|
|
|
key={uniqueId(`${name}-`)}
|
2022-04-14 21:59:54 +08:00
|
|
|
onClick={() => this.handleMuteUser(id)}
|
2022-12-08 03:47:31 +08:00
|
|
|
label={name}
|
2022-04-14 21:59:54 +08:00
|
|
|
tooltipLabel={!muted && amIModerator
|
2022-12-08 03:47:31 +08:00
|
|
|
? `${intl.formatMessage(intlMessages.muteLabel)} ${name}`
|
2022-04-14 21:59:54 +08:00
|
|
|
: null}
|
|
|
|
data-test={talking ? 'isTalking' : 'wasTalking'}
|
|
|
|
aria-label={ariaLabel}
|
|
|
|
aria-describedby={talking ? 'description' : null}
|
|
|
|
color="primary"
|
|
|
|
icon={icon}
|
|
|
|
size="lg"
|
|
|
|
style={{
|
|
|
|
backgroundColor: color,
|
|
|
|
border: `solid 2px ${color}`,
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{talking ? (
|
|
|
|
<Styled.Hidden id="description">
|
|
|
|
{`${intl.formatMessage(intlMessages.ariaMuteDesc)}`}
|
|
|
|
</Styled.Hidden>
|
|
|
|
) : null}
|
|
|
|
</Styled.TalkingIndicatorButton>
|
|
|
|
</Styled.TalkingIndicatorWrapper>
|
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
|
|
|
|
|
|
|
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 (
|
2021-11-03 00:25:39 +08:00
|
|
|
<Styled.TalkingIndicatorButton
|
2022-06-30 01:15:42 +08:00
|
|
|
$spoke={nobodyTalking}
|
|
|
|
$muted={false}
|
|
|
|
$isViewer={false}
|
2023-02-23 22:23:51 +08:00
|
|
|
key={uniqueId('_has__More_')}
|
2021-10-08 03:00:39 +08:00
|
|
|
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 (
|
2022-02-09 23:52:42 +08:00
|
|
|
<Styled.IsTalkingWrapper data-test="talkingIndicator">
|
2021-11-03 00:25:39 +08:00
|
|
|
<Styled.Speaking>
|
2019-11-02 03:29:33 +08:00
|
|
|
{talkingUserElements}
|
2021-10-08 03:00:39 +08:00
|
|
|
{maxIndicator()}
|
2021-11-03 00:25:39 +08:00
|
|
|
</Styled.Speaking>
|
|
|
|
</Styled.IsTalkingWrapper>
|
2019-11-02 03:29:33 +08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-15 23:54:07 +08:00
|
|
|
export default injectIntl(TalkingIndicator);
|