@microsoft/omnichannel-chat-widget 1.7.8-main.9e74278 → 1.7.8-main.d38af40
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/lib/cjs/common/telemetry/TelemetryConstants.js +5 -0
- package/lib/cjs/components/livechatwidget/common/ActivitySubscriber/BotAuthActivitySubscriber.js +4 -1
- package/lib/cjs/components/livechatwidget/common/endChat.js +4 -18
- package/lib/cjs/components/livechatwidget/livechatwidgetstateful/LiveChatWidgetStateful.js +14 -8
- package/lib/cjs/components/ooohpanestateful/OOOHPaneStateful.js +4 -0
- package/lib/cjs/components/postchatsurveypanestateful/PostChatSurveyPaneStateful.js +22 -6
- package/lib/cjs/components/postchatsurveypanestateful/common/isValidSurveyUrl.js +28 -0
- package/lib/cjs/contexts/common/LiveChatWidgetContextInitialState.js +4 -4
- package/lib/cjs/firstresponselatency/Constants.js +13 -0
- package/lib/cjs/firstresponselatency/FirstResponseLatencyTracker.js +152 -0
- package/lib/cjs/firstresponselatency/util.js +85 -0
- package/lib/cjs/plugins/createChatTranscript.js +4 -4
- package/lib/cjs/plugins/newMessageEventHandler.js +102 -88
- package/lib/esm/common/telemetry/TelemetryConstants.js +5 -0
- package/lib/esm/components/livechatwidget/common/ActivitySubscriber/BotAuthActivitySubscriber.js +4 -1
- package/lib/esm/components/livechatwidget/common/endChat.js +4 -18
- package/lib/esm/components/livechatwidget/livechatwidgetstateful/LiveChatWidgetStateful.js +14 -8
- package/lib/esm/components/ooohpanestateful/OOOHPaneStateful.js +4 -0
- package/lib/esm/components/postchatsurveypanestateful/PostChatSurveyPaneStateful.js +22 -6
- package/lib/esm/components/postchatsurveypanestateful/common/isValidSurveyUrl.js +21 -0
- package/lib/esm/contexts/common/LiveChatWidgetContextInitialState.js +4 -4
- package/lib/esm/firstresponselatency/Constants.js +6 -0
- package/lib/esm/firstresponselatency/FirstResponseLatencyTracker.js +145 -0
- package/lib/esm/firstresponselatency/util.js +75 -0
- package/lib/esm/plugins/createChatTranscript.js +4 -4
- package/lib/esm/plugins/newMessageEventHandler.js +100 -86
- package/lib/types/common/telemetry/TelemetryConstants.d.ts +5 -0
- package/lib/types/components/postchatsurveypanestateful/common/isValidSurveyUrl.d.ts +2 -0
- package/lib/types/contexts/common/ILiveChatWidgetContext.d.ts +1 -1
- package/lib/types/firstresponselatency/Constants.d.ts +30 -0
- package/lib/types/firstresponselatency/FirstResponseLatencyTracker.d.ts +17 -0
- package/lib/types/firstresponselatency/util.d.ts +6 -0
- package/package.json +1 -1
|
@@ -5,102 +5,116 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.createOnNewAdapterActivityHandler = void 0;
|
|
7
7
|
var _TelemetryConstants = require("../common/telemetry/TelemetryConstants");
|
|
8
|
+
var _Constants = require("../firstresponselatency/Constants");
|
|
9
|
+
var _util = require("../firstresponselatency/util");
|
|
8
10
|
var _omnichannelChatComponents = require("@microsoft/omnichannel-chat-components");
|
|
9
|
-
var
|
|
11
|
+
var _Constants2 = require("../common/Constants");
|
|
12
|
+
var _FirstResponseLatencyTracker = require("../firstresponselatency/FirstResponseLatencyTracker");
|
|
10
13
|
var _TelemetryHelper = require("../common/telemetry/TelemetryHelper");
|
|
11
14
|
var _TelemetryManager = require("../common/telemetry/TelemetryManager");
|
|
12
15
|
const createOnNewAdapterActivityHandler = (chatId, userId) => {
|
|
16
|
+
// Hooking the message tracker in the listener, a bit invasive but easier to control.
|
|
17
|
+
const firstResponseLatencyTracker = new _FirstResponseLatencyTracker.FirstResponseLatencyTracker();
|
|
18
|
+
// epoch time in utc for when start to listen.
|
|
19
|
+
// We dont longer have a mechanism to know if a message is history or new, so any message older than the time we start listening will be considered a history message.
|
|
20
|
+
// this is a workaround for the fact that we dont have a way to identify if a message is history or new, and it will provide consistency across different scenarios
|
|
21
|
+
const startTime = new Date().getTime();
|
|
22
|
+
let isHistoryMessageReceivedEventRaised = false;
|
|
13
23
|
const onNewAdapterActivityHandler = activity => {
|
|
14
|
-
|
|
15
|
-
const isActivityMessage = (activity === null || activity === void 0 ? void 0 : activity.type) === _Constants.Constants.message;
|
|
16
|
-
const isHistoryMessage = isActivityMessage && ((activity === null || activity === void 0 ? void 0 : (_activity$channelData = activity.channelData) === null || _activity$channelData === void 0 ? void 0 : (_activity$channelData2 = _activity$channelData.tags) === null || _activity$channelData2 === void 0 ? void 0 : _activity$channelData2.includes(_Constants.Constants.historyMessageTag)) || (activity === null || activity === void 0 ? void 0 : (_activity$channelData3 = activity.channelData) === null || _activity$channelData3 === void 0 ? void 0 : _activity$channelData3.fromList));
|
|
17
|
-
raiseMessageEvent(activity, isHistoryMessage);
|
|
24
|
+
raiseMessageEvent(activity);
|
|
18
25
|
};
|
|
19
|
-
|
|
20
|
-
|
|
26
|
+
const userSendMessageStrategy = activity => {
|
|
27
|
+
var _TelemetryManager$Int;
|
|
28
|
+
const payload = (0, _util.buildMessagePayload)(activity, userId);
|
|
21
29
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
channelData: activity === null || activity === void 0 ? void 0 : activity.channelData,
|
|
27
|
-
chatId: activity === null || activity === void 0 ? void 0 : (_activity$conversatio = activity.conversation) === null || _activity$conversatio === void 0 ? void 0 : _activity$conversatio.id,
|
|
28
|
-
conversationId: (_TelemetryManager$Int = _TelemetryManager.TelemetryManager.InternalTelemetryData) === null || _TelemetryManager$Int === void 0 ? void 0 : _TelemetryManager$Int.conversationId,
|
|
29
|
-
id: activity === null || activity === void 0 ? void 0 : activity.id,
|
|
30
|
-
isChatComplete: false,
|
|
31
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
32
|
-
text: activity === null || activity === void 0 ? void 0 : activity.text,
|
|
33
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
34
|
-
attachment: (activity === null || activity === void 0 ? void 0 : (_attachments = activity.attachments) === null || _attachments === void 0 ? void 0 : _attachments.length) >= 1 ? activity === null || activity === void 0 ? void 0 : activity.attachments : []
|
|
35
|
-
};
|
|
30
|
+
payload.messageType = _Constants2.Constants.userMessageTag;
|
|
31
|
+
const newMessageSentEvent = {
|
|
32
|
+
eventName: _TelemetryConstants.BroadcastEvent.NewMessageSent,
|
|
33
|
+
payload: (0, _util.polyfillMessagePayloadForEvent)(activity, payload, (_TelemetryManager$Int = _TelemetryManager.TelemetryManager.InternalTelemetryData) === null || _TelemetryManager$Int === void 0 ? void 0 : _TelemetryManager$Int.conversationId)
|
|
36
34
|
};
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
35
|
+
_omnichannelChatComponents.BroadcastService.postMessage(newMessageSentEvent);
|
|
36
|
+
if (!(0, _util.isHistoryMessage)(activity, startTime)) {
|
|
37
|
+
firstResponseLatencyTracker.startClock(payload);
|
|
38
|
+
}
|
|
39
|
+
_TelemetryHelper.TelemetryHelper.logActionEvent(_TelemetryConstants.LogLevel.INFO, {
|
|
40
|
+
Event: _TelemetryConstants.TelemetryEvent.MessageSent,
|
|
41
|
+
Description: "New message sent"
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
const systemMessageStrategy = activity => {
|
|
45
|
+
const payload = (0, _util.buildMessagePayload)(activity, userId);
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
47
|
+
payload.messageType = _Constants2.Constants.systemMessageTag;
|
|
48
|
+
_TelemetryHelper.TelemetryHelper.logActionEvent(_TelemetryConstants.LogLevel.INFO, {
|
|
49
|
+
Event: _TelemetryConstants.TelemetryEvent.SystemMessageReceived,
|
|
50
|
+
Description: "System message received"
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
const historyMessageStrategy = payload => {
|
|
54
|
+
const newMessageReceivedEvent = {
|
|
55
|
+
eventName: _TelemetryConstants.BroadcastEvent.HistoryMessageReceived,
|
|
56
|
+
payload: payload
|
|
57
|
+
};
|
|
58
|
+
_omnichannelChatComponents.BroadcastService.postMessage(newMessageReceivedEvent);
|
|
59
|
+
if (!isHistoryMessageReceivedEventRaised) {
|
|
60
|
+
// this is needed for reload scenarios, it helps to identify the last message received before the reload
|
|
61
|
+
isHistoryMessageReceivedEventRaised = true;
|
|
62
|
+
_TelemetryHelper.TelemetryHelper.logActionEvent(_TelemetryConstants.LogLevel.INFO, {
|
|
63
|
+
Event: _TelemetryConstants.TelemetryEvent.RehydrateMessageReceived,
|
|
64
|
+
Description: "History message received",
|
|
65
|
+
CustomProperties: payload
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const isValidMessage = activity => {
|
|
70
|
+
var _activity$channelData, _activity$channelData2, _activity$channelData3;
|
|
71
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
72
|
+
const messageHasNoText = !(activity !== null && activity !== void 0 && activity.text);
|
|
73
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
74
|
+
const messageHasNoTags = !(activity !== null && activity !== void 0 && activity.channelData) || !(activity !== null && activity !== void 0 && (_activity$channelData = activity.channelData) !== null && _activity$channelData !== void 0 && _activity$channelData.tags) || (activity === null || activity === void 0 ? void 0 : (_activity$channelData2 = activity.channelData) === null || _activity$channelData2 === void 0 ? void 0 : (_activity$channelData3 = _activity$channelData2.tags) === null || _activity$channelData3 === void 0 ? void 0 : _activity$channelData3.length) === 0;
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
76
|
+
const messageHasNoAttachments = !(activity !== null && activity !== void 0 && activity.attachments) || (activity === null || activity === void 0 ? void 0 : activity.attachments.length) === 0;
|
|
77
|
+
if (messageHasNoTags && messageHasNoText && messageHasNoAttachments) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
};
|
|
82
|
+
const receivedMessageStrategy = activity => {
|
|
83
|
+
var _TelemetryManager$Int3;
|
|
84
|
+
if (!isValidMessage(activity)) return;
|
|
85
|
+
const isHistoryMessageReceived = (0, _util.isHistoryMessage)(activity, startTime);
|
|
86
|
+
const payload = (0, _util.buildMessagePayload)(activity, userId);
|
|
87
|
+
payload.messageType = _Constants2.Constants.userMessageTag;
|
|
88
|
+
if (isHistoryMessageReceived) {
|
|
89
|
+
var _TelemetryManager$Int2;
|
|
90
|
+
historyMessageStrategy((0, _util.polyfillMessagePayloadForEvent)(activity, payload, (_TelemetryManager$Int2 = _TelemetryManager.TelemetryManager.InternalTelemetryData) === null || _TelemetryManager$Int2 === void 0 ? void 0 : _TelemetryManager$Int2.conversationId));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
firstResponseLatencyTracker.stopClock(payload);
|
|
94
|
+
const newMessageReceivedEvent = {
|
|
95
|
+
eventName: _TelemetryConstants.BroadcastEvent.NewMessageReceived,
|
|
96
|
+
payload: (0, _util.polyfillMessagePayloadForEvent)(activity, payload, (_TelemetryManager$Int3 = _TelemetryManager.TelemetryManager.InternalTelemetryData) === null || _TelemetryManager$Int3 === void 0 ? void 0 : _TelemetryManager$Int3.conversationId)
|
|
97
|
+
};
|
|
98
|
+
_omnichannelChatComponents.BroadcastService.postMessage(newMessageReceivedEvent);
|
|
99
|
+
_TelemetryHelper.TelemetryHelper.logActionEvent(_TelemetryConstants.LogLevel.INFO, {
|
|
100
|
+
Event: _TelemetryConstants.TelemetryEvent.MessageReceived,
|
|
101
|
+
Description: "New message received",
|
|
102
|
+
CustomProperties: payload
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
const raiseMessageEvent = activity => {
|
|
106
|
+
if ((activity === null || activity === void 0 ? void 0 : activity.type) === _Constants2.Constants.message) {
|
|
107
|
+
const scenarioType = (0, _util.getScenarioType)(activity);
|
|
108
|
+
switch (scenarioType) {
|
|
109
|
+
case _Constants.ScenarioType.UserSendMessageStrategy:
|
|
110
|
+
userSendMessageStrategy(activity);
|
|
111
|
+
break;
|
|
112
|
+
case _Constants.ScenarioType.SystemMessageStrategy:
|
|
113
|
+
systemMessageStrategy(activity);
|
|
114
|
+
break;
|
|
115
|
+
case _Constants.ScenarioType.ReceivedMessageStrategy:
|
|
116
|
+
receivedMessageStrategy(activity);
|
|
117
|
+
break;
|
|
104
118
|
}
|
|
105
119
|
}
|
|
106
120
|
};
|
|
@@ -199,6 +199,9 @@ export let TelemetryEvent;
|
|
|
199
199
|
TelemetryEvent["ReconnectChatMinimize"] = "ReconnectChatMinimize";
|
|
200
200
|
TelemetryEvent["MessageSent"] = "MessageSent";
|
|
201
201
|
TelemetryEvent["MessageReceived"] = "MessageReceived";
|
|
202
|
+
TelemetryEvent["MessageLapTrack"] = "MessageLapTrack";
|
|
203
|
+
TelemetryEvent["MessageStartLapTrackError"] = "MessageStartLapTrackError";
|
|
204
|
+
TelemetryEvent["MessageStopLapTrackError"] = "MessageStopLapTrackError";
|
|
202
205
|
TelemetryEvent["SystemMessageReceived"] = "SystemMessageReceived";
|
|
203
206
|
TelemetryEvent["RehydrateMessageReceived"] = "RehydrateMessageReceived";
|
|
204
207
|
TelemetryEvent["CustomContextReceived"] = "CustomContextReceived";
|
|
@@ -213,6 +216,8 @@ export let TelemetryEvent;
|
|
|
213
216
|
TelemetryEvent["PostChatContextCallFailed"] = "PostChatContextCallFailed";
|
|
214
217
|
TelemetryEvent["PostChatSurveyLoadingPaneLoaded"] = "PostChatSurveyLoadingPaneLoaded";
|
|
215
218
|
TelemetryEvent["PostChatSurveyLoaded"] = "PostChatSurveyLoaded";
|
|
219
|
+
TelemetryEvent["PostChatSurveyUrlValidationCompleted"] = "PostChatSurveyUrlValidationCompleted";
|
|
220
|
+
TelemetryEvent["PostChatSurveyUrlValidationFailed"] = "PostChatSurveyUrlValidationFailed";
|
|
216
221
|
TelemetryEvent["ChatDisconnectThreadEventReceived"] = "ChatDisconnectThreadEventReceived";
|
|
217
222
|
TelemetryEvent["HiddenAdaptiveCardMessageReceived"] = "HiddenAdaptiveCardMessageReceived";
|
|
218
223
|
TelemetryEvent["EndingAdapterAfterDisconnectionError"] = "EndingAdapterAfterDisconnectionError";
|
package/lib/esm/components/livechatwidget/common/ActivitySubscriber/BotAuthActivitySubscriber.js
CHANGED
|
@@ -6,6 +6,7 @@ function _toPrimitive(input, hint) { if (typeof input !== "object" || input ===
|
|
|
6
6
|
import { BroadcastService } from "@microsoft/omnichannel-chat-components";
|
|
7
7
|
import { BroadcastEvent, LogLevel, TelemetryEvent } from "../../../../common/telemetry/TelemetryConstants";
|
|
8
8
|
import { TelemetryHelper } from "../../../../common/telemetry/TelemetryHelper";
|
|
9
|
+
import { TelemetryManager } from "../../../../common/telemetry/TelemetryManager";
|
|
9
10
|
const supportedSignInCardContentTypes = ["application/vnd.microsoft.card.signin", "application/vnd.microsoft.card.oauth"];
|
|
10
11
|
const botOauthUrlRegex = /[\S]+.botframework.com\/api\/oauth\/signin\?signin=([\S]+)/;
|
|
11
12
|
const delay = t => new Promise(resolve => setTimeout(resolve, t));
|
|
@@ -83,6 +84,7 @@ export class BotAuthActivitySubscriber {
|
|
|
83
84
|
return (activity === null || activity === void 0 ? void 0 : (_activity$attachments = activity.attachments) === null || _activity$attachments === void 0 ? void 0 : _activity$attachments.length) > 0 && activity.attachments[0] && supportedSignInCardContentTypes.indexOf(activity.attachments[0].contentType) >= 0;
|
|
84
85
|
}
|
|
85
86
|
async apply(activity) {
|
|
87
|
+
var _TelemetryManager$Int;
|
|
86
88
|
this.observer.next(false); // Hides card
|
|
87
89
|
const attachment = activity.attachments[0];
|
|
88
90
|
const signInUrl = attachment.content.buttons[0].value;
|
|
@@ -102,7 +104,8 @@ export class BotAuthActivitySubscriber {
|
|
|
102
104
|
const event = {
|
|
103
105
|
eventName: BroadcastEvent.SigninCardReceived,
|
|
104
106
|
payload: {
|
|
105
|
-
sasUrl
|
|
107
|
+
sasUrl,
|
|
108
|
+
conversationId: (_TelemetryManager$Int = TelemetryManager.InternalTelemetryData) === null || _TelemetryManager$Int === void 0 ? void 0 : _TelemetryManager$Int.conversationId
|
|
106
109
|
}
|
|
107
110
|
};
|
|
108
111
|
if (!sasUrl) {
|
|
@@ -203,7 +203,7 @@ const endChat = async (props, facadeChatSDK, state, dispatch, setAdapter, setWeb
|
|
|
203
203
|
payload: undefined
|
|
204
204
|
});
|
|
205
205
|
// Always allow to close the chat for embedded mode irrespective of end chat errors
|
|
206
|
-
closeChatWidget(dispatch
|
|
206
|
+
closeChatWidget(dispatch);
|
|
207
207
|
facadeChatSDK.destroy();
|
|
208
208
|
}
|
|
209
209
|
}
|
|
@@ -327,21 +327,7 @@ export const endVoiceVideoCallIfOngoing = async (facadeChatSDK, dispatch) => {
|
|
|
327
327
|
}, callId);
|
|
328
328
|
}
|
|
329
329
|
};
|
|
330
|
-
const closeChatWidget =
|
|
331
|
-
var _state$appStates5;
|
|
332
|
-
if (state !== null && state !== void 0 && (_state$appStates5 = state.appStates) !== null && _state$appStates5 !== void 0 && _state$appStates5.hideStartChatButton) {
|
|
333
|
-
var _props$controlProps2, _props$controlProps3;
|
|
334
|
-
// Only close chat if header is enabled for popout
|
|
335
|
-
// TODO : This condition needs to be removed eventually when the filler UX is ready for popout, removing this condition would show a blank screen for OOB Widget
|
|
336
|
-
if ((props === null || props === void 0 ? void 0 : (_props$controlProps2 = props.controlProps) === null || _props$controlProps2 === void 0 ? void 0 : _props$controlProps2.hideHeader) === undefined || (props === null || props === void 0 ? void 0 : (_props$controlProps3 = props.controlProps) === null || _props$controlProps3 === void 0 ? void 0 : _props$controlProps3.hideHeader) === false) {
|
|
337
|
-
dispatch({
|
|
338
|
-
type: LiveChatWidgetActionType.SET_CONVERSATION_STATE,
|
|
339
|
-
payload: ConversationState.Closed
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
|
|
330
|
+
const closeChatWidget = dispatch => {
|
|
345
331
|
// Embedded chat
|
|
346
332
|
dispatch({
|
|
347
333
|
type: LiveChatWidgetActionType.SET_CONVERSATION_STATE,
|
|
@@ -361,7 +347,7 @@ const chatTokenCleanUp = async dispatch => {
|
|
|
361
347
|
};
|
|
362
348
|
|
|
363
349
|
const getEndChatEventName = async (facadeChatSDK, props) => {
|
|
364
|
-
var _facadeChatSDK$getCha2, _facadeChatSDK$getCha3, _facadeChatSDK$getCha4, _facadeChatSDK$getCha5, _props$
|
|
365
|
-
return getWidgetEndChatEventName((_facadeChatSDK$getCha2 = facadeChatSDK.getChatSDK()) === null || _facadeChatSDK$getCha2 === void 0 ? void 0 : (_facadeChatSDK$getCha3 = _facadeChatSDK$getCha2.omnichannelConfig) === null || _facadeChatSDK$getCha3 === void 0 ? void 0 : _facadeChatSDK$getCha3.orgId, (_facadeChatSDK$getCha4 = facadeChatSDK.getChatSDK()) === null || _facadeChatSDK$getCha4 === void 0 ? void 0 : (_facadeChatSDK$getCha5 = _facadeChatSDK$getCha4.omnichannelConfig) === null || _facadeChatSDK$getCha5 === void 0 ? void 0 : _facadeChatSDK$getCha5.widgetId, (props === null || props === void 0 ? void 0 : (_props$
|
|
350
|
+
var _facadeChatSDK$getCha2, _facadeChatSDK$getCha3, _facadeChatSDK$getCha4, _facadeChatSDK$getCha5, _props$controlProps2;
|
|
351
|
+
return getWidgetEndChatEventName((_facadeChatSDK$getCha2 = facadeChatSDK.getChatSDK()) === null || _facadeChatSDK$getCha2 === void 0 ? void 0 : (_facadeChatSDK$getCha3 = _facadeChatSDK$getCha2.omnichannelConfig) === null || _facadeChatSDK$getCha3 === void 0 ? void 0 : _facadeChatSDK$getCha3.orgId, (_facadeChatSDK$getCha4 = facadeChatSDK.getChatSDK()) === null || _facadeChatSDK$getCha4 === void 0 ? void 0 : (_facadeChatSDK$getCha5 = _facadeChatSDK$getCha4.omnichannelConfig) === null || _facadeChatSDK$getCha5 === void 0 ? void 0 : _facadeChatSDK$getCha5.widgetId, (props === null || props === void 0 ? void 0 : (_props$controlProps2 = props.controlProps) === null || _props$controlProps2 === void 0 ? void 0 : _props$controlProps2.widgetInstanceId) ?? "");
|
|
366
352
|
};
|
|
367
353
|
export { prepareEndChat, endChat };
|
|
@@ -409,7 +409,7 @@ export const LiveChatWidgetStateful = props => {
|
|
|
409
409
|
|
|
410
410
|
// Start chat from SDK Event
|
|
411
411
|
BroadcastService.getMessageByEventName(BroadcastEvent.StartChat).subscribe(msg => {
|
|
412
|
-
var _props$chatConfig5, _props$chatConfig5$Li, _props$chatConfig6, _props$chatConfig6$Li, _msg$payload5, _msg$payload6, _msg$payload7, _msg$payload9, _inMemoryState$appSta2, _inMemoryState$appSta3
|
|
412
|
+
var _props$chatConfig5, _props$chatConfig5$Li, _props$chatConfig6, _props$chatConfig6$Li, _msg$payload5, _msg$payload6, _msg$payload7, _msg$payload9, _inMemoryState$appSta2, _inMemoryState$appSta3;
|
|
413
413
|
// If chat is out of operating hours chat widget sets the conversation state to OutOfOffice.
|
|
414
414
|
if (typeof (props === null || props === void 0 ? void 0 : (_props$chatConfig5 = props.chatConfig) === null || _props$chatConfig5 === void 0 ? void 0 : (_props$chatConfig5$Li = _props$chatConfig5.LiveWSAndLiveChatEngJoin) === null || _props$chatConfig5$Li === void 0 ? void 0 : _props$chatConfig5$Li.OutOfOperatingHours) === "string" && (props === null || props === void 0 ? void 0 : (_props$chatConfig6 = props.chatConfig) === null || _props$chatConfig6 === void 0 ? void 0 : (_props$chatConfig6$Li = _props$chatConfig6.LiveWSAndLiveChatEngJoin) === null || _props$chatConfig6$Li === void 0 ? void 0 : _props$chatConfig6$Li.OutOfOperatingHours.toLowerCase()) === "true") {
|
|
415
415
|
(state === null || state === void 0 ? void 0 : state.appStates.isMinimized) && dispatch({
|
|
@@ -447,8 +447,14 @@ export const LiveChatWidgetStateful = props => {
|
|
|
447
447
|
});
|
|
448
448
|
inMemoryState.domainStates.customContext = msg === null || msg === void 0 ? void 0 : (_msg$payload9 = msg.payload) === null || _msg$payload9 === void 0 ? void 0 : _msg$payload9.customContext;
|
|
449
449
|
|
|
450
|
-
|
|
451
|
-
|
|
450
|
+
/*
|
|
451
|
+
* If the conversation is in closed state then we start a new chat,
|
|
452
|
+
* else if the conversation is in active state then we maximize the chat
|
|
453
|
+
* If the conversation is in inactive or postchat state then we maximize the chat.
|
|
454
|
+
*
|
|
455
|
+
* To start a new chat, it needs to be called via the close button or close chat via SDK.
|
|
456
|
+
**/
|
|
457
|
+
if (((_inMemoryState$appSta2 = inMemoryState.appStates) === null || _inMemoryState$appSta2 === void 0 ? void 0 : _inMemoryState$appSta2.conversationState) === ConversationState.Closed) {
|
|
452
458
|
BroadcastService.postMessage({
|
|
453
459
|
eventName: BroadcastEvent.ChatInitiated
|
|
454
460
|
});
|
|
@@ -457,7 +463,7 @@ export const LiveChatWidgetStateful = props => {
|
|
|
457
463
|
}
|
|
458
464
|
|
|
459
465
|
// If minimized, maximize the chat
|
|
460
|
-
if ((inMemoryState === null || inMemoryState === void 0 ? void 0 : (_inMemoryState$
|
|
466
|
+
if ((inMemoryState === null || inMemoryState === void 0 ? void 0 : (_inMemoryState$appSta3 = inMemoryState.appStates) === null || _inMemoryState$appSta3 === void 0 ? void 0 : _inMemoryState$appSta3.isMinimized) === true) {
|
|
461
467
|
var _inMemoryState$domain, _inMemoryState$domain2, _inMemoryState$domain3, _inMemoryState$domain4;
|
|
462
468
|
dispatch({
|
|
463
469
|
type: LiveChatWidgetActionType.SET_MINIMIZED,
|
|
@@ -585,12 +591,12 @@ export const LiveChatWidgetStateful = props => {
|
|
|
585
591
|
disablePolling: true
|
|
586
592
|
});
|
|
587
593
|
facadeChatSDK === null || facadeChatSDK === void 0 ? void 0 : facadeChatSDK.onAgentEndSession(event => {
|
|
588
|
-
var _inMemoryState$
|
|
594
|
+
var _inMemoryState$appSta4;
|
|
589
595
|
const inMemoryState = executeReducer(state, {
|
|
590
596
|
type: LiveChatWidgetActionType.GET_IN_MEMORY_STATE,
|
|
591
597
|
payload: null
|
|
592
598
|
});
|
|
593
|
-
if ("participantsRemoved" in event && (inMemoryState === null || inMemoryState === void 0 ? void 0 : (_inMemoryState$
|
|
599
|
+
if ("participantsRemoved" in event && (inMemoryState === null || inMemoryState === void 0 ? void 0 : (_inMemoryState$appSta4 = inMemoryState.appStates) === null || _inMemoryState$appSta4 === void 0 ? void 0 : _inMemoryState$appSta4.conversationState) === ConversationState.Active) {
|
|
594
600
|
setWebChatStyles(styles => {
|
|
595
601
|
return {
|
|
596
602
|
...styles,
|
|
@@ -733,13 +739,13 @@ export const LiveChatWidgetStateful = props => {
|
|
|
733
739
|
|
|
734
740
|
// Handle Chat disconnect cases
|
|
735
741
|
useEffect(() => {
|
|
736
|
-
var _inMemoryState$
|
|
742
|
+
var _inMemoryState$appSta5;
|
|
737
743
|
const inMemoryState = executeReducer(state, {
|
|
738
744
|
type: LiveChatWidgetActionType.GET_IN_MEMORY_STATE,
|
|
739
745
|
payload: null
|
|
740
746
|
});
|
|
741
747
|
handleChatDisconnect(props, inMemoryState, setWebChatStyles);
|
|
742
|
-
const chatDisconnectState = inMemoryState === null || inMemoryState === void 0 ? void 0 : (_inMemoryState$
|
|
748
|
+
const chatDisconnectState = inMemoryState === null || inMemoryState === void 0 ? void 0 : (_inMemoryState$appSta5 = inMemoryState.appStates) === null || _inMemoryState$appSta5 === void 0 ? void 0 : _inMemoryState$appSta5.chatDisconnectEventReceived;
|
|
743
749
|
if (chatDisconnectState && adapter) {
|
|
744
750
|
try {
|
|
745
751
|
adapter.end();
|
|
@@ -5,6 +5,7 @@ import { OutOfOfficeHoursPane } from "@microsoft/omnichannel-chat-components";
|
|
|
5
5
|
import { TelemetryHelper } from "../../common/telemetry/TelemetryHelper";
|
|
6
6
|
import { defaultGeneralStyleProps } from "./common/defaultStyleProps/defaultgeneralOOOHPaneStyleProps";
|
|
7
7
|
import useChatContextStore from "../../hooks/useChatContextStore";
|
|
8
|
+
import DOMPurify from "dompurify";
|
|
8
9
|
let uiTimer;
|
|
9
10
|
export const OutOfOfficeHoursPaneStateful = props => {
|
|
10
11
|
var _props$styleProps;
|
|
@@ -40,6 +41,9 @@ export const OutOfOfficeHoursPaneStateful = props => {
|
|
|
40
41
|
ElapsedTimeInMilliseconds: uiTimer.milliSecondsElapsed
|
|
41
42
|
});
|
|
42
43
|
}, []);
|
|
44
|
+
if (controlProps !== null && controlProps !== void 0 && controlProps.titleText) {
|
|
45
|
+
controlProps.titleText = DOMPurify.sanitize(controlProps.titleText);
|
|
46
|
+
}
|
|
43
47
|
return /*#__PURE__*/React.createElement(OutOfOfficeHoursPane, {
|
|
44
48
|
componentOverrides: props.componentOverrides,
|
|
45
49
|
controlProps: controlProps,
|
|
@@ -8,14 +8,16 @@ import { TelemetryHelper } from "../../common/telemetry/TelemetryHelper";
|
|
|
8
8
|
import { defaultGeneralPostChatSurveyPaneStyleProps } from "./common/defaultStyleProps/defaultgeneralPostChatSurveyPaneStyleProps";
|
|
9
9
|
import { findAllFocusableElement } from "../../common/utils";
|
|
10
10
|
import useChatContextStore from "../../hooks/useChatContextStore";
|
|
11
|
+
import isValidSurveyUrl from "./common/isValidSurveyUrl";
|
|
11
12
|
const generateSurveyInviteLink = function (surveyInviteLink, isEmbed, locale, compact) {
|
|
12
13
|
let showMultiLingual = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
const surveyLinkParams = new URLSearchParams({
|
|
15
|
+
embed: isEmbed.toString(),
|
|
16
|
+
compact: (compact ?? true).toString(),
|
|
17
|
+
lang: locale ?? "en-us",
|
|
18
|
+
showmultilingual: (showMultiLingual ?? false).toString()
|
|
19
|
+
});
|
|
20
|
+
return `${surveyInviteLink}&${surveyLinkParams.toString()}`;
|
|
19
21
|
};
|
|
20
22
|
export const PostChatSurveyPaneStateful = props => {
|
|
21
23
|
var _props$styleProps, _state$appStates, _props$controlProps;
|
|
@@ -45,6 +47,20 @@ export const PostChatSurveyPaneStateful = props => {
|
|
|
45
47
|
surveyURL: ((_props$controlProps = props.controlProps) === null || _props$controlProps === void 0 ? void 0 : _props$controlProps.surveyURL) ?? surveyInviteLink,
|
|
46
48
|
...props.controlProps
|
|
47
49
|
};
|
|
50
|
+
if (controlProps.surveyURL) {
|
|
51
|
+
if (!isValidSurveyUrl(controlProps.surveyURL)) {
|
|
52
|
+
TelemetryHelper.logLoadingEvent(LogLevel.ERROR, {
|
|
53
|
+
Event: TelemetryEvent.PostChatSurveyUrlValidationFailed,
|
|
54
|
+
Description: `${controlProps.surveyURL} is not a valid Survey URL`
|
|
55
|
+
});
|
|
56
|
+
controlProps.surveyURL = "";
|
|
57
|
+
} else {
|
|
58
|
+
TelemetryHelper.logLoadingEvent(LogLevel.INFO, {
|
|
59
|
+
Event: TelemetryEvent.PostChatSurveyUrlValidationCompleted,
|
|
60
|
+
Description: `${controlProps.surveyURL} is a valid Survey URL`
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
48
64
|
|
|
49
65
|
// Move focus to the first button
|
|
50
66
|
useEffect(() => {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { isNullOrEmptyString } from "../../../common/utils";
|
|
2
|
+
const validRootDomains = ["microsoft.com", "microsoft.us", "appsplatform.us", "powervirtualagents.cn"];
|
|
3
|
+
const isValidSurveyUrl = url => {
|
|
4
|
+
if (isNullOrEmptyString(url)) {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
try {
|
|
8
|
+
const objectUrl = new URL(url);
|
|
9
|
+
if (!objectUrl.origin || objectUrl.origin === "null") {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
const validDomain = validRootDomains.find(domain => objectUrl.origin.endsWith(domain));
|
|
13
|
+
if (validDomain) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
} catch (error) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
return false;
|
|
20
|
+
};
|
|
21
|
+
export default isValidSurveyUrl;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { ConversationState } from "./ConversationState";
|
|
2
|
-
import { defaultMiddlewareLocalizedTexts } from "../../components/webchatcontainerstateful/common/defaultProps/defaultMiddlewareLocalizedTexts";
|
|
3
|
-
import { getWidgetCacheIdfromProps, isNullOrUndefined } from "../../common/utils";
|
|
4
|
-
import { defaultClientDataStoreProvider } from "../../common/storage/default/defaultClientDataStoreProvider";
|
|
5
1
|
import { ConfirmationState, Constants, ConversationEndEntity, StorageType } from "../../common/Constants";
|
|
2
|
+
import { getWidgetCacheIdfromProps, isNullOrUndefined } from "../../common/utils";
|
|
3
|
+
import { ConversationState } from "./ConversationState";
|
|
6
4
|
import { StartChatFailureType } from "./StartChatFailureType";
|
|
5
|
+
import { defaultClientDataStoreProvider } from "../../common/storage/default/defaultClientDataStoreProvider";
|
|
6
|
+
import { defaultMiddlewareLocalizedTexts } from "../../components/webchatcontainerstateful/common/defaultProps/defaultMiddlewareLocalizedTexts";
|
|
7
7
|
export const getLiveChatWidgetContextInitialState = props => {
|
|
8
8
|
var _props$controlProps, _props$webChatContain;
|
|
9
9
|
const widgetCacheId = getWidgetCacheIdfromProps(props);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export let ScenarioType;
|
|
2
|
+
(function (ScenarioType) {
|
|
3
|
+
ScenarioType["UserSendMessageStrategy"] = "UserSendMessageStrategy";
|
|
4
|
+
ScenarioType["SystemMessageStrategy"] = "SystemMessageStrategy";
|
|
5
|
+
ScenarioType["ReceivedMessageStrategy"] = "ReceivedMessageStrategy";
|
|
6
|
+
})(ScenarioType || (ScenarioType = {}));
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
2
|
+
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
|
|
3
|
+
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
|
|
4
|
+
import { LogLevel, TelemetryEvent } from "../common/telemetry/TelemetryConstants";
|
|
5
|
+
import { TelemetryHelper } from "../common/telemetry/TelemetryHelper";
|
|
6
|
+
export class FirstResponseLatencyTracker {
|
|
7
|
+
constructor() {
|
|
8
|
+
_defineProperty(this, "isABotConversation", false);
|
|
9
|
+
_defineProperty(this, "isStarted", false);
|
|
10
|
+
_defineProperty(this, "isEnded", false);
|
|
11
|
+
_defineProperty(this, "startTrackingMessage", void 0);
|
|
12
|
+
_defineProperty(this, "stopTrackingMessage", void 0);
|
|
13
|
+
// this is a workaround to ensure in reload we track effectively the messages
|
|
14
|
+
// we do have a mechanism in place to prevent log agent messages.
|
|
15
|
+
this.isABotConversation = true;
|
|
16
|
+
}
|
|
17
|
+
createTrackingMessage(payload, type) {
|
|
18
|
+
return {
|
|
19
|
+
Id: payload.Id,
|
|
20
|
+
role: payload.role,
|
|
21
|
+
timestamp: payload === null || payload === void 0 ? void 0 : payload.timestamp,
|
|
22
|
+
tags: payload.tags,
|
|
23
|
+
messageType: payload.messageType,
|
|
24
|
+
text: payload.text,
|
|
25
|
+
type: type,
|
|
26
|
+
checkTime: new Date().getTime()
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Tracking Functions
|
|
31
|
+
startTracking(payload) {
|
|
32
|
+
// this prevents to initiate tracking for multiple incoming messages
|
|
33
|
+
if (this.isStarted) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
// this is to ensure we track only messages where bot is engaged
|
|
37
|
+
if (!this.isABotConversation) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// control of states to prevent clashing of messages
|
|
42
|
+
this.isStarted = true;
|
|
43
|
+
this.isEnded = false;
|
|
44
|
+
|
|
45
|
+
// The idea of using types is to enrich telemetry data
|
|
46
|
+
this.startTrackingMessage = this.createTrackingMessage(payload, "userMessage");
|
|
47
|
+
}
|
|
48
|
+
handleAgentMessage(payload) {
|
|
49
|
+
var _payload$tags;
|
|
50
|
+
// this tag so far is only present in agent messages
|
|
51
|
+
if (payload !== null && payload !== void 0 && (_payload$tags = payload.tags) !== null && _payload$tags !== void 0 && _payload$tags.includes("public")) {
|
|
52
|
+
this.deregister();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
stopTracking(payload) {
|
|
56
|
+
var _this$stopTrackingMes, _this$startTrackingMe;
|
|
57
|
+
// this prevents execution for multiple incoming messages from the bot.
|
|
58
|
+
if (this.isEnded && !this.isStarted) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// control of states to prevent clashing of messages
|
|
63
|
+
this.isEnded = true;
|
|
64
|
+
this.isStarted = false;
|
|
65
|
+
|
|
66
|
+
// The idea of using types is to enrich telemetry data
|
|
67
|
+
this.stopTrackingMessage = this.createTrackingMessage(payload, "botMessage");
|
|
68
|
+
// calculating elapsed time
|
|
69
|
+
const elapsedTime = (((_this$stopTrackingMes = this.stopTrackingMessage) === null || _this$stopTrackingMes === void 0 ? void 0 : _this$stopTrackingMes.checkTime) ?? 0) - (((_this$startTrackingMe = this.startTrackingMessage) === null || _this$startTrackingMe === void 0 ? void 0 : _this$startTrackingMe.checkTime) ?? 0);
|
|
70
|
+
TelemetryHelper.logActionEvent(LogLevel.INFO, {
|
|
71
|
+
Event: TelemetryEvent.MessageLapTrack,
|
|
72
|
+
Description: "First response latency tracking",
|
|
73
|
+
CustomProperties: {
|
|
74
|
+
elapsedTime,
|
|
75
|
+
userMessage: this.startTrackingMessage,
|
|
76
|
+
botMessage: this.stopTrackingMessage
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// mechanism to ensure we track only allowed conversations
|
|
82
|
+
isMessageFromValidSender(payload) {
|
|
83
|
+
var _payload$tags2;
|
|
84
|
+
// agent scenario
|
|
85
|
+
if (payload !== null && payload !== void 0 && (_payload$tags2 = payload.tags) !== null && _payload$tags2 !== void 0 && _payload$tags2.includes("public")) {
|
|
86
|
+
this.handleAgentMessage(payload);
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
startClock(payload) {
|
|
92
|
+
try {
|
|
93
|
+
if (!payload || !payload.Id) {
|
|
94
|
+
throw new Error("Invalid payload");
|
|
95
|
+
}
|
|
96
|
+
// in the case of a reload, tracker will be paused, until last history message is received
|
|
97
|
+
// this is because we dont have a way to identidy send messages as part of the history
|
|
98
|
+
//if (this.inPause) return;
|
|
99
|
+
this.startTracking(payload);
|
|
100
|
+
} catch (e) {
|
|
101
|
+
TelemetryHelper.logActionEvent(LogLevel.ERROR, {
|
|
102
|
+
Event: TelemetryEvent.MessageStartLapTrackError,
|
|
103
|
+
Description: "Error while starting the clock",
|
|
104
|
+
ExceptionDetails: e,
|
|
105
|
+
CustomProperties: {
|
|
106
|
+
payload: payload
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
stopClock(payload) {
|
|
112
|
+
try {
|
|
113
|
+
if (!payload || !payload.Id) {
|
|
114
|
+
throw new Error("Invalid payload");
|
|
115
|
+
}
|
|
116
|
+
if (!this.isMessageFromValidSender(payload)) return;
|
|
117
|
+
if (this.isABotConversation && this.isStarted) {
|
|
118
|
+
this.stopTracking(payload);
|
|
119
|
+
}
|
|
120
|
+
} catch (e) {
|
|
121
|
+
console.error("FRL : error while trying to stop the tracker", e);
|
|
122
|
+
TelemetryHelper.logActionEvent(LogLevel.ERROR, {
|
|
123
|
+
Event: TelemetryEvent.MessageStopLapTrackError,
|
|
124
|
+
Description: "Error while stopping the clock",
|
|
125
|
+
ExceptionDetails: e,
|
|
126
|
+
CustomProperties: {
|
|
127
|
+
payload: payload
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
//reset state
|
|
131
|
+
this.startTrackingMessage = undefined;
|
|
132
|
+
this.stopTrackingMessage = undefined;
|
|
133
|
+
this.isStarted = false;
|
|
134
|
+
this.isEnded = false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
deregister() {
|
|
138
|
+
// Reset State
|
|
139
|
+
this.isABotConversation = false;
|
|
140
|
+
this.isStarted = false;
|
|
141
|
+
this.isEnded = false;
|
|
142
|
+
this.startTrackingMessage = undefined;
|
|
143
|
+
this.stopTrackingMessage = undefined;
|
|
144
|
+
}
|
|
145
|
+
}
|