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

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 (33) 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 +2 -1
  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 +2 -1
  9. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/enums/NotificationScenarios.js +1 -0
  10. package/lib/cjs/contexts/common/LiveChatWidgetActionType.js +1 -0
  11. package/lib/cjs/contexts/common/LiveChatWidgetContextInitialState.js +2 -1
  12. package/lib/cjs/contexts/createReducer.js +8 -0
  13. package/lib/esm/common/Constants.js +1 -0
  14. package/lib/esm/common/telemetry/TelemetryConstants.js +1 -0
  15. package/lib/esm/common/utils.js +19 -1
  16. package/lib/esm/components/livechatwidget/common/chatDisconnectHelper.js +26 -0
  17. package/lib/esm/components/livechatwidget/common/defaultProps/dummyDefaultProps.js +2 -1
  18. package/lib/esm/components/livechatwidget/common/endChat.js +4 -0
  19. package/lib/esm/components/livechatwidget/livechatwidgetstateful/LiveChatWidgetStateful.js +27 -3
  20. package/lib/esm/components/webchatcontainerstateful/common/defaultProps/defaultMiddlewareLocalizedTexts.js +2 -1
  21. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/enums/NotificationScenarios.js +1 -0
  22. package/lib/esm/contexts/common/LiveChatWidgetActionType.js +1 -0
  23. package/lib/esm/contexts/common/LiveChatWidgetContextInitialState.js +2 -1
  24. package/lib/esm/contexts/createReducer.js +8 -0
  25. package/lib/types/common/Constants.d.ts +1 -0
  26. package/lib/types/common/telemetry/TelemetryConstants.d.ts +2 -1
  27. package/lib/types/common/utils.d.ts +1 -0
  28. package/lib/types/components/livechatwidget/common/chatDisconnectHelper.d.ts +4 -0
  29. package/lib/types/components/webchatcontainerstateful/webchatcontroller/enums/NotificationScenarios.d.ts +2 -1
  30. package/lib/types/contexts/common/ILiveChatWidgetContext.d.ts +1 -0
  31. package/lib/types/contexts/common/ILiveChatWidgetLocalizedTexts.d.ts +1 -0
  32. package/lib/types/contexts/common/LiveChatWidgetActionType.d.ts +2 -1
  33. 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;
@@ -1775,7 +1775,8 @@ const dummyDefaultProps = {
1775
1775
  MIDDLEWARE_MESSAGE_NOT_DELIVERED: "Not Delivered",
1776
1776
  MIDDLEWARE_MESSAGE_RETRY: "Retry",
1777
1777
  PRECHAT_REQUIRED_FIELD_MISSING_MESSAGE: "{0} field is required",
1778
- 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."
1779
1780
  },
1780
1781
  botMagicCode: {
1781
1782
  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, {
@@ -22,6 +22,7 @@ const defaultMiddlewareLocalizedTexts = {
22
22
  MIDDLEWARE_MESSAGE_SENDING: "Sending ...",
23
23
  MIDDLEWARE_MESSAGE_DELIVERED: "Sent",
24
24
  MIDDLEWARE_MESSAGE_NOT_DELIVERED: "Not Delivered",
25
- MIDDLEWARE_MESSAGE_RETRY: "Retry"
25
+ MIDDLEWARE_MESSAGE_RETRY: "Retry",
26
+ MIDDLEWARE_BANNER_CHAT_DISCONNECT: "Your conversation has been disconnected. For additional assistance, please start a new chat."
26
27
  };
27
28
  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 = {}));
@@ -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 };
@@ -1769,7 +1769,8 @@ export const dummyDefaultProps = {
1769
1769
  MIDDLEWARE_MESSAGE_NOT_DELIVERED: "Not Delivered",
1770
1770
  MIDDLEWARE_MESSAGE_RETRY: "Retry",
1771
1771
  PRECHAT_REQUIRED_FIELD_MISSING_MESSAGE: "{0} field is required",
1772
- MARKDOWN_EXTERNAL_LINK_ALT: "Opens in a new window; external."
1772
+ MARKDOWN_EXTERNAL_LINK_ALT: "Opens in a new window; external.",
1773
+ MIDDLEWARE_BANNER_CHAT_DISCONNECT: "Your conversation has been disconnected. For additional assistance, please start a new chat."
1773
1774
  },
1774
1775
  botMagicCode: {
1775
1776
  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, {
@@ -16,5 +16,6 @@ export const defaultMiddlewareLocalizedTexts = {
16
16
  MIDDLEWARE_MESSAGE_SENDING: "Sending ...",
17
17
  MIDDLEWARE_MESSAGE_DELIVERED: "Sent",
18
18
  MIDDLEWARE_MESSAGE_NOT_DELIVERED: "Not Delivered",
19
- MIDDLEWARE_MESSAGE_RETRY: "Retry"
19
+ MIDDLEWARE_MESSAGE_RETRY: "Retry",
20
+ MIDDLEWARE_BANNER_CHAT_DISCONNECT: "Your conversation has been disconnected. For additional assistance, please start a new chat."
20
21
  };
@@ -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 = {}));
@@ -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.b2301a3",
4
4
  "description": "Microsoft Omnichannel Chat Widget",
5
5
  "main": "lib/cjs/index.js",
6
6
  "types": "lib/types/index.d.ts",