@microsoft/omnichannel-chat-widget 1.0.1-main.068a14e → 1.0.2-main.2112105

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.
Files changed (35) hide show
  1. package/lib/cjs/common/Constants.js +1 -0
  2. package/lib/cjs/common/telemetry/TelemetryConstants.js +1 -0
  3. package/lib/cjs/common/utils.js +21 -2
  4. package/lib/cjs/components/livechatwidget/common/chatDisconnectHelper.js +32 -0
  5. package/lib/cjs/components/livechatwidget/common/defaultProps/dummyDefaultProps.js +14 -7
  6. package/lib/cjs/components/livechatwidget/common/endChat.js +4 -0
  7. package/lib/cjs/components/livechatwidget/livechatwidgetstateful/LiveChatWidgetStateful.js +25 -1
  8. package/lib/cjs/components/webchatcontainerstateful/common/defaultProps/defaultMiddlewareLocalizedTexts.js +15 -7
  9. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/enums/NotificationScenarios.js +1 -0
  10. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/attachmentUploadValidatorMiddleware.js +27 -13
  11. package/lib/cjs/contexts/common/LiveChatWidgetActionType.js +1 -0
  12. package/lib/cjs/contexts/common/LiveChatWidgetContextInitialState.js +2 -1
  13. package/lib/cjs/contexts/createReducer.js +8 -0
  14. package/lib/esm/common/Constants.js +1 -0
  15. package/lib/esm/common/telemetry/TelemetryConstants.js +1 -0
  16. package/lib/esm/common/utils.js +19 -1
  17. package/lib/esm/components/livechatwidget/common/chatDisconnectHelper.js +26 -0
  18. package/lib/esm/components/livechatwidget/common/defaultProps/dummyDefaultProps.js +14 -7
  19. package/lib/esm/components/livechatwidget/common/endChat.js +4 -0
  20. package/lib/esm/components/livechatwidget/livechatwidgetstateful/LiveChatWidgetStateful.js +27 -3
  21. package/lib/esm/components/webchatcontainerstateful/common/defaultProps/defaultMiddlewareLocalizedTexts.js +15 -7
  22. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/enums/NotificationScenarios.js +1 -0
  23. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/attachmentUploadValidatorMiddleware.js +27 -13
  24. package/lib/esm/contexts/common/LiveChatWidgetActionType.js +1 -0
  25. package/lib/esm/contexts/common/LiveChatWidgetContextInitialState.js +2 -1
  26. package/lib/esm/contexts/createReducer.js +8 -0
  27. package/lib/types/common/Constants.d.ts +1 -0
  28. package/lib/types/common/telemetry/TelemetryConstants.d.ts +2 -1
  29. package/lib/types/common/utils.d.ts +1 -0
  30. package/lib/types/components/livechatwidget/common/chatDisconnectHelper.d.ts +4 -0
  31. package/lib/types/components/webchatcontainerstateful/webchatcontroller/enums/NotificationScenarios.d.ts +2 -1
  32. package/lib/types/contexts/common/ILiveChatWidgetContext.d.ts +1 -0
  33. package/lib/types/contexts/common/ILiveChatWidgetLocalizedTexts.d.ts +1 -0
  34. package/lib/types/contexts/common/LiveChatWidgetActionType.d.ts +2 -1
  35. package/package.json +1 -1
@@ -92,6 +92,7 @@ _defineProperty(Constants, "ChatWidgetStateChangedPrefix", "ChatWidgetStateChang
92
92
  _defineProperty(Constants, "PostChatLoadingDurationInMs", 2000);
93
93
  _defineProperty(Constants, "BrowserUnloadConfirmationMessage", "Do you want to leave chat?");
94
94
  _defineProperty(Constants, "CacheTtlInMinutes", 15);
95
+ _defineProperty(Constants, "LWICheckOnVisibilityTimeout", 3 * 60 * 1000);
95
96
  const Regex = (_class = class Regex {}, _defineProperty(_class, "EmailRegex", "(?:[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-zA-Z0-9-]*[a-zA-Z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"), _class);
96
97
  exports.Regex = Regex;
97
98
  class HtmlIdNames {}
@@ -198,6 +198,7 @@ exports.TelemetryEvent = TelemetryEvent;
198
198
  TelemetryEvent["PostChatContextCallFailed"] = "PostChatContextCallFailed";
199
199
  TelemetryEvent["PostChatSurveyLoadingPaneLoaded"] = "PostChatSurveyLoadingPaneLoaded";
200
200
  TelemetryEvent["PostChatSurveyLoaded"] = "PostChatSurveyLoaded";
201
+ TelemetryEvent["ChatDisconnectThreadEventReceived"] = "ChatDisconnectThreadEventReceived";
201
202
  })(TelemetryEvent || (exports.TelemetryEvent = TelemetryEvent = {}));
202
203
  class TelemetryConstants {
203
204
  static map(eventTypeOrScenarioType) {
@@ -3,12 +3,13 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.setTabIndices = exports.setFocusOnSendBox = exports.setFocusOnElement = exports.preventFocusToMoveOutOfElement = exports.parseAdaptiveCardPayload = exports.newGuid = exports.isUndefinedOrEmpty = exports.isNullOrUndefined = exports.isNullOrEmptyString = exports.getWidgetEndChatEventName = exports.getWidgetCacheId = exports.getTimestampHourMinute = exports.getStateFromCache = exports.getLocaleDirection = exports.getIconText = exports.getDomain = exports.getBroadcastChannelName = exports.findParentFocusableElementsWithoutChildContainer = exports.findAllFocusableElement = exports.extractPreChatSurveyResponseValues = exports.escapeHtml = exports.debounceLeading = exports.createTimer = exports.changeLanguageCodeFormatForWebChat = exports.addDelayInMs = void 0;
6
+ exports.setTabIndices = exports.setFocusOnSendBox = exports.setFocusOnElement = exports.preventFocusToMoveOutOfElement = exports.parseAdaptiveCardPayload = exports.newGuid = exports.isUndefinedOrEmpty = exports.isNullOrUndefined = exports.isNullOrEmptyString = exports.getWidgetEndChatEventName = exports.getWidgetCacheId = exports.getTimestampHourMinute = exports.getStateFromCache = exports.getLocaleDirection = exports.getIconText = exports.getDomain = exports.getConversationDetailsCall = exports.getBroadcastChannelName = exports.findParentFocusableElementsWithoutChildContainer = exports.findAllFocusableElement = exports.extractPreChatSurveyResponseValues = exports.escapeHtml = exports.debounceLeading = exports.createTimer = exports.changeLanguageCodeFormatForWebChat = exports.addDelayInMs = void 0;
7
7
  var _Constants = require("./Constants");
8
8
  var _DataStoreManager = require("./contextDataStore/DataStoreManager");
9
9
  var _KeyCodes = require("./KeyCodes");
10
10
  var _TelemetryConstants = require("./telemetry/TelemetryConstants");
11
11
  var _md5Typescript = require("md5-typescript");
12
+ var _TelemetryHelper = require("./telemetry/TelemetryHelper");
12
13
  var _this = void 0;
13
14
  const getElementBySelector = selector => {
14
15
  let element;
@@ -355,4 +356,22 @@ const debounceLeading = function (fn) {
355
356
  }, ms);
356
357
  };
357
358
  };
358
- exports.debounceLeading = debounceLeading;
359
+
360
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
361
+ exports.debounceLeading = debounceLeading;
362
+ const getConversationDetailsCall = async chatSDK => {
363
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
364
+ let conversationDetails = undefined;
365
+ try {
366
+ conversationDetails = await chatSDK.getConversationDetails();
367
+ } catch (error) {
368
+ _TelemetryHelper.TelemetryHelper.logSDKEvent(_TelemetryConstants.LogLevel.ERROR, {
369
+ Event: _TelemetryConstants.TelemetryEvent.GetConversationDetailsCallFailed,
370
+ ExceptionDetails: {
371
+ exception: `Get Conversation Details Call Failed : ${error}`
372
+ }
373
+ });
374
+ }
375
+ return conversationDetails;
376
+ };
377
+ exports.getConversationDetailsCall = getConversationDetailsCall;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.handleChatDisconnect = void 0;
7
+ var _NotificationHandler = require("../../webchatcontainerstateful/webchatcontroller/notification/NotificationHandler");
8
+ var _NotificationScenarios = require("../../webchatcontainerstateful/webchatcontroller/enums/NotificationScenarios");
9
+ var _defaultMiddlewareLocalizedTexts = require("../../webchatcontainerstateful/common/defaultProps/defaultMiddlewareLocalizedTexts");
10
+ var _TelemetryConstants = require("../../../common/telemetry/TelemetryConstants");
11
+ var _TelemetryHelper = require("../../../common/telemetry/TelemetryHelper");
12
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ const handleChatDisconnect = (props, state, setWebChatStyles) => {
14
+ var _state$appStates;
15
+ if (state !== null && state !== void 0 && (_state$appStates = state.appStates) !== null && _state$appStates !== void 0 && _state$appStates.chatDisconnectEventReceived) {
16
+ var _props$webChatContain, _props$webChatContain2;
17
+ if ((props === null || props === void 0 ? void 0 : (_props$webChatContain = props.webChatContainerProps) === null || _props$webChatContain === void 0 ? void 0 : (_props$webChatContain2 = _props$webChatContain.renderingMiddlewareProps) === null || _props$webChatContain2 === void 0 ? void 0 : _props$webChatContain2.hideSendboxOnConversationEnd) !== false) {
18
+ setWebChatStyles(styles => {
19
+ return {
20
+ ...styles,
21
+ hideSendBox: true
22
+ };
23
+ });
24
+ }
25
+ _NotificationHandler.NotificationHandler.notifyWarning(_NotificationScenarios.NotificationScenarios.ChatDisconnect, _defaultMiddlewareLocalizedTexts.defaultMiddlewareLocalizedTexts.MIDDLEWARE_BANNER_CHAT_DISCONNECT);
26
+ _TelemetryHelper.TelemetryHelper.logActionEvent(_TelemetryConstants.LogLevel.INFO, {
27
+ Event: _TelemetryConstants.TelemetryEvent.ChatDisconnectThreadEventReceived,
28
+ Description: "Chat disconnected due to timeout, left or removed."
29
+ });
30
+ }
31
+ };
32
+ exports.handleChatDisconnect = handleChatDisconnect;
@@ -1756,13 +1756,19 @@ const dummyDefaultProps = {
1756
1756
  }
1757
1757
  },
1758
1758
  localizedTexts: {
1759
+ /*
1760
+ MIDDLEWARE_BANNER_FILE parameters:
1761
+ {0} = File limit size
1762
+ {1} = File extension
1763
+ {2} = File name
1764
+ */
1759
1765
  MIDDLEWARE_BANNER_FILE_NULL_ERROR: "There was an error uploading the file, please try again.",
1760
- MIDDLEWARE_BANNER_FILE_SIZE_WITHOUT_EXTENSION_ERROR: "File exceeds the allowed limit of {0} MB and please upload the file with an appropriate file extension.",
1761
- MIDDLEWARE_BANNER_FILE_SIZE_EXTENSION_ERROR: "File exceeds the allowed limit of {0} MB and {1} files are not supported.",
1762
- MIDDLEWARE_BANNER_FILE_WITHOUT_EXTENSION: "File upload error. Please upload the file with an appropriate file extension.",
1763
- MIDDLEWARE_BANNER_FILE_EXTENSION_ERROR: "{0} files are not supported.",
1764
- MIDDLEWARE_BANNER_FILE_SIZE_ERROR: "File exceeds the allowed limit of {0} MB.",
1765
- MIDDLEWARE_BANNER_FILE_IS_EMPTY_ERROR: "This file can't be attached because it's empty. Please try again with a different file.",
1766
+ MIDDLEWARE_BANNER_FILE_SIZE_WITHOUT_EXTENSION_ERROR: "File {2} exceeds the allowed limit of {0} MB and please upload the file with an appropriate file extension.",
1767
+ MIDDLEWARE_BANNER_FILE_SIZE_EXTENSION_ERROR: "File {2} exceeds the allowed limit of {0} MB and {1} files are not supported.",
1768
+ MIDDLEWARE_BANNER_FILE_WITHOUT_EXTENSION: "File upload error. Please upload the file {2} with an appropriate file extension.",
1769
+ MIDDLEWARE_BANNER_FILE_EXTENSION_ERROR: "{1} files are not supported.",
1770
+ MIDDLEWARE_BANNER_FILE_SIZE_ERROR: "File {2} exceeds the allowed limit of {0} MB.",
1771
+ MIDDLEWARE_BANNER_FILE_IS_EMPTY_ERROR: "This file {2} can't be attached because it's empty. Please try again with a different file.",
1766
1772
  MIDDLEWARE_BANNER_ERROR_MESSAGE: "Upload failed, please try again.",
1767
1773
  MIDDLEWARE_BANNER_INTERNET_BACK_ONLINE: "You're back online.",
1768
1774
  MIDDLEWARE_BANNER_NO_INTERNET_CONNECTION: "Unable to connect—please check your internet connection.",
@@ -1775,7 +1781,8 @@ const dummyDefaultProps = {
1775
1781
  MIDDLEWARE_MESSAGE_NOT_DELIVERED: "Not Delivered",
1776
1782
  MIDDLEWARE_MESSAGE_RETRY: "Retry",
1777
1783
  PRECHAT_REQUIRED_FIELD_MISSING_MESSAGE: "{0} field is required",
1778
- MARKDOWN_EXTERNAL_LINK_ALT: "Opens in a new window; external."
1784
+ MARKDOWN_EXTERNAL_LINK_ALT: "Opens in a new window; external.",
1785
+ MIDDLEWARE_BANNER_CHAT_DISCONNECT: "Your conversation has been disconnected. For additional assistance, please start a new chat."
1779
1786
  },
1780
1787
  botMagicCode: {
1781
1788
  disabled: false,
@@ -93,6 +93,10 @@ const endChat = async (props, chatSDK, setAdapter, setWebChatStyles, dispatch, a
93
93
  type: _LiveChatWidgetActionType.LiveChatWidgetActionType.SET_RECONNECT_ID,
94
94
  payload: undefined
95
95
  });
96
+ dispatch({
97
+ type: _LiveChatWidgetActionType.LiveChatWidgetActionType.SET_CHAT_DISCONNECT_EVENT_RECEIVED,
98
+ payload: false
99
+ });
96
100
  if (!skipCloseChat) {
97
101
  try {
98
102
  var _props$webChatContain;
@@ -53,6 +53,7 @@ var _useChatSDKStore = _interopRequireDefault(require("../../../hooks/useChatSDK
53
53
  var _ConversationEndEntity = require("../../../contexts/common/ConversationEndEntity");
54
54
  var _agentEndConversationHelper = require("../common/agentEndConversationHelper");
55
55
  var _reconnectChatHelper = require("../common/reconnectChatHelper");
56
+ var _chatDisconnectHelper = require("../common/chatDisconnectHelper");
56
57
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
57
58
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
58
59
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
@@ -87,6 +88,7 @@ const LiveChatWidgetStateful = props => {
87
88
  _TelemetryManager.TelemetryTimers.LcwLoadToChatButtonTimer = (0, _utils.createTimer)();
88
89
  const widgetElementId = ((_props$controlProps2 = props.controlProps) === null || _props$controlProps2 === void 0 ? void 0 : _props$controlProps2.id) || "oc-lcw";
89
90
  const currentMessageCountRef = (0, _react2.useRef)(0);
91
+ const lastLWICheckTimeRef = (0, _react2.useRef)(0);
90
92
  let widgetStateEventName = "";
91
93
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
92
94
  let optionalParams;
@@ -253,7 +255,7 @@ const LiveChatWidgetStateful = props => {
253
255
  });
254
256
 
255
257
  // Toggle chat visibility
256
- _omnichannelChatComponents.BroadcastService.getMessageByEventName(_TelemetryConstants.BroadcastEvent.HideChatVisibilityChangeEvent).subscribe(event => {
258
+ _omnichannelChatComponents.BroadcastService.getMessageByEventName(_TelemetryConstants.BroadcastEvent.HideChatVisibilityChangeEvent).subscribe(async event => {
257
259
  var _event$payload;
258
260
  if ((event === null || event === void 0 ? void 0 : (_event$payload = event.payload) === null || _event$payload === void 0 ? void 0 : _event$payload.isChatHidden) !== undefined) {
259
261
  var _event$payload2, _props$controlProps10;
@@ -268,6 +270,21 @@ const LiveChatWidgetStateful = props => {
268
270
  payload: event === null || event === void 0 ? void 0 : (_event$payload3 = event.payload) === null || _event$payload3 === void 0 ? void 0 : _event$payload3.isChatHidden
269
271
  });
270
272
  }
273
+ const dateNow = Date.now();
274
+ if (dateNow - lastLWICheckTimeRef.current > _Constants.Constants.LWICheckOnVisibilityTimeout) {
275
+ const conversationDetails = await (0, _utils.getConversationDetailsCall)(chatSDK);
276
+ lastLWICheckTimeRef.current = dateNow;
277
+ if ((conversationDetails === null || conversationDetails === void 0 ? void 0 : conversationDetails.state) === _Constants.LiveWorkItemState.WrapUp || (conversationDetails === null || conversationDetails === void 0 ? void 0 : conversationDetails.state) === _Constants.LiveWorkItemState.Closed) {
278
+ dispatch({
279
+ type: _LiveChatWidgetActionType.LiveChatWidgetActionType.SET_CHAT_DISCONNECT_EVENT_RECEIVED,
280
+ payload: true
281
+ });
282
+ _TelemetryHelper.TelemetryHelper.logActionEvent(_TelemetryConstants.LogLevel.INFO, {
283
+ Event: _TelemetryConstants.TelemetryEvent.ChatDisconnectThreadEventReceived,
284
+ Description: "Chat disconnected due to timeout, left or removed."
285
+ });
286
+ }
287
+ }
271
288
  }
272
289
  });
273
290
 
@@ -487,6 +504,13 @@ const LiveChatWidgetStateful = props => {
487
504
  (0, _agentEndConversationHelper.handleAgentEndConversation)(props, state, dispatch);
488
505
  }
489
506
  }, [state.appStates.conversationEndedByAgentEventReceived]);
507
+
508
+ // Handle Chat disconnect cases
509
+ (0, _react2.useEffect)(() => {
510
+ if (state.appStates.chatDisconnectEventReceived) {
511
+ (0, _chatDisconnectHelper.handleChatDisconnect)(props, state, setWebChatStyles);
512
+ }
513
+ }, [state.appStates.chatDisconnectEventReceived]);
490
514
  const initiateEndChatOnBrowserUnload = () => {
491
515
  var _DataStoreManager$cli;
492
516
  _TelemetryHelper.TelemetryHelper.logActionEvent(_TelemetryConstants.LogLevel.INFO, {
@@ -4,14 +4,21 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.defaultMiddlewareLocalizedTexts = void 0;
7
+ /*
8
+ MIDDLEWARE_BANNER_FILE parameters:
9
+ {0} = File limit size
10
+ {1} = File extension
11
+ {2} = File name
12
+ */
13
+
7
14
  const defaultMiddlewareLocalizedTexts = {
8
15
  MIDDLEWARE_BANNER_FILE_NULL_ERROR: "There was an error uploading the file, please try again.",
9
- MIDDLEWARE_BANNER_FILE_SIZE_WITHOUT_EXTENSION_ERROR: "File exceeds the allowed limit of {0} MB and please upload the file with an appropriate file extension.",
10
- MIDDLEWARE_BANNER_FILE_SIZE_EXTENSION_ERROR: "File exceeds the allowed limit of {0} MB and {1} files are not supported.",
11
- MIDDLEWARE_BANNER_FILE_WITHOUT_EXTENSION: "File upload error. Please upload the file with an appropriate file extension.",
12
- MIDDLEWARE_BANNER_FILE_EXTENSION_ERROR: "{0} files are not supported.",
13
- MIDDLEWARE_BANNER_FILE_SIZE_ERROR: "File exceeds the allowed limit of {0} MB.",
14
- MIDDLEWARE_BANNER_FILE_IS_EMPTY_ERROR: "This file can't be attached because it's empty. Please try again with a different file.",
16
+ MIDDLEWARE_BANNER_FILE_SIZE_WITHOUT_EXTENSION_ERROR: "File {2} exceeds the allowed limit of {0} MB and please upload the file with an appropriate file extension.",
17
+ MIDDLEWARE_BANNER_FILE_SIZE_EXTENSION_ERROR: "File {2} exceeds the allowed limit of {0} MB and {1} files are not supported.",
18
+ MIDDLEWARE_BANNER_FILE_WITHOUT_EXTENSION: "File upload error. Please upload the file {2} with an appropriate file extension.",
19
+ MIDDLEWARE_BANNER_FILE_EXTENSION_ERROR: "{1} files are not supported.",
20
+ MIDDLEWARE_BANNER_FILE_SIZE_ERROR: "File {2} exceeds the allowed limit of {0} MB.",
21
+ MIDDLEWARE_BANNER_FILE_IS_EMPTY_ERROR: "This file {2} can't be attached because it's empty. Please try again with a different file.",
15
22
  MIDDLEWARE_BANNER_ERROR_MESSAGE: "Upload failed, please try again.",
16
23
  MIDDLEWARE_BANNER_INTERNET_BACK_ONLINE: "You’re back online.",
17
24
  MIDDLEWARE_BANNER_NO_INTERNET_CONNECTION: "Unable to connect—please check your internet connection.",
@@ -22,6 +29,7 @@ const defaultMiddlewareLocalizedTexts = {
22
29
  MIDDLEWARE_MESSAGE_SENDING: "Sending ...",
23
30
  MIDDLEWARE_MESSAGE_DELIVERED: "Sent",
24
31
  MIDDLEWARE_MESSAGE_NOT_DELIVERED: "Not Delivered",
25
- MIDDLEWARE_MESSAGE_RETRY: "Retry"
32
+ MIDDLEWARE_MESSAGE_RETRY: "Retry",
33
+ MIDDLEWARE_BANNER_CHAT_DISCONNECT: "Your conversation has been disconnected. For additional assistance, please start a new chat."
26
34
  };
27
35
  exports.defaultMiddlewareLocalizedTexts = defaultMiddlewareLocalizedTexts;
@@ -13,4 +13,5 @@ exports.NotificationScenarios = NotificationScenarios;
13
13
  NotificationScenarios["AttachmentError"] = "attachment";
14
14
  NotificationScenarios["InternetConnection"] = "internet connection";
15
15
  NotificationScenarios["MaxSizeError"] = "max size";
16
+ NotificationScenarios["ChatDisconnect"] = "chat disconnect";
16
17
  })(NotificationScenarios || (exports.NotificationScenarios = NotificationScenarios = {}));
@@ -76,6 +76,11 @@ const getMaxUploadFileSize = (maxFileSizeSupportedByDynamicsStr, contentType) =>
76
76
  const isImage = contentType => {
77
77
  return _Constants.AMSConstants.supportedImagesMimeTypes.includes(contentType);
78
78
  };
79
+ const textEllipsis = function (str) {
80
+ let maxLength = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 20;
81
+ const ellipsis = "...";
82
+ return str.length > maxLength ? str.slice(0, maxLength - ellipsis.length) + ellipsis : str;
83
+ };
79
84
  const buildErrorMessage = (fileName, supportedFileExtension, supportedFileSize, fileIsEmpty, maxUploadFileSize, maxFileSizeSupportedByDynamics, localizedTexts) => {
80
85
  let errorMessage = "";
81
86
  if (!fileName || !maxUploadFileSize) {
@@ -91,10 +96,11 @@ const buildErrorMessage = (fileName, supportedFileExtension, supportedFileSize,
91
96
  if (!supportedFileExtension && !supportedFileSize) {
92
97
  errorMessage = getFileSizeAndFileExtensionErrorMessage(fileName, maxUploadFileSize, maxFileSizeSupportedByDynamics, localizedTexts);
93
98
  } else if (!supportedFileSize) {
94
- errorMessage = getFileSizeErrorMessage(maxUploadFileSize, maxFileSizeSupportedByDynamics, localizedTexts);
99
+ errorMessage = getFileSizeErrorMessage(fileName, maxUploadFileSize, maxFileSizeSupportedByDynamics, localizedTexts);
95
100
  } else if (!supportedFileExtension) {
96
101
  errorMessage = getFileExtensionErrorMessage(fileName, localizedTexts);
97
102
  } else if (fileIsEmpty) {
103
+ var _errorMessage;
98
104
  _TelemetryHelper.TelemetryHelper.logActionEvent(_TelemetryConstants.LogLevel.ERROR, {
99
105
  Event: _TelemetryConstants.TelemetryEvent.AttachmentUploadValidatorMiddlewareFailed,
100
106
  Description: "Attachment validation failed",
@@ -102,7 +108,8 @@ const buildErrorMessage = (fileName, supportedFileExtension, supportedFileSize,
102
108
  ErrorDetails: "File provided is empty"
103
109
  }
104
110
  });
105
- errorMessage = localizedTexts.MIDDLEWARE_BANNER_FILE_IS_EMPTY_ERROR ?? "";
111
+ errorMessage = localizedTexts.MIDDLEWARE_BANNER_FILE_IS_EMPTY_ERROR || "";
112
+ if ((_errorMessage = errorMessage) !== null && _errorMessage !== void 0 && _errorMessage.includes("{2}")) errorMessage = errorMessage.replace("{2}", textEllipsis(fileName));
106
113
  } else {
107
114
  _TelemetryHelper.TelemetryHelper.logActionEvent(_TelemetryConstants.LogLevel.ERROR, {
108
115
  Event: _TelemetryConstants.TelemetryEvent.AttachmentUploadValidatorMiddlewareFailed,
@@ -116,19 +123,18 @@ const buildErrorMessage = (fileName, supportedFileExtension, supportedFileSize,
116
123
  return errorMessage;
117
124
  };
118
125
  const getFileSizeAndFileExtensionErrorMessage = (fileName, maxUploadFileSize, maxFileSizeSupportedByDynamics, localizedTexts) => {
126
+ var _errorMessage3;
119
127
  const index = fileName.lastIndexOf(".");
120
128
  let errorMessage, exceptionDetails;
121
129
  if (index < 0) {
122
130
  errorMessage = localizedTexts.MIDDLEWARE_BANNER_FILE_SIZE_WITHOUT_EXTENSION_ERROR;
123
131
  exceptionDetails = `File exceeded the allowed limit of ${maxUploadFileSize} MB and File provided without file extension`;
124
132
  } else {
125
- var _errorMessage;
133
+ var _errorMessage2;
126
134
  const fileExtension = fileName.substring(index);
127
135
  errorMessage = localizedTexts.MIDDLEWARE_BANNER_FILE_SIZE_EXTENSION_ERROR;
136
+ if ((_errorMessage2 = errorMessage) !== null && _errorMessage2 !== void 0 && _errorMessage2.includes("{1}")) errorMessage = errorMessage.replace("{1}", fileExtension);
128
137
  exceptionDetails = `File exceeds the allowed limit of ${maxUploadFileSize} MB and ${fileExtension} files are not supported`;
129
- if ((_errorMessage = errorMessage) !== null && _errorMessage !== void 0 && _errorMessage.includes("{1}")) {
130
- errorMessage = errorMessage.replace("{1}", fileExtension);
131
- }
132
138
  }
133
139
  _TelemetryHelper.TelemetryHelper.logActionEvent(_TelemetryConstants.LogLevel.ERROR, {
134
140
  Event: _TelemetryConstants.TelemetryEvent.AttachmentUploadValidatorMiddlewareFailed,
@@ -137,10 +143,12 @@ const getFileSizeAndFileExtensionErrorMessage = (fileName, maxUploadFileSize, ma
137
143
  ErrorDetails: `${exceptionDetails} Dynamics file size limit=${maxFileSizeSupportedByDynamics} AMS image size limit=${_Constants.AMSConstants.maxSupportedImageSize} AMS file size limit=${_Constants.AMSConstants.maxSupportedFileSize}`
138
144
  }
139
145
  });
140
- return errorMessage ? errorMessage.includes("{0}") ? errorMessage.replace("{0}", maxUploadFileSize) : errorMessage : "";
146
+ if ((_errorMessage3 = errorMessage) !== null && _errorMessage3 !== void 0 && _errorMessage3.includes("{0}")) errorMessage = errorMessage.replace("{0}", maxUploadFileSize);
147
+ return errorMessage ? errorMessage.includes("{2}") ? errorMessage.replace("{2}", textEllipsis(fileName)) : errorMessage : "";
141
148
  };
142
149
  const getFileExtensionErrorMessage = (fileName, localizedTexts) => {
143
150
  const index = fileName.lastIndexOf(".");
151
+ let errorMessage;
144
152
  if (index < 0) {
145
153
  _TelemetryHelper.TelemetryHelper.logActionEvent(_TelemetryConstants.LogLevel.ERROR, {
146
154
  Event: _TelemetryConstants.TelemetryEvent.AttachmentUploadValidatorMiddlewareFailed,
@@ -149,8 +157,10 @@ const getFileExtensionErrorMessage = (fileName, localizedTexts) => {
149
157
  ErrorDetails: "File provided without file extension"
150
158
  }
151
159
  });
152
- return localizedTexts.MIDDLEWARE_BANNER_FILE_WITHOUT_EXTENSION ?? "";
160
+ errorMessage = localizedTexts.MIDDLEWARE_BANNER_FILE_WITHOUT_EXTENSION;
161
+ return errorMessage ? errorMessage.includes("{2}") ? errorMessage.replace("{2}", textEllipsis(fileName)) : errorMessage : "";
153
162
  } else {
163
+ var _errorMessage4, _errorMessage5;
154
164
  const fileExtension = fileName.substring(index);
155
165
  _TelemetryHelper.TelemetryHelper.logActionEvent(_TelemetryConstants.LogLevel.ERROR, {
156
166
  Event: _TelemetryConstants.TelemetryEvent.AttachmentUploadValidatorMiddlewareFailed,
@@ -159,11 +169,14 @@ const getFileExtensionErrorMessage = (fileName, localizedTexts) => {
159
169
  ErrorDetails: `${fileExtension} files extension is not supported.`
160
170
  }
161
171
  });
162
- const errorMessage = localizedTexts.MIDDLEWARE_BANNER_FILE_EXTENSION_ERROR;
163
- return errorMessage ? errorMessage.includes("{0}") ? errorMessage.replace("{0}", fileExtension) : errorMessage : "";
172
+ errorMessage = localizedTexts.MIDDLEWARE_BANNER_FILE_EXTENSION_ERROR;
173
+ if ((_errorMessage4 = errorMessage) !== null && _errorMessage4 !== void 0 && _errorMessage4.includes("{0}")) errorMessage = errorMessage.replace("{0}", fileExtension); //keeping backwards compatibility for this localized string
174
+ if ((_errorMessage5 = errorMessage) !== null && _errorMessage5 !== void 0 && _errorMessage5.includes("{1}")) errorMessage = errorMessage.replace("{1}", fileExtension);
175
+ return errorMessage && errorMessage.length > 0 ? errorMessage : "";
164
176
  }
165
177
  };
166
- const getFileSizeErrorMessage = (maxUploadFileSize, maxFileSizeSupportedByDynamics, localizedTexts) => {
178
+ const getFileSizeErrorMessage = (fileName, maxUploadFileSize, maxFileSizeSupportedByDynamics, localizedTexts) => {
179
+ var _errorMessage6;
167
180
  _TelemetryHelper.TelemetryHelper.logActionEvent(_TelemetryConstants.LogLevel.ERROR, {
168
181
  Event: _TelemetryConstants.TelemetryEvent.AttachmentUploadValidatorMiddlewareFailed,
169
182
  Description: "Attachment validation failed",
@@ -171,8 +184,9 @@ const getFileSizeErrorMessage = (maxUploadFileSize, maxFileSizeSupportedByDynami
171
184
  ErrorDetails: `File exceeds the allowed limit of ${maxUploadFileSize}MB. Dynamics file size limit=${maxFileSizeSupportedByDynamics} AMS image size limit=${_Constants.AMSConstants.maxSupportedImageSize} AMS file size limit=${_Constants.AMSConstants.maxSupportedFileSize}`
172
185
  }
173
186
  });
174
- const errorMessage = localizedTexts.MIDDLEWARE_BANNER_FILE_SIZE_ERROR;
175
- return errorMessage ? errorMessage.includes("{0}") ? errorMessage.replace("{0}", maxUploadFileSize) : errorMessage : "";
187
+ let errorMessage = localizedTexts.MIDDLEWARE_BANNER_FILE_SIZE_ERROR;
188
+ if ((_errorMessage6 = errorMessage) !== null && _errorMessage6 !== void 0 && _errorMessage6.includes("{0}")) errorMessage = errorMessage.replace("{0}", maxUploadFileSize);
189
+ return errorMessage ? errorMessage.includes("{2}") ? errorMessage.replace("{2}", textEllipsis(fileName)) : errorMessage : "";
176
190
  };
177
191
 
178
192
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
@@ -47,4 +47,5 @@ exports.LiveChatWidgetActionType = LiveChatWidgetActionType;
47
47
  LiveChatWidgetActionType[LiveChatWidgetActionType["SET_POST_CHAT_WORKFLOW_IN_PROGRESS"] = 37] = "SET_POST_CHAT_WORKFLOW_IN_PROGRESS";
48
48
  LiveChatWidgetActionType[LiveChatWidgetActionType["SET_INITIAL_CHAT_SDK_REQUEST_ID"] = 38] = "SET_INITIAL_CHAT_SDK_REQUEST_ID";
49
49
  LiveChatWidgetActionType[LiveChatWidgetActionType["SET_SHOULD_USE_BOT_SURVEY"] = 39] = "SET_SHOULD_USE_BOT_SURVEY";
50
+ LiveChatWidgetActionType[LiveChatWidgetActionType["SET_CHAT_DISCONNECT_EVENT_RECEIVED"] = 40] = "SET_CHAT_DISCONNECT_EVENT_RECEIVED";
50
51
  })(LiveChatWidgetActionType || (exports.LiveChatWidgetActionType = LiveChatWidgetActionType = {}));
@@ -55,7 +55,8 @@ const getLiveChatWidgetContextInitialState = props => {
55
55
  conversationEndedByAgentEventReceived: false,
56
56
  conversationEndedBy: undefined,
57
57
  postChatWorkflowInProgress: false,
58
- shouldUseBotSurvey: false
58
+ shouldUseBotSurvey: false,
59
+ chatDisconnectEventReceived: false
59
60
  },
60
61
  uiStates: {
61
62
  showConfirmationPane: false,
@@ -333,6 +333,14 @@ const createReducer = () => {
333
333
  shouldUseBotSurvey: action.payload
334
334
  }
335
335
  };
336
+ case _LiveChatWidgetActionType.LiveChatWidgetActionType.SET_CHAT_DISCONNECT_EVENT_RECEIVED:
337
+ return {
338
+ ...state,
339
+ appStates: {
340
+ ...state.appStates,
341
+ chatDisconnectEventReceived: action.payload
342
+ }
343
+ };
336
344
  default:
337
345
  return state;
338
346
  }
@@ -85,6 +85,7 @@ _defineProperty(Constants, "ChatWidgetStateChangedPrefix", "ChatWidgetStateChang
85
85
  _defineProperty(Constants, "PostChatLoadingDurationInMs", 2000);
86
86
  _defineProperty(Constants, "BrowserUnloadConfirmationMessage", "Do you want to leave chat?");
87
87
  _defineProperty(Constants, "CacheTtlInMinutes", 15);
88
+ _defineProperty(Constants, "LWICheckOnVisibilityTimeout", 3 * 60 * 1000);
88
89
  export const Regex = (_class = class Regex {}, _defineProperty(_class, "EmailRegex", "(?:[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-zA-Z0-9-]*[a-zA-Z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"), _class);
89
90
  export class HtmlIdNames {}
90
91
  _defineProperty(HtmlIdNames, "MSLiveChatWidget", "MSLiveChatWidget");
@@ -192,6 +192,7 @@ export let TelemetryEvent;
192
192
  TelemetryEvent["PostChatContextCallFailed"] = "PostChatContextCallFailed";
193
193
  TelemetryEvent["PostChatSurveyLoadingPaneLoaded"] = "PostChatSurveyLoadingPaneLoaded";
194
194
  TelemetryEvent["PostChatSurveyLoaded"] = "PostChatSurveyLoaded";
195
+ TelemetryEvent["ChatDisconnectThreadEventReceived"] = "ChatDisconnectThreadEventReceived";
195
196
  })(TelemetryEvent || (TelemetryEvent = {}));
196
197
  export class TelemetryConstants {
197
198
  static map(eventTypeOrScenarioType) {
@@ -2,8 +2,9 @@ var _this = this;
2
2
  import { AriaTelemetryConstants, Constants, LocaleConstants } from "./Constants";
3
3
  import { DataStoreManager } from "./contextDataStore/DataStoreManager";
4
4
  import { KeyCodes } from "./KeyCodes";
5
- import { BroadcastEvent } from "./telemetry/TelemetryConstants";
5
+ import { BroadcastEvent, LogLevel, TelemetryEvent } from "./telemetry/TelemetryConstants";
6
6
  import { Md5 } from "md5-typescript";
7
+ import { TelemetryHelper } from "./telemetry/TelemetryHelper";
7
8
  const getElementBySelector = selector => {
8
9
  let element;
9
10
  if (typeof selector === "string") {
@@ -324,4 +325,21 @@ export const debounceLeading = function (fn) {
324
325
  timeoutId = null;
325
326
  }, ms);
326
327
  };
328
+ };
329
+
330
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
331
+ export const getConversationDetailsCall = async chatSDK => {
332
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
333
+ let conversationDetails = undefined;
334
+ try {
335
+ conversationDetails = await chatSDK.getConversationDetails();
336
+ } catch (error) {
337
+ TelemetryHelper.logSDKEvent(LogLevel.ERROR, {
338
+ Event: TelemetryEvent.GetConversationDetailsCallFailed,
339
+ ExceptionDetails: {
340
+ exception: `Get Conversation Details Call Failed : ${error}`
341
+ }
342
+ });
343
+ }
344
+ return conversationDetails;
327
345
  };
@@ -0,0 +1,26 @@
1
+ import { NotificationHandler } from "../../webchatcontainerstateful/webchatcontroller/notification/NotificationHandler";
2
+ import { NotificationScenarios } from "../../webchatcontainerstateful/webchatcontroller/enums/NotificationScenarios";
3
+ import { defaultMiddlewareLocalizedTexts } from "../../webchatcontainerstateful/common/defaultProps/defaultMiddlewareLocalizedTexts";
4
+ import { LogLevel, TelemetryEvent } from "../../../common/telemetry/TelemetryConstants";
5
+ import { TelemetryHelper } from "../../../common/telemetry/TelemetryHelper";
6
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
+ const handleChatDisconnect = (props, state, setWebChatStyles) => {
8
+ var _state$appStates;
9
+ if (state !== null && state !== void 0 && (_state$appStates = state.appStates) !== null && _state$appStates !== void 0 && _state$appStates.chatDisconnectEventReceived) {
10
+ var _props$webChatContain, _props$webChatContain2;
11
+ if ((props === null || props === void 0 ? void 0 : (_props$webChatContain = props.webChatContainerProps) === null || _props$webChatContain === void 0 ? void 0 : (_props$webChatContain2 = _props$webChatContain.renderingMiddlewareProps) === null || _props$webChatContain2 === void 0 ? void 0 : _props$webChatContain2.hideSendboxOnConversationEnd) !== false) {
12
+ setWebChatStyles(styles => {
13
+ return {
14
+ ...styles,
15
+ hideSendBox: true
16
+ };
17
+ });
18
+ }
19
+ NotificationHandler.notifyWarning(NotificationScenarios.ChatDisconnect, defaultMiddlewareLocalizedTexts.MIDDLEWARE_BANNER_CHAT_DISCONNECT);
20
+ TelemetryHelper.logActionEvent(LogLevel.INFO, {
21
+ Event: TelemetryEvent.ChatDisconnectThreadEventReceived,
22
+ Description: "Chat disconnected due to timeout, left or removed."
23
+ });
24
+ }
25
+ };
26
+ export { handleChatDisconnect };
@@ -1750,13 +1750,19 @@ export const dummyDefaultProps = {
1750
1750
  }
1751
1751
  },
1752
1752
  localizedTexts: {
1753
+ /*
1754
+ MIDDLEWARE_BANNER_FILE parameters:
1755
+ {0} = File limit size
1756
+ {1} = File extension
1757
+ {2} = File name
1758
+ */
1753
1759
  MIDDLEWARE_BANNER_FILE_NULL_ERROR: "There was an error uploading the file, please try again.",
1754
- MIDDLEWARE_BANNER_FILE_SIZE_WITHOUT_EXTENSION_ERROR: "File exceeds the allowed limit of {0} MB and please upload the file with an appropriate file extension.",
1755
- MIDDLEWARE_BANNER_FILE_SIZE_EXTENSION_ERROR: "File exceeds the allowed limit of {0} MB and {1} files are not supported.",
1756
- MIDDLEWARE_BANNER_FILE_WITHOUT_EXTENSION: "File upload error. Please upload the file with an appropriate file extension.",
1757
- MIDDLEWARE_BANNER_FILE_EXTENSION_ERROR: "{0} files are not supported.",
1758
- MIDDLEWARE_BANNER_FILE_SIZE_ERROR: "File exceeds the allowed limit of {0} MB.",
1759
- MIDDLEWARE_BANNER_FILE_IS_EMPTY_ERROR: "This file can't be attached because it's empty. Please try again with a different file.",
1760
+ MIDDLEWARE_BANNER_FILE_SIZE_WITHOUT_EXTENSION_ERROR: "File {2} exceeds the allowed limit of {0} MB and please upload the file with an appropriate file extension.",
1761
+ MIDDLEWARE_BANNER_FILE_SIZE_EXTENSION_ERROR: "File {2} exceeds the allowed limit of {0} MB and {1} files are not supported.",
1762
+ MIDDLEWARE_BANNER_FILE_WITHOUT_EXTENSION: "File upload error. Please upload the file {2} with an appropriate file extension.",
1763
+ MIDDLEWARE_BANNER_FILE_EXTENSION_ERROR: "{1} files are not supported.",
1764
+ MIDDLEWARE_BANNER_FILE_SIZE_ERROR: "File {2} exceeds the allowed limit of {0} MB.",
1765
+ MIDDLEWARE_BANNER_FILE_IS_EMPTY_ERROR: "This file {2} can't be attached because it's empty. Please try again with a different file.",
1760
1766
  MIDDLEWARE_BANNER_ERROR_MESSAGE: "Upload failed, please try again.",
1761
1767
  MIDDLEWARE_BANNER_INTERNET_BACK_ONLINE: "You're back online.",
1762
1768
  MIDDLEWARE_BANNER_NO_INTERNET_CONNECTION: "Unable to connect—please check your internet connection.",
@@ -1769,7 +1775,8 @@ export const dummyDefaultProps = {
1769
1775
  MIDDLEWARE_MESSAGE_NOT_DELIVERED: "Not Delivered",
1770
1776
  MIDDLEWARE_MESSAGE_RETRY: "Retry",
1771
1777
  PRECHAT_REQUIRED_FIELD_MISSING_MESSAGE: "{0} field is required",
1772
- MARKDOWN_EXTERNAL_LINK_ALT: "Opens in a new window; external."
1778
+ MARKDOWN_EXTERNAL_LINK_ALT: "Opens in a new window; external.",
1779
+ MIDDLEWARE_BANNER_CHAT_DISCONNECT: "Your conversation has been disconnected. For additional assistance, please start a new chat."
1773
1780
  },
1774
1781
  botMagicCode: {
1775
1782
  disabled: false,
@@ -87,6 +87,10 @@ const endChat = async (props, chatSDK, setAdapter, setWebChatStyles, dispatch, a
87
87
  type: LiveChatWidgetActionType.SET_RECONNECT_ID,
88
88
  payload: undefined
89
89
  });
90
+ dispatch({
91
+ type: LiveChatWidgetActionType.SET_CHAT_DISCONNECT_EVENT_RECEIVED,
92
+ payload: false
93
+ });
90
94
  if (!skipCloseChat) {
91
95
  try {
92
96
  var _props$webChatContain;
@@ -4,7 +4,7 @@ import { BroadcastService, BroadcastServiceInitialize, decodeComponentString } f
4
4
  import { Stack } from "@fluentui/react";
5
5
  import React, { useEffect, useRef, useState } from "react";
6
6
  import { checkIfConversationStillValid, initStartChat, prepareStartChat, setPreChatAndInitiateChat } from "../common/startChat";
7
- import { createTimer, getBroadcastChannelName, getLocaleDirection, getStateFromCache, getWidgetCacheId, getWidgetEndChatEventName, isNullOrEmptyString, isUndefinedOrEmpty } from "../../../common/utils";
7
+ import { createTimer, getBroadcastChannelName, getLocaleDirection, getStateFromCache, getWidgetCacheId, getWidgetEndChatEventName, isNullOrEmptyString, isUndefinedOrEmpty, getConversationDetailsCall } from "../../../common/utils";
8
8
  import { endChat, prepareEndChat } from "../common/endChat";
9
9
  import { shouldShowCallingContainer, shouldShowChatButton, shouldShowConfirmationPane, shouldShowEmailTranscriptPane, shouldShowHeader, shouldShowLoadingPane, shouldShowOutOfOfficeHoursPane, shouldShowPostChatLoadingPane, shouldShowPostChatSurveyPane, shouldShowPreChatSurveyPane, shouldShowProactiveChatPane, shouldShowReconnectChatPane, shouldShowWebChatContainer } from "../../../controller/componentController";
10
10
  import { ActivityStreamHandler } from "../common/ActivityStreamHandler";
@@ -14,7 +14,7 @@ import { Components } from "botframework-webchat";
14
14
  import ConfirmationPaneStateful from "../../confirmationpanestateful/ConfirmationPaneStateful";
15
15
  import { ConversationState } from "../../../contexts/common/ConversationState";
16
16
  import { DataStoreManager } from "../../../common/contextDataStore/DataStoreManager";
17
- import { Constants, E2VVOptions } from "../../../common/Constants";
17
+ import { Constants, E2VVOptions, LiveWorkItemState } from "../../../common/Constants";
18
18
  import { ElementType } from "@microsoft/omnichannel-chat-components";
19
19
  import EmailTranscriptPaneStateful from "../../emailtranscriptpanestateful/EmailTranscriptPaneStateful";
20
20
  import HeaderStateful from "../../headerstateful/HeaderStateful";
@@ -49,6 +49,7 @@ import useChatSDKStore from "../../../hooks/useChatSDKStore";
49
49
  import { ConversationEndEntity } from "../../../contexts/common/ConversationEndEntity";
50
50
  import { handleAgentEndConversation } from "../common/agentEndConversationHelper";
51
51
  import { handleChatReconnect, isReconnectEnabled } from "../common/reconnectChatHelper";
52
+ import { handleChatDisconnect } from "../common/chatDisconnectHelper";
52
53
  export const LiveChatWidgetStateful = props => {
53
54
  var _props$webChatContain, _props$styleProps, _chatSDK$omnichannelC, _props$controlProps, _props$controlProps2, _props$webChatContain3, _props$webChatContain4, _props$styleProps2, _props$controlProps15, _props$controlProps16, _props$componentOverr, _props$controlProps17, _props$componentOverr2, _props$controlProps18, _props$componentOverr3, _props$controlProps19, _props$componentOverr4, _props$controlProps20, _props$componentOverr5, _props$controlProps21, _props$componentOverr6, _props$controlProps22, _props$componentOverr7, _props$controlProps23, _props$controlProps24, _props$componentOverr8, _props$controlProps25, _props$componentOverr9, _props$controlProps26, _props$componentOverr10, _props$componentOverr11, _props$componentOverr12;
54
55
  const [state, dispatch] = useChatContextStore();
@@ -79,6 +80,7 @@ export const LiveChatWidgetStateful = props => {
79
80
  TelemetryTimers.LcwLoadToChatButtonTimer = createTimer();
80
81
  const widgetElementId = ((_props$controlProps2 = props.controlProps) === null || _props$controlProps2 === void 0 ? void 0 : _props$controlProps2.id) || "oc-lcw";
81
82
  const currentMessageCountRef = useRef(0);
83
+ const lastLWICheckTimeRef = useRef(0);
82
84
  let widgetStateEventName = "";
83
85
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
84
86
  let optionalParams;
@@ -245,7 +247,7 @@ export const LiveChatWidgetStateful = props => {
245
247
  });
246
248
 
247
249
  // Toggle chat visibility
248
- BroadcastService.getMessageByEventName(BroadcastEvent.HideChatVisibilityChangeEvent).subscribe(event => {
250
+ BroadcastService.getMessageByEventName(BroadcastEvent.HideChatVisibilityChangeEvent).subscribe(async event => {
249
251
  var _event$payload;
250
252
  if ((event === null || event === void 0 ? void 0 : (_event$payload = event.payload) === null || _event$payload === void 0 ? void 0 : _event$payload.isChatHidden) !== undefined) {
251
253
  var _event$payload2, _props$controlProps10;
@@ -260,6 +262,21 @@ export const LiveChatWidgetStateful = props => {
260
262
  payload: event === null || event === void 0 ? void 0 : (_event$payload3 = event.payload) === null || _event$payload3 === void 0 ? void 0 : _event$payload3.isChatHidden
261
263
  });
262
264
  }
265
+ const dateNow = Date.now();
266
+ if (dateNow - lastLWICheckTimeRef.current > Constants.LWICheckOnVisibilityTimeout) {
267
+ const conversationDetails = await getConversationDetailsCall(chatSDK);
268
+ lastLWICheckTimeRef.current = dateNow;
269
+ if ((conversationDetails === null || conversationDetails === void 0 ? void 0 : conversationDetails.state) === LiveWorkItemState.WrapUp || (conversationDetails === null || conversationDetails === void 0 ? void 0 : conversationDetails.state) === LiveWorkItemState.Closed) {
270
+ dispatch({
271
+ type: LiveChatWidgetActionType.SET_CHAT_DISCONNECT_EVENT_RECEIVED,
272
+ payload: true
273
+ });
274
+ TelemetryHelper.logActionEvent(LogLevel.INFO, {
275
+ Event: TelemetryEvent.ChatDisconnectThreadEventReceived,
276
+ Description: "Chat disconnected due to timeout, left or removed."
277
+ });
278
+ }
279
+ }
263
280
  }
264
281
  });
265
282
 
@@ -479,6 +496,13 @@ export const LiveChatWidgetStateful = props => {
479
496
  handleAgentEndConversation(props, state, dispatch);
480
497
  }
481
498
  }, [state.appStates.conversationEndedByAgentEventReceived]);
499
+
500
+ // Handle Chat disconnect cases
501
+ useEffect(() => {
502
+ if (state.appStates.chatDisconnectEventReceived) {
503
+ handleChatDisconnect(props, state, setWebChatStyles);
504
+ }
505
+ }, [state.appStates.chatDisconnectEventReceived]);
482
506
  const initiateEndChatOnBrowserUnload = () => {
483
507
  var _DataStoreManager$cli;
484
508
  TelemetryHelper.logActionEvent(LogLevel.INFO, {
@@ -1,11 +1,18 @@
1
+ /*
2
+ MIDDLEWARE_BANNER_FILE parameters:
3
+ {0} = File limit size
4
+ {1} = File extension
5
+ {2} = File name
6
+ */
7
+
1
8
  export const defaultMiddlewareLocalizedTexts = {
2
9
  MIDDLEWARE_BANNER_FILE_NULL_ERROR: "There was an error uploading the file, please try again.",
3
- MIDDLEWARE_BANNER_FILE_SIZE_WITHOUT_EXTENSION_ERROR: "File exceeds the allowed limit of {0} MB and please upload the file with an appropriate file extension.",
4
- MIDDLEWARE_BANNER_FILE_SIZE_EXTENSION_ERROR: "File exceeds the allowed limit of {0} MB and {1} files are not supported.",
5
- MIDDLEWARE_BANNER_FILE_WITHOUT_EXTENSION: "File upload error. Please upload the file with an appropriate file extension.",
6
- MIDDLEWARE_BANNER_FILE_EXTENSION_ERROR: "{0} files are not supported.",
7
- MIDDLEWARE_BANNER_FILE_SIZE_ERROR: "File exceeds the allowed limit of {0} MB.",
8
- MIDDLEWARE_BANNER_FILE_IS_EMPTY_ERROR: "This file can't be attached because it's empty. Please try again with a different file.",
10
+ MIDDLEWARE_BANNER_FILE_SIZE_WITHOUT_EXTENSION_ERROR: "File {2} exceeds the allowed limit of {0} MB and please upload the file with an appropriate file extension.",
11
+ MIDDLEWARE_BANNER_FILE_SIZE_EXTENSION_ERROR: "File {2} exceeds the allowed limit of {0} MB and {1} files are not supported.",
12
+ MIDDLEWARE_BANNER_FILE_WITHOUT_EXTENSION: "File upload error. Please upload the file {2} with an appropriate file extension.",
13
+ MIDDLEWARE_BANNER_FILE_EXTENSION_ERROR: "{1} files are not supported.",
14
+ MIDDLEWARE_BANNER_FILE_SIZE_ERROR: "File {2} exceeds the allowed limit of {0} MB.",
15
+ MIDDLEWARE_BANNER_FILE_IS_EMPTY_ERROR: "This file {2} can't be attached because it's empty. Please try again with a different file.",
9
16
  MIDDLEWARE_BANNER_ERROR_MESSAGE: "Upload failed, please try again.",
10
17
  MIDDLEWARE_BANNER_INTERNET_BACK_ONLINE: "You’re back online.",
11
18
  MIDDLEWARE_BANNER_NO_INTERNET_CONNECTION: "Unable to connect—please check your internet connection.",
@@ -16,5 +23,6 @@ export const defaultMiddlewareLocalizedTexts = {
16
23
  MIDDLEWARE_MESSAGE_SENDING: "Sending ...",
17
24
  MIDDLEWARE_MESSAGE_DELIVERED: "Sent",
18
25
  MIDDLEWARE_MESSAGE_NOT_DELIVERED: "Not Delivered",
19
- MIDDLEWARE_MESSAGE_RETRY: "Retry"
26
+ MIDDLEWARE_MESSAGE_RETRY: "Retry",
27
+ MIDDLEWARE_BANNER_CHAT_DISCONNECT: "Your conversation has been disconnected. For additional assistance, please start a new chat."
20
28
  };
@@ -6,4 +6,5 @@ export let NotificationScenarios;
6
6
  NotificationScenarios["AttachmentError"] = "attachment";
7
7
  NotificationScenarios["InternetConnection"] = "internet connection";
8
8
  NotificationScenarios["MaxSizeError"] = "max size";
9
+ NotificationScenarios["ChatDisconnect"] = "chat disconnect";
9
10
  })(NotificationScenarios || (NotificationScenarios = {}));
@@ -70,6 +70,11 @@ const getMaxUploadFileSize = (maxFileSizeSupportedByDynamicsStr, contentType) =>
70
70
  const isImage = contentType => {
71
71
  return AMSConstants.supportedImagesMimeTypes.includes(contentType);
72
72
  };
73
+ const textEllipsis = function (str) {
74
+ let maxLength = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 20;
75
+ const ellipsis = "...";
76
+ return str.length > maxLength ? str.slice(0, maxLength - ellipsis.length) + ellipsis : str;
77
+ };
73
78
  const buildErrorMessage = (fileName, supportedFileExtension, supportedFileSize, fileIsEmpty, maxUploadFileSize, maxFileSizeSupportedByDynamics, localizedTexts) => {
74
79
  let errorMessage = "";
75
80
  if (!fileName || !maxUploadFileSize) {
@@ -85,10 +90,11 @@ const buildErrorMessage = (fileName, supportedFileExtension, supportedFileSize,
85
90
  if (!supportedFileExtension && !supportedFileSize) {
86
91
  errorMessage = getFileSizeAndFileExtensionErrorMessage(fileName, maxUploadFileSize, maxFileSizeSupportedByDynamics, localizedTexts);
87
92
  } else if (!supportedFileSize) {
88
- errorMessage = getFileSizeErrorMessage(maxUploadFileSize, maxFileSizeSupportedByDynamics, localizedTexts);
93
+ errorMessage = getFileSizeErrorMessage(fileName, maxUploadFileSize, maxFileSizeSupportedByDynamics, localizedTexts);
89
94
  } else if (!supportedFileExtension) {
90
95
  errorMessage = getFileExtensionErrorMessage(fileName, localizedTexts);
91
96
  } else if (fileIsEmpty) {
97
+ var _errorMessage;
92
98
  TelemetryHelper.logActionEvent(LogLevel.ERROR, {
93
99
  Event: TelemetryEvent.AttachmentUploadValidatorMiddlewareFailed,
94
100
  Description: "Attachment validation failed",
@@ -96,7 +102,8 @@ const buildErrorMessage = (fileName, supportedFileExtension, supportedFileSize,
96
102
  ErrorDetails: "File provided is empty"
97
103
  }
98
104
  });
99
- errorMessage = localizedTexts.MIDDLEWARE_BANNER_FILE_IS_EMPTY_ERROR ?? "";
105
+ errorMessage = localizedTexts.MIDDLEWARE_BANNER_FILE_IS_EMPTY_ERROR || "";
106
+ if ((_errorMessage = errorMessage) !== null && _errorMessage !== void 0 && _errorMessage.includes("{2}")) errorMessage = errorMessage.replace("{2}", textEllipsis(fileName));
100
107
  } else {
101
108
  TelemetryHelper.logActionEvent(LogLevel.ERROR, {
102
109
  Event: TelemetryEvent.AttachmentUploadValidatorMiddlewareFailed,
@@ -110,19 +117,18 @@ const buildErrorMessage = (fileName, supportedFileExtension, supportedFileSize,
110
117
  return errorMessage;
111
118
  };
112
119
  const getFileSizeAndFileExtensionErrorMessage = (fileName, maxUploadFileSize, maxFileSizeSupportedByDynamics, localizedTexts) => {
120
+ var _errorMessage3;
113
121
  const index = fileName.lastIndexOf(".");
114
122
  let errorMessage, exceptionDetails;
115
123
  if (index < 0) {
116
124
  errorMessage = localizedTexts.MIDDLEWARE_BANNER_FILE_SIZE_WITHOUT_EXTENSION_ERROR;
117
125
  exceptionDetails = `File exceeded the allowed limit of ${maxUploadFileSize} MB and File provided without file extension`;
118
126
  } else {
119
- var _errorMessage;
127
+ var _errorMessage2;
120
128
  const fileExtension = fileName.substring(index);
121
129
  errorMessage = localizedTexts.MIDDLEWARE_BANNER_FILE_SIZE_EXTENSION_ERROR;
130
+ if ((_errorMessage2 = errorMessage) !== null && _errorMessage2 !== void 0 && _errorMessage2.includes("{1}")) errorMessage = errorMessage.replace("{1}", fileExtension);
122
131
  exceptionDetails = `File exceeds the allowed limit of ${maxUploadFileSize} MB and ${fileExtension} files are not supported`;
123
- if ((_errorMessage = errorMessage) !== null && _errorMessage !== void 0 && _errorMessage.includes("{1}")) {
124
- errorMessage = errorMessage.replace("{1}", fileExtension);
125
- }
126
132
  }
127
133
  TelemetryHelper.logActionEvent(LogLevel.ERROR, {
128
134
  Event: TelemetryEvent.AttachmentUploadValidatorMiddlewareFailed,
@@ -131,10 +137,12 @@ const getFileSizeAndFileExtensionErrorMessage = (fileName, maxUploadFileSize, ma
131
137
  ErrorDetails: `${exceptionDetails} Dynamics file size limit=${maxFileSizeSupportedByDynamics} AMS image size limit=${AMSConstants.maxSupportedImageSize} AMS file size limit=${AMSConstants.maxSupportedFileSize}`
132
138
  }
133
139
  });
134
- return errorMessage ? errorMessage.includes("{0}") ? errorMessage.replace("{0}", maxUploadFileSize) : errorMessage : "";
140
+ if ((_errorMessage3 = errorMessage) !== null && _errorMessage3 !== void 0 && _errorMessage3.includes("{0}")) errorMessage = errorMessage.replace("{0}", maxUploadFileSize);
141
+ return errorMessage ? errorMessage.includes("{2}") ? errorMessage.replace("{2}", textEllipsis(fileName)) : errorMessage : "";
135
142
  };
136
143
  const getFileExtensionErrorMessage = (fileName, localizedTexts) => {
137
144
  const index = fileName.lastIndexOf(".");
145
+ let errorMessage;
138
146
  if (index < 0) {
139
147
  TelemetryHelper.logActionEvent(LogLevel.ERROR, {
140
148
  Event: TelemetryEvent.AttachmentUploadValidatorMiddlewareFailed,
@@ -143,8 +151,10 @@ const getFileExtensionErrorMessage = (fileName, localizedTexts) => {
143
151
  ErrorDetails: "File provided without file extension"
144
152
  }
145
153
  });
146
- return localizedTexts.MIDDLEWARE_BANNER_FILE_WITHOUT_EXTENSION ?? "";
154
+ errorMessage = localizedTexts.MIDDLEWARE_BANNER_FILE_WITHOUT_EXTENSION;
155
+ return errorMessage ? errorMessage.includes("{2}") ? errorMessage.replace("{2}", textEllipsis(fileName)) : errorMessage : "";
147
156
  } else {
157
+ var _errorMessage4, _errorMessage5;
148
158
  const fileExtension = fileName.substring(index);
149
159
  TelemetryHelper.logActionEvent(LogLevel.ERROR, {
150
160
  Event: TelemetryEvent.AttachmentUploadValidatorMiddlewareFailed,
@@ -153,11 +163,14 @@ const getFileExtensionErrorMessage = (fileName, localizedTexts) => {
153
163
  ErrorDetails: `${fileExtension} files extension is not supported.`
154
164
  }
155
165
  });
156
- const errorMessage = localizedTexts.MIDDLEWARE_BANNER_FILE_EXTENSION_ERROR;
157
- return errorMessage ? errorMessage.includes("{0}") ? errorMessage.replace("{0}", fileExtension) : errorMessage : "";
166
+ errorMessage = localizedTexts.MIDDLEWARE_BANNER_FILE_EXTENSION_ERROR;
167
+ if ((_errorMessage4 = errorMessage) !== null && _errorMessage4 !== void 0 && _errorMessage4.includes("{0}")) errorMessage = errorMessage.replace("{0}", fileExtension); //keeping backwards compatibility for this localized string
168
+ if ((_errorMessage5 = errorMessage) !== null && _errorMessage5 !== void 0 && _errorMessage5.includes("{1}")) errorMessage = errorMessage.replace("{1}", fileExtension);
169
+ return errorMessage && errorMessage.length > 0 ? errorMessage : "";
158
170
  }
159
171
  };
160
- const getFileSizeErrorMessage = (maxUploadFileSize, maxFileSizeSupportedByDynamics, localizedTexts) => {
172
+ const getFileSizeErrorMessage = (fileName, maxUploadFileSize, maxFileSizeSupportedByDynamics, localizedTexts) => {
173
+ var _errorMessage6;
161
174
  TelemetryHelper.logActionEvent(LogLevel.ERROR, {
162
175
  Event: TelemetryEvent.AttachmentUploadValidatorMiddlewareFailed,
163
176
  Description: "Attachment validation failed",
@@ -165,8 +178,9 @@ const getFileSizeErrorMessage = (maxUploadFileSize, maxFileSizeSupportedByDynami
165
178
  ErrorDetails: `File exceeds the allowed limit of ${maxUploadFileSize}MB. Dynamics file size limit=${maxFileSizeSupportedByDynamics} AMS image size limit=${AMSConstants.maxSupportedImageSize} AMS file size limit=${AMSConstants.maxSupportedFileSize}`
166
179
  }
167
180
  });
168
- const errorMessage = localizedTexts.MIDDLEWARE_BANNER_FILE_SIZE_ERROR;
169
- return errorMessage ? errorMessage.includes("{0}") ? errorMessage.replace("{0}", maxUploadFileSize) : errorMessage : "";
181
+ let errorMessage = localizedTexts.MIDDLEWARE_BANNER_FILE_SIZE_ERROR;
182
+ if ((_errorMessage6 = errorMessage) !== null && _errorMessage6 !== void 0 && _errorMessage6.includes("{0}")) errorMessage = errorMessage.replace("{0}", maxUploadFileSize);
183
+ return errorMessage ? errorMessage.includes("{2}") ? errorMessage.replace("{2}", textEllipsis(fileName)) : errorMessage : "";
170
184
  };
171
185
 
172
186
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
@@ -40,4 +40,5 @@ export let LiveChatWidgetActionType;
40
40
  LiveChatWidgetActionType[LiveChatWidgetActionType["SET_POST_CHAT_WORKFLOW_IN_PROGRESS"] = 37] = "SET_POST_CHAT_WORKFLOW_IN_PROGRESS";
41
41
  LiveChatWidgetActionType[LiveChatWidgetActionType["SET_INITIAL_CHAT_SDK_REQUEST_ID"] = 38] = "SET_INITIAL_CHAT_SDK_REQUEST_ID";
42
42
  LiveChatWidgetActionType[LiveChatWidgetActionType["SET_SHOULD_USE_BOT_SURVEY"] = 39] = "SET_SHOULD_USE_BOT_SURVEY";
43
+ LiveChatWidgetActionType[LiveChatWidgetActionType["SET_CHAT_DISCONNECT_EVENT_RECEIVED"] = 40] = "SET_CHAT_DISCONNECT_EVENT_RECEIVED";
43
44
  })(LiveChatWidgetActionType || (LiveChatWidgetActionType = {}));
@@ -49,7 +49,8 @@ export const getLiveChatWidgetContextInitialState = props => {
49
49
  conversationEndedByAgentEventReceived: false,
50
50
  conversationEndedBy: undefined,
51
51
  postChatWorkflowInProgress: false,
52
- shouldUseBotSurvey: false
52
+ shouldUseBotSurvey: false,
53
+ chatDisconnectEventReceived: false
53
54
  },
54
55
  uiStates: {
55
56
  showConfirmationPane: false,
@@ -327,6 +327,14 @@ export const createReducer = () => {
327
327
  shouldUseBotSurvey: action.payload
328
328
  }
329
329
  };
330
+ case LiveChatWidgetActionType.SET_CHAT_DISCONNECT_EVENT_RECEIVED:
331
+ return {
332
+ ...state,
333
+ appStates: {
334
+ ...state.appStates,
335
+ chatDisconnectEventReceived: action.payload
336
+ }
337
+ };
330
338
  default:
331
339
  return state;
332
340
  }
@@ -81,6 +81,7 @@ export declare class Constants {
81
81
  static readonly PostChatLoadingDurationInMs = 2000;
82
82
  static readonly BrowserUnloadConfirmationMessage = "Do you want to leave chat?";
83
83
  static readonly CacheTtlInMinutes = 15;
84
+ static readonly LWICheckOnVisibilityTimeout: number;
84
85
  }
85
86
  export declare const Regex: {
86
87
  new (): {};
@@ -184,7 +184,8 @@ export declare enum TelemetryEvent {
184
184
  PostChatContextCallSucceed = "PostChatContextCallSucceed",
185
185
  PostChatContextCallFailed = "PostChatContextCallFailed",
186
186
  PostChatSurveyLoadingPaneLoaded = "PostChatSurveyLoadingPaneLoaded",
187
- PostChatSurveyLoaded = "PostChatSurveyLoaded"
187
+ PostChatSurveyLoaded = "PostChatSurveyLoaded",
188
+ ChatDisconnectThreadEventReceived = "ChatDisconnectThreadEventReceived"
188
189
  }
189
190
  export interface TelemetryInput {
190
191
  scenarioType: ScenarioType;
@@ -29,3 +29,4 @@ export declare const isUndefinedOrEmpty: (object: any) => boolean;
29
29
  export declare const addDelayInMs: (ms: number) => Promise<void>;
30
30
  export declare const getBroadcastChannelName: (widgetId: string, widgetInstanceId: string) => string;
31
31
  export declare const debounceLeading: (fn: any, ms?: number) => (...args: any[]) => void;
32
+ export declare const getConversationDetailsCall: (chatSDK: any) => Promise<any>;
@@ -0,0 +1,4 @@
1
+ import { ILiveChatWidgetContext } from "../../../contexts/common/ILiveChatWidgetContext";
2
+ import { ILiveChatWidgetProps } from "../interfaces/ILiveChatWidgetProps";
3
+ declare const handleChatDisconnect: (props: ILiveChatWidgetProps, state: ILiveChatWidgetContext, setWebChatStyles: any) => void;
4
+ export { handleChatDisconnect };
@@ -4,5 +4,6 @@ export declare enum NotificationScenarios {
4
4
  EmailTranscriptError = "email transcript",
5
5
  AttachmentError = "attachment",
6
6
  InternetConnection = "internet connection",
7
- MaxSizeError = "max size"
7
+ MaxSizeError = "max size",
8
+ ChatDisconnect = "chat disconnect"
8
9
  }
@@ -43,6 +43,7 @@ export interface ILiveChatWidgetContext {
43
43
  conversationEndedBy: ConversationEndEntity | undefined;
44
44
  postChatWorkflowInProgress: boolean;
45
45
  shouldUseBotSurvey: boolean;
46
+ chatDisconnectEventReceived: boolean;
46
47
  };
47
48
  uiStates: {
48
49
  showConfirmationPane: boolean;
@@ -19,4 +19,5 @@ export interface ILiveChatWidgetLocalizedTexts {
19
19
  MIDDLEWARE_MESSAGE_RETRY?: string;
20
20
  PRECHAT_REQUIRED_FIELD_MISSING_MESSAGE?: string;
21
21
  MARKDOWN_EXTERNAL_LINK_ALT?: string;
22
+ MIDDLEWARE_BANNER_CHAT_DISCONNECT?: string;
22
23
  }
@@ -38,5 +38,6 @@ export declare enum LiveChatWidgetActionType {
38
38
  SET_LIVE_CHAT_CONFIG = 36,
39
39
  SET_POST_CHAT_WORKFLOW_IN_PROGRESS = 37,
40
40
  SET_INITIAL_CHAT_SDK_REQUEST_ID = 38,
41
- SET_SHOULD_USE_BOT_SURVEY = 39
41
+ SET_SHOULD_USE_BOT_SURVEY = 39,
42
+ SET_CHAT_DISCONNECT_EVENT_RECEIVED = 40
42
43
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@microsoft/omnichannel-chat-widget",
3
- "version": "1.0.1-main.068a14e",
3
+ "version": "1.0.2-main.2112105",
4
4
  "description": "Microsoft Omnichannel Chat Widget",
5
5
  "main": "lib/cjs/index.js",
6
6
  "types": "lib/types/index.d.ts",