communication-react-19
Version:
React library for building modern communication user experiences utilizing Azure Communication Services (React 19 compatible fork)
161 lines • 9.33 kB
JavaScript
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { toFlatCommunicationIdentifier, _formatString } from "../../../../../acs-ui-common/src";
import { useMemo, useRef, useState } from 'react';
import { useLocale } from '../../localization';
import { useSelector } from '../hooks/useSelector';
import { getRemoteParticipantsConnectedSelector } from '../selectors/mediaGallerySelector';
import { isMicrosoftTeamsAppIdentifier, isPhoneNumberIdentifier } from '@azure/communication-common';
/**
* sets the announcement string whenever a Participant comes or goes from a call to be
* used by the system narrator.
*
* @returns string to be used by the narrator and Announcer component
*
* @internal
*/
export const useParticipantChangedAnnouncement = () => {
const locale = useLocale().strings.call;
const strings = useMemo(() => {
return {
participantJoinedNoticeString: locale.participantJoinedNoticeString,
twoParticipantJoinedNoticeString: locale.twoParticipantJoinedNoticeString,
threeParticipantJoinedNoticeString: locale.threeParticipantJoinedNoticeString,
participantLeftNoticeString: locale.participantLeftNoticeString,
twoParticipantLeftNoticeString: locale.twoParticipantLeftNoticeString,
threeParticipantLeftNoticeString: locale.threeParticipantLeftNoticeString,
unnamedParticipantString: locale.unnamedParticipantString,
manyParticipantsJoined: locale.manyParticipantsJoined,
manyParticipantsLeft: locale.manyParticipantsLeft,
manyUnnamedParticipantsJoined: locale.manyUnnamedParticipantsJoined,
manyUnnamedParticipantsLeft: locale.manyUnnamedParticipantsLeft
};
}, [locale]);
const [announcerString, setAnnouncerString] = useState('');
const currentParticipants = useSelector(getRemoteParticipantsConnectedSelector);
/**
* We want to use a useRef here since we want to not fire this hook based on the previous participants
* this allows this value to be used in the hook without being in the dependency array.
*
* Note: By definition if this hook is used in another component it is not pure anymore.
*/
const previousParticipants = useRef(currentParticipants);
const resetAnnoucement = (string) => {
setAnnouncerString(string);
};
useMemo(() => {
const currentIds = currentParticipants.map((p) => toFlatCommunicationIdentifier(p.identifier));
const previousIds = previousParticipants.current.map((p) => toFlatCommunicationIdentifier(p.identifier));
const whoJoined = currentParticipants.filter((p) => !previousIds.includes(toFlatCommunicationIdentifier(p.identifier)));
const whoLeft = previousParticipants.current.filter((p) => !currentIds.includes(toFlatCommunicationIdentifier(p.identifier)));
if (whoJoined.length > 0) {
resetAnnoucement(createAnnouncementString('joined', whoJoined, strings));
}
if (whoLeft.length > 0) {
resetAnnoucement(createAnnouncementString('left', whoLeft, strings));
}
// Update cached value at the end.
previousParticipants.current = currentParticipants;
}, [currentParticipants, strings]);
return announcerString;
};
/**
* Generates the announcement string for when a participant joins or leaves a call.
*/
export const createAnnouncementString = (direction, participants, strings) => {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
/**
* If there are no participants return empty string.
*/
if (participants.length === 0) {
return '';
}
/**
* Filter participants into two arrays to put all the unnamed participants at the back of the
* names being announced.
*/
const unnamedParticipants = participants.filter((p) => !p.displayName);
const namedParicipants = participants.filter((p) => p.displayName);
const sortedParticipants = namedParicipants.concat(unnamedParticipants);
/**
* if there are only unnamed participants present in the array announce a special unnamed participants
* only string.
*/
if (sortedParticipants.filter((p) => p.displayName).length === 0 && sortedParticipants.length > 1) {
return _formatString(direction === 'joined' ? strings.manyUnnamedParticipantsJoined : strings.manyUnnamedParticipantsLeft, {
numOfParticipants: (sortedParticipants.length - 1).toString()
});
}
switch (sortedParticipants.length) {
case 1:
return _formatString(direction === 'joined' ? strings.participantJoinedNoticeString : strings.participantLeftNoticeString, { displayName: (_b = (_a = sortedParticipants[0]) === null || _a === void 0 ? void 0 : _a.displayName) !== null && _b !== void 0 ? _b : strings.unnamedParticipantString });
case 2:
return _formatString(direction === 'joined' ? strings.twoParticipantJoinedNoticeString : strings.twoParticipantLeftNoticeString, {
displayName1: (_d = (_c = sortedParticipants[0]) === null || _c === void 0 ? void 0 : _c.displayName) !== null && _d !== void 0 ? _d : strings.unnamedParticipantString,
displayName2: (_f = (_e = sortedParticipants[1]) === null || _e === void 0 ? void 0 : _e.displayName) !== null && _f !== void 0 ? _f : strings.unnamedParticipantString
});
case 3:
return _formatString(direction === 'joined' ? strings.threeParticipantJoinedNoticeString : strings.threeParticipantLeftNoticeString, {
displayName1: (_h = (_g = sortedParticipants[0]) === null || _g === void 0 ? void 0 : _g.displayName) !== null && _h !== void 0 ? _h : strings.unnamedParticipantString,
displayName2: (_k = (_j = sortedParticipants[1]) === null || _j === void 0 ? void 0 : _j.displayName) !== null && _k !== void 0 ? _k : strings.unnamedParticipantString,
displayName3: (_m = (_l = sortedParticipants[2]) === null || _l === void 0 ? void 0 : _l.displayName) !== null && _m !== void 0 ? _m : strings.unnamedParticipantString
});
}
/**
* If we have more than 3 participants joining we need to do something more to announce them
* appropriately.
*
* We don't want to announce every name when more than 3 participants join at once so
* we parse out the first 3 names we have and announce those with the number of others.
*/
const numberOfExtraParticipants = sortedParticipants.length - 3;
return _formatString(direction === 'joined' ? strings.manyParticipantsJoined : strings.manyParticipantsLeft, {
displayName1: (_p = (_o = sortedParticipants[0]) === null || _o === void 0 ? void 0 : _o.displayName) !== null && _p !== void 0 ? _p : strings.unnamedParticipantString,
displayName2: (_r = (_q = sortedParticipants[1]) === null || _q === void 0 ? void 0 : _q.displayName) !== null && _r !== void 0 ? _r : strings.unnamedParticipantString,
displayName3: (_t = (_s = sortedParticipants[2]) === null || _s === void 0 ? void 0 : _s.displayName) !== null && _t !== void 0 ? _t : strings.unnamedParticipantString,
numOfParticipants: numberOfExtraParticipants.toString()
});
};
/**
* determines if the media gallery should be replaced by the dtmf dialer
* @param callees Target callees to determine if the dtmf dialer should be shown
* @param remoteParticipants Remote participants to determine if the dtmf dialer should be shown if there are participants in the call
* when joining
* @returns whether the dialer should be the gallery content or not
*/
export const showDtmfDialer = (callees, remoteParticipants, dialerOptions) => {
let showDtmfDialerAuto = false;
if (typeof dialerOptions === 'object' && 'dialerBehavior' in dialerOptions) {
const hideDtmfDialerAlways = dialerOptions.dialerBehavior && dialerOptions.dialerBehavior === 'alwaysHide';
const showDtmfDialerAlways = dialerOptions.dialerBehavior === 'alwaysShow';
showDtmfDialerAuto = dialerOptions.dialerBehavior === 'autoShow' ? true : false;
if (showDtmfDialerAlways) {
return true;
}
if (hideDtmfDialerAlways) {
return false;
}
}
let showDtmfDialer = false;
/**
* We also want to check to see if the option is undefined. If this is the case we want this function
* to fallback on the original logic so that it will also render the callControls to show and hide the dialpad
* for the user.
*/
if (showDtmfDialerAuto || dialerOptions === undefined || dialerOptions === false) {
callees === null || callees === void 0 ? void 0 : callees.forEach((callee) => {
if (isMicrosoftTeamsAppIdentifier(callee) || isPhoneNumberIdentifier(callee)) {
showDtmfDialer = true;
}
});
if (remoteParticipants) {
remoteParticipants.forEach((participant) => {
if (!('phoneNumber' in participant.identifier || 'teamsAppId' in participant.identifier)) {
showDtmfDialer = false;
}
});
}
}
return showDtmfDialer;
};
//# sourceMappingURL=MediaGalleryUtils.js.map