@azure/communication-react 1.4.3-alpha-202212130014.0 → 1.4.3-alpha-202212150014.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dist-cjs/communication-react/index.js +576 -518
- package/dist/dist-cjs/communication-react/index.js.map +1 -1
- package/dist/dist-esm/acs-ui-common/src/telemetryVersion.js +1 -1
- package/dist/dist-esm/acs-ui-common/src/telemetryVersion.js.map +1 -1
- package/dist/dist-esm/calling-component-bindings/src/baseSelectors.d.ts +5 -0
- package/dist/dist-esm/calling-component-bindings/src/baseSelectors.js +7 -0
- package/dist/dist-esm/calling-component-bindings/src/baseSelectors.js.map +1 -1
- package/dist/dist-esm/calling-stateful-client/src/TypeGuards.js +2 -2
- package/dist/dist-esm/calling-stateful-client/src/TypeGuards.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/UnsupportedEnvironment.js +1 -1
- package/dist/dist-esm/react-components/src/components/UnsupportedEnvironment.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/styles/UnsupportedEnvironment.styles.js +4 -4
- package/dist/dist-esm/react-components/src/components/styles/UnsupportedEnvironment.styles.js.map +1 -1
- package/dist/dist-esm/react-composites/src/composites/CallComposite/adapter/AzureCommunicationCallAdapter.js +4 -1
- package/dist/dist-esm/react-composites/src/composites/CallComposite/adapter/AzureCommunicationCallAdapter.js.map +1 -1
- package/dist/dist-esm/react-composites/src/composites/CallComposite/components/CallArrangement.js +11 -11
- package/dist/dist-esm/react-composites/src/composites/CallComposite/components/CallArrangement.js.map +1 -1
- package/dist/dist-esm/react-composites/src/composites/CallComposite/components/buttons/Microphone.js +1 -1
- package/dist/dist-esm/react-composites/src/composites/CallComposite/components/buttons/Microphone.js.map +1 -1
- package/dist/dist-esm/react-composites/src/composites/CallComposite/hooks/useAdaptedSelector.js +11 -3
- package/dist/dist-esm/react-composites/src/composites/CallComposite/hooks/useAdaptedSelector.js.map +1 -1
- package/dist/dist-esm/react-composites/src/composites/CallComposite/styles/CallPage.styles.d.ts +4 -0
- package/dist/dist-esm/react-composites/src/composites/CallComposite/styles/CallPage.styles.js +8 -0
- package/dist/dist-esm/react-composites/src/composites/CallComposite/styles/CallPage.styles.js.map +1 -1
- package/dist/dist-esm/react-composites/src/composites/CallComposite/utils/Utils.d.ts +9 -0
- package/dist/dist-esm/react-composites/src/composites/CallComposite/utils/Utils.js +14 -1
- package/dist/dist-esm/react-composites/src/composites/CallComposite/utils/Utils.js.map +1 -1
- package/dist/dist-esm/react-composites/src/composites/CallWithChatComposite/CallWithChatControlBar.js +11 -1
- package/dist/dist-esm/react-composites/src/composites/CallWithChatComposite/CallWithChatControlBar.js.map +1 -1
- package/dist/dist-esm/react-composites/src/composites/CallWithChatComposite/styles/CallWithChatCompositeStyles.d.ts +2 -0
- package/dist/dist-esm/react-composites/src/composites/CallWithChatComposite/styles/CallWithChatCompositeStyles.js +15 -0
- package/dist/dist-esm/react-composites/src/composites/CallWithChatComposite/styles/CallWithChatCompositeStyles.js.map +1 -1
- package/dist/dist-esm/react-composites/src/composites/ChatComposite/adapter/AzureCommunicationChatAdapter.js +4 -0
- package/dist/dist-esm/react-composites/src/composites/ChatComposite/adapter/AzureCommunicationChatAdapter.js.map +1 -1
- package/package.json +8 -8
@@ -202,7 +202,7 @@ const _toCommunicationIdentifier = (id) => {
|
|
202
202
|
// Copyright (c) Microsoft Corporation.
|
203
203
|
// Licensed under the MIT license.
|
204
204
|
// GENERATED FILE. DO NOT EDIT MANUALLY.
|
205
|
-
var telemetryVersion = '1.4.3-alpha-
|
205
|
+
var telemetryVersion = '1.4.3-alpha-202212150014.0';
|
206
206
|
|
207
207
|
// Copyright (c) Microsoft Corporation.
|
208
208
|
/**
|
@@ -1799,14 +1799,14 @@ const findOldestCallEnded = (calls) => {
|
|
1799
1799
|
*/
|
1800
1800
|
const _isACSCall = (call) => {
|
1801
1801
|
/* @conditional-compile-remove(teams-identity-support) */
|
1802
|
-
return call.kind === 'Call';
|
1802
|
+
return !call.kind || call.kind === 'Call';
|
1803
1803
|
};
|
1804
1804
|
/**
|
1805
1805
|
* @internal
|
1806
1806
|
*/
|
1807
1807
|
const _isACSCallAgent = (callAgent) => {
|
1808
1808
|
/* @conditional-compile-remove(teams-identity-support) */
|
1809
|
-
return callAgent.kind === 'CallAgent';
|
1809
|
+
return !callAgent.kind || callAgent.kind === 'CallAgent';
|
1810
1810
|
};
|
1811
1811
|
/**
|
1812
1812
|
* @internal
|
@@ -11789,8 +11789,8 @@ const linkTextStyles = {
|
|
11789
11789
|
*/
|
11790
11790
|
const containerStyles$2 = {
|
11791
11791
|
root: {
|
11792
|
-
|
11793
|
-
|
11792
|
+
maxWidth: _pxToRem(375),
|
11793
|
+
padding: '2rem'
|
11794
11794
|
}
|
11795
11795
|
};
|
11796
11796
|
/**
|
@@ -11801,8 +11801,8 @@ const continueAnywayButtonStyles = (theme) => {
|
|
11801
11801
|
root: {
|
11802
11802
|
backgroundColor: '#C4314B',
|
11803
11803
|
borderColor: theme.palette.neutralLight,
|
11804
|
-
|
11805
|
-
|
11804
|
+
color: theme.palette.white,
|
11805
|
+
padding: '1rem'
|
11806
11806
|
}
|
11807
11807
|
};
|
11808
11808
|
};
|
@@ -11818,7 +11818,7 @@ const UnsupportedEnvironmentContainer = (props) => {
|
|
11818
11818
|
React__default['default'].createElement(react.Text, { styles: mainTextStyles }, strings === null || strings === void 0 ? void 0 : strings.primaryText),
|
11819
11819
|
React__default['default'].createElement(react.Text, { styles: secondaryTextStyles }, strings === null || strings === void 0 ? void 0 : strings.secondaryText)),
|
11820
11820
|
onTroubleshootingClick && (React__default['default'].createElement(react.Link, { styles: linkTextStyles, onClick: onTroubleshootingClick, "data-ui-id": "unsupported-environment-link" }, strings === null || strings === void 0 ? void 0 : strings.moreHelpLinkText)),
|
11821
|
-
onContinueClick && (React__default['default'].createElement(react.DefaultButton, { styles: continueAnywayButtonStyles(theme), onClick: onContinueClick }, strings === null || strings === void 0 ? void 0 : strings.continueAnywayButtonText))));
|
11821
|
+
onContinueClick && (React__default['default'].createElement(react.DefaultButton, { "data-ui-id": "allowUnsupportedBrowserButton", styles: continueAnywayButtonStyles(theme), onClick: onContinueClick }, strings === null || strings === void 0 ? void 0 : strings.continueAnywayButtonText))));
|
11822
11822
|
};
|
11823
11823
|
/**
|
11824
11824
|
* UI to display to the user that the environment they are using is not supported by calling application.
|
@@ -14747,6 +14747,280 @@ const convertObservableFileUploadToFileUploadsUiState = (fileUploads) => {
|
|
14747
14747
|
}, {});
|
14748
14748
|
};
|
14749
14749
|
|
14750
|
+
// Copyright (c) Microsoft Corporation.
|
14751
|
+
// Licensed under the MIT license.
|
14752
|
+
/**
|
14753
|
+
* Subset of CallCompositePages that represent an end call state.
|
14754
|
+
* @private
|
14755
|
+
*/
|
14756
|
+
const END_CALL_PAGES = [
|
14757
|
+
'accessDeniedTeamsMeeting',
|
14758
|
+
'joinCallFailedDueToNoNetwork',
|
14759
|
+
'leftCall',
|
14760
|
+
/* @conditional-compile-remove(rooms) */ 'deniedPermissionToRoom',
|
14761
|
+
'removedFromCall',
|
14762
|
+
/* @conditional-compile-remove(rooms) */ 'roomNotFound',
|
14763
|
+
/* @conditional-compile-remove(unsupported-browser) */ 'unsupportedEnvironment'
|
14764
|
+
];
|
14765
|
+
|
14766
|
+
// Copyright (c) Microsoft Corporation.
|
14767
|
+
const ACCESS_DENIED_TEAMS_MEETING_SUB_CODE = 5854;
|
14768
|
+
const REMOTE_PSTN_USER_HUNG_UP = 560000;
|
14769
|
+
const REMOVED_FROM_CALL_SUB_CODES = [5000, 5300, REMOTE_PSTN_USER_HUNG_UP];
|
14770
|
+
/* @conditional-compile-remove(rooms) */
|
14771
|
+
const ROOM_NOT_FOUND_SUB_CODE = 5751;
|
14772
|
+
/* @conditional-compile-remove(rooms) */
|
14773
|
+
const DENIED_PERMISSION_TO_ROOM_SUB_CODE = 5828;
|
14774
|
+
/**
|
14775
|
+
* @private
|
14776
|
+
*/
|
14777
|
+
const isCameraOn = (state) => {
|
14778
|
+
if (state.call) {
|
14779
|
+
const stream = state.call.localVideoStreams.find((stream) => stream.mediaStreamType === 'Video');
|
14780
|
+
return !!stream;
|
14781
|
+
}
|
14782
|
+
else {
|
14783
|
+
if (state.devices.selectedCamera) {
|
14784
|
+
const previewOn = _isPreviewOn(state.devices);
|
14785
|
+
return previewOn;
|
14786
|
+
}
|
14787
|
+
}
|
14788
|
+
return false;
|
14789
|
+
};
|
14790
|
+
/**
|
14791
|
+
* Reduce the set of call controls visible on mobile.
|
14792
|
+
* For example do not show screenshare button.
|
14793
|
+
*
|
14794
|
+
* @private
|
14795
|
+
*/
|
14796
|
+
const reduceCallControlsForMobile = (callControlOptions) => {
|
14797
|
+
if (callControlOptions === false) {
|
14798
|
+
return false;
|
14799
|
+
}
|
14800
|
+
// Ensure call controls a valid object.
|
14801
|
+
const reduceCallControlOptions = callControlOptions === true ? {} : callControlOptions || {};
|
14802
|
+
// Set to compressed mode when composite is optimized for mobile
|
14803
|
+
reduceCallControlOptions.displayType = 'compact';
|
14804
|
+
// Do not show screen share button when composite is optimized for mobile unless the developer
|
14805
|
+
// has explicitly opted in.
|
14806
|
+
if (reduceCallControlOptions.screenShareButton !== true) {
|
14807
|
+
reduceCallControlOptions.screenShareButton = false;
|
14808
|
+
}
|
14809
|
+
return reduceCallControlOptions;
|
14810
|
+
};
|
14811
|
+
var CallEndReasons;
|
14812
|
+
(function (CallEndReasons) {
|
14813
|
+
CallEndReasons[CallEndReasons["LEFT_CALL"] = 0] = "LEFT_CALL";
|
14814
|
+
CallEndReasons[CallEndReasons["ACCESS_DENIED"] = 1] = "ACCESS_DENIED";
|
14815
|
+
CallEndReasons[CallEndReasons["REMOVED_FROM_CALL"] = 2] = "REMOVED_FROM_CALL";
|
14816
|
+
CallEndReasons[CallEndReasons["ROOM_NOT_FOUND"] = 3] = "ROOM_NOT_FOUND";
|
14817
|
+
CallEndReasons[CallEndReasons["DENIED_PERMISSION_TO_ROOM"] = 4] = "DENIED_PERMISSION_TO_ROOM";
|
14818
|
+
})(CallEndReasons || (CallEndReasons = {}));
|
14819
|
+
const getCallEndReason = (call) => {
|
14820
|
+
var _a, _b, _c, _d, _e;
|
14821
|
+
const remoteParticipantsEndedArray = Array.from(Object.values(call.remoteParticipantsEnded));
|
14822
|
+
/**
|
14823
|
+
* Handle the special case in a PSTN call where removing the last user kicks the caller out of the call.
|
14824
|
+
* The code and subcode is the same as when a user is removed from a teams interop call.
|
14825
|
+
* Hence, we look at the last remote participant removed to determine if the last participant removed was a phone number.
|
14826
|
+
* If yes, the caller was kicked out of the call, but we need to show them that they left the call.
|
14827
|
+
* Note: This check will only work for 1:1 PSTN Calls. The subcode is different for 1:N PSTN calls, and we do not need to handle that case.
|
14828
|
+
*/
|
14829
|
+
if (remoteParticipantsEndedArray.length === 1 &&
|
14830
|
+
communicationCommon.isPhoneNumberIdentifier(remoteParticipantsEndedArray[0].identifier) &&
|
14831
|
+
((_a = call.callEndReason) === null || _a === void 0 ? void 0 : _a.subCode) !== REMOTE_PSTN_USER_HUNG_UP) {
|
14832
|
+
return CallEndReasons.LEFT_CALL;
|
14833
|
+
}
|
14834
|
+
if (((_b = call.callEndReason) === null || _b === void 0 ? void 0 : _b.subCode) && call.callEndReason.subCode === ACCESS_DENIED_TEAMS_MEETING_SUB_CODE) {
|
14835
|
+
return CallEndReasons.ACCESS_DENIED;
|
14836
|
+
}
|
14837
|
+
if (((_c = call.callEndReason) === null || _c === void 0 ? void 0 : _c.subCode) && REMOVED_FROM_CALL_SUB_CODES.includes(call.callEndReason.subCode)) {
|
14838
|
+
return CallEndReasons.REMOVED_FROM_CALL;
|
14839
|
+
}
|
14840
|
+
/* @conditional-compile-remove(rooms) */
|
14841
|
+
if (((_d = call.callEndReason) === null || _d === void 0 ? void 0 : _d.subCode) && call.callEndReason.subCode === ROOM_NOT_FOUND_SUB_CODE) {
|
14842
|
+
return CallEndReasons.ROOM_NOT_FOUND;
|
14843
|
+
}
|
14844
|
+
/* @conditional-compile-remove(rooms) */
|
14845
|
+
if (((_e = call.callEndReason) === null || _e === void 0 ? void 0 : _e.subCode) && call.callEndReason.subCode === DENIED_PERMISSION_TO_ROOM_SUB_CODE) {
|
14846
|
+
return CallEndReasons.DENIED_PERMISSION_TO_ROOM;
|
14847
|
+
}
|
14848
|
+
if (call.callEndReason) {
|
14849
|
+
// No error codes match, assume the user simply left the call regularly
|
14850
|
+
return CallEndReasons.LEFT_CALL;
|
14851
|
+
}
|
14852
|
+
throw new Error('No matching call end reason');
|
14853
|
+
};
|
14854
|
+
/**
|
14855
|
+
* Get the current call composite page based on the current call composite state
|
14856
|
+
*
|
14857
|
+
* @param Call - The current call state
|
14858
|
+
* @param previousCall - The state of the most recent previous call that has ended.
|
14859
|
+
*
|
14860
|
+
* @remarks - The previousCall state is needed to determine if the call has ended.
|
14861
|
+
* When the call ends a new call object is created, and so we must lookback at the
|
14862
|
+
* previous call state to understand how the call has ended. If there is no previous
|
14863
|
+
* call we know that this is a fresh call and can display the configuration page.
|
14864
|
+
*
|
14865
|
+
* @private
|
14866
|
+
*/
|
14867
|
+
const getCallCompositePage = (call, previousCall, unsupportedBrowserInfo) => {
|
14868
|
+
/* @conditional-compile-remove(unsupported-browser) */
|
14869
|
+
if (isUnsupportedEnvironment(unsupportedBrowserInfo.features, unsupportedBrowserInfo.environmentInfo, unsupportedBrowserInfo.unsupportedBrowserVersionOptedIn)) {
|
14870
|
+
return 'unsupportedEnvironment';
|
14871
|
+
}
|
14872
|
+
if (call) {
|
14873
|
+
// Must check for ongoing call *before* looking at any previous calls.
|
14874
|
+
// If the composite completes one call and joins another, the previous calls
|
14875
|
+
// will be populated, but not relevant for determining the page.
|
14876
|
+
// `_isInLobbyOrConnecting` needs to be checked first because `_isInCall` also returns true when call is in lobby.
|
14877
|
+
if (_isInLobbyOrConnecting(call === null || call === void 0 ? void 0 : call.state)) {
|
14878
|
+
return 'lobby';
|
14879
|
+
// `LocalHold` needs to be checked before `isInCall` since it is also a state that's considered in call.
|
14880
|
+
}
|
14881
|
+
else if ((call === null || call === void 0 ? void 0 : call.state) === 'LocalHold') {
|
14882
|
+
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
|
14883
|
+
return 'hold';
|
14884
|
+
}
|
14885
|
+
else if (_isInCall(call === null || call === void 0 ? void 0 : call.state)) {
|
14886
|
+
return 'call';
|
14887
|
+
}
|
14888
|
+
else {
|
14889
|
+
// When the call object has been constructed after clicking , but before 'connecting' has been
|
14890
|
+
// set on the call object, we continue to show the configuration screen.
|
14891
|
+
// The call object does not correctly reflect local device state until `call.state` moves to `connecting`.
|
14892
|
+
// Moving to the 'lobby' page too soon leads to components that depend on the `call` object to show incorrect
|
14893
|
+
// transitional state.
|
14894
|
+
return 'configuration';
|
14895
|
+
}
|
14896
|
+
}
|
14897
|
+
if (previousCall) {
|
14898
|
+
const reason = getCallEndReason(previousCall);
|
14899
|
+
/* @conditional-compile-remove(rooms) */
|
14900
|
+
switch (reason) {
|
14901
|
+
case CallEndReasons.ROOM_NOT_FOUND:
|
14902
|
+
return 'roomNotFound';
|
14903
|
+
case CallEndReasons.DENIED_PERMISSION_TO_ROOM:
|
14904
|
+
return 'deniedPermissionToRoom';
|
14905
|
+
}
|
14906
|
+
switch (reason) {
|
14907
|
+
case CallEndReasons.ACCESS_DENIED:
|
14908
|
+
return 'accessDeniedTeamsMeeting';
|
14909
|
+
case CallEndReasons.REMOVED_FROM_CALL:
|
14910
|
+
return 'removedFromCall';
|
14911
|
+
case CallEndReasons.LEFT_CALL:
|
14912
|
+
if (previousCall.diagnostics.network.latest.noNetwork) {
|
14913
|
+
return 'joinCallFailedDueToNoNetwork';
|
14914
|
+
}
|
14915
|
+
return 'leftCall';
|
14916
|
+
}
|
14917
|
+
}
|
14918
|
+
// No call state - show starting page (configuration)
|
14919
|
+
return 'configuration';
|
14920
|
+
};
|
14921
|
+
/** @private */
|
14922
|
+
const IsCallEndedPage = (
|
14923
|
+
/**
|
14924
|
+
* Explicitly listing the pages of this function intentionally.
|
14925
|
+
* This protects against adding a new composite page that should be marked as an callEndedPage.
|
14926
|
+
* EndCallPages are used to trigger onCallEnded events so this could easily be missed.
|
14927
|
+
* When you add a new composite page this will throw a compiler error. If this new page is an
|
14928
|
+
* EndCallPage ensure you update the END_CALL_PAGES. Afterwards update the `page` parameter
|
14929
|
+
* type below to allow your new page, i.e. add `| <your new page>
|
14930
|
+
*/
|
14931
|
+
page) => END_CALL_PAGES.includes(page);
|
14932
|
+
/**
|
14933
|
+
* Creates a new call control options object and sets the correct values for disabling
|
14934
|
+
* the buttons provided in the `disabledControls` array.
|
14935
|
+
* Returns a new object without changing the original object.
|
14936
|
+
* @param callControlOptions options for the call control component that need to be modified.
|
14937
|
+
* @param disabledControls An array of controls to disable.
|
14938
|
+
* @returns a copy of callControlOptions with disabledControls disabled
|
14939
|
+
* @private
|
14940
|
+
*/
|
14941
|
+
const disableCallControls = (callControlOptions, disabledControls) => {
|
14942
|
+
var _a;
|
14943
|
+
if (callControlOptions === false) {
|
14944
|
+
return false;
|
14945
|
+
}
|
14946
|
+
// Ensure we clone the prop if it is an object to ensure we do not mutate the original prop.
|
14947
|
+
let newOptions = (_a = (callControlOptions instanceof Object ? Object.assign({}, callControlOptions) : callControlOptions)) !== null && _a !== void 0 ? _a : {};
|
14948
|
+
if (newOptions === true || newOptions === undefined) {
|
14949
|
+
newOptions = disabledControls.reduce((acc, key) => {
|
14950
|
+
acc[key] = { disabled: true };
|
14951
|
+
return acc;
|
14952
|
+
}, {});
|
14953
|
+
}
|
14954
|
+
else {
|
14955
|
+
disabledControls.forEach((key) => {
|
14956
|
+
if (newOptions[key] !== false) {
|
14957
|
+
newOptions[key] = { disabled: true };
|
14958
|
+
}
|
14959
|
+
});
|
14960
|
+
}
|
14961
|
+
return newOptions;
|
14962
|
+
};
|
14963
|
+
/**
|
14964
|
+
* Check if a disabled object is provided for a button and returns if the button is disabled.
|
14965
|
+
* A button is only disabled if is explicitly set to disabled.
|
14966
|
+
*
|
14967
|
+
* @param option
|
14968
|
+
* @returns whether a button is disabled
|
14969
|
+
* @private
|
14970
|
+
*/
|
14971
|
+
const isDisabled$2 = (option) => {
|
14972
|
+
if (option === undefined || typeof option === 'boolean') {
|
14973
|
+
return false;
|
14974
|
+
}
|
14975
|
+
return option.disabled;
|
14976
|
+
};
|
14977
|
+
/* @conditional-compile-remove(call-readiness) */
|
14978
|
+
/**
|
14979
|
+
*
|
14980
|
+
* This function uses permission API to determine if device permission state is granted, prompt or denied
|
14981
|
+
* @returns whether device permission state is granted, prompt or denied
|
14982
|
+
* If permission API is not supported on this browser, do nothing and log out error
|
14983
|
+
* @private
|
14984
|
+
*/
|
14985
|
+
const getDevicePermissionState = (setVideoState, setAudioState) => {
|
14986
|
+
navigator.permissions
|
14987
|
+
.query({ name: 'camera' })
|
14988
|
+
.then((result) => {
|
14989
|
+
setVideoState(result.state);
|
14990
|
+
})
|
14991
|
+
.catch(() => {
|
14992
|
+
setVideoState('unsupported');
|
14993
|
+
});
|
14994
|
+
navigator.permissions
|
14995
|
+
.query({ name: 'microphone' })
|
14996
|
+
.then((result) => {
|
14997
|
+
setAudioState(result.state);
|
14998
|
+
})
|
14999
|
+
.catch(() => {
|
15000
|
+
setAudioState('unsupported');
|
15001
|
+
});
|
15002
|
+
};
|
15003
|
+
/* @conditional-compile-remove(unsupported-browser) */
|
15004
|
+
const isUnsupportedEnvironment = (features, environmentInfo, unsupportedBrowserVersionOptedIn) => {
|
15005
|
+
return !!((features === null || features === void 0 ? void 0 : features.unsupportedEnvironment) &&
|
15006
|
+
((environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.isSupportedBrowser) === false ||
|
15007
|
+
((environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.isSupportedBrowserVersion) === false && !unsupportedBrowserVersionOptedIn) ||
|
15008
|
+
(environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.isSupportedPlatform) === false));
|
15009
|
+
};
|
15010
|
+
/**
|
15011
|
+
* Check if an object is identifier.
|
15012
|
+
*
|
15013
|
+
* @param identifier
|
15014
|
+
* @returns whether an identifier is one of identifier types (for runtime validation)
|
15015
|
+
* @private
|
15016
|
+
*/
|
15017
|
+
const isValidIdentifier = (identifier) => {
|
15018
|
+
return (communicationCommon.isCommunicationUserIdentifier(identifier) ||
|
15019
|
+
communicationCommon.isPhoneNumberIdentifier(identifier) ||
|
15020
|
+
communicationCommon.isMicrosoftTeamsUserIdentifier(identifier) ||
|
15021
|
+
communicationCommon.isUnknownIdentifier(identifier));
|
15022
|
+
};
|
15023
|
+
|
14750
15024
|
// Copyright (c) Microsoft Corporation.
|
14751
15025
|
// Licensed under the MIT license.
|
14752
15026
|
var __awaiter$c = (window && window.__awaiter) || function (thisArg, _arguments, P, generator) {
|
@@ -15097,6 +15371,9 @@ const convertEventType = (type) => {
|
|
15097
15371
|
* @public
|
15098
15372
|
*/
|
15099
15373
|
const createAzureCommunicationChatAdapter = ({ endpoint: endpointUrl, userId, displayName, credential, threadId }) => __awaiter$c(void 0, void 0, void 0, function* () {
|
15374
|
+
if (!isValidIdentifier(userId)) {
|
15375
|
+
throw new Error('Provided userId is invalid. Please provide valid identifier object.');
|
15376
|
+
}
|
15100
15377
|
const chatClient = createStatefulChatClient({
|
15101
15378
|
userId,
|
15102
15379
|
displayName,
|
@@ -15759,514 +16036,261 @@ const ChatScreenPeoplePane = (props) => {
|
|
15759
16036
|
return (React__default['default'].createElement(ParticipantContainer, { participantListProps: participantListProps, title: chatListHeader, onFetchAvatarPersonaData: onFetchAvatarPersonaData, onFetchParticipantMenuItems: onFetchParticipantMenuItems, isMobile: isMobile }));
|
15760
16037
|
};
|
15761
16038
|
|
15762
|
-
/**
|
15763
|
-
* @private
|
15764
|
-
*/
|
15765
|
-
/**
|
15766
|
-
* @private
|
15767
|
-
*/
|
15768
|
-
const getFileUploads = (state) => {
|
15769
|
-
/* @conditional-compile-remove(file-sharing) */
|
15770
|
-
return state === null || state === void 0 ? void 0 : state.fileUploads;
|
15771
|
-
};
|
15772
|
-
|
15773
|
-
// Copyright (c) Microsoft Corporation.
|
15774
|
-
/**
|
15775
|
-
* @private
|
15776
|
-
*/
|
15777
|
-
const fileUploadsSelector = reselect.createSelector([getFileUploads], (fileUploads) => {
|
15778
|
-
const files = Object.values(fileUploads || {}).map((fileUpload) => (Object.assign(Object.assign({}, fileUpload), { uploadComplete: !!fileUpload.metadata })));
|
15779
|
-
return { files: files };
|
15780
|
-
});
|
15781
|
-
|
15782
|
-
// Copyright (c) Microsoft Corporation.
|
15783
|
-
/**
|
15784
|
-
* @private
|
15785
|
-
*/
|
15786
|
-
const useSelector$2 = (selector, selectorProps) => {
|
15787
|
-
// use selector with no adaptation
|
15788
|
-
return useSelectorWithAdaptation$1(selector, (state) => state, selectorProps);
|
15789
|
-
};
|
15790
|
-
|
15791
|
-
// Copyright (c) Microsoft Corporation.
|
15792
|
-
/**
|
15793
|
-
* @private
|
15794
|
-
*/
|
15795
|
-
const FileDownloadErrorBar = (props) => {
|
15796
|
-
const { fileDownloadErrorMessage, onDismissDownloadErrorMessage } = props;
|
15797
|
-
const messageBarIconProps = { iconName: 'ProtectedDocument' };
|
15798
|
-
if (fileDownloadErrorMessage !== '') {
|
15799
|
-
return (React__default['default'].createElement(react.Stack, { horizontal: true, horizontalAlign: "space-between", verticalAlign: "center" },
|
15800
|
-
React__default['default'].createElement(react.MessageBar, { messageBarType: react.MessageBarType.warning, onDismiss: () => {
|
15801
|
-
onDismissDownloadErrorMessage();
|
15802
|
-
}, messageBarIconProps: messageBarIconProps }, fileDownloadErrorMessage)));
|
15803
|
-
}
|
15804
|
-
else {
|
15805
|
-
return React__default['default'].createElement(React__default['default'].Fragment, null);
|
15806
|
-
}
|
15807
|
-
};
|
15808
|
-
|
15809
|
-
// Copyright (c) Microsoft Corporation.
|
15810
|
-
/**
|
15811
|
-
* @private
|
15812
|
-
*/
|
15813
|
-
const ChatScreen = (props) => {
|
15814
|
-
const { onFetchAvatarPersonaData, onRenderMessage, onRenderTypingIndicator, options, styles, fileSharing, formFactor } = props;
|
15815
|
-
const defaultNumberOfChatMessagesToReload = 5;
|
15816
|
-
/* @conditional-compile-remove(file-sharing) */
|
15817
|
-
const [downloadErrorMessage, setDownloadErrorMessage] = React__default['default'].useState('');
|
15818
|
-
const adapter = useAdapter$1();
|
15819
|
-
const theme = useTheme();
|
15820
|
-
React.useEffect(() => {
|
15821
|
-
// Initial data should be always fetched by the composite(or external caller) instead of the adapter
|
15822
|
-
adapter.fetchInitialData();
|
15823
|
-
}, [adapter]);
|
15824
|
-
const messageThreadProps = usePropsFor$2(MessageThread);
|
15825
|
-
const sendBoxProps = usePropsFor$2(SendBox);
|
15826
|
-
const typingIndicatorProps = usePropsFor$2(TypingIndicator);
|
15827
|
-
const headerProps = useAdaptedSelector$1(getHeaderProps);
|
15828
|
-
const errorBarProps = usePropsFor$2(ErrorBar);
|
15829
|
-
const onRenderAvatarCallback = React.useCallback((userId, defaultOptions) => {
|
15830
|
-
return (React__default['default'].createElement(AvatarPersona, Object.assign({ userId: userId, hidePersonaDetails: true }, defaultOptions, { dataProvider: onFetchAvatarPersonaData })));
|
15831
|
-
}, [onFetchAvatarPersonaData]);
|
15832
|
-
const messageThreadStyles = Object.assign({}, messageThreadChatCompositeStyles(theme.semanticColors.bodyBackground), styles === null || styles === void 0 ? void 0 : styles.messageThread);
|
15833
|
-
const typingIndicatorStyles = Object.assign({}, styles === null || styles === void 0 ? void 0 : styles.typingIndicator);
|
15834
|
-
const sendBoxStyles = Object.assign({}, styles === null || styles === void 0 ? void 0 : styles.sendBox);
|
15835
|
-
const userId = toFlatCommunicationIdentifier(adapter.getState().userId);
|
15836
|
-
const fileUploadButtonOnChange = React.useCallback((files) => {
|
15837
|
-
if (!files) {
|
15838
|
-
return;
|
15839
|
-
}
|
15840
|
-
/* @conditional-compile-remove(file-sharing) */
|
15841
|
-
const fileUploads = adapter.registerActiveFileUploads(Array.from(files));
|
15842
|
-
/* @conditional-compile-remove(file-sharing) */
|
15843
|
-
fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.uploadHandler(userId, fileUploads);
|
15844
|
-
}, [adapter, fileSharing, userId]);
|
15845
|
-
/* @conditional-compile-remove(file-sharing) */
|
15846
|
-
const onRenderFileDownloads = React.useCallback((userId, message) => (React__default['default'].createElement(_FileDownloadCards, { userId: userId, fileMetadata: message.attachedFilesMetadata || [], downloadHandler: fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.downloadHandler, onDownloadErrorMessage: (errorMessage) => {
|
15847
|
-
setDownloadErrorMessage(errorMessage);
|
15848
|
-
} })), [fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.downloadHandler]);
|
15849
|
-
const AttachFileButton = React.useCallback(() => {
|
15850
|
-
if (!(fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.uploadHandler)) {
|
15851
|
-
return null;
|
15852
|
-
}
|
15853
|
-
return (React__default['default'].createElement(FileUploadButtonWrapper, { accept: fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.accept, multiple: fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.multiple, onChange: fileUploadButtonOnChange }));
|
15854
|
-
}, [fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.accept, fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.multiple, fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.uploadHandler, fileUploadButtonOnChange]);
|
15855
|
-
return (React__default['default'].createElement(react.Stack, { className: chatContainer, grow: true },
|
15856
|
-
(options === null || options === void 0 ? void 0 : options.topic) !== false && React__default['default'].createElement(ChatHeader, Object.assign({}, headerProps)),
|
15857
|
-
React__default['default'].createElement(react.Stack, { className: chatArea, tokens: participantListContainerPadding, horizontal: true, grow: true },
|
15858
|
-
React__default['default'].createElement(react.Stack, { className: chatWrapper, grow: true },
|
15859
|
-
(options === null || options === void 0 ? void 0 : options.errorBar) !== false && React__default['default'].createElement(ErrorBar, Object.assign({}, errorBarProps)),
|
15860
|
-
/* @conditional-compile-remove(file-sharing) */
|
15861
|
-
React__default['default'].createElement(FileDownloadErrorBar, { onDismissDownloadErrorMessage: React.useCallback(() => {
|
15862
|
-
setDownloadErrorMessage('');
|
15863
|
-
}, []), fileDownloadErrorMessage: downloadErrorMessage || '' }),
|
15864
|
-
React__default['default'].createElement(MessageThread, Object.assign({}, messageThreadProps, { onRenderAvatar: onRenderAvatarCallback, onRenderMessage: onRenderMessage,
|
15865
|
-
/* @conditional-compile-remove(file-sharing) */
|
15866
|
-
onRenderFileDownloads: onRenderFileDownloads, numberOfChatMessagesToReload: defaultNumberOfChatMessagesToReload, styles: messageThreadStyles })),
|
15867
|
-
React__default['default'].createElement(react.Stack, { className: react.mergeStyles(sendboxContainerStyles) },
|
15868
|
-
React__default['default'].createElement("div", { className: react.mergeStyles(typingIndicatorContainerStyles) }, onRenderTypingIndicator ? (onRenderTypingIndicator(typingIndicatorProps.typingUsers)) : (React__default['default'].createElement(TypingIndicator, Object.assign({}, typingIndicatorProps, { styles: typingIndicatorStyles })))),
|
15869
|
-
React__default['default'].createElement(react.Stack, { horizontal: formFactor === 'mobile' },
|
15870
|
-
formFactor === 'mobile' && (React__default['default'].createElement(react.Stack, { verticalAlign: "center" },
|
15871
|
-
React__default['default'].createElement(AttachFileButton, null))),
|
15872
|
-
React__default['default'].createElement(react.Stack, { grow: true },
|
15873
|
-
React__default['default'].createElement(SendBox, Object.assign({}, sendBoxProps, { autoFocus: options === null || options === void 0 ? void 0 : options.autoFocus, styles: sendBoxStyles,
|
15874
|
-
/* @conditional-compile-remove(file-sharing) */
|
15875
|
-
activeFileUploads: useSelector$2(fileUploadsSelector).files,
|
15876
|
-
/* @conditional-compile-remove(file-sharing) */
|
15877
|
-
onCancelFileUpload: adapter.cancelFileUpload }))),
|
15878
|
-
formFactor !== 'mobile' && React__default['default'].createElement(AttachFileButton, null)))),
|
15879
|
-
/* @conditional-compile-remove(chat-composite-participant-pane) */
|
15880
|
-
(options === null || options === void 0 ? void 0 : options.participantPane) === true && (React__default['default'].createElement(ChatScreenPeoplePane, { onFetchAvatarPersonaData: onFetchAvatarPersonaData, onFetchParticipantMenuItems: props.onFetchParticipantMenuItems, isMobile: formFactor === 'mobile' })))));
|
15881
|
-
};
|
15882
|
-
|
15883
|
-
// Copyright (c) Microsoft Corporation.
|
15884
|
-
/**
|
15885
|
-
* A customizable UI composite for the chat experience.
|
15886
|
-
*
|
15887
|
-
* @remarks Chat composite min width and height are respectively 17.5rem and 20rem (280px and 320px, with default rem at 16px)
|
15888
|
-
*
|
15889
|
-
* @public
|
15890
|
-
*/
|
15891
|
-
const ChatComposite = (props) => {
|
15892
|
-
const { adapter, options, onFetchAvatarPersonaData, onRenderTypingIndicator, onRenderMessage, onFetchParticipantMenuItems } = props;
|
15893
|
-
const formFactor = props['formFactor'] || 'desktop';
|
15894
|
-
/**
|
15895
|
-
* @TODO Remove this function and pass the props directly when file-sharing is promoted to stable.
|
15896
|
-
* @private
|
15897
|
-
*/
|
15898
|
-
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
15899
|
-
const fileSharingOptions = () => {
|
15900
|
-
/* @conditional-compile-remove(file-sharing) */
|
15901
|
-
return {
|
15902
|
-
fileSharing: options === null || options === void 0 ? void 0 : options.fileSharing
|
15903
|
-
};
|
15904
|
-
};
|
15905
|
-
return (React__default['default'].createElement("div", { className: chatScreenContainerStyle },
|
15906
|
-
React__default['default'].createElement(BaseProvider, Object.assign({}, props),
|
15907
|
-
React__default['default'].createElement(ChatAdapterProvider, { adapter: adapter },
|
15908
|
-
React__default['default'].createElement(ChatScreen, Object.assign({ formFactor: formFactor, options: options, onFetchAvatarPersonaData: onFetchAvatarPersonaData, onRenderTypingIndicator: onRenderTypingIndicator, onRenderMessage: onRenderMessage, onFetchParticipantMenuItems: onFetchParticipantMenuItems }, fileSharingOptions()))))));
|
15909
|
-
};
|
15910
|
-
|
15911
|
-
// Copyright (c) Microsoft Corporation.
|
15912
|
-
const CallAdapterContext = React.createContext(undefined);
|
15913
|
-
/**
|
15914
|
-
* @private
|
15915
|
-
*/
|
15916
|
-
const CallAdapterProvider = (props) => {
|
15917
|
-
const { adapter } = props;
|
15918
|
-
return React__default['default'].createElement(CallAdapterContext.Provider, { value: adapter }, props.children);
|
15919
|
-
};
|
15920
|
-
/**
|
15921
|
-
* @private
|
15922
|
-
*/
|
15923
|
-
const useAdapter = () => {
|
15924
|
-
const adapter = React.useContext(CallAdapterContext);
|
15925
|
-
if (!adapter) {
|
15926
|
-
throw 'Cannot find adapter please initialize before usage.';
|
15927
|
-
}
|
15928
|
-
return adapter;
|
15929
|
-
};
|
15930
|
-
|
15931
|
-
// Copyright (c) Microsoft Corporation.
|
15932
|
-
// Licensed under the MIT license.
|
15933
|
-
/** @private */
|
15934
|
-
const containerDivStyles = { position: 'relative', width: '100%', height: '100%' };
|
15935
|
-
|
15936
|
-
// Copyright (c) Microsoft Corporation.
|
15937
|
-
/**
|
15938
|
-
* @private
|
15939
|
-
*/
|
15940
|
-
const useAdaptedSelector = (selector, selectorProps) => {
|
15941
|
-
return useSelectorWithAdaptation(selector, adaptCompositeState, selectorProps);
|
15942
|
-
};
|
15943
|
-
/**
|
15944
|
-
* @private
|
15945
|
-
*/
|
15946
|
-
const useSelectorWithAdaptation = (selector, adaptState, selectorProps) => {
|
15947
|
-
var _a;
|
15948
|
-
const adapter = useAdapter();
|
15949
|
-
// Keeps track of whether the current component is mounted or not. If it has unmounted, make sure we do not modify the
|
15950
|
-
// state or it will cause React warnings in the console. https://skype.visualstudio.com/SPOOL/_workitems/edit/2453212
|
15951
|
-
const mounted = React.useRef(false);
|
15952
|
-
React.useEffect(() => {
|
15953
|
-
mounted.current = true;
|
15954
|
-
return () => {
|
15955
|
-
mounted.current = false;
|
15956
|
-
};
|
15957
|
-
});
|
15958
|
-
const callId = (_a = adapter.getState().call) === null || _a === void 0 ? void 0 : _a.id;
|
15959
|
-
const callConfigProps = React.useMemo(() => ({
|
15960
|
-
callId
|
15961
|
-
}), [callId]);
|
15962
|
-
const [props, setProps] = React.useState(selector(adaptState(adapter.getState()), selectorProps !== null && selectorProps !== void 0 ? selectorProps : callConfigProps));
|
15963
|
-
const propRef = React.useRef(props);
|
15964
|
-
propRef.current = props;
|
15965
|
-
React.useEffect(() => {
|
15966
|
-
const onStateChange = (state) => {
|
15967
|
-
if (!mounted.current) {
|
15968
|
-
return;
|
15969
|
-
}
|
15970
|
-
const newProps = selector(adaptState(state), selectorProps !== null && selectorProps !== void 0 ? selectorProps : callConfigProps);
|
15971
|
-
if (propRef.current !== newProps) {
|
15972
|
-
setProps(newProps);
|
15973
|
-
}
|
15974
|
-
};
|
15975
|
-
adapter.onStateChange(onStateChange);
|
15976
|
-
return () => {
|
15977
|
-
adapter.offStateChange(onStateChange);
|
15978
|
-
};
|
15979
|
-
}, [adaptState, adapter, selector, selectorProps, callConfigProps]);
|
15980
|
-
return props;
|
15981
|
-
};
|
15982
|
-
const memoizeState = memoizeOne__default['default']((userId, deviceManager, calls, latestErrors, displayName) => ({
|
15983
|
-
userId,
|
15984
|
-
incomingCalls: {},
|
15985
|
-
incomingCallsEnded: {},
|
15986
|
-
callsEnded: {},
|
15987
|
-
deviceManager,
|
15988
|
-
callAgent: { displayName },
|
15989
|
-
calls,
|
15990
|
-
latestErrors
|
15991
|
-
}));
|
15992
|
-
const memoizeCalls = memoizeOne__default['default']((call) => (call ? { [call.id]: call } : {}));
|
15993
|
-
const adaptCompositeState = (compositeState) => {
|
15994
|
-
return memoizeState(compositeState.userId, compositeState.devices, memoizeCalls(compositeState.call),
|
15995
|
-
// This is an unsafe type expansion.
|
15996
|
-
// compositeState.latestErrors can contain properties that are not valid in CallErrors.
|
15997
|
-
//
|
15998
|
-
// But there is no way to check for valid property names at runtime:
|
15999
|
-
// - The set of valid property names is built from types in the @azure/communication-calling.
|
16000
|
-
// Thus we don't have a literal array of allowed strings at runtime.
|
16001
|
-
// - Due to minification / uglification, the property names from the objects at runtime can't be used
|
16002
|
-
// to compare against permissible values inferred from the types.
|
16003
|
-
//
|
16004
|
-
// This is not a huge problem -- it simply means that our adapted selector will include some extra operations
|
16005
|
-
// that are unknown to the UI component and data binding libraries. Generic handling of the errors (e.g.,
|
16006
|
-
// just displaying them in some UI surface) will continue to work for these operations. Handling of
|
16007
|
-
// specific operations (e.g., acting on errors related to permission issues) will ignore these operations.
|
16008
|
-
compositeState.latestErrors, compositeState.displayName);
|
16009
|
-
};
|
16010
|
-
|
16039
|
+
/**
|
16040
|
+
* @private
|
16041
|
+
*/
|
16042
|
+
/**
|
16043
|
+
* @private
|
16044
|
+
*/
|
16045
|
+
const getFileUploads = (state) => {
|
16046
|
+
/* @conditional-compile-remove(file-sharing) */
|
16047
|
+
return state === null || state === void 0 ? void 0 : state.fileUploads;
|
16048
|
+
};
|
16049
|
+
|
16011
16050
|
// Copyright (c) Microsoft Corporation.
|
16012
|
-
// Licensed under the MIT license.
|
16013
16051
|
/**
|
16014
|
-
* Subset of CallCompositePages that represent an end call state.
|
16015
16052
|
* @private
|
16016
16053
|
*/
|
16017
|
-
const
|
16018
|
-
|
16019
|
-
|
16020
|
-
|
16021
|
-
/* @conditional-compile-remove(rooms) */ 'deniedPermissionToRoom',
|
16022
|
-
'removedFromCall',
|
16023
|
-
/* @conditional-compile-remove(rooms) */ 'roomNotFound',
|
16024
|
-
/* @conditional-compile-remove(unsupported-browser) */ 'unsupportedEnvironment'
|
16025
|
-
];
|
16054
|
+
const fileUploadsSelector = reselect.createSelector([getFileUploads], (fileUploads) => {
|
16055
|
+
const files = Object.values(fileUploads || {}).map((fileUpload) => (Object.assign(Object.assign({}, fileUpload), { uploadComplete: !!fileUpload.metadata })));
|
16056
|
+
return { files: files };
|
16057
|
+
});
|
16026
16058
|
|
16027
16059
|
// Copyright (c) Microsoft Corporation.
|
16028
|
-
const ACCESS_DENIED_TEAMS_MEETING_SUB_CODE = 5854;
|
16029
|
-
const REMOTE_PSTN_USER_HUNG_UP = 560000;
|
16030
|
-
const REMOVED_FROM_CALL_SUB_CODES = [5000, 5300, REMOTE_PSTN_USER_HUNG_UP];
|
16031
|
-
/* @conditional-compile-remove(rooms) */
|
16032
|
-
const ROOM_NOT_FOUND_SUB_CODE = 5751;
|
16033
|
-
/* @conditional-compile-remove(rooms) */
|
16034
|
-
const DENIED_PERMISSION_TO_ROOM_SUB_CODE = 5828;
|
16035
16060
|
/**
|
16036
16061
|
* @private
|
16037
16062
|
*/
|
16038
|
-
const
|
16039
|
-
|
16040
|
-
|
16041
|
-
return !!stream;
|
16042
|
-
}
|
16043
|
-
else {
|
16044
|
-
if (state.devices.selectedCamera) {
|
16045
|
-
const previewOn = _isPreviewOn(state.devices);
|
16046
|
-
return previewOn;
|
16047
|
-
}
|
16048
|
-
}
|
16049
|
-
return false;
|
16063
|
+
const useSelector$2 = (selector, selectorProps) => {
|
16064
|
+
// use selector with no adaptation
|
16065
|
+
return useSelectorWithAdaptation$1(selector, (state) => state, selectorProps);
|
16050
16066
|
};
|
16067
|
+
|
16068
|
+
// Copyright (c) Microsoft Corporation.
|
16051
16069
|
/**
|
16052
|
-
* Reduce the set of call controls visible on mobile.
|
16053
|
-
* For example do not show screenshare button.
|
16054
|
-
*
|
16055
16070
|
* @private
|
16056
16071
|
*/
|
16057
|
-
const
|
16058
|
-
|
16059
|
-
|
16060
|
-
|
16061
|
-
|
16062
|
-
|
16063
|
-
|
16064
|
-
|
16065
|
-
// Do not show screen share button when composite is optimized for mobile unless the developer
|
16066
|
-
// has explicitly opted in.
|
16067
|
-
if (reduceCallControlOptions.screenShareButton !== true) {
|
16068
|
-
reduceCallControlOptions.screenShareButton = false;
|
16069
|
-
}
|
16070
|
-
return reduceCallControlOptions;
|
16071
|
-
};
|
16072
|
-
var CallEndReasons;
|
16073
|
-
(function (CallEndReasons) {
|
16074
|
-
CallEndReasons[CallEndReasons["LEFT_CALL"] = 0] = "LEFT_CALL";
|
16075
|
-
CallEndReasons[CallEndReasons["ACCESS_DENIED"] = 1] = "ACCESS_DENIED";
|
16076
|
-
CallEndReasons[CallEndReasons["REMOVED_FROM_CALL"] = 2] = "REMOVED_FROM_CALL";
|
16077
|
-
CallEndReasons[CallEndReasons["ROOM_NOT_FOUND"] = 3] = "ROOM_NOT_FOUND";
|
16078
|
-
CallEndReasons[CallEndReasons["DENIED_PERMISSION_TO_ROOM"] = 4] = "DENIED_PERMISSION_TO_ROOM";
|
16079
|
-
})(CallEndReasons || (CallEndReasons = {}));
|
16080
|
-
const getCallEndReason = (call) => {
|
16081
|
-
var _a, _b, _c, _d, _e;
|
16082
|
-
const remoteParticipantsEndedArray = Array.from(Object.values(call.remoteParticipantsEnded));
|
16083
|
-
/**
|
16084
|
-
* Handle the special case in a PSTN call where removing the last user kicks the caller out of the call.
|
16085
|
-
* The code and subcode is the same as when a user is removed from a teams interop call.
|
16086
|
-
* Hence, we look at the last remote participant removed to determine if the last participant removed was a phone number.
|
16087
|
-
* If yes, the caller was kicked out of the call, but we need to show them that they left the call.
|
16088
|
-
* Note: This check will only work for 1:1 PSTN Calls. The subcode is different for 1:N PSTN calls, and we do not need to handle that case.
|
16089
|
-
*/
|
16090
|
-
if (remoteParticipantsEndedArray.length === 1 &&
|
16091
|
-
communicationCommon.isPhoneNumberIdentifier(remoteParticipantsEndedArray[0].identifier) &&
|
16092
|
-
((_a = call.callEndReason) === null || _a === void 0 ? void 0 : _a.subCode) !== REMOTE_PSTN_USER_HUNG_UP) {
|
16093
|
-
return CallEndReasons.LEFT_CALL;
|
16094
|
-
}
|
16095
|
-
if (((_b = call.callEndReason) === null || _b === void 0 ? void 0 : _b.subCode) && call.callEndReason.subCode === ACCESS_DENIED_TEAMS_MEETING_SUB_CODE) {
|
16096
|
-
return CallEndReasons.ACCESS_DENIED;
|
16097
|
-
}
|
16098
|
-
if (((_c = call.callEndReason) === null || _c === void 0 ? void 0 : _c.subCode) && REMOVED_FROM_CALL_SUB_CODES.includes(call.callEndReason.subCode)) {
|
16099
|
-
return CallEndReasons.REMOVED_FROM_CALL;
|
16100
|
-
}
|
16101
|
-
/* @conditional-compile-remove(rooms) */
|
16102
|
-
if (((_d = call.callEndReason) === null || _d === void 0 ? void 0 : _d.subCode) && call.callEndReason.subCode === ROOM_NOT_FOUND_SUB_CODE) {
|
16103
|
-
return CallEndReasons.ROOM_NOT_FOUND;
|
16104
|
-
}
|
16105
|
-
/* @conditional-compile-remove(rooms) */
|
16106
|
-
if (((_e = call.callEndReason) === null || _e === void 0 ? void 0 : _e.subCode) && call.callEndReason.subCode === DENIED_PERMISSION_TO_ROOM_SUB_CODE) {
|
16107
|
-
return CallEndReasons.DENIED_PERMISSION_TO_ROOM;
|
16072
|
+
const FileDownloadErrorBar = (props) => {
|
16073
|
+
const { fileDownloadErrorMessage, onDismissDownloadErrorMessage } = props;
|
16074
|
+
const messageBarIconProps = { iconName: 'ProtectedDocument' };
|
16075
|
+
if (fileDownloadErrorMessage !== '') {
|
16076
|
+
return (React__default['default'].createElement(react.Stack, { horizontal: true, horizontalAlign: "space-between", verticalAlign: "center" },
|
16077
|
+
React__default['default'].createElement(react.MessageBar, { messageBarType: react.MessageBarType.warning, onDismiss: () => {
|
16078
|
+
onDismissDownloadErrorMessage();
|
16079
|
+
}, messageBarIconProps: messageBarIconProps }, fileDownloadErrorMessage)));
|
16108
16080
|
}
|
16109
|
-
|
16110
|
-
|
16111
|
-
return CallEndReasons.LEFT_CALL;
|
16081
|
+
else {
|
16082
|
+
return React__default['default'].createElement(React__default['default'].Fragment, null);
|
16112
16083
|
}
|
16113
|
-
throw new Error('No matching call end reason');
|
16114
16084
|
};
|
16085
|
+
|
16086
|
+
// Copyright (c) Microsoft Corporation.
|
16115
16087
|
/**
|
16116
|
-
* Get the current call composite page based on the current call composite state
|
16117
|
-
*
|
16118
|
-
* @param Call - The current call state
|
16119
|
-
* @param previousCall - The state of the most recent previous call that has ended.
|
16120
|
-
*
|
16121
|
-
* @remarks - The previousCall state is needed to determine if the call has ended.
|
16122
|
-
* When the call ends a new call object is created, and so we must lookback at the
|
16123
|
-
* previous call state to understand how the call has ended. If there is no previous
|
16124
|
-
* call we know that this is a fresh call and can display the configuration page.
|
16125
|
-
*
|
16126
16088
|
* @private
|
16127
16089
|
*/
|
16128
|
-
const
|
16129
|
-
|
16130
|
-
|
16131
|
-
|
16132
|
-
|
16133
|
-
|
16134
|
-
|
16135
|
-
|
16136
|
-
//
|
16137
|
-
|
16138
|
-
|
16139
|
-
|
16140
|
-
|
16141
|
-
|
16142
|
-
|
16143
|
-
|
16144
|
-
|
16145
|
-
}
|
16146
|
-
|
16147
|
-
|
16148
|
-
|
16149
|
-
|
16150
|
-
|
16151
|
-
|
16152
|
-
|
16153
|
-
|
16154
|
-
// transitional state.
|
16155
|
-
return 'configuration';
|
16156
|
-
}
|
16157
|
-
}
|
16158
|
-
if (previousCall) {
|
16159
|
-
const reason = getCallEndReason(previousCall);
|
16160
|
-
/* @conditional-compile-remove(rooms) */
|
16161
|
-
switch (reason) {
|
16162
|
-
case CallEndReasons.ROOM_NOT_FOUND:
|
16163
|
-
return 'roomNotFound';
|
16164
|
-
case CallEndReasons.DENIED_PERMISSION_TO_ROOM:
|
16165
|
-
return 'deniedPermissionToRoom';
|
16090
|
+
const ChatScreen = (props) => {
|
16091
|
+
const { onFetchAvatarPersonaData, onRenderMessage, onRenderTypingIndicator, options, styles, fileSharing, formFactor } = props;
|
16092
|
+
const defaultNumberOfChatMessagesToReload = 5;
|
16093
|
+
/* @conditional-compile-remove(file-sharing) */
|
16094
|
+
const [downloadErrorMessage, setDownloadErrorMessage] = React__default['default'].useState('');
|
16095
|
+
const adapter = useAdapter$1();
|
16096
|
+
const theme = useTheme();
|
16097
|
+
React.useEffect(() => {
|
16098
|
+
// Initial data should be always fetched by the composite(or external caller) instead of the adapter
|
16099
|
+
adapter.fetchInitialData();
|
16100
|
+
}, [adapter]);
|
16101
|
+
const messageThreadProps = usePropsFor$2(MessageThread);
|
16102
|
+
const sendBoxProps = usePropsFor$2(SendBox);
|
16103
|
+
const typingIndicatorProps = usePropsFor$2(TypingIndicator);
|
16104
|
+
const headerProps = useAdaptedSelector$1(getHeaderProps);
|
16105
|
+
const errorBarProps = usePropsFor$2(ErrorBar);
|
16106
|
+
const onRenderAvatarCallback = React.useCallback((userId, defaultOptions) => {
|
16107
|
+
return (React__default['default'].createElement(AvatarPersona, Object.assign({ userId: userId, hidePersonaDetails: true }, defaultOptions, { dataProvider: onFetchAvatarPersonaData })));
|
16108
|
+
}, [onFetchAvatarPersonaData]);
|
16109
|
+
const messageThreadStyles = Object.assign({}, messageThreadChatCompositeStyles(theme.semanticColors.bodyBackground), styles === null || styles === void 0 ? void 0 : styles.messageThread);
|
16110
|
+
const typingIndicatorStyles = Object.assign({}, styles === null || styles === void 0 ? void 0 : styles.typingIndicator);
|
16111
|
+
const sendBoxStyles = Object.assign({}, styles === null || styles === void 0 ? void 0 : styles.sendBox);
|
16112
|
+
const userId = toFlatCommunicationIdentifier(adapter.getState().userId);
|
16113
|
+
const fileUploadButtonOnChange = React.useCallback((files) => {
|
16114
|
+
if (!files) {
|
16115
|
+
return;
|
16166
16116
|
}
|
16167
|
-
|
16168
|
-
|
16169
|
-
|
16170
|
-
|
16171
|
-
|
16172
|
-
|
16173
|
-
|
16174
|
-
|
16175
|
-
|
16176
|
-
|
16117
|
+
/* @conditional-compile-remove(file-sharing) */
|
16118
|
+
const fileUploads = adapter.registerActiveFileUploads(Array.from(files));
|
16119
|
+
/* @conditional-compile-remove(file-sharing) */
|
16120
|
+
fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.uploadHandler(userId, fileUploads);
|
16121
|
+
}, [adapter, fileSharing, userId]);
|
16122
|
+
/* @conditional-compile-remove(file-sharing) */
|
16123
|
+
const onRenderFileDownloads = React.useCallback((userId, message) => (React__default['default'].createElement(_FileDownloadCards, { userId: userId, fileMetadata: message.attachedFilesMetadata || [], downloadHandler: fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.downloadHandler, onDownloadErrorMessage: (errorMessage) => {
|
16124
|
+
setDownloadErrorMessage(errorMessage);
|
16125
|
+
} })), [fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.downloadHandler]);
|
16126
|
+
const AttachFileButton = React.useCallback(() => {
|
16127
|
+
if (!(fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.uploadHandler)) {
|
16128
|
+
return null;
|
16177
16129
|
}
|
16178
|
-
|
16179
|
-
|
16180
|
-
return '
|
16130
|
+
return (React__default['default'].createElement(FileUploadButtonWrapper, { accept: fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.accept, multiple: fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.multiple, onChange: fileUploadButtonOnChange }));
|
16131
|
+
}, [fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.accept, fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.multiple, fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.uploadHandler, fileUploadButtonOnChange]);
|
16132
|
+
return (React__default['default'].createElement(react.Stack, { className: chatContainer, grow: true },
|
16133
|
+
(options === null || options === void 0 ? void 0 : options.topic) !== false && React__default['default'].createElement(ChatHeader, Object.assign({}, headerProps)),
|
16134
|
+
React__default['default'].createElement(react.Stack, { className: chatArea, tokens: participantListContainerPadding, horizontal: true, grow: true },
|
16135
|
+
React__default['default'].createElement(react.Stack, { className: chatWrapper, grow: true },
|
16136
|
+
(options === null || options === void 0 ? void 0 : options.errorBar) !== false && React__default['default'].createElement(ErrorBar, Object.assign({}, errorBarProps)),
|
16137
|
+
/* @conditional-compile-remove(file-sharing) */
|
16138
|
+
React__default['default'].createElement(FileDownloadErrorBar, { onDismissDownloadErrorMessage: React.useCallback(() => {
|
16139
|
+
setDownloadErrorMessage('');
|
16140
|
+
}, []), fileDownloadErrorMessage: downloadErrorMessage || '' }),
|
16141
|
+
React__default['default'].createElement(MessageThread, Object.assign({}, messageThreadProps, { onRenderAvatar: onRenderAvatarCallback, onRenderMessage: onRenderMessage,
|
16142
|
+
/* @conditional-compile-remove(file-sharing) */
|
16143
|
+
onRenderFileDownloads: onRenderFileDownloads, numberOfChatMessagesToReload: defaultNumberOfChatMessagesToReload, styles: messageThreadStyles })),
|
16144
|
+
React__default['default'].createElement(react.Stack, { className: react.mergeStyles(sendboxContainerStyles) },
|
16145
|
+
React__default['default'].createElement("div", { className: react.mergeStyles(typingIndicatorContainerStyles) }, onRenderTypingIndicator ? (onRenderTypingIndicator(typingIndicatorProps.typingUsers)) : (React__default['default'].createElement(TypingIndicator, Object.assign({}, typingIndicatorProps, { styles: typingIndicatorStyles })))),
|
16146
|
+
React__default['default'].createElement(react.Stack, { horizontal: formFactor === 'mobile' },
|
16147
|
+
formFactor === 'mobile' && (React__default['default'].createElement(react.Stack, { verticalAlign: "center" },
|
16148
|
+
React__default['default'].createElement(AttachFileButton, null))),
|
16149
|
+
React__default['default'].createElement(react.Stack, { grow: true },
|
16150
|
+
React__default['default'].createElement(SendBox, Object.assign({}, sendBoxProps, { autoFocus: options === null || options === void 0 ? void 0 : options.autoFocus, styles: sendBoxStyles,
|
16151
|
+
/* @conditional-compile-remove(file-sharing) */
|
16152
|
+
activeFileUploads: useSelector$2(fileUploadsSelector).files,
|
16153
|
+
/* @conditional-compile-remove(file-sharing) */
|
16154
|
+
onCancelFileUpload: adapter.cancelFileUpload }))),
|
16155
|
+
formFactor !== 'mobile' && React__default['default'].createElement(AttachFileButton, null)))),
|
16156
|
+
/* @conditional-compile-remove(chat-composite-participant-pane) */
|
16157
|
+
(options === null || options === void 0 ? void 0 : options.participantPane) === true && (React__default['default'].createElement(ChatScreenPeoplePane, { onFetchAvatarPersonaData: onFetchAvatarPersonaData, onFetchParticipantMenuItems: props.onFetchParticipantMenuItems, isMobile: formFactor === 'mobile' })))));
|
16158
|
+
};
|
16159
|
+
|
16160
|
+
// Copyright (c) Microsoft Corporation.
|
16161
|
+
/**
|
16162
|
+
* A customizable UI composite for the chat experience.
|
16163
|
+
*
|
16164
|
+
* @remarks Chat composite min width and height are respectively 17.5rem and 20rem (280px and 320px, with default rem at 16px)
|
16165
|
+
*
|
16166
|
+
* @public
|
16167
|
+
*/
|
16168
|
+
const ChatComposite = (props) => {
|
16169
|
+
const { adapter, options, onFetchAvatarPersonaData, onRenderTypingIndicator, onRenderMessage, onFetchParticipantMenuItems } = props;
|
16170
|
+
const formFactor = props['formFactor'] || 'desktop';
|
16171
|
+
/**
|
16172
|
+
* @TODO Remove this function and pass the props directly when file-sharing is promoted to stable.
|
16173
|
+
* @private
|
16174
|
+
*/
|
16175
|
+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
16176
|
+
const fileSharingOptions = () => {
|
16177
|
+
/* @conditional-compile-remove(file-sharing) */
|
16178
|
+
return {
|
16179
|
+
fileSharing: options === null || options === void 0 ? void 0 : options.fileSharing
|
16180
|
+
};
|
16181
|
+
};
|
16182
|
+
return (React__default['default'].createElement("div", { className: chatScreenContainerStyle },
|
16183
|
+
React__default['default'].createElement(BaseProvider, Object.assign({}, props),
|
16184
|
+
React__default['default'].createElement(ChatAdapterProvider, { adapter: adapter },
|
16185
|
+
React__default['default'].createElement(ChatScreen, Object.assign({ formFactor: formFactor, options: options, onFetchAvatarPersonaData: onFetchAvatarPersonaData, onRenderTypingIndicator: onRenderTypingIndicator, onRenderMessage: onRenderMessage, onFetchParticipantMenuItems: onFetchParticipantMenuItems }, fileSharingOptions()))))));
|
16181
16186
|
};
|
16182
|
-
|
16183
|
-
|
16187
|
+
|
16188
|
+
// Copyright (c) Microsoft Corporation.
|
16189
|
+
const CallAdapterContext = React.createContext(undefined);
|
16184
16190
|
/**
|
16185
|
-
*
|
16186
|
-
* This protects against adding a new composite page that should be marked as an callEndedPage.
|
16187
|
-
* EndCallPages are used to trigger onCallEnded events so this could easily be missed.
|
16188
|
-
* When you add a new composite page this will throw a compiler error. If this new page is an
|
16189
|
-
* EndCallPage ensure you update the END_CALL_PAGES. Afterwards update the `page` parameter
|
16190
|
-
* type below to allow your new page, i.e. add `| <your new page>
|
16191
|
+
* @private
|
16191
16192
|
*/
|
16192
|
-
|
16193
|
+
const CallAdapterProvider = (props) => {
|
16194
|
+
const { adapter } = props;
|
16195
|
+
return React__default['default'].createElement(CallAdapterContext.Provider, { value: adapter }, props.children);
|
16196
|
+
};
|
16193
16197
|
/**
|
16194
|
-
* Creates a new call control options object and sets the correct values for disabling
|
16195
|
-
* the buttons provided in the `disabledControls` array.
|
16196
|
-
* Returns a new object without changing the original object.
|
16197
|
-
* @param callControlOptions options for the call control component that need to be modified.
|
16198
|
-
* @param disabledControls An array of controls to disable.
|
16199
|
-
* @returns a copy of callControlOptions with disabledControls disabled
|
16200
16198
|
* @private
|
16201
16199
|
*/
|
16202
|
-
const
|
16203
|
-
|
16204
|
-
if (
|
16205
|
-
|
16206
|
-
}
|
16207
|
-
// Ensure we clone the prop if it is an object to ensure we do not mutate the original prop.
|
16208
|
-
let newOptions = (_a = (callControlOptions instanceof Object ? Object.assign({}, callControlOptions) : callControlOptions)) !== null && _a !== void 0 ? _a : {};
|
16209
|
-
if (newOptions === true || newOptions === undefined) {
|
16210
|
-
newOptions = disabledControls.reduce((acc, key) => {
|
16211
|
-
acc[key] = { disabled: true };
|
16212
|
-
return acc;
|
16213
|
-
}, {});
|
16214
|
-
}
|
16215
|
-
else {
|
16216
|
-
disabledControls.forEach((key) => {
|
16217
|
-
if (newOptions[key] !== false) {
|
16218
|
-
newOptions[key] = { disabled: true };
|
16219
|
-
}
|
16220
|
-
});
|
16200
|
+
const useAdapter = () => {
|
16201
|
+
const adapter = React.useContext(CallAdapterContext);
|
16202
|
+
if (!adapter) {
|
16203
|
+
throw 'Cannot find adapter please initialize before usage.';
|
16221
16204
|
}
|
16222
|
-
return
|
16205
|
+
return adapter;
|
16223
16206
|
};
|
16207
|
+
|
16208
|
+
// Copyright (c) Microsoft Corporation.
|
16209
|
+
// Licensed under the MIT license.
|
16210
|
+
/** @private */
|
16211
|
+
const containerDivStyles = { position: 'relative', width: '100%', height: '100%' };
|
16212
|
+
|
16213
|
+
// Copyright (c) Microsoft Corporation.
|
16224
16214
|
/**
|
16225
|
-
* Check if a disabled object is provided for a button and returns if the button is disabled.
|
16226
|
-
* A button is only disabled if is explicitly set to disabled.
|
16227
|
-
*
|
16228
|
-
* @param option
|
16229
|
-
* @returns whether a button is disabled
|
16230
16215
|
* @private
|
16231
16216
|
*/
|
16232
|
-
const
|
16233
|
-
|
16234
|
-
return false;
|
16235
|
-
}
|
16236
|
-
return option.disabled;
|
16217
|
+
const useAdaptedSelector = (selector, selectorProps) => {
|
16218
|
+
return useSelectorWithAdaptation(selector, adaptCompositeState, selectorProps);
|
16237
16219
|
};
|
16238
|
-
/* @conditional-compile-remove(call-readiness) */
|
16239
16220
|
/**
|
16240
|
-
*
|
16241
|
-
* This function uses permission API to determine if device permission state is granted, prompt or denied
|
16242
|
-
* @returns whether device permission state is granted, prompt or denied
|
16243
|
-
* If permission API is not supported on this browser, do nothing and log out error
|
16244
16221
|
* @private
|
16245
16222
|
*/
|
16246
|
-
const
|
16247
|
-
|
16248
|
-
|
16249
|
-
|
16250
|
-
|
16251
|
-
|
16252
|
-
|
16253
|
-
|
16254
|
-
|
16255
|
-
|
16256
|
-
|
16257
|
-
.then((result) => {
|
16258
|
-
setAudioState(result.state);
|
16259
|
-
})
|
16260
|
-
.catch(() => {
|
16261
|
-
setAudioState('unsupported');
|
16223
|
+
const useSelectorWithAdaptation = (selector, adaptState, selectorProps) => {
|
16224
|
+
var _a;
|
16225
|
+
const adapter = useAdapter();
|
16226
|
+
// Keeps track of whether the current component is mounted or not. If it has unmounted, make sure we do not modify the
|
16227
|
+
// state or it will cause React warnings in the console. https://skype.visualstudio.com/SPOOL/_workitems/edit/2453212
|
16228
|
+
const mounted = React.useRef(false);
|
16229
|
+
React.useEffect(() => {
|
16230
|
+
mounted.current = true;
|
16231
|
+
return () => {
|
16232
|
+
mounted.current = false;
|
16233
|
+
};
|
16262
16234
|
});
|
16235
|
+
const callId = (_a = adapter.getState().call) === null || _a === void 0 ? void 0 : _a.id;
|
16236
|
+
const callConfigProps = React.useMemo(() => ({
|
16237
|
+
callId
|
16238
|
+
}), [callId]);
|
16239
|
+
const [props, setProps] = React.useState(selector(adaptState(adapter.getState()), selectorProps !== null && selectorProps !== void 0 ? selectorProps : callConfigProps));
|
16240
|
+
const propRef = React.useRef(props);
|
16241
|
+
propRef.current = props;
|
16242
|
+
React.useEffect(() => {
|
16243
|
+
const onStateChange = (state) => {
|
16244
|
+
if (!mounted.current) {
|
16245
|
+
return;
|
16246
|
+
}
|
16247
|
+
const newProps = selector(adaptState(state), selectorProps !== null && selectorProps !== void 0 ? selectorProps : callConfigProps);
|
16248
|
+
if (propRef.current !== newProps) {
|
16249
|
+
setProps(newProps);
|
16250
|
+
}
|
16251
|
+
};
|
16252
|
+
adapter.onStateChange(onStateChange);
|
16253
|
+
return () => {
|
16254
|
+
adapter.offStateChange(onStateChange);
|
16255
|
+
};
|
16256
|
+
}, [adaptState, adapter, selector, selectorProps, callConfigProps]);
|
16257
|
+
return props;
|
16263
16258
|
};
|
16264
|
-
|
16265
|
-
|
16266
|
-
|
16267
|
-
|
16268
|
-
|
16269
|
-
|
16259
|
+
const memoizeState = memoizeOne__default['default']((userId, deviceManager, calls, latestErrors, displayName, alternateCallerId, environmentInfo) => ({
|
16260
|
+
userId,
|
16261
|
+
incomingCalls: {},
|
16262
|
+
incomingCallsEnded: {},
|
16263
|
+
callsEnded: {},
|
16264
|
+
deviceManager,
|
16265
|
+
callAgent: { displayName },
|
16266
|
+
calls,
|
16267
|
+
latestErrors,
|
16268
|
+
/* @conditional-compile-remove(PSTN-calls) */
|
16269
|
+
alternateCallerId,
|
16270
|
+
/* @conditional-compile-remove(unsupported-browser) */
|
16271
|
+
environmentInfo
|
16272
|
+
}));
|
16273
|
+
const memoizeCalls = memoizeOne__default['default']((call) => (call ? { [call.id]: call } : {}));
|
16274
|
+
const adaptCompositeState = (compositeState) => {
|
16275
|
+
return memoizeState(compositeState.userId, compositeState.devices, memoizeCalls(compositeState.call),
|
16276
|
+
// This is an unsafe type expansion.
|
16277
|
+
// compositeState.latestErrors can contain properties that are not valid in CallErrors.
|
16278
|
+
//
|
16279
|
+
// But there is no way to check for valid property names at runtime:
|
16280
|
+
// - The set of valid property names is built from types in the @azure/communication-calling.
|
16281
|
+
// Thus we don't have a literal array of allowed strings at runtime.
|
16282
|
+
// - Due to minification / uglification, the property names from the objects at runtime can't be used
|
16283
|
+
// to compare against permissible values inferred from the types.
|
16284
|
+
//
|
16285
|
+
// This is not a huge problem -- it simply means that our adapted selector will include some extra operations
|
16286
|
+
// that are unknown to the UI component and data binding libraries. Generic handling of the errors (e.g.,
|
16287
|
+
// just displaying them in some UI surface) will continue to work for these operations. Handling of
|
16288
|
+
// specific operations (e.g., acting on errors related to permission issues) will ignore these operations.
|
16289
|
+
compositeState.latestErrors, compositeState.displayName,
|
16290
|
+
/* @conditional-compile-remove(PSTN-calls) */
|
16291
|
+
compositeState.alternateCallerId,
|
16292
|
+
/* @conditional-compile-remove(unsupported-browser) */
|
16293
|
+
compositeState.environmentInfo);
|
16270
16294
|
};
|
16271
16295
|
|
16272
16296
|
// Copyright (c) Microsoft Corporation.
|
@@ -16665,7 +16689,7 @@ const Microphone = (props) => {
|
|
16665
16689
|
: {};
|
16666
16690
|
const styles = React.useMemo(() => { var _a; return concatButtonBaseStyles((_a = props.styles) !== null && _a !== void 0 ? _a : {}); }, [props.styles]);
|
16667
16691
|
// tab focus on MicrophoneButton on page load
|
16668
|
-
return (React__default['default'].createElement(MicrophoneButton, Object.assign({
|
16692
|
+
return (React__default['default'].createElement(MicrophoneButton, Object.assign({ "data-ui-id": "call-composite-microphone-button" }, microphoneButtonProps, { showLabel: props.displayType !== 'compact', styles: styles }, microphoneButtonStrings, { enableDeviceSelectionMenu: props.splitButtonsForDeviceSelection, disabled: microphoneButtonProps.disabled || props.disabled })));
|
16669
16693
|
};
|
16670
16694
|
|
16671
16695
|
// Copyright (c) Microsoft Corporation.
|
@@ -17096,6 +17120,14 @@ const bannerNotificationStyles = {
|
|
17096
17120
|
pointerEvents: 'auto' // to allow the dismissal or error and warning bars in the notification container
|
17097
17121
|
}
|
17098
17122
|
};
|
17123
|
+
/**
|
17124
|
+
* @private
|
17125
|
+
*/
|
17126
|
+
const callArrangementContainerStyles = {
|
17127
|
+
root: {
|
17128
|
+
flexDirection: 'column-reverse' // to allow first initial keyboard focus on ControlBar
|
17129
|
+
}
|
17130
|
+
};
|
17099
17131
|
|
17100
17132
|
// Copyright (c) Microsoft Corporation.
|
17101
17133
|
/**
|
@@ -18081,25 +18113,25 @@ const CallArrangement = (props) => {
|
|
18081
18113
|
}
|
18082
18114
|
return (React__default['default'].createElement("div", { ref: containerRef, className: react.mergeStyles(containerDivStyles) },
|
18083
18115
|
React__default['default'].createElement(react.Stack, { verticalFill: true, horizontalAlign: "stretch", className: containerClassName, "data-ui-id": props.dataUiId },
|
18084
|
-
React__default['default'].createElement(react.Stack, { horizontal: true, grow: true },
|
18116
|
+
React__default['default'].createElement(react.Stack, { horizontal: true, grow: true, styles: callArrangementContainerStyles },
|
18085
18117
|
React__default['default'].createElement(react.Stack.Item, { styles: notificationsContainerStyles },
|
18086
18118
|
React__default['default'].createElement(react.Stack, { styles: bannerNotificationStyles },
|
18087
18119
|
React__default['default'].createElement(_ComplianceBanner, Object.assign({}, props.complianceBannerProps))),
|
18088
18120
|
errorBarProps !== false && (React__default['default'].createElement(react.Stack, { styles: bannerNotificationStyles },
|
18089
18121
|
React__default['default'].createElement(ErrorBar, Object.assign({}, errorBarProps)))),
|
18090
18122
|
canUnmute && !!props.mutedNotificationProps && React__default['default'].createElement(MutedNotification, Object.assign({}, props.mutedNotificationProps))),
|
18123
|
+
((_b = props.callControlProps) === null || _b === void 0 ? void 0 : _b.options) !== false &&
|
18124
|
+
/* @conditional-compile-remove(one-to-n-calling) @conditional-compile-remove(PSTN-calls) */
|
18125
|
+
!isMobileWithActivePane && (React__default['default'].createElement(react.Stack.Item, { className: callControlsContainerStyles },
|
18126
|
+
React__default['default'].createElement(CallControls, Object.assign({}, props.callControlProps, { containerWidth: containerWidth, containerHeight: containerHeight, isMobile: props.mobileView,
|
18127
|
+
/* @conditional-compile-remove(one-to-n-calling) */
|
18128
|
+
peopleButtonChecked: activePane === 'people',
|
18129
|
+
/* @conditional-compile-remove(one-to-n-calling) */
|
18130
|
+
onPeopleButtonClicked: togglePeoplePane })))),
|
18091
18131
|
React__default['default'].createElement(react.Stack.Item, { grow: true, style: callCompositeContainerFlex() },
|
18092
18132
|
React__default['default'].createElement(react.Stack.Item, { styles: callGalleryStyles, grow: true }, props.onRenderGalleryContent && (React__default['default'].createElement(react.Stack, { verticalFill: true, styles: mediaGalleryContainerStyles }, props.onRenderGalleryContent())))),
|
18093
18133
|
/* @conditional-compile-remove(one-to-n-calling) @conditional-compile-remove(PSTN-calls) */
|
18094
|
-
callPaneContent())
|
18095
|
-
((_b = props.callControlProps) === null || _b === void 0 ? void 0 : _b.options) !== false &&
|
18096
|
-
/* @conditional-compile-remove(one-to-n-calling) @conditional-compile-remove(PSTN-calls) */
|
18097
|
-
!isMobileWithActivePane && (React__default['default'].createElement(react.Stack.Item, { className: callControlsContainerStyles },
|
18098
|
-
React__default['default'].createElement(CallControls, Object.assign({}, props.callControlProps, { containerWidth: containerWidth, containerHeight: containerHeight, isMobile: props.mobileView,
|
18099
|
-
/* @conditional-compile-remove(one-to-n-calling) */
|
18100
|
-
peopleButtonChecked: activePane === 'people',
|
18101
|
-
/* @conditional-compile-remove(one-to-n-calling) */
|
18102
|
-
onPeopleButtonClicked: togglePeoplePane })))))));
|
18134
|
+
callPaneContent()))));
|
18103
18135
|
};
|
18104
18136
|
/* @conditional-compile-remove(one-to-n-calling) @conditional-compile-remove(PSTN-calls) */
|
18105
18137
|
const showShowPeopleTabHeaderButton$1 = (callControls) => {
|
@@ -20595,6 +20627,9 @@ class AzureCommunicationCallAdapter {
|
|
20595
20627
|
const createAzureCommunicationCallAdapter = ({ userId, displayName, credential, locator,
|
20596
20628
|
/* @conditional-compile-remove(PSTN-calls) */ alternateCallerId,
|
20597
20629
|
/* @conditional-compile-remove(rooms) */ options }) => __awaiter$4(void 0, void 0, void 0, function* () {
|
20630
|
+
if (!isValidIdentifier(userId)) {
|
20631
|
+
throw new Error('Invalid identifier. Please provide valid identifier object.');
|
20632
|
+
}
|
20598
20633
|
const callClient = createStatefulCallClient({
|
20599
20634
|
userId,
|
20600
20635
|
/* @conditional-compile-remove(PSTN-calls) */ alternateCallerId
|
@@ -21087,6 +21122,50 @@ const DesktopMoreButton = (props) => {
|
|
21087
21122
|
strings: moreButtonStrings, menuIconProps: { hidden: true }, menuProps: { items: moreButtonContextualMenuItems() } })));
|
21088
21123
|
};
|
21089
21124
|
|
21125
|
+
// Copyright (c) Microsoft Corporation.
|
21126
|
+
// Licensed under the MIT license.
|
21127
|
+
/**
|
21128
|
+
* @private
|
21129
|
+
*/
|
21130
|
+
const compositeOuterContainerStyles = {
|
21131
|
+
root: {
|
21132
|
+
width: '100%',
|
21133
|
+
// Create a new stacking context so that DrawerMenu can be positioned absolutely.
|
21134
|
+
position: 'relative'
|
21135
|
+
}
|
21136
|
+
};
|
21137
|
+
/** @private */
|
21138
|
+
const callCompositeContainerStyles = {
|
21139
|
+
root: {
|
21140
|
+
// Start a new stacking context so that any `position:absolute` elements
|
21141
|
+
// inside the call composite do not compete with its siblings.
|
21142
|
+
position: 'relative'
|
21143
|
+
}
|
21144
|
+
};
|
21145
|
+
/** @private */
|
21146
|
+
const controlBarContainerStyles = {
|
21147
|
+
root: {
|
21148
|
+
// Start a new stacking context so that any `position:absolute` elements
|
21149
|
+
// inside the control bar do not compete with its siblings.
|
21150
|
+
position: 'relative'
|
21151
|
+
}
|
21152
|
+
};
|
21153
|
+
/** @private */
|
21154
|
+
const hiddenAutoFocusButtonStyles = {
|
21155
|
+
root: {
|
21156
|
+
width: '0',
|
21157
|
+
height: '0',
|
21158
|
+
margin: '0',
|
21159
|
+
minHeight: '0',
|
21160
|
+
minWidth: '0',
|
21161
|
+
maxHeight: '0',
|
21162
|
+
maxWidth: '0',
|
21163
|
+
outline: 'none',
|
21164
|
+
padding: '0',
|
21165
|
+
position: 'absolute'
|
21166
|
+
}
|
21167
|
+
};
|
21168
|
+
|
21090
21169
|
// Copyright (c) Microsoft Corporation.
|
21091
21170
|
const inferCallWithChatControlOptions$1 = (mobileView, callWithChatControls) => {
|
21092
21171
|
if (callWithChatControls === false) {
|
@@ -21109,6 +21188,13 @@ const inferCallWithChatControlOptions$1 = (mobileView, callWithChatControls) =>
|
|
21109
21188
|
*/
|
21110
21189
|
const CallWithChatControlBar = (props) => {
|
21111
21190
|
var _a, _b;
|
21191
|
+
React.useEffect(() => {
|
21192
|
+
var _a;
|
21193
|
+
// On mount, button used for initial focus is hidden to prevent screen readers from announcing the initial focus
|
21194
|
+
if (document.querySelector('[data-ui-id=call-with-chat-autofocus-hidden-button]') === document.activeElement) {
|
21195
|
+
(_a = document.activeElement) === null || _a === void 0 ? void 0 : _a.setAttribute('hidden', 'true');
|
21196
|
+
}
|
21197
|
+
}, []);
|
21112
21198
|
const theme = react.useTheme();
|
21113
21199
|
const callWithChatStrings = useCallWithChatCompositeStrings();
|
21114
21200
|
const options = inferCallWithChatControlOptions$1(props.mobileView, props.callControls);
|
@@ -21149,6 +21235,7 @@ const CallWithChatControlBar = (props) => {
|
|
21149
21235
|
React__default['default'].createElement(react.Stack.Item, { grow: true },
|
21150
21236
|
React__default['default'].createElement(CallAdapterProvider, { adapter: props.callAdapter },
|
21151
21237
|
React__default['default'].createElement(react.Stack, { horizontalAlign: "center" },
|
21238
|
+
React__default['default'].createElement(ControlBarButton, { autoFocus: true, ariaHidden: true, "data-ui-id": 'call-with-chat-autofocus-hidden-button', styles: hiddenAutoFocusButtonStyles, tabIndex: -1 }),
|
21152
21239
|
React__default['default'].createElement(react.Stack.Item, null,
|
21153
21240
|
React__default['default'].createElement(ControlBar, { layout: "horizontal", styles: centerContainerStyles },
|
21154
21241
|
isEnabled$1(options.microphoneButton) && (React__default['default'].createElement(Microphone, { displayType: options.displayType, styles: commonButtonStyles, splitButtonsForDeviceSelection: !props.mobileView,
|
@@ -21255,35 +21342,6 @@ const getDesktopEndCallButtonStyles = (theme) => {
|
|
21255
21342
|
};
|
21256
21343
|
const isEnabled$1 = (option) => option !== false;
|
21257
21344
|
|
21258
|
-
// Copyright (c) Microsoft Corporation.
|
21259
|
-
// Licensed under the MIT license.
|
21260
|
-
/**
|
21261
|
-
* @private
|
21262
|
-
*/
|
21263
|
-
const compositeOuterContainerStyles = {
|
21264
|
-
root: {
|
21265
|
-
width: '100%',
|
21266
|
-
// Create a new stacking context so that DrawerMenu can be positioned absolutely.
|
21267
|
-
position: 'relative'
|
21268
|
-
}
|
21269
|
-
};
|
21270
|
-
/** @private */
|
21271
|
-
const callCompositeContainerStyles = {
|
21272
|
-
root: {
|
21273
|
-
// Start a new stacking context so that any `position:absolute` elements
|
21274
|
-
// inside the call composite do not compete with its siblings.
|
21275
|
-
position: 'relative'
|
21276
|
-
}
|
21277
|
-
};
|
21278
|
-
/** @private */
|
21279
|
-
const controlBarContainerStyles = {
|
21280
|
-
root: {
|
21281
|
-
// Start a new stacking context so that any `position:absolute` elements
|
21282
|
-
// inside the control bar do not compete with its siblings.
|
21283
|
-
position: 'relative'
|
21284
|
-
}
|
21285
|
-
};
|
21286
|
-
|
21287
21345
|
// Copyright (c) Microsoft Corporation.
|
21288
21346
|
// Licensed under the MIT license.
|
21289
21347
|
var __awaiter$3 = (window && window.__awaiter) || function (thisArg, _arguments, P, generator) {
|