2021-04-21 13:48:05 +00:00
|
|
|
// @flow
|
|
|
|
|
|
|
|
import React from 'react';
|
|
|
|
|
2021-08-04 08:51:05 +00:00
|
|
|
import {
|
|
|
|
getLocalParticipant,
|
|
|
|
getParticipantByIdOrUndefined,
|
|
|
|
getParticipantDisplayName
|
|
|
|
} from '../../../base/participants';
|
2021-07-12 15:14:38 +00:00
|
|
|
import { connect } from '../../../base/redux';
|
|
|
|
import { isParticipantAudioMuted, isParticipantVideoMuted } from '../../../base/tracks';
|
|
|
|
import { ACTION_TRIGGER, MEDIA_STATE, type MediaState } from '../../constants';
|
|
|
|
import { getParticipantAudioMediaState, getQuickActionButtonType } from '../../functions';
|
|
|
|
import ParticipantQuickAction from '../ParticipantQuickAction';
|
2021-04-21 13:48:05 +00:00
|
|
|
|
2021-07-09 12:36:19 +00:00
|
|
|
import ParticipantItem from './ParticipantItem';
|
2021-04-21 13:48:05 +00:00
|
|
|
import { ParticipantActionEllipsis } from './styled';
|
|
|
|
|
|
|
|
type Props = {
|
|
|
|
|
2021-07-09 12:36:19 +00:00
|
|
|
/**
|
|
|
|
* Media state for audio.
|
|
|
|
*/
|
|
|
|
_audioMediaState: MediaState,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The display name of the participant.
|
|
|
|
*/
|
|
|
|
_displayName: string,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* True if the participant is video muted.
|
|
|
|
*/
|
|
|
|
_isVideoMuted: boolean,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* True if the participant is the local participant.
|
|
|
|
*/
|
|
|
|
_local: boolean,
|
|
|
|
|
2021-08-04 08:51:05 +00:00
|
|
|
/**
|
|
|
|
* Shared video local participant owner.
|
|
|
|
*/
|
|
|
|
_localVideoOwner: boolean,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The participant.
|
|
|
|
*/
|
|
|
|
_participant: Object,
|
|
|
|
|
2021-07-09 12:36:19 +00:00
|
|
|
/**
|
|
|
|
* The participant ID.
|
|
|
|
*
|
|
|
|
* NOTE: This ID may be different from participantID prop in the case when we pass undefined for the local
|
|
|
|
* participant. In this case the local participant ID will be filled trough _participantID prop.
|
|
|
|
*/
|
|
|
|
_participantID: string,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The type of button to be rendered for the quick action.
|
|
|
|
*/
|
|
|
|
_quickActionButtonType: string,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* True if the participant have raised hand.
|
|
|
|
*/
|
|
|
|
_raisedHand: boolean,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The translated ask unmute text for the qiuck action buttons.
|
|
|
|
*/
|
|
|
|
askUnmuteText: string,
|
|
|
|
|
2021-04-21 13:48:05 +00:00
|
|
|
/**
|
|
|
|
* Is this item highlighted
|
|
|
|
*/
|
|
|
|
isHighlighted: boolean,
|
|
|
|
|
2021-06-23 11:23:44 +00:00
|
|
|
/**
|
|
|
|
* Callback used to open a confirmation dialog for audio muting.
|
|
|
|
*/
|
|
|
|
muteAudio: Function,
|
|
|
|
|
2021-07-09 12:36:19 +00:00
|
|
|
/**
|
|
|
|
* The translated text for the mute participant button.
|
|
|
|
*/
|
|
|
|
muteParticipantButtonText: string,
|
|
|
|
|
2021-04-21 13:48:05 +00:00
|
|
|
/**
|
|
|
|
* Callback for the activation of this item's context menu
|
|
|
|
*/
|
|
|
|
onContextMenu: Function,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Callback for the mouse leaving this item
|
|
|
|
*/
|
|
|
|
onLeave: Function,
|
|
|
|
|
|
|
|
/**
|
2021-07-09 12:36:19 +00:00
|
|
|
* The aria-label for the ellipsis action.
|
|
|
|
*/
|
|
|
|
participantActionEllipsisLabel: string,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The ID of the participant.
|
2021-04-21 13:48:05 +00:00
|
|
|
*/
|
2021-07-09 12:36:19 +00:00
|
|
|
participantID: ?string,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The translated "you" text.
|
|
|
|
*/
|
|
|
|
youText: string
|
2021-04-21 13:48:05 +00:00
|
|
|
};
|
|
|
|
|
2021-07-09 12:36:19 +00:00
|
|
|
/**
|
|
|
|
* Implements the MeetingParticipantItem component.
|
|
|
|
*
|
|
|
|
* @param {Props} props - The props of the component.
|
|
|
|
* @returns {ReactElement}
|
|
|
|
*/
|
|
|
|
function MeetingParticipantItem({
|
|
|
|
_audioMediaState,
|
|
|
|
_displayName,
|
|
|
|
_isVideoMuted,
|
2021-08-04 08:51:05 +00:00
|
|
|
_localVideoOwner,
|
2021-07-09 12:36:19 +00:00
|
|
|
_local,
|
2021-08-04 08:51:05 +00:00
|
|
|
_participant,
|
2021-07-09 12:36:19 +00:00
|
|
|
_participantID,
|
|
|
|
_quickActionButtonType,
|
|
|
|
_raisedHand,
|
|
|
|
askUnmuteText,
|
2021-04-21 13:48:05 +00:00
|
|
|
isHighlighted,
|
|
|
|
onContextMenu,
|
|
|
|
onLeave,
|
2021-06-23 11:23:44 +00:00
|
|
|
muteAudio,
|
2021-07-09 12:36:19 +00:00
|
|
|
muteParticipantButtonText,
|
|
|
|
participantActionEllipsisLabel,
|
|
|
|
youText
|
|
|
|
}: Props) {
|
2021-04-21 13:48:05 +00:00
|
|
|
return (
|
|
|
|
<ParticipantItem
|
2021-06-23 11:23:44 +00:00
|
|
|
actionsTrigger = { ACTION_TRIGGER.HOVER }
|
2021-07-09 12:36:19 +00:00
|
|
|
audioMediaState = { _audioMediaState }
|
|
|
|
displayName = { _displayName }
|
2021-04-21 13:48:05 +00:00
|
|
|
isHighlighted = { isHighlighted }
|
2021-07-09 12:36:19 +00:00
|
|
|
local = { _local }
|
2021-04-21 13:48:05 +00:00
|
|
|
onLeave = { onLeave }
|
2021-07-09 12:36:19 +00:00
|
|
|
participantID = { _participantID }
|
|
|
|
raisedHand = { _raisedHand }
|
|
|
|
videoMuteState = { _isVideoMuted ? MEDIA_STATE.MUTED : MEDIA_STATE.UNMUTED }
|
|
|
|
youText = { youText }>
|
2021-08-04 08:51:05 +00:00
|
|
|
{
|
|
|
|
!_participant.isFakeParticipant && (
|
|
|
|
<>
|
|
|
|
<ParticipantQuickAction
|
|
|
|
askUnmuteText = { askUnmuteText }
|
|
|
|
buttonType = { _quickActionButtonType }
|
|
|
|
muteAudio = { muteAudio }
|
|
|
|
muteParticipantButtonText = { muteParticipantButtonText }
|
|
|
|
participantID = { _participantID } />
|
|
|
|
<ParticipantActionEllipsis
|
|
|
|
aria-label = { participantActionEllipsisLabel }
|
|
|
|
onClick = { onContextMenu } />
|
|
|
|
</>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
{
|
|
|
|
_participant.isFakeParticipant && _localVideoOwner && (
|
|
|
|
<ParticipantActionEllipsis
|
|
|
|
aria-label = { participantActionEllipsisLabel }
|
|
|
|
onClick = { onContextMenu } />
|
|
|
|
)
|
|
|
|
}
|
2021-04-21 13:48:05 +00:00
|
|
|
</ParticipantItem>
|
|
|
|
);
|
2021-07-09 12:36:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Maps (parts of) the redux state to the associated props for this component.
|
|
|
|
*
|
|
|
|
* @param {Object} state - The Redux state.
|
|
|
|
* @param {Object} ownProps - The own props of the component.
|
|
|
|
* @private
|
|
|
|
* @returns {Props}
|
|
|
|
*/
|
|
|
|
function _mapStateToProps(state, ownProps): Object {
|
|
|
|
const { participantID } = ownProps;
|
2021-08-04 08:51:05 +00:00
|
|
|
const { ownerId } = state['features/shared-video'];
|
|
|
|
const localParticipantId = getLocalParticipant(state).id;
|
2021-07-09 12:36:19 +00:00
|
|
|
|
|
|
|
const participant = getParticipantByIdOrUndefined(state, participantID);
|
|
|
|
|
|
|
|
const _isAudioMuted = isParticipantAudioMuted(participant, state);
|
|
|
|
const _isVideoMuted = isParticipantVideoMuted(participant, state);
|
|
|
|
const _audioMediaState = getParticipantAudioMediaState(participant, _isAudioMuted, state);
|
|
|
|
const _quickActionButtonType = getQuickActionButtonType(participant, _isAudioMuted, state);
|
|
|
|
|
|
|
|
return {
|
|
|
|
_audioMediaState,
|
|
|
|
_displayName: getParticipantDisplayName(state, participant?.id),
|
|
|
|
_isAudioMuted,
|
|
|
|
_isVideoMuted,
|
|
|
|
_local: Boolean(participant?.local),
|
2021-08-04 08:51:05 +00:00
|
|
|
_localVideoOwner: Boolean(ownerId === localParticipantId),
|
|
|
|
_participant: participant,
|
2021-07-09 12:36:19 +00:00
|
|
|
_participantID: participant?.id,
|
|
|
|
_quickActionButtonType,
|
|
|
|
_raisedHand: Boolean(participant?.raisedHand)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export default connect(_mapStateToProps)(MeetingParticipantItem);
|