@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.
- package/README.md +46 -1
- package/lib/cjs/common/Constants.js +8 -2
- package/lib/cjs/common/telemetry/TelemetryConstants.js +2 -0
- package/lib/cjs/common/utils.js +27 -2
- package/lib/cjs/components/chatbuttonstateful/ChatButtonStateful.js +4 -4
- package/lib/cjs/components/livechatwidget/common/createInternetConnectionChangeHandler.js +22 -9
- package/lib/cjs/components/livechatwidget/common/createMarkdown.js +54 -1
- package/lib/cjs/components/livechatwidget/common/customEventHandler.js +53 -0
- package/lib/cjs/components/livechatwidget/common/endChat.js +1 -0
- package/lib/cjs/components/livechatwidget/common/initWebChatComposer.js +5 -1
- package/lib/cjs/components/livechatwidget/common/renderSurveyHelpers.js +23 -0
- package/lib/cjs/components/livechatwidget/common/startChat.js +1 -1
- package/lib/cjs/components/livechatwidget/livechatwidgetstateful/LiveChatWidgetStateful.js +5 -1
- package/lib/cjs/components/webchatcontainerstateful/WebChatContainerStateful.js +1 -1
- package/lib/cjs/components/webchatcontainerstateful/common/DesignerChatAdapter.js +3 -1
- package/lib/cjs/components/webchatcontainerstateful/common/utils/chatAdapterUtils.js +27 -2
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/callActionMiddleware.js +42 -0
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/customEventMiddleware.js +41 -0
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/queueOverflowHandlerMiddleware.js +45 -0
- package/lib/cjs/contexts/common/CustomEventType.js +1 -0
- package/lib/cjs/firstresponselatency/FirstMessageTrackerFromBot.js +101 -36
- package/lib/cjs/firstresponselatency/FirstResponseLatencyTracker.js +39 -21
- package/lib/cjs/firstresponselatency/util.js +12 -8
- package/lib/cjs/plugins/createChatTranscript.js +13 -0
- package/lib/esm/common/Constants.js +8 -2
- package/lib/esm/common/telemetry/TelemetryConstants.js +2 -0
- package/lib/esm/common/utils.js +21 -0
- package/lib/esm/components/chatbuttonstateful/ChatButtonStateful.js +4 -4
- package/lib/esm/components/livechatwidget/common/createInternetConnectionChangeHandler.js +22 -9
- package/lib/esm/components/livechatwidget/common/createMarkdown.js +54 -1
- package/lib/esm/components/livechatwidget/common/customEventHandler.js +45 -0
- package/lib/esm/components/livechatwidget/common/endChat.js +1 -0
- package/lib/esm/components/livechatwidget/common/initWebChatComposer.js +5 -1
- package/lib/esm/components/livechatwidget/common/renderSurveyHelpers.js +23 -0
- package/lib/esm/components/livechatwidget/common/startChat.js +1 -1
- package/lib/esm/components/livechatwidget/livechatwidgetstateful/LiveChatWidgetStateful.js +5 -1
- package/lib/esm/components/webchatcontainerstateful/WebChatContainerStateful.js +1 -1
- package/lib/esm/components/webchatcontainerstateful/common/DesignerChatAdapter.js +4 -2
- package/lib/esm/components/webchatcontainerstateful/common/utils/chatAdapterUtils.js +23 -0
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/callActionMiddleware.js +36 -0
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/customEventMiddleware.js +33 -0
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/queueOverflowHandlerMiddleware.js +38 -0
- package/lib/esm/contexts/common/CustomEventType.js +1 -0
- package/lib/esm/firstresponselatency/FirstMessageTrackerFromBot.js +101 -36
- package/lib/esm/firstresponselatency/FirstResponseLatencyTracker.js +39 -21
- package/lib/esm/firstresponselatency/util.js +12 -8
- package/lib/esm/plugins/createChatTranscript.js +13 -0
- package/lib/types/common/Constants.d.ts +8 -2
- package/lib/types/common/telemetry/TelemetryConstants.d.ts +2 -0
- package/lib/types/common/utils.d.ts +8 -0
- package/lib/types/components/livechatwidget/common/customEventHandler.d.ts +4 -0
- package/lib/types/components/webchatcontainerstateful/common/utils/chatAdapterUtils.d.ts +2 -0
- package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/callActionMiddleware.d.ts +8 -0
- package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/customEventMiddleware.d.ts +22 -0
- package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/queueOverflowHandlerMiddleware.d.ts +5 -0
- package/lib/types/contexts/common/CustomEventType.d.ts +6 -0
- package/lib/types/firstresponselatency/FirstResponseLatencyTracker.d.ts +2 -2
- 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
|
|
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(
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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"
|
|
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
|
|
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}
|
|
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
|
-
|
|
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 {};
|