@microsoft/omnichannel-chat-widget 1.8.2-main.fc93d3d → 1.8.3-main.38c88a7

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 (58) hide show
  1. package/README.md +46 -1
  2. package/lib/cjs/common/Constants.js +8 -2
  3. package/lib/cjs/common/telemetry/TelemetryConstants.js +2 -0
  4. package/lib/cjs/common/utils.js +27 -2
  5. package/lib/cjs/components/chatbuttonstateful/ChatButtonStateful.js +4 -4
  6. package/lib/cjs/components/livechatwidget/common/createInternetConnectionChangeHandler.js +22 -9
  7. package/lib/cjs/components/livechatwidget/common/createMarkdown.js +54 -1
  8. package/lib/cjs/components/livechatwidget/common/customEventHandler.js +53 -0
  9. package/lib/cjs/components/livechatwidget/common/endChat.js +1 -0
  10. package/lib/cjs/components/livechatwidget/common/initWebChatComposer.js +5 -1
  11. package/lib/cjs/components/livechatwidget/common/renderSurveyHelpers.js +23 -0
  12. package/lib/cjs/components/livechatwidget/common/startChat.js +1 -1
  13. package/lib/cjs/components/livechatwidget/livechatwidgetstateful/LiveChatWidgetStateful.js +5 -1
  14. package/lib/cjs/components/webchatcontainerstateful/WebChatContainerStateful.js +1 -1
  15. package/lib/cjs/components/webchatcontainerstateful/common/DesignerChatAdapter.js +3 -1
  16. package/lib/cjs/components/webchatcontainerstateful/common/utils/chatAdapterUtils.js +27 -2
  17. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/callActionMiddleware.js +42 -0
  18. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/customEventMiddleware.js +41 -0
  19. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/queueOverflowHandlerMiddleware.js +45 -0
  20. package/lib/cjs/contexts/common/CustomEventType.js +1 -0
  21. package/lib/cjs/firstresponselatency/FirstMessageTrackerFromBot.js +101 -36
  22. package/lib/cjs/firstresponselatency/FirstResponseLatencyTracker.js +39 -21
  23. package/lib/cjs/firstresponselatency/util.js +12 -8
  24. package/lib/cjs/plugins/createChatTranscript.js +13 -0
  25. package/lib/esm/common/Constants.js +8 -2
  26. package/lib/esm/common/telemetry/TelemetryConstants.js +2 -0
  27. package/lib/esm/common/utils.js +21 -0
  28. package/lib/esm/components/chatbuttonstateful/ChatButtonStateful.js +4 -4
  29. package/lib/esm/components/livechatwidget/common/createInternetConnectionChangeHandler.js +22 -9
  30. package/lib/esm/components/livechatwidget/common/createMarkdown.js +54 -1
  31. package/lib/esm/components/livechatwidget/common/customEventHandler.js +45 -0
  32. package/lib/esm/components/livechatwidget/common/endChat.js +1 -0
  33. package/lib/esm/components/livechatwidget/common/initWebChatComposer.js +5 -1
  34. package/lib/esm/components/livechatwidget/common/renderSurveyHelpers.js +23 -0
  35. package/lib/esm/components/livechatwidget/common/startChat.js +1 -1
  36. package/lib/esm/components/livechatwidget/livechatwidgetstateful/LiveChatWidgetStateful.js +5 -1
  37. package/lib/esm/components/webchatcontainerstateful/WebChatContainerStateful.js +1 -1
  38. package/lib/esm/components/webchatcontainerstateful/common/DesignerChatAdapter.js +4 -2
  39. package/lib/esm/components/webchatcontainerstateful/common/utils/chatAdapterUtils.js +23 -0
  40. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/callActionMiddleware.js +36 -0
  41. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/customEventMiddleware.js +33 -0
  42. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/queueOverflowHandlerMiddleware.js +38 -0
  43. package/lib/esm/contexts/common/CustomEventType.js +1 -0
  44. package/lib/esm/firstresponselatency/FirstMessageTrackerFromBot.js +101 -36
  45. package/lib/esm/firstresponselatency/FirstResponseLatencyTracker.js +39 -21
  46. package/lib/esm/firstresponselatency/util.js +12 -8
  47. package/lib/esm/plugins/createChatTranscript.js +13 -0
  48. package/lib/types/common/Constants.d.ts +8 -2
  49. package/lib/types/common/telemetry/TelemetryConstants.d.ts +2 -0
  50. package/lib/types/common/utils.d.ts +8 -0
  51. package/lib/types/components/livechatwidget/common/customEventHandler.d.ts +4 -0
  52. package/lib/types/components/webchatcontainerstateful/common/utils/chatAdapterUtils.d.ts +2 -0
  53. package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/callActionMiddleware.d.ts +8 -0
  54. package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/customEventMiddleware.d.ts +22 -0
  55. package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/queueOverflowHandlerMiddleware.d.ts +5 -0
  56. package/lib/types/contexts/common/CustomEventType.d.ts +6 -0
  57. package/lib/types/firstresponselatency/FirstResponseLatencyTracker.d.ts +2 -2
  58. package/package.json +3 -3
@@ -7,34 +7,47 @@ import { TelemetryHelper } from "../../../common/telemetry/TelemetryHelper";
7
7
  import { defaultMiddlewareLocalizedTexts } from "../../webchatcontainerstateful/common/defaultProps/defaultMiddlewareLocalizedTexts";
8
8
  import { executeReducer } from "../../../contexts/createReducer";
9
9
  import { LiveChatWidgetActionType } from "../../../contexts/common/LiveChatWidgetActionType";
10
- const isInternetConnected = async () => {
10
+ const getRegionBasedInternetTestUrl = widgetSnippet => {
11
+ var _widgetSnippet$match;
12
+ if (!widgetSnippet) {
13
+ return null;
14
+ }
15
+ const widgetSnippetSourceRegex = new RegExp("src=\"(https:\\/\\/[\\w-.]+)[\\w-.\\/]+\"");
16
+ const baseCdnUrl = (_widgetSnippet$match = widgetSnippet.match(widgetSnippetSourceRegex)) === null || _widgetSnippet$match === void 0 ? void 0 : _widgetSnippet$match[1];
17
+ return baseCdnUrl ? `${baseCdnUrl}${Constants.internetConnectionTestPath}` : null;
18
+ };
19
+ const isInternetConnected = async testUrl => {
11
20
  try {
12
- const response = await fetch(Constants.internetConnectionTestUrl);
13
- const text = await response.text();
14
- return text === Constants.internetConnectionTestUrlText;
21
+ const response = await fetch(testUrl, {
22
+ method: "GET",
23
+ cache: "no-cache"
24
+ });
25
+ return response.ok;
15
26
  } catch {
16
27
  return false;
17
28
  }
18
29
  };
19
30
  export const createInternetConnectionChangeHandler = async state => {
20
31
  const handler = async () => {
21
- const connected = await isInternetConnected();
32
+ var _inMemoryState$domain, _inMemoryState$domain2;
22
33
  const inMemoryState = executeReducer(state, {
23
34
  type: LiveChatWidgetActionType.GET_IN_MEMORY_STATE,
24
35
  payload: null
25
36
  });
37
+ const testUrl = getRegionBasedInternetTestUrl((_inMemoryState$domain = inMemoryState.domainStates.liveChatConfig) === null || _inMemoryState$domain === void 0 ? void 0 : (_inMemoryState$domain2 = _inMemoryState$domain.LiveWSAndLiveChatEngJoin) === null || _inMemoryState$domain2 === void 0 ? void 0 : _inMemoryState$domain2.msdyn_widgetsnippet);
38
+ const connected = testUrl ? await isInternetConnected(testUrl) : false;
26
39
  if (!connected) {
27
- var _inMemoryState$domain, _inMemoryState$domain2;
40
+ var _inMemoryState$domain3, _inMemoryState$domain4;
28
41
  TelemetryHelper.logActionEvent(LogLevel.WARN, {
29
42
  Event: TelemetryEvent.NetworkDisconnected
30
43
  });
31
- NotificationHandler.notifyError(NotificationScenarios.InternetConnection, (inMemoryState === null || inMemoryState === void 0 ? void 0 : (_inMemoryState$domain = inMemoryState.domainStates) === null || _inMemoryState$domain === void 0 ? void 0 : (_inMemoryState$domain2 = _inMemoryState$domain.middlewareLocalizedTexts) === null || _inMemoryState$domain2 === void 0 ? void 0 : _inMemoryState$domain2.MIDDLEWARE_BANNER_NO_INTERNET_CONNECTION) ?? defaultMiddlewareLocalizedTexts.MIDDLEWARE_BANNER_NO_INTERNET_CONNECTION);
44
+ NotificationHandler.notifyError(NotificationScenarios.InternetConnection, (inMemoryState === null || inMemoryState === void 0 ? void 0 : (_inMemoryState$domain3 = inMemoryState.domainStates) === null || _inMemoryState$domain3 === void 0 ? void 0 : (_inMemoryState$domain4 = _inMemoryState$domain3.middlewareLocalizedTexts) === null || _inMemoryState$domain4 === void 0 ? void 0 : _inMemoryState$domain4.MIDDLEWARE_BANNER_NO_INTERNET_CONNECTION) ?? defaultMiddlewareLocalizedTexts.MIDDLEWARE_BANNER_NO_INTERNET_CONNECTION);
32
45
  } else {
33
- var _inMemoryState$domain3, _inMemoryState$domain4;
46
+ var _inMemoryState$domain5, _inMemoryState$domain6;
34
47
  TelemetryHelper.logActionEvent(LogLevel.WARN, {
35
48
  Event: TelemetryEvent.NetworkReconnected
36
49
  });
37
- NotificationHandler.notifySuccess(NotificationScenarios.InternetConnection, (inMemoryState === null || inMemoryState === void 0 ? void 0 : (_inMemoryState$domain3 = inMemoryState.domainStates) === null || _inMemoryState$domain3 === void 0 ? void 0 : (_inMemoryState$domain4 = _inMemoryState$domain3.middlewareLocalizedTexts) === null || _inMemoryState$domain4 === void 0 ? void 0 : _inMemoryState$domain4.MIDDLEWARE_BANNER_INTERNET_BACK_ONLINE) ?? defaultMiddlewareLocalizedTexts.MIDDLEWARE_BANNER_INTERNET_BACK_ONLINE);
50
+ NotificationHandler.notifySuccess(NotificationScenarios.InternetConnection, (inMemoryState === null || inMemoryState === void 0 ? void 0 : (_inMemoryState$domain5 = inMemoryState.domainStates) === null || _inMemoryState$domain5 === void 0 ? void 0 : (_inMemoryState$domain6 = _inMemoryState$domain5.middlewareLocalizedTexts) === null || _inMemoryState$domain6 === void 0 ? void 0 : _inMemoryState$domain6.MIDDLEWARE_BANNER_INTERNET_BACK_ONLINE) ?? defaultMiddlewareLocalizedTexts.MIDDLEWARE_BANNER_INTERNET_BACK_ONLINE);
38
51
  BroadcastService.postMessage({
39
52
  eventName: BroadcastEvent.NetworkReconnected
40
53
  });
@@ -28,12 +28,65 @@ export const createMarkdown = (disableMarkdownMessageFormatting, disableNewLineM
28
28
  // Rule to process html blocks and paragraphs
29
29
  "html_inline",
30
30
  // Rule to process html tags
31
- "newline" // Rule to proceess '\n'
31
+ "newline",
32
+ // Rule to proceess '\n'
33
+ "list" // Enable list parsing rule
32
34
  ]);
33
35
  }
34
36
 
35
37
  markdown.disable(["strikethrough"]);
36
38
 
39
+ // Custom plugin to fix numbered list continuity
40
+ markdown.use(function (md) {
41
+ const originalRender = md.render.bind(md);
42
+ const originalRenderInline = md.renderInline.bind(md);
43
+ function preprocessText(text) {
44
+ // Handle numbered lists that come with double line breaks (knowledge article format)
45
+ // This ensures proper continuous numbering instead of separate lists
46
+
47
+ let result = text;
48
+
49
+ // Only process if the text contains the double line break pattern
50
+ // But exclude simple numbered lists (where content after \n\n starts with another number)
51
+ if (!/\d+\.\s+.*?\n\n(?!\d+\.\s)[\s\S]*?(?:\n\n\d+\.|\s*$)/.test(text)) {
52
+ return result;
53
+ }
54
+
55
+ // Convert "1. Item\n\nContent\n\n2. Item" to proper markdown list format
56
+ // Use improved pattern with negative lookahead to exclude cases where content starts with numbered list
57
+ const listPattern = /(\d+\.\s+[^\n]+)(\n\n(?!\d+\.\s)[\s\S]*?)(?=\n\n\d+\.|\s*$)/g;
58
+ if (listPattern.test(result)) {
59
+ // Reset regex state for actual replacement
60
+ listPattern.lastIndex = 0;
61
+ result = result.replace(listPattern, (match, listItem, content) => {
62
+ if (!content) {
63
+ return match;
64
+ }
65
+
66
+ // Format content with proper indentation
67
+ const cleanContent = content.substring(2); // Remove leading \n\n
68
+ const lines = cleanContent.split("\n");
69
+ const indentedContent = lines.map(line => line.trim() ? `${Constants.MARKDOWN_LIST_INDENTATION}${line}` : "").join("\n");
70
+ const lineBreak = disableNewLineMarkdownSupport ? "\n" : "\n\n";
71
+ return `${listItem}${lineBreak}${indentedContent}`;
72
+ });
73
+ }
74
+ return result;
75
+ }
76
+
77
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
78
+ md.render = function (text, env) {
79
+ const processedText = preprocessText(text);
80
+ return originalRender(processedText, env);
81
+ };
82
+
83
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
84
+ md.renderInline = function (text, env) {
85
+ const processedText = preprocessText(text);
86
+ return originalRenderInline(processedText, env);
87
+ };
88
+ });
89
+
37
90
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
91
  markdown.use(MarkdownItForInline, "url_new_win", "link_open", function (tokens, idx, env) {
39
92
  const targetAttrIndex = tokens[idx].attrIndex(Constants.Target);
@@ -0,0 +1,45 @@
1
+ import { Constants } from "../../../common/Constants";
2
+ import { TelemetryHelper } from "../../../common/telemetry/TelemetryHelper";
3
+ import { LogLevel, TelemetryEvent } from "../../../common/telemetry/TelemetryConstants";
4
+ import { getCustomEventValue, isValidCustomEvent } from "../../../common/utils";
5
+ export const customEventCallback = facadeChatSDK => event => {
6
+ if (!(Constants.payload in event)) return;
7
+ if (isValidCustomEvent(event.payload)) {
8
+ const customEventPayload = event.payload;
9
+ try {
10
+ const customEventValueStr = getCustomEventValue(customEventPayload);
11
+ const customEventName = customEventPayload.customEventName;
12
+ const messageMeta = {
13
+ customEvent: Constants.true,
14
+ customEventName: customEventName,
15
+ customEventValue: customEventValueStr
16
+ };
17
+ const messagePayload = {
18
+ content: "",
19
+ tags: [Constants.Hidden],
20
+ metadata: messageMeta,
21
+ timestamp: new Date()
22
+ };
23
+ facadeChatSDK.sendMessage(messagePayload);
24
+ TelemetryHelper.logActionEventToAllTelemetry(LogLevel.DEBUG, {
25
+ Event: TelemetryEvent.CustomEventAction,
26
+ Description: "Sent customEvent.",
27
+ CustomProperties: {
28
+ customEventName,
29
+ lengthCustomEventValue: customEventValueStr.length
30
+ }
31
+ });
32
+ } catch (error) {
33
+ TelemetryHelper.logActionEventToAllTelemetry(LogLevel.ERROR, {
34
+ Event: TelemetryEvent.CustomEventAction,
35
+ Description: "Failed to process CustomEvent.",
36
+ ExceptionDetails: {
37
+ error
38
+ }
39
+ });
40
+ }
41
+ }
42
+ };
43
+ export const subscribeToSendCustomEvent = (broadcastService, facadeChatSDK, customEventCallback) => {
44
+ broadcastService.getMessageByEventName(Constants.sendCustomEvent).subscribe(customEventCallback(facadeChatSDK));
45
+ };
@@ -35,6 +35,7 @@ const prepareEndChat = async (props, facadeChatSDK, state, dispatch, setAdapter,
35
35
  Description: PrepareEndChatDescriptionConstants.ConversationEndedByCustomerWithoutPostChat
36
36
  });
37
37
  await endChat(props, facadeChatSDK, state, dispatch, setAdapter, setWebChatStyles, adapter, false, false, true);
38
+ return;
38
39
  }
39
40
 
40
41
  // Use Case: If ended by Agent, stay chat in InActive state
@@ -32,8 +32,12 @@ import htmlTextMiddleware from "../../webchatcontainerstateful/webchatcontroller
32
32
  import preProcessingMiddleware from "../../webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/preProcessingMiddleware";
33
33
  import sanitizationMiddleware from "../../webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/sanitizationMiddleware";
34
34
  import { Constants } from "../../../common/Constants";
35
+ import createCallActionMiddleware from "../../webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/callActionMiddleware";
36
+ import createCustomEventMiddleware from "../../webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/customEventMiddleware";
35
37
  import { ConversationState } from "../../../contexts/common/ConversationState";
36
38
  import { executeReducer } from "../../../contexts/createReducer";
39
+ import { createQueueOverflowMiddleware } from "../../webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/queueOverflowHandlerMiddleware";
40
+ import { BroadcastService } from "@microsoft/omnichannel-chat-components";
37
41
 
38
42
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
39
43
  export const initWebChatComposer = (props, state, dispatch, facadeChatSDK, endChat) => {
@@ -112,7 +116,7 @@ export const initWebChatComposer = (props, state, dispatch, facadeChatSDK, endCh
112
116
  };
113
117
  webChatStore = createStore({},
114
118
  //initial state
115
- preProcessingMiddleware, attachmentProcessingMiddleware, createAttachmentUploadValidatorMiddleware((_state$domainStates$l = state.domainStates.liveChatConfig) === null || _state$domainStates$l === void 0 ? void 0 : _state$domainStates$l.allowedFileExtensions, (_state$domainStates$l2 = state.domainStates.liveChatConfig) === null || _state$domainStates$l2 === void 0 ? void 0 : _state$domainStates$l2.maxUploadFileSize, localizedTexts), channelDataMiddleware(addConversationalSurveyTagsCallback), createConversationEndMiddleware(conversationEndCallback, startConversationalSurveyCallback, endConversationalSurveyCallback), createDataMaskingMiddleware((_state$domainStates$l3 = state.domainStates.liveChatConfig) === null || _state$domainStates$l3 === void 0 ? void 0 : _state$domainStates$l3.DataMaskingInfo), createMessageTimeStampMiddleware, createMessageSequenceIdOverrideMiddleware, gifUploadMiddleware, htmlPlayerMiddleware, htmlTextMiddleware(honorsTargetInHTMLLinks), createMaxMessageSizeValidator(localizedTexts), sanitizationMiddleware,
119
+ preProcessingMiddleware, attachmentProcessingMiddleware, createAttachmentUploadValidatorMiddleware((_state$domainStates$l = state.domainStates.liveChatConfig) === null || _state$domainStates$l === void 0 ? void 0 : _state$domainStates$l.allowedFileExtensions, (_state$domainStates$l2 = state.domainStates.liveChatConfig) === null || _state$domainStates$l2 === void 0 ? void 0 : _state$domainStates$l2.maxUploadFileSize, localizedTexts), createCustomEventMiddleware(BroadcastService), createQueueOverflowMiddleware(state, dispatch), channelDataMiddleware(addConversationalSurveyTagsCallback), createConversationEndMiddleware(conversationEndCallback, startConversationalSurveyCallback, endConversationalSurveyCallback), createDataMaskingMiddleware((_state$domainStates$l3 = state.domainStates.liveChatConfig) === null || _state$domainStates$l3 === void 0 ? void 0 : _state$domainStates$l3.DataMaskingInfo), createMessageTimeStampMiddleware, createMessageSequenceIdOverrideMiddleware, gifUploadMiddleware, htmlPlayerMiddleware, htmlTextMiddleware(honorsTargetInHTMLLinks), createMaxMessageSizeValidator(localizedTexts), sanitizationMiddleware, createCallActionMiddleware(),
116
120
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
117
121
  ...(((_props$webChatContain7 = props.webChatContainerProps) === null || _props$webChatContain7 === void 0 ? void 0 : _props$webChatContain7.storeMiddlewares) ?? []));
118
122
  WebChatStoreLoader.store = webChatStore;
@@ -6,6 +6,7 @@ import { PostChatSurveyMode } from "../../postchatsurveypanestateful/enums/PostC
6
6
  import { TelemetryHelper } from "../../../common/telemetry/TelemetryHelper";
7
7
  import { addDelayInMs } from "../../../common/utils";
8
8
  import { getPostChatSurveyConfig } from "./liveChatConfigUtils";
9
+ import { executeReducer } from "../../../contexts/createReducer";
9
10
 
10
11
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
12
  let conversationDetails = undefined;
@@ -59,6 +60,13 @@ const renderSurvey = async (postChatContext, state, dispatch) => {
59
60
  // Function for embed mode postchat workflow which is essentially same for both customer and agent
60
61
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
61
62
  const embedModePostChatWorkflow = async (postChatContext, state, dispatch) => {
63
+ const inMemoryState = executeReducer(state, {
64
+ type: LiveChatWidgetActionType.GET_IN_MEMORY_STATE,
65
+ payload: null
66
+ });
67
+ if (inMemoryState.appStates.conversationState === ConversationState.Closed) {
68
+ return;
69
+ }
62
70
  TelemetryHelper.logActionEvent(LogLevel.INFO, {
63
71
  Event: TelemetryEvent.EmbedModePostChatWorkflowStarted
64
72
  });
@@ -79,6 +87,13 @@ const embedModePostChatWorkflow = async (postChatContext, state, dispatch) => {
79
87
  payload: ConversationState.PostchatLoading
80
88
  });
81
89
  await addDelayInMs(Constants.PostChatLoadingDurationInMs);
90
+ const inMemoryState = executeReducer(state, {
91
+ type: LiveChatWidgetActionType.GET_IN_MEMORY_STATE,
92
+ payload: null
93
+ });
94
+ if (inMemoryState.appStates.conversationState === ConversationState.Closed) {
95
+ return;
96
+ }
82
97
  dispatch({
83
98
  type: LiveChatWidgetActionType.SET_CONVERSATION_STATE,
84
99
  payload: ConversationState.Postchat
@@ -97,6 +112,14 @@ const embedModePostChatWorkflow = async (postChatContext, state, dispatch) => {
97
112
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
98
113
  const initiatePostChat = async (props, conversationDetailsParam, state, dispatch, postchatContext) => {
99
114
  var _conversationDetails;
115
+ const inMemoryState = executeReducer(state, {
116
+ type: LiveChatWidgetActionType.GET_IN_MEMORY_STATE,
117
+ payload: null
118
+ });
119
+ if (inMemoryState.appStates.conversationState === ConversationState.Closed) {
120
+ // If the conversation is closed, we need to reset the state
121
+ return;
122
+ }
100
123
  conversationDetails = conversationDetailsParam;
101
124
  const participantType = ((_conversationDetails = conversationDetails) === null || _conversationDetails === void 0 ? void 0 : _conversationDetails.participantType) ?? postchatContext.participantType;
102
125
  await setSurveyMode(props, participantType, state, dispatch);
@@ -148,7 +148,6 @@ const setPreChatAndInitiateChat = async (facadeChatSDK, dispatch, setAdapter, is
148
148
  const optionalParams = {
149
149
  isProactiveChat
150
150
  };
151
- createTrackingForFirstMessage();
152
151
  await initStartChat(facadeChatSDK, dispatch, setAdapter, state, props, optionalParams);
153
152
  };
154
153
 
@@ -199,6 +198,7 @@ const initStartChat = async (facadeChatSDK, dispatch, setAdapter, state, props,
199
198
  const startChatOptionalParams = Object.assign({}, params, optionalParams, defaultOptionalParams);
200
199
  // startTime is used to determine if a message is history or new, better to be set before creating the adapter to get bandwidth
201
200
  const startTime = new Date().getTime();
201
+ createTrackingForFirstMessage();
202
202
  await facadeChatSDK.startChat(startChatOptionalParams);
203
203
  isStartChatSuccessful = true;
204
204
  await createAdapterAndSubscribe(facadeChatSDK, dispatch, setAdapter, startTime, props);
@@ -53,6 +53,7 @@ import { startProactiveChat } from "../common/startProactiveChat";
53
53
  import useChatAdapterStore from "../../../hooks/useChatAdapterStore";
54
54
  import useChatContextStore from "../../../hooks/useChatContextStore";
55
55
  import useFacadeSDKStore from "../../../hooks/useFacadeChatSDKStore";
56
+ import { customEventCallback, subscribeToSendCustomEvent } from "../common/customEventHandler";
56
57
  let uiTimer;
57
58
  export const LiveChatWidgetStateful = props => {
58
59
  var _props$webChatContain, _props$webChatContain2, _props$webChatContain3, _props$webChatContain4, _props$webChatContain5, _props$webChatContain6, _props$webChatContain7, _props$webChatContain8, _props$webChatContain9, _props$styleProps, _props$webChatContain10, _props$webChatContain11, _props$controlProps, _props$controlProps3, _state$appStates7, _props$webChatContain15, _state$appStates14, _props$webChatContain17, _props$webChatContain18, _props$controlProps12, _props$draggableChatW, _props$draggableChatW2, _props$draggableChatW3, _props$draggableChatW4, _props$draggableChatW5, _livechatProps$webCha, _livechatProps$styleP, _livechatProps$contro, _livechatProps$contro2, _livechatProps$compon, _livechatProps$contro3, _livechatProps$compon2, _livechatProps$contro4, _livechatProps$compon3, _livechatProps$contro5, _livechatProps$compon4, _livechatProps$contro6, _livechatProps$compon5, _livechatProps$contro7, _livechatProps$compon6, _livechatProps$contro8, _livechatProps$compon7, _livechatProps$contro9, _livechatProps$compon8, _livechatProps$contro10, _livechatProps$contro11, _livechatProps$compon9, _livechatProps$contro12, _livechatProps$compon10, _livechatProps$contro13, _livechatProps$compon11, _livechatProps$compon12, _livechatProps$compon13;
@@ -413,7 +414,7 @@ export const LiveChatWidgetStateful = props => {
413
414
  BroadcastService.getMessageByEventName(BroadcastEvent.StartChat).subscribe(msg => {
414
415
  var _msg$payload5, _msg$payload6, _msg$payload7, _msg$payload9, _inMemoryState$appSta2, _inMemoryState$appSta3, _inMemoryState$appSta4;
415
416
  // If chat is out of operating hours chat widget sets the conversation state to OutOfOffice.
416
- if (state.appStates.outsideOperatingHours === true) {
417
+ if (state.appStates.outsideOperatingHours && state.appStates.conversationState !== ConversationState.Active) {
417
418
  dispatch({
418
419
  type: LiveChatWidgetActionType.SET_MINIMIZED,
419
420
  payload: false
@@ -580,6 +581,9 @@ export const LiveChatWidgetStateful = props => {
580
581
  }
581
582
  });
582
583
 
584
+ // subscribe custom event
585
+ subscribeToSendCustomEvent(BroadcastService, facadeChatSDK, customEventCallback);
586
+
583
587
  // Check for TPC and log in telemetry if blocked
584
588
  isCookieAllowed();
585
589
  return () => {
@@ -178,7 +178,7 @@ export const WebChatContainerStateful = props => {
178
178
  }
179
179
 
180
180
  .webchat__bubble__content>div#ms_lcw_webchat_adaptive_card .ac-textBlock {
181
- color: ${(webChatContainerProps === null || webChatContainerProps === void 0 ? void 0 : (_webChatContainerProp2 = webChatContainerProps.adaptiveCardStyles) === null || _webChatContainerProp2 === void 0 ? void 0 : _webChatContainerProp2.color) ?? defaultAdaptiveCardStyles.color} !important;
181
+ color: ${(webChatContainerProps === null || webChatContainerProps === void 0 ? void 0 : (_webChatContainerProp2 = webChatContainerProps.adaptiveCardStyles) === null || _webChatContainerProp2 === void 0 ? void 0 : _webChatContainerProp2.color) ?? defaultAdaptiveCardStyles.color};
182
182
  }
183
183
 
184
184
  .webchat__stacked-layout__content div.webchat__stacked-layout__message-row div.webchat__bubble--from-user {
@@ -12,7 +12,7 @@ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Re
12
12
  function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
13
13
  import { Observable } from "rxjs/Observable";
14
14
  import MockAdapter from "./mockadapter";
15
- import { customerUser, postBotMessageActivity, postEchoActivity, postSystemMessageActivity } from "./utils/chatAdapterUtils";
15
+ import { customerUser, postAgentMessageActivity, postBotMessageActivity, postEchoActivity, postSystemMessageActivity } from "./utils/chatAdapterUtils";
16
16
  export let DesignerChatAdapter = /*#__PURE__*/function (_MockAdapter) {
17
17
  _inherits(DesignerChatAdapter, _MockAdapter);
18
18
  var _super = _createSuper(DesignerChatAdapter);
@@ -22,10 +22,12 @@ export let DesignerChatAdapter = /*#__PURE__*/function (_MockAdapter) {
22
22
  _this = _super.call(this);
23
23
  setTimeout(() => {
24
24
  postBotMessageActivity(_this.activityObserver, "Thank you for contacting us! How can I help you today?", undefined, 0);
25
+ postBotMessageActivity(_this.activityObserver, "Please accept terms and conditions to proceed. Visit the link for terms and conditions <a href=\"\">here</a>.", undefined, 0);
25
26
  _this.postUserActivity("I need to change my address.", 0);
26
27
  postBotMessageActivity(_this.activityObserver, "Okay, let me connect you with a live agent.", undefined, 100);
27
28
  postSystemMessageActivity(_this.activityObserver, "John has joined the chat", 100);
28
- postBotMessageActivity(_this.activityObserver, "I'd be happy to help you update your account.", undefined, 100);
29
+ postAgentMessageActivity(_this.activityObserver, "I'd be happy to help you update your account.", undefined, 100);
30
+ _this.postUserActivity("I have trouble visiting the signin page <a href=\"\">signin</a>.", 0);
29
31
  }, 1000);
30
32
  return _this;
31
33
  }
@@ -9,6 +9,11 @@ export const botUser = {
9
9
  name: "Bot",
10
10
  role: "bot"
11
11
  };
12
+ export const agentUser = {
13
+ id: "AgentId",
14
+ name: "John",
15
+ role: "bot"
16
+ };
12
17
 
13
18
  // WebChat expects an "echo" activity to confirm the message has been sent successfully
14
19
  export const postEchoActivity = function (activityObserver, activity, user) {
@@ -44,6 +49,24 @@ export const postBotMessageActivity = function (activityObserver, text) {
44
49
  });
45
50
  }, delay);
46
51
  };
52
+ export const postAgentMessageActivity = function (activityObserver, text) {
53
+ let tags = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "";
54
+ let delay = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1000;
55
+ setTimeout(() => {
56
+ activityObserver === null || activityObserver === void 0 ? void 0 : activityObserver.next({
57
+ id: uuidv4(),
58
+ from: {
59
+ ...agentUser
60
+ },
61
+ text,
62
+ type: "message",
63
+ channelData: {
64
+ tags
65
+ },
66
+ timestamp: new Date().toISOString()
67
+ });
68
+ }, delay);
69
+ };
47
70
  export const postSystemMessageActivity = function (activityObserver, text) {
48
71
  let delay = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1000;
49
72
  postBotMessageActivity(activityObserver, text, "system", delay);
@@ -0,0 +1,36 @@
1
+ /******
2
+ * CallActionMiddleware
3
+ *
4
+ * Intercepts custom call actions and handles tel: URL navigation
5
+ ******/
6
+
7
+ import { WebChatActionType } from "../../enums/WebChatActionType";
8
+
9
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
10
+ const createCallActionMiddleware = () => () => next => action => {
11
+ // Intercept incoming activities to modify suggested actions with call type
12
+ if (action.type === WebChatActionType.DIRECT_LINE_INCOMING_ACTIVITY) {
13
+ var _action$payload, _activity$suggestedAc;
14
+ const activity = (_action$payload = action.payload) === null || _action$payload === void 0 ? void 0 : _action$payload.activity;
15
+
16
+ // Check if activity has suggested actions with call type
17
+ if (activity !== null && activity !== void 0 && (_activity$suggestedAc = activity.suggestedActions) !== null && _activity$suggestedAc !== void 0 && _activity$suggestedAc.actions) {
18
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
+ activity.suggestedActions.actions = activity.suggestedActions.actions.map(suggestedAction => {
20
+ if (suggestedAction.type === "call") {
21
+ // Convert call action to openUrl with encoded tel URL scheme
22
+ const telUrl = suggestedAction.value;
23
+ const convertedAction = {
24
+ ...suggestedAction,
25
+ type: "openUrl",
26
+ value: `tel:${telUrl}`
27
+ };
28
+ return convertedAction;
29
+ }
30
+ return suggestedAction;
31
+ });
32
+ }
33
+ }
34
+ return next(action);
35
+ };
36
+ export default createCallActionMiddleware;
@@ -0,0 +1,33 @@
1
+ /******
2
+ * CustomEventMiddleware
3
+ *
4
+ * This middleware is invoked when a custom event is received.
5
+ * The callback is then invoked to handle the custom event.
6
+ ******/
7
+
8
+ import { Constants } from "../../../../../common/Constants";
9
+ import { WebChatActionType } from "../../enums/WebChatActionType";
10
+ export const isValidCustomEvent = activity => {
11
+ var _activity$channelData, _activity$channelData2, _activity$channelData3, _activity$channelData4, _activity$channelData5, _activity$channelData6, _activity$channelData7, _activity$from, _activity$channelData8, _activity$channelData9, _activity$channelData10, _activity$channelData11;
12
+ return !!(activity !== null && activity !== void 0 && (_activity$channelData = activity.channelData) !== null && _activity$channelData !== void 0 && (_activity$channelData2 = _activity$channelData.metadata) !== null && _activity$channelData2 !== void 0 && _activity$channelData2.customEvent && typeof (activity === null || activity === void 0 ? void 0 : (_activity$channelData3 = activity.channelData) === null || _activity$channelData3 === void 0 ? void 0 : (_activity$channelData4 = _activity$channelData3.metadata) === null || _activity$channelData4 === void 0 ? void 0 : _activity$channelData4.customEvent) === Constants.String && (activity === null || activity === void 0 ? void 0 : (_activity$channelData5 = activity.channelData) === null || _activity$channelData5 === void 0 ? void 0 : (_activity$channelData6 = _activity$channelData5.metadata) === null || _activity$channelData6 === void 0 ? void 0 : (_activity$channelData7 = _activity$channelData6.customEvent) === null || _activity$channelData7 === void 0 ? void 0 : _activity$channelData7.toLowerCase()) === Constants.true && (activity === null || activity === void 0 ? void 0 : (_activity$from = activity.from) === null || _activity$from === void 0 ? void 0 : _activity$from.role) !== Constants.userMessageTag && typeof (activity === null || activity === void 0 ? void 0 : (_activity$channelData8 = activity.channelData) === null || _activity$channelData8 === void 0 ? void 0 : (_activity$channelData9 = _activity$channelData8.metadata) === null || _activity$channelData9 === void 0 ? void 0 : _activity$channelData9.customEventName) === Constants.String && activity !== null && activity !== void 0 && (_activity$channelData10 = activity.channelData) !== null && _activity$channelData10 !== void 0 && (_activity$channelData11 = _activity$channelData10.metadata) !== null && _activity$channelData11 !== void 0 && _activity$channelData11.customEventValue);
13
+ };
14
+ const createCustomEventMiddleware = broadcastservice => () => next => action => {
15
+ var _action$payload;
16
+ if ((action === null || action === void 0 ? void 0 : action.type) == WebChatActionType.DIRECT_LINE_INCOMING_ACTIVITY && (_action$payload = action.payload) !== null && _action$payload !== void 0 && _action$payload.activity) {
17
+ const activity = action.payload.activity;
18
+ if (isValidCustomEvent(activity)) {
19
+ const customEvent = {
20
+ eventName: Constants.onCustomEvent,
21
+ payload: {
22
+ messageId: activity.messageid ?? activity.id,
23
+ customEventName: activity.channelData.metadata.customEventName,
24
+ customEventValue: activity.channelData.metadata.customEventValue
25
+ }
26
+ };
27
+ broadcastservice.postMessage(customEvent);
28
+ return;
29
+ }
30
+ }
31
+ return next(action);
32
+ };
33
+ export default createCustomEventMiddleware;
@@ -0,0 +1,38 @@
1
+ import { WebChatActionType } from "../../enums/WebChatActionType";
2
+ import { LogLevel, TelemetryEvent } from "../../../../../common/telemetry/TelemetryConstants";
3
+ import { TelemetryHelper } from "../../../../../common/telemetry/TelemetryHelper";
4
+ import { LiveChatWidgetActionType } from "../../../../../contexts/common/LiveChatWidgetActionType";
5
+ import { executeReducer } from "../../../../../contexts/createReducer";
6
+ import { isEndConversationDueToOverflowActivity } from "../../../../../common/utils";
7
+ const queueOverflowHandlingHelper = async (state, dispatch) => {
8
+ const {
9
+ appStates
10
+ } = executeReducer(state, {
11
+ type: LiveChatWidgetActionType.GET_IN_MEMORY_STATE,
12
+ payload: undefined
13
+ });
14
+ if (!appStates.chatDisconnectEventReceived) {
15
+ dispatch({
16
+ type: LiveChatWidgetActionType.SET_CHAT_DISCONNECT_EVENT_RECEIVED,
17
+ payload: true
18
+ });
19
+ TelemetryHelper.logActionEvent(LogLevel.INFO, {
20
+ Event: TelemetryEvent.QueueOverflowEvent,
21
+ Description: "Set chat disconnect event received."
22
+ });
23
+ }
24
+ };
25
+ export const createQueueOverflowMiddleware = (state, dispatch) => () => next => action => {
26
+ var _action$payload;
27
+ if ((action === null || action === void 0 ? void 0 : action.type) == WebChatActionType.DIRECT_LINE_INCOMING_ACTIVITY && (_action$payload = action.payload) !== null && _action$payload !== void 0 && _action$payload.activity) {
28
+ const activity = action.payload.activity;
29
+ if (isEndConversationDueToOverflowActivity(activity)) {
30
+ TelemetryHelper.logActionEvent(LogLevel.INFO, {
31
+ Event: TelemetryEvent.QueueOverflowEvent,
32
+ Description: "Queue overflow event received."
33
+ });
34
+ queueOverflowHandlingHelper(state, dispatch);
35
+ }
36
+ }
37
+ return next(action);
38
+ };
@@ -0,0 +1 @@
1
+ export {};