/* eslint-disable lines-around-comment */ import { Theme } from '@mui/material'; import React, { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { useDispatch, useSelector } from 'react-redux'; import { makeStyles } from 'tss-react/mui'; import { IState } from '../../../app/types'; // @ts-ignore import { isSupported as isAvModerationSupported } from '../../../av-moderation/functions'; // @ts-ignore import { Avatar } from '../../../base/avatar'; import ContextMenu from '../../../base/components/context-menu/ContextMenu'; import ContextMenuItemGroup from '../../../base/components/context-menu/ContextMenuItemGroup'; import { isIosMobileBrowser, isMobileBrowser } from '../../../base/environment/utils'; import { IconShareVideo } from '../../../base/icons/svg'; import { MEDIA_TYPE } from '../../../base/media/constants'; import { PARTICIPANT_ROLE } from '../../../base/participants/constants'; import { getLocalParticipant } from '../../../base/participants/functions'; import { Participant } from '../../../base/participants/types'; // @ts-ignore import { isParticipantAudioMuted } from '../../../base/tracks'; // @ts-ignore import { getBreakoutRooms, getCurrentRoomId, isInBreakoutRoom } from '../../../breakout-rooms/functions'; // @ts-ignore import { setVolume } from '../../../filmstrip/actions.web'; // @ts-ignore import { isStageFilmstripAvailable } from '../../../filmstrip/functions.web'; // @ts-ignore import { isForceMuted } from '../../../participants-pane/functions'; // @ts-ignore import { requestRemoteControl, stopController } from '../../../remote-control'; // @ts-ignore import { stopSharedVideo } from '../../../shared-video/actions.any'; // @ts-ignore import { showOverflowDrawer } from '../../../toolbox/functions.web'; // @ts-ignore import { REMOTE_CONTROL_MENU_STATES } from './RemoteControlButton'; // @ts-ignore import SendToRoomButton from './SendToRoomButton'; import { AskToUnmuteButton, ConnectionStatusButton, GrantModeratorButton, MuteButton, MuteEveryoneElseButton, MuteEveryoneElsesVideoButton, MuteVideoButton, KickButton, PrivateMessageMenuButton, RemoteControlButton, TogglePinToStageButton, VolumeSlider // @ts-ignore } from './'; type Props = { /** * Class name for the context menu. */ className?: string; /** * Closes a drawer if open. */ closeDrawer?: () => void; /** * The participant for which the drawer is open. * It contains the displayName & participantID. */ drawerParticipant?: { displayName: string; participantID: string; }; /** * Shared video local participant owner. */ localVideoOwner?: boolean; /** * Target elements against which positioning calculations are made. */ offsetTarget?: HTMLElement; /** * Callback for the mouse entering the component. */ onEnter?: (e?: React.MouseEvent) => void; /** * Callback for the mouse leaving the component. */ onLeave?: (e?: React.MouseEvent) => void; /** * Callback for making a selection in the menu. */ onSelect: (value?: boolean | React.MouseEvent) => void; /** * Participant reference. */ participant: Participant; /** * The current state of the participant's remote control session. */ remoteControlState?: number; /** * Whether or not the menu is displayed in the thumbnail remote video menu. */ thumbnailMenu?: boolean; }; const useStyles = makeStyles()((theme: Theme) => { return { text: { color: theme.palette.text02, padding: '10px 16px', height: '40px', overflow: 'hidden', display: 'flex', alignItems: 'center', boxSizing: 'border-box' } }; }); const ParticipantContextMenu = ({ className, closeDrawer, drawerParticipant, localVideoOwner, offsetTarget, onEnter, onLeave, onSelect, participant, remoteControlState, thumbnailMenu }: Props) => { const dispatch = useDispatch(); const { t } = useTranslation(); const { classes: styles } = useStyles(); const localParticipant = useSelector(getLocalParticipant); const _isModerator = Boolean(localParticipant?.role === PARTICIPANT_ROLE.MODERATOR); const _isAudioForceMuted = useSelector(state => isForceMuted(participant, MEDIA_TYPE.AUDIO, state)); const _isVideoForceMuted = useSelector(state => isForceMuted(participant, MEDIA_TYPE.VIDEO, state)); const _isAudioMuted = useSelector(state => isParticipantAudioMuted(participant, state)); const _overflowDrawer: boolean = useSelector(showOverflowDrawer); const { remoteVideoMenu = {}, disableRemoteMute, startSilent } = useSelector((state: IState) => state['features/base/config']); const { disableKick, disableGrantModerator, disablePrivateChat } = remoteVideoMenu; const { participantsVolume } = useSelector((state: IState) => state['features/filmstrip']); const _volume = (participant?.local ?? true ? undefined : participant?.id ? participantsVolume[participant?.id] : undefined) ?? 1; const isBreakoutRoom = useSelector(isInBreakoutRoom); const isModerationSupported = useSelector(isAvModerationSupported); const stageFilmstrip = useSelector(isStageFilmstripAvailable); const _currentRoomId = useSelector(getCurrentRoomId); const _rooms: Array<{ id: string; }> = Object.values(useSelector(getBreakoutRooms)); const _onVolumeChange = useCallback(value => { dispatch(setVolume(participant.id, value)); }, [ setVolume, dispatch ]); const clickHandler = useCallback(() => onSelect(true), [ onSelect ]); const _onStopSharedVideo = useCallback(() => { clickHandler(); dispatch(stopSharedVideo()); }, [ stopSharedVideo ]); const _getCurrentParticipantId = useCallback(() => { const drawer = _overflowDrawer && !thumbnailMenu; return (drawer ? drawerParticipant?.participantID : participant?.id) ?? ''; } , [ thumbnailMenu, _overflowDrawer, drawerParticipant, participant ]); const buttons = []; const buttons2 = []; const showVolumeSlider = !startSilent && !isIosMobileBrowser() && (_overflowDrawer || thumbnailMenu) && typeof _volume === 'number' && !isNaN(_volume); const fakeParticipantActions = [ { accessibilityLabel: t('toolbar.stopSharedVideo'), icon: IconShareVideo, onClick: _onStopSharedVideo, text: t('toolbar.stopSharedVideo') } ]; if (_isModerator) { if ((thumbnailMenu || _overflowDrawer) && isModerationSupported && _isAudioMuted) { buttons.push( ); } if (!disableRemoteMute) { buttons.push( ); buttons.push( ); buttons.push( ); buttons.push( ); } if (!disableGrantModerator && !isBreakoutRoom) { buttons2.push( ); } if (!disableKick) { buttons2.push( ); } } if (stageFilmstrip) { buttons2.push(); } if (!disablePrivateChat) { buttons2.push( ); } if (thumbnailMenu && isMobileBrowser()) { buttons2.push( ); } if (thumbnailMenu && remoteControlState) { let onRemoteControlToggle = null; if (remoteControlState === REMOTE_CONTROL_MENU_STATES.STARTED) { onRemoteControlToggle = () => dispatch(stopController(true)); } else if (remoteControlState === REMOTE_CONTROL_MENU_STATES.NOT_STARTED) { onRemoteControlToggle = () => dispatch(requestRemoteControl(_getCurrentParticipantId())); } buttons2.push( ); } const breakoutRoomsButtons: any = []; if (!thumbnailMenu && _isModerator) { _rooms.forEach(room => { if (room.id !== _currentRoomId) { breakoutRoomsButtons.push( ); } }); } return ( ); }; export default ParticipantContextMenu;