123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- // @flow
-
- import React, { useCallback, useLayoutEffect, useRef, useState } from 'react';
- import { useTranslation } from 'react-i18next';
- import { useDispatch, useSelector } from 'react-redux';
-
- import { isToolbarButtonEnabled } from '../../base/config/functions.web';
- import { openDialog } from '../../base/dialog';
- import {
- IconCloseCircle,
- IconCrown,
- IconMessage,
- IconMuteEveryoneElse,
- IconVideoOff
- } from '../../base/icons';
- import { isLocalParticipantModerator } from '../../base/participants';
- import { getIsParticipantVideoMuted } from '../../base/tracks';
- import { openChat } from '../../chat/actions';
- import { GrantModeratorDialog, KickRemoteParticipantDialog, MuteEveryoneDialog } from '../../video-menu';
- import MuteRemoteParticipantsVideoDialog from '../../video-menu/components/web/MuteRemoteParticipantsVideoDialog';
- import { getComputedOuterHeight } from '../functions';
-
- import {
- ContextMenu,
- ContextMenuIcon,
- ContextMenuItem,
- ContextMenuItemGroup,
- ignoredChildClassName
- } from './styled';
-
- type Props = {
-
- /**
- * Target elements against which positioning calculations are made
- */
- offsetTarget: HTMLElement,
-
- /**
- * Callback for the mouse entering the component
- */
- onEnter: Function,
-
- /**
- * Callback for the mouse leaving the component
- */
- onLeave: Function,
-
- /**
- * Callback for making a selection in the menu
- */
- onSelect: Function,
-
- /**
- * Participant reference
- */
- participant: Object
- };
-
- export const MeetingParticipantContextMenu = ({
- offsetTarget,
- onEnter,
- onLeave,
- onSelect,
- participant
- }: Props) => {
- const dispatch = useDispatch();
- const containerRef = useRef(null);
- const isLocalModerator = useSelector(isLocalParticipantModerator);
- const isChatButtonEnabled = useSelector(isToolbarButtonEnabled('chat'));
- const isParticipantVideoMuted = useSelector(getIsParticipantVideoMuted(participant));
- const [ isHidden, setIsHidden ] = useState(true);
- const { t } = useTranslation();
-
- useLayoutEffect(() => {
- if (participant
- && containerRef.current
- && offsetTarget?.offsetParent
- && offsetTarget.offsetParent instanceof HTMLElement
- ) {
- const { current: container } = containerRef;
- const { offsetTop, offsetParent: { offsetHeight, scrollTop } } = offsetTarget;
- const outerHeight = getComputedOuterHeight(container);
-
- container.style.top = offsetTop + outerHeight > offsetHeight + scrollTop
- ? offsetTop - outerHeight
- : offsetTop;
-
- setIsHidden(false);
- } else {
- setIsHidden(true);
- }
- }, [ participant, offsetTarget ]);
-
- const grantModerator = useCallback(() => {
- dispatch(openDialog(GrantModeratorDialog, {
- participantID: participant.id
- }));
- }, [ dispatch, participant ]);
-
- const kick = useCallback(() => {
- dispatch(openDialog(KickRemoteParticipantDialog, {
- participantID: participant.id
- }));
- }, [ dispatch, participant ]);
-
- const muteEveryoneElse = useCallback(() => {
- dispatch(openDialog(MuteEveryoneDialog, {
- exclude: [ participant.id ]
- }));
- }, [ dispatch, participant ]);
-
- const muteVideo = useCallback(() => {
- dispatch(openDialog(MuteRemoteParticipantsVideoDialog, {
- participantID: participant.id
- }));
- }, [ dispatch, participant ]);
-
- const sendPrivateMessage = useCallback(() => {
- dispatch(openChat(participant));
- }, [ dispatch, participant ]);
-
- if (!participant) {
- return null;
- }
-
- return (
- <ContextMenu
- className = { ignoredChildClassName }
- innerRef = { containerRef }
- isHidden = { isHidden }
- onClick = { onSelect }
- onMouseEnter = { onEnter }
- onMouseLeave = { onLeave }>
- <ContextMenuItemGroup>
- {isLocalModerator && (
- <ContextMenuItem onClick = { muteEveryoneElse }>
- <ContextMenuIcon src = { IconMuteEveryoneElse } />
- <span>{t('toolbar.accessibilityLabel.muteEveryoneElse')}</span>
- </ContextMenuItem>
- )}
- {isLocalModerator && (isParticipantVideoMuted || (
- <ContextMenuItem onClick = { muteVideo }>
- <ContextMenuIcon src = { IconVideoOff } />
- <span>{t('participantsPane.actions.stopVideo')}</span>
- </ContextMenuItem>
- ))}
- </ContextMenuItemGroup>
- <ContextMenuItemGroup>
- {isLocalModerator && (
- <ContextMenuItem onClick = { grantModerator }>
- <ContextMenuIcon src = { IconCrown } />
- <span>{t('toolbar.accessibilityLabel.grantModerator')}</span>
- </ContextMenuItem>
- )}
- {isLocalModerator && (
- <ContextMenuItem onClick = { kick }>
- <ContextMenuIcon src = { IconCloseCircle } />
- <span>{t('videothumbnail.kick')}</span>
- </ContextMenuItem>
- )}
- {isChatButtonEnabled && (
- <ContextMenuItem onClick = { sendPrivateMessage }>
- <ContextMenuIcon src = { IconMessage } />
- <span>{t('toolbar.accessibilityLabel.privateMessage')}</span>
- </ContextMenuItem>
- )}
- </ContextMenuItemGroup>
- </ContextMenu>
- );
- };
|