UNPKG

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
// 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