@azure/communication-react
Version:
React library for building modern communication user experiences utilizing Azure Communication Services
117 lines • 11.1 kB
JavaScript
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { DiagnosticQuality } from '@azure/communication-calling';
import { useId } from '@fluentui/react-hooks';
import { _isInCall } from "../../../../../calling-component-bindings/src";
import { _useContainerHeight, _useContainerWidth, ErrorBar } from "../../../../../react-components/src";
import { VideoTile } from "../../../../../react-components/src";
import React, { useMemo, useRef } from 'react';
import { useCallback } from 'react';
import { useState } from 'react';
import { AvatarPersona } from '../../common/AvatarPersona';
import { useLocale } from '../../localization';
import { CallArrangement } from '../components/CallArrangement';
import { MediaGallery } from '../components/MediaGallery';
import { NetworkReconnectTile } from '../components/NetworkReconnectTile';
import { useHandlers } from '../hooks/useHandlers';
import { usePropsFor } from '../hooks/usePropsFor';
import { useSelector } from '../hooks/useSelector';
import { callStatusSelector } from '../selectors/callStatusSelector';
import { complianceBannerSelector } from '../selectors/complianceBannerSelector';
import { mediaGallerySelector } from '../selectors/mediaGallerySelector';
import { getRemoteParticipantsConnectedSelector } from '../selectors/mediaGallerySelector';
import { mutedNotificationSelector } from '../selectors/mutedNotificationSelector';
import { networkReconnectTileSelector } from '../selectors/networkReconnectTileSelector';
import { reduceCallControlsForMobile } from '../utils';
import { DtmfDialpadPage } from './DtmfDialpadPage';
import { showDtmfDialer } from '../utils/MediaGalleryUtils';
import { getTargetCallees } from '../selectors/baseSelectors';
import { Prompt } from '../components/Prompt';
import { toFlatCommunicationIdentifier } from "../../../../../acs-ui-common/src";
import { mergeStyles, Stack } from '@fluentui/react';
import { isPhoneNumberIdentifier } from '@azure/communication-common';
/**
* @private
*/
export const CallPage = (props) => {
var _a, _b;
const { callInvitationURL, onFetchAvatarPersonaData, onFetchParticipantMenuItems, options, mobileView, galleryLayout = 'floatingLocalVideo', onUserSetGalleryLayoutChange, userSetOverflowGalleryPosition = 'Responsive', onSetUserSetOverflowGalleryPosition, onCloseChatPane, pinnedParticipants = [], setPinnedParticipants, compositeAudioContext, disableAutoShowDtmfDialer = {
dialerBehavior: 'autoShow'
}, latestNotifications, onDismissNotification } = props;
// To use useProps to get these states, we need to create another file wrapping Call,
// It seems unnecessary in this case, so we get the updated states using this approach.
const { callStatus } = useSelector(callStatusSelector);
const mediaGalleryProps = useSelector(mediaGallerySelector);
const mediaGalleryHandlers = useHandlers(MediaGallery);
const complianceBannerProps = useSelector(complianceBannerSelector);
const errorBarProps = usePropsFor(ErrorBar);
const mutedNotificationProps = useSelector(mutedNotificationSelector);
const networkReconnectTileProps = useSelector(networkReconnectTileSelector);
const remoteParticipantsConnected = useSelector(getRemoteParticipantsConnectedSelector);
const callees = useSelector(getTargetCallees);
const renderDtmfDialerFromStart = showDtmfDialer(callees, remoteParticipantsConnected, disableAutoShowDtmfDialer);
const [dtmfDialerPresent, setDtmfDialerPresent] = useState(renderDtmfDialerFromStart);
const isPstnCall = callees === null || callees === void 0 ? void 0 : callees.some(callee => isPhoneNumberIdentifier(callee));
const isCTECall = useSelector(state => state.userId.kind === 'microsoftTeamsUser');
const containerRef = useRef(null);
const containerWidth = _useContainerWidth(containerRef);
const containerHeight = _useContainerHeight(containerRef);
const containerAspectRatio = containerWidth && containerHeight ? containerWidth / containerHeight : 0;
const strings = useLocale().strings.call;
const pinnedParticipantsChecked = useMemo(() => pinnedParticipants.filter(pinnedParticipant => remoteParticipantsConnected.find(remoteParticipant => toFlatCommunicationIdentifier(remoteParticipant.identifier) === pinnedParticipant)), [pinnedParticipants, remoteParticipantsConnected]);
// Reduce the controls shown when mobile view is enabled.
const callControlOptions = mobileView ? reduceCallControlsForMobile(options === null || options === void 0 ? void 0 : options.callControls) : options === null || options === void 0 ? void 0 : options.callControls;
const drawerMenuHostId = useId('drawerMenuHost');
const [isPromptOpen, setIsPromptOpen] = useState(false);
const [promptProps, setPromptProps] = useState();
const page = useSelector(state => state.page);
const userId = useSelector(state => state.userId);
const displayName = useSelector(state => state.displayName);
const onRenderAvatar = useCallback((userId, options) => {
return React.createElement(Stack, { className: mergeStyles({
position: 'absolute',
height: '100%',
width: '100%'
}) },
React.createElement(Stack, { styles: {
root: {
margin: 'auto',
maxHeight: '100%'
}
} }, (options === null || options === void 0 ? void 0 : options.coinSize) && React.createElement(AvatarPersona, Object.assign({ userId: userId }, options, { dataProvider: props.onFetchAvatarPersonaData }))));
}, [props.onFetchAvatarPersonaData]);
let galleryContentWhenNotInCall = React.createElement(React.Fragment, null);
if (!_isInCall(callStatus) && page === 'returningFromBreakoutRoom') {
galleryContentWhenNotInCall = React.createElement(VideoTile, { userId: toFlatCommunicationIdentifier(userId), displayName: displayName, initialsName: displayName, onRenderPlaceholder: onRenderAvatar });
}
const onRenderGalleryContentTrampoline = () => {
var _a, _b;
if (dtmfDialerPresent) {
return React.createElement(DtmfDialpadPage, { mobileView: props.mobileView, modalLayerHostId: props.modalLayerHostId, options: props.options, updateSidePaneRenderer: props.updateSidePaneRenderer, mobileChatTabHeader: props.mobileChatTabHeader, latestErrors: props.latestErrors, onDismissError: props.onDismissError, capabilitiesChangedNotificationBarProps: props.capabilitiesChangedNotificationBarProps, onSetDialpadPage: () => setDtmfDialerPresent(!dtmfDialerPresent), dtmfDialerPresent: dtmfDialerPresent, compositeAudioContext: compositeAudioContext });
}
else {
return React.createElement(MediaGallery, Object.assign({ isMobile: mobileView }, mediaGalleryProps, mediaGalleryHandlers, { onFetchAvatarPersonaData: onFetchAvatarPersonaData, remoteVideoTileMenuOptions: options === null || options === void 0 ? void 0 : options.remoteVideoTileMenuOptions, drawerMenuHostId: drawerMenuHostId, localVideoTileOptions: options === null || options === void 0 ? void 0 : options.localVideoTile, userSetOverflowGalleryPosition: userSetOverflowGalleryPosition, userSetGalleryLayout: galleryLayout, pinnedParticipants: pinnedParticipantsChecked, setPinnedParticipants: setPinnedParticipants, setIsPromptOpen: setIsPromptOpen, setPromptProps: setPromptProps, hideSpotlightButtons: (_a = options === null || options === void 0 ? void 0 : options.spotlight) === null || _a === void 0 ? void 0 : _a.hideSpotlightButtons, videoTilesOptions: options === null || options === void 0 ? void 0 : options.videoTilesOptions, captionsOptions: options === null || options === void 0 ? void 0 : options.captionsBanner, localScreenShareView: (_b = options === null || options === void 0 ? void 0 : options.galleryOptions) === null || _b === void 0 ? void 0 : _b.localScreenShareView, compositeContainerAspectRatio: containerAspectRatio }));
}
};
return React.createElement("div", { ref: containerRef, style: {
height: '100%',
width: '100%'
} },
React.createElement(CallArrangement, { id: drawerMenuHostId, complianceBannerProps: Object.assign(Object.assign({}, complianceBannerProps), { strings }), errorBarProps: (options === null || options === void 0 ? void 0 : options.errorBar) !== false && errorBarProps, showErrorNotifications: (_a = options === null || options === void 0 ? void 0 : options.errorBar) !== null && _a !== void 0 ? _a : true, mutedNotificationProps: mutedNotificationProps, callControlProps: {
callInvitationURL: callInvitationURL,
onFetchParticipantMenuItems: onFetchParticipantMenuItems,
options: callControlOptions,
increaseFlyoutItemSize: mobileView
}, onFetchAvatarPersonaData: onFetchAvatarPersonaData, mobileView: mobileView, modalLayerHostId: props.modalLayerHostId, onRenderGalleryContent: () => _isInCall(callStatus) ? isNetworkHealthy(networkReconnectTileProps.networkReconnectValue) ? onRenderGalleryContentTrampoline() : React.createElement(NetworkReconnectTile, Object.assign({}, networkReconnectTileProps, { isMobile: mobileView })) : galleryContentWhenNotInCall, updateSidePaneRenderer: props.updateSidePaneRenderer, mobileChatTabHeader: props.mobileChatTabHeader, onCloseChatPane: onCloseChatPane, dataUiId: 'call-page', latestErrors: props.latestErrors, latestNotifications: latestNotifications, onDismissError: props.onDismissError, onDismissNotification: onDismissNotification, onUserSetOverflowGalleryPositionChange: onSetUserSetOverflowGalleryPosition, onUserSetGalleryLayoutChange: onUserSetGalleryLayoutChange, userSetGalleryLayout: galleryLayout, capabilitiesChangedNotificationBarProps: props.capabilitiesChangedNotificationBarProps, onSetDialpadPage: () => setDtmfDialerPresent(!dtmfDialerPresent), dtmfDialerPresent: dtmfDialerPresent, setIsPromptOpen: setIsPromptOpen, setPromptProps: setPromptProps, hideSpotlightButtons: (_b = options === null || options === void 0 ? void 0 : options.spotlight) === null || _b === void 0 ? void 0 : _b.hideSpotlightButtons, pinnedParticipants: pinnedParticipantsChecked, setPinnedParticipants: setPinnedParticipants, captionsOptions: options === null || options === void 0 ? void 0 : options.captionsBanner, dtmfDialerOptions: disableAutoShowDtmfDialer, notificationOptions: props.notificationOptions, isRTTSupportedCall: !isPstnCall && !isCTECall }),
React.createElement(Prompt, Object.assign({ isOpen: isPromptOpen, onDismiss: () => setIsPromptOpen(false) }, promptProps)));
};
/**
* @private
*/
export const isNetworkHealthy = (value) => {
// We know that the value is actually of type DiagnosticQuality for this diagnostic.
// We ignore any boolen values, considering the network to still be healthy.
// Thus, only DiagnosticQuality.Poor or .Bad indicate network problems.
return value === true || value === false || value === undefined || value === DiagnosticQuality.Good;
};
//# sourceMappingURL=CallPage.js.map