@microsoft/omnichannel-chat-widget 0.1.0-main.ae27766 → 0.1.0-main.bcfe8a3

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 (75) hide show
  1. package/README.md +32 -0
  2. package/lib/cjs/common/Constants.js +14 -2
  3. package/lib/cjs/common/telemetry/TelemetryConstants.js +20 -3
  4. package/lib/cjs/common/telemetry/TelemetryManager.js +7 -1
  5. package/lib/cjs/common/telemetry/loggers/ariaTelemetryLogger.js +17 -16
  6. package/lib/cjs/common/telemetry/loggers/consoleLogger.js +6 -5
  7. package/lib/cjs/common/utils.js +17 -2
  8. package/lib/cjs/components/callingcontainerstateful/CallingContainerStateful.js +14 -0
  9. package/lib/cjs/components/chatbuttonstateful/ChatButtonStateful.js +16 -4
  10. package/lib/cjs/components/footerstateful/downloadtranscriptstateful/DownloadTranscriptStateful.js +11 -2
  11. package/lib/cjs/components/livechatwidget/common/defaultProps/dummyDefaultProps.js +7 -13
  12. package/lib/cjs/components/livechatwidget/common/endChat.js +28 -13
  13. package/lib/cjs/components/livechatwidget/common/initWebChatComposer.js +12 -3
  14. package/lib/cjs/components/livechatwidget/common/startChat.js +49 -10
  15. package/lib/cjs/components/livechatwidget/livechatwidgetstateful/LiveChatWidgetStateful.js +150 -31
  16. package/lib/cjs/components/prechatsurveypanestateful/PreChatSurveyPaneStateful.js +4 -5
  17. package/lib/cjs/components/proactivechatpanestateful/ProactiveChatPaneStateful.js +16 -0
  18. package/lib/cjs/components/webchatcontainerstateful/WebChatContainerStateful.js +80 -0
  19. package/lib/cjs/components/webchatcontainerstateful/interfaces/IBotMagicCodeConfig.js +1 -0
  20. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/BotMagicCodeStore.js +14 -0
  21. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activityMiddleware.js +16 -2
  22. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/cardActionMiddleware.js +52 -0
  23. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/cardActionMiddleware.spec.js +98 -0
  24. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/messageTimestampMiddleware.js +117 -0
  25. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/webchattelemetry/WebChatLogger.js +1 -0
  26. package/lib/cjs/contexts/common/LiveChatWidgetActionType.js +24 -21
  27. package/lib/cjs/contexts/common/LiveChatWidgetContextInitialState.js +3 -1
  28. package/lib/cjs/contexts/createReducer.js +16 -0
  29. package/lib/cjs/controller/componentController.js +1 -1
  30. package/lib/cjs/plugins/newMessageEventHandler.js +10 -13
  31. package/lib/esm/common/Constants.js +14 -2
  32. package/lib/esm/common/telemetry/TelemetryConstants.js +20 -3
  33. package/lib/esm/common/telemetry/TelemetryManager.js +6 -1
  34. package/lib/esm/common/telemetry/loggers/ariaTelemetryLogger.js +18 -13
  35. package/lib/esm/common/telemetry/loggers/consoleLogger.js +6 -5
  36. package/lib/esm/common/utils.js +8 -0
  37. package/lib/esm/components/callingcontainerstateful/CallingContainerStateful.js +14 -0
  38. package/lib/esm/components/chatbuttonstateful/ChatButtonStateful.js +18 -7
  39. package/lib/esm/components/footerstateful/downloadtranscriptstateful/DownloadTranscriptStateful.js +9 -3
  40. package/lib/esm/components/livechatwidget/common/defaultProps/dummyDefaultProps.js +7 -13
  41. package/lib/esm/components/livechatwidget/common/endChat.js +26 -14
  42. package/lib/esm/components/livechatwidget/common/initWebChatComposer.js +11 -4
  43. package/lib/esm/components/livechatwidget/common/startChat.js +51 -14
  44. package/lib/esm/components/livechatwidget/livechatwidgetstateful/LiveChatWidgetStateful.js +139 -31
  45. package/lib/esm/components/prechatsurveypanestateful/PreChatSurveyPaneStateful.js +6 -7
  46. package/lib/esm/components/proactivechatpanestateful/ProactiveChatPaneStateful.js +16 -0
  47. package/lib/esm/components/webchatcontainerstateful/WebChatContainerStateful.js +72 -0
  48. package/lib/esm/components/webchatcontainerstateful/interfaces/IBotMagicCodeConfig.js +1 -0
  49. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/BotMagicCodeStore.js +5 -0
  50. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activityMiddleware.js +16 -2
  51. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/cardActionMiddleware.js +41 -0
  52. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/cardActionMiddleware.spec.js +94 -0
  53. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/messageTimestampMiddleware.js +107 -0
  54. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/webchattelemetry/WebChatLogger.js +1 -0
  55. package/lib/esm/contexts/common/LiveChatWidgetActionType.js +24 -21
  56. package/lib/esm/contexts/common/LiveChatWidgetContextInitialState.js +3 -1
  57. package/lib/esm/contexts/createReducer.js +16 -0
  58. package/lib/esm/controller/componentController.js +1 -1
  59. package/lib/esm/plugins/newMessageEventHandler.js +10 -12
  60. package/lib/types/common/Constants.d.ts +7 -1
  61. package/lib/types/common/interfaces/IContextDataStore.d.ts +1 -1
  62. package/lib/types/common/telemetry/TelemetryConstants.d.ts +20 -5
  63. package/lib/types/common/telemetry/TelemetryHelper.d.ts +1 -0
  64. package/lib/types/common/telemetry/definitions/Payload.d.ts +12 -9
  65. package/lib/types/common/utils.d.ts +2 -0
  66. package/lib/types/components/livechatwidget/common/endChat.d.ts +1 -1
  67. package/lib/types/components/webchatcontainerstateful/interfaces/IBotMagicCodeConfig.d.ts +4 -0
  68. package/lib/types/components/webchatcontainerstateful/interfaces/IWebChatContainerStatefulProps.d.ts +2 -0
  69. package/lib/types/components/webchatcontainerstateful/webchatcontroller/BotMagicCodeStore.d.ts +3 -0
  70. package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/cardActionMiddleware.d.ts +2 -0
  71. package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/cardActionMiddleware.spec.d.ts +1 -0
  72. package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/messageTimestampMiddleware.d.ts +5 -0
  73. package/lib/types/contexts/common/ILiveChatWidgetContext.d.ts +2 -0
  74. package/lib/types/contexts/common/LiveChatWidgetActionType.d.ts +24 -21
  75. package/package.json +2 -2
@@ -4,7 +4,7 @@ import { BroadcastEvent, LogLevel, TelemetryEvent } from "../../../common/teleme
4
4
  import { BroadcastService, decodeComponentString } from "@microsoft/omnichannel-chat-components";
5
5
  import { Stack } from "@fluentui/react";
6
6
  import React, { useEffect, useRef, useState } from "react";
7
- import { createTimer, getLocaleDirection } from "../../../common/utils";
7
+ import { createTimer, getLocaleDirection, getWidgetCacheId, getWidgetEndChatEventName } from "../../../common/utils";
8
8
  import { getReconnectIdForAuthenticatedChat, handleUnauthenticatedReconnectChat, startUnauthenticatedReconnectChat } from "../common/reconnectChatHelper";
9
9
  import { initStartChat, prepareStartChat } from "../common/startChat";
10
10
  import { shouldShowCallingContainer, shouldShowChatButton, shouldShowConfirmationPane, shouldShowEmailTranscriptPane, shouldShowHeader, shouldShowLoadingPane, shouldShowOutOfOfficeHoursPane, shouldShowPostChatLoadingPane, shouldShowPostChatSurveyPane, shouldShowPreChatSurveyPane, shouldShowProactiveChatPane, shouldShowReconnectChatPane, shouldShowWebChatContainer } from "../../../controller/componentController";
@@ -53,7 +53,8 @@ export const LiveChatWidgetStateful = props => {
53
53
  ...((_props$webChatContain = props.webChatContainerProps) === null || _props$webChatContain === void 0 ? void 0 : _props$webChatContain.webChatStyles)
54
54
  }); // eslint-disable-next-line @typescript-eslint/no-explicit-any
55
55
 
56
- const chatSDK = useChatSDKStore();
56
+ const chatSDK = useChatSDKStore(); // eslint-disable-next-line @typescript-eslint/no-explicit-any
57
+
57
58
  const [voiceVideoCallingSDK, setVoiceVideoCallingSDK] = useState(undefined);
58
59
  const {
59
60
  Composer
@@ -67,6 +68,33 @@ export const LiveChatWidgetStateful = props => {
67
68
  TelemetryTimers.LcwLoadToChatButtonTimer = createTimer();
68
69
  const widgetElementId = ((_props$controlProps = props.controlProps) === null || _props$controlProps === void 0 ? void 0 : _props$controlProps.id) || "oc-lcw";
69
70
  const currentMessageCountRef = useRef(0);
71
+ let widgetStateEventName = "";
72
+
73
+ const initiateEndChatOnBrowserUnload = () => {
74
+ var _DataStoreManager$cli;
75
+
76
+ const persistedState = getStateFromCache(); // End chat if the chat is still active and browser closed
77
+
78
+ if (persistedState.appStates.conversationState === ConversationState.Active) {
79
+ //Browser close scenario/no room for PCS/so just end chat and notify agent immidiately
80
+ endChat(props, chatSDK, setAdapter, setWebChatStyles, dispatch, adapter, false, false, false);
81
+ } // Clean local storage
82
+
83
+
84
+ (_DataStoreManager$cli = DataStoreManager.clientDataStore) === null || _DataStoreManager$cli === void 0 ? void 0 : _DataStoreManager$cli.removeData(widgetStateEventName, "localStorage");
85
+ }; // eslint-disable-next-line @typescript-eslint/no-explicit-any
86
+
87
+
88
+ const getStateFromCache = () => {
89
+ var _chatSDK$omnichannelC, _chatSDK$omnichannelC2, _DataStoreManager$cli2;
90
+
91
+ // Getting updated state from cache
92
+ const widgetStateEventName = getWidgetCacheId((chatSDK === null || chatSDK === void 0 ? void 0 : (_chatSDK$omnichannelC = chatSDK.omnichannelConfig) === null || _chatSDK$omnichannelC === void 0 ? void 0 : _chatSDK$omnichannelC.orgId) ?? "", (chatSDK === null || chatSDK === void 0 ? void 0 : (_chatSDK$omnichannelC2 = chatSDK.omnichannelConfig) === null || _chatSDK$omnichannelC2 === void 0 ? void 0 : _chatSDK$omnichannelC2.widgetId) ?? "");
93
+ const widgetStateFromCache = (_DataStoreManager$cli2 = DataStoreManager.clientDataStore) === null || _DataStoreManager$cli2 === void 0 ? void 0 : _DataStoreManager$cli2.getData(widgetStateEventName, "localStorage");
94
+ const persistedState = widgetStateFromCache ? JSON.parse(widgetStateFromCache) : undefined;
95
+ return persistedState;
96
+ };
97
+
70
98
  useEffect(() => {
71
99
  var _props$controlProps2, _props$controlProps3, _props$reconnectChatP, _props$controlProps4, _props$chatConfig, _props$chatConfig$Cha, _state$domainStates;
72
100
 
@@ -81,6 +109,10 @@ export const LiveChatWidgetStateful = props => {
81
109
  type: LiveChatWidgetActionType.SET_SKIP_CHAT_BUTTON_RENDERING,
82
110
  payload: ((_props$controlProps2 = props.controlProps) === null || _props$controlProps2 === void 0 ? void 0 : _props$controlProps2.skipChatButtonRendering) || false
83
111
  });
112
+ dispatch({
113
+ type: LiveChatWidgetActionType.SET_E2VV_ENABLED,
114
+ payload: false
115
+ });
84
116
  initCallingSdk(chatSDK, setVoiceVideoCallingSDK).then(sdkCreated => {
85
117
  sdkCreated && dispatch({
86
118
  type: LiveChatWidgetActionType.SET_E2VV_ENABLED,
@@ -109,11 +141,16 @@ export const LiveChatWidgetStateful = props => {
109
141
  };
110
142
  initStartChat(chatSDK, dispatch, setAdapter, optionalParams);
111
143
  }
112
- }, []);
144
+ }, []); // useEffect for when skip chat button rendering
145
+
113
146
  useEffect(() => {
114
147
  if (state.appStates.skipChatButtonRendering) {
115
148
  var _props$reconnectChatP3;
116
149
 
150
+ BroadcastService.postMessage({
151
+ eventName: BroadcastEvent.ChatInitiated
152
+ });
153
+
117
154
  if ((_props$reconnectChatP3 = props.reconnectChatPaneProps) !== null && _props$reconnectChatP3 !== void 0 && _props$reconnectChatP3.reconnectId && !state.appStates.reconnectId) {
118
155
  var _props$reconnectChatP4, _props$reconnectChatP5;
119
156
 
@@ -143,9 +180,23 @@ export const LiveChatWidgetStateful = props => {
143
180
  });
144
181
  }
145
182
  }
146
- }, [state.appStates.skipChatButtonRendering]);
183
+ }, [state.appStates.skipChatButtonRendering]); // useEffect for when skip chat button rendering
184
+
147
185
  useEffect(() => {
148
- BroadcastService.getMessageByEventName("StartProactiveChat").subscribe(msg => {
186
+ var _chatSDK$omnichannelC3, _chatSDK$omnichannelC4;
187
+
188
+ // Add the custom context on receiving the SetCustomContext event
189
+ BroadcastService.getMessageByEventName(BroadcastEvent.SetCustomContext).subscribe(msg => {
190
+ TelemetryHelper.logActionEvent(LogLevel.INFO, {
191
+ Event: TelemetryEvent.CustomContextReceived,
192
+ Description: "CustomContext received."
193
+ });
194
+ dispatch({
195
+ type: LiveChatWidgetActionType.SET_CUSTOM_CONTEXT,
196
+ payload: msg === null || msg === void 0 ? void 0 : msg.payload
197
+ });
198
+ });
199
+ BroadcastService.getMessageByEventName(BroadcastEvent.StartProactiveChat).subscribe(msg => {
149
200
  TelemetryHelper.logActionEvent(LogLevel.INFO, {
150
201
  Event: TelemetryEvent.StartProactiveChatEventReceived,
151
202
  Description: "Start proactive chat event received."
@@ -161,30 +212,46 @@ export const LiveChatWidgetStateful = props => {
161
212
  Description: "Start proactive chat method called, when chat was already triggered."
162
213
  });
163
214
  }
164
- }); // start chat from SDK Event
215
+ }); // Start chat from SDK Event
165
216
 
166
- BroadcastService.getMessageByEventName("StartChat").subscribe(() => {
217
+ BroadcastService.getMessageByEventName(BroadcastEvent.StartChat).subscribe(() => {
167
218
  TelemetryHelper.logActionEvent(LogLevel.INFO, {
168
219
  Event: TelemetryEvent.StartChatEventRecevied,
169
220
  Description: "Start chat event received."
170
221
  });
222
+ const persistedState = getStateFromCache();
171
223
 
172
- if (state.appStates.isMinimized) {
224
+ if (persistedState && (persistedState.appStates.conversationState === ConversationState.Closed || persistedState.appStates.conversationState === ConversationState.InActive || persistedState.appStates.conversationState === ConversationState.Postchat)) {
225
+ // Embedded mode
226
+ BroadcastService.postMessage({
227
+ eventName: BroadcastEvent.ChatInitiated
228
+ });
229
+ prepareStartChat(props, chatSDK, state, dispatch, setAdapter);
230
+ } else if (!persistedState) {
231
+ // Popout chat
232
+ BroadcastService.postMessage({
233
+ eventName: BroadcastEvent.ChatInitiated
234
+ });
235
+ prepareStartChat(props, chatSDK, state, dispatch, setAdapter);
236
+ } else {
237
+ var _persistedState$domai, _persistedState$domai2, _persistedState$domai3, _persistedState$domai4;
238
+
239
+ // Minimize to Maximize
173
240
  dispatch({
174
241
  type: LiveChatWidgetActionType.SET_MINIMIZED,
175
242
  payload: false
176
243
  });
177
- } else {
178
- prepareStartChat(props, chatSDK, state, dispatch, setAdapter);
244
+ BroadcastService.postMessage({
245
+ eventName: BroadcastEvent.MaximizeChat,
246
+ payload: {
247
+ height: persistedState === null || persistedState === void 0 ? void 0 : (_persistedState$domai = persistedState.domainStates) === null || _persistedState$domai === void 0 ? void 0 : (_persistedState$domai2 = _persistedState$domai.widgetSize) === null || _persistedState$domai2 === void 0 ? void 0 : _persistedState$domai2.height,
248
+ width: persistedState === null || persistedState === void 0 ? void 0 : (_persistedState$domai3 = persistedState.domainStates) === null || _persistedState$domai3 === void 0 ? void 0 : (_persistedState$domai4 = _persistedState$domai3.widgetSize) === null || _persistedState$domai4 === void 0 ? void 0 : _persistedState$domai4.width
249
+ }
250
+ });
179
251
  }
180
- }); // end chat from SDK Event
181
-
182
- BroadcastService.getMessageByEventName("EndChat").subscribe(async () => {
183
- TelemetryHelper.logActionEvent(LogLevel.INFO, {
184
- Event: TelemetryEvent.EndChatEventReceived,
185
- Description: "End chat event received."
186
- });
252
+ }); // End chat
187
253
 
254
+ BroadcastService.getMessageByEventName(BroadcastEvent.InitiateEndChat).subscribe(async () => {
188
255
  if (canEndChat.current) {
189
256
  prepareEndChat(props, chatSDK, setAdapter, setWebChatStyles, dispatch, adapter, state);
190
257
  } else {
@@ -192,17 +259,52 @@ export const LiveChatWidgetStateful = props => {
192
259
  const skipCloseChat = false;
193
260
  endChat(props, chatSDK, setAdapter, setWebChatStyles, dispatch, adapter, skipEndChatSDK, skipCloseChat);
194
261
  }
262
+
263
+ BroadcastService.postMessage({
264
+ eventName: BroadcastEvent.CloseChat
265
+ });
195
266
  });
267
+ BroadcastService.getMessageByEventName(BroadcastEvent.InitiateEndChatOnBrowserUnload).subscribe(() => {
268
+ initiateEndChatOnBrowserUnload();
269
+ }); // reset proactive chat params
270
+
271
+ BroadcastService.getMessageByEventName(BroadcastEvent.ResetProactiveChatParams).subscribe(async () => {
272
+ dispatch({
273
+ type: LiveChatWidgetActionType.SET_PROACTIVE_CHAT_PARAMS,
274
+ payload: {
275
+ proactiveChatBodyTitle: "",
276
+ proactiveChatEnablePrechat: false,
277
+ proactiveChatInNewWindow: false
278
+ }
279
+ });
280
+ }); // Listen to end chat event from other tabs
281
+
282
+ const endChatEventName = getWidgetEndChatEventName(chatSDK === null || chatSDK === void 0 ? void 0 : (_chatSDK$omnichannelC3 = chatSDK.omnichannelConfig) === null || _chatSDK$omnichannelC3 === void 0 ? void 0 : _chatSDK$omnichannelC3.orgId, chatSDK === null || chatSDK === void 0 ? void 0 : (_chatSDK$omnichannelC4 = chatSDK.omnichannelConfig) === null || _chatSDK$omnichannelC4 === void 0 ? void 0 : _chatSDK$omnichannelC4.widgetId);
283
+ BroadcastService.getMessageByEventName(endChatEventName).subscribe(async () => {
284
+ endChat(props, chatSDK, setAdapter, setWebChatStyles, dispatch, adapter, false, false, false);
285
+ }); // Close popout window
286
+
196
287
  window.addEventListener("beforeunload", () => {
288
+ TelemetryHelper.logLoadingEvent(LogLevel.INFO, {
289
+ Event: TelemetryEvent.WindowClosed,
290
+ Description: "Closed window."
291
+ });
197
292
  disposeTelemetryLoggers();
198
293
  });
199
294
 
200
295
  if (state.appStates.conversationEndedByAgent) {
201
296
  endChat(props, chatSDK, setAdapter, setWebChatStyles, dispatch, adapter);
202
- }
297
+ } //Listen to WidgetSize
298
+
299
+
300
+ BroadcastService.getMessageByEventName("WidgetSize").subscribe(msg => {
301
+ dispatch({
302
+ type: LiveChatWidgetActionType.SET_WIDGET_SIZE,
303
+ payload: msg === null || msg === void 0 ? void 0 : msg.payload
304
+ });
305
+ });
203
306
  }, []);
204
307
  useEffect(() => {
205
- canStartProactiveChat.current = state.appStates.conversationState === ConversationState.Closed;
206
308
  canEndChat.current = state.appStates.conversationState === ConversationState.Active;
207
309
 
208
310
  if (state.appStates.conversationState === ConversationState.Active) {
@@ -223,7 +325,10 @@ export const LiveChatWidgetStateful = props => {
223
325
  });
224
326
  });
225
327
  }
226
- }, [state.appStates.conversationState]); // Reset the UnreadMessageCount when minimized is toggled and broadcast it.
328
+ }, [state.appStates.conversationState]);
329
+ useEffect(() => {
330
+ canStartProactiveChat.current = state.appStates.conversationState === ConversationState.Closed && !state.appStates.proactiveChatStates.proactiveChatInNewWindow;
331
+ }, [state.appStates.conversationState, state.appStates.proactiveChatStates.proactiveChatInNewWindow]); // Reset the UnreadMessageCount when minimized is toggled and broadcast it.
227
332
 
228
333
  useEffect(() => {
229
334
  currentMessageCountRef.current = -1;
@@ -255,7 +360,19 @@ export const LiveChatWidgetStateful = props => {
255
360
  setWebChatStyles({ ...webChatStyles,
256
361
  ...((_props$webChatContain2 = props.webChatContainerProps) === null || _props$webChatContain2 === void 0 ? void 0 : _props$webChatContain2.webChatStyles)
257
362
  });
258
- }, [(_props$webChatContain3 = props.webChatContainerProps) === null || _props$webChatContain3 === void 0 ? void 0 : _props$webChatContain3.webChatStyles]);
363
+ }, [(_props$webChatContain3 = props.webChatContainerProps) === null || _props$webChatContain3 === void 0 ? void 0 : _props$webChatContain3.webChatStyles]); // Publish chat widget state
364
+
365
+ useEffect(() => {
366
+ var _props$chatSDK, _props$chatSDK$omnich, _props$chatSDK2, _props$chatSDK2$omnic;
367
+
368
+ widgetStateEventName = getWidgetCacheId(props === null || props === void 0 ? void 0 : (_props$chatSDK = props.chatSDK) === null || _props$chatSDK === void 0 ? void 0 : (_props$chatSDK$omnich = _props$chatSDK.omnichannelConfig) === null || _props$chatSDK$omnich === void 0 ? void 0 : _props$chatSDK$omnich.orgId, props === null || props === void 0 ? void 0 : (_props$chatSDK2 = props.chatSDK) === null || _props$chatSDK2 === void 0 ? void 0 : (_props$chatSDK2$omnic = _props$chatSDK2.omnichannelConfig) === null || _props$chatSDK2$omnic === void 0 ? void 0 : _props$chatSDK2$omnic.widgetId);
369
+ const chatWidgetStateChangeEvent = {
370
+ eventName: widgetStateEventName,
371
+ payload: { ...state
372
+ }
373
+ };
374
+ BroadcastService.postMessage(chatWidgetStateChangeEvent);
375
+ }, [state]);
259
376
  const webChatProps = initWebChatComposer(props, chatSDK, state, dispatch, setWebChatStyles);
260
377
 
261
378
  const setPostChatContextRelay = () => setPostChatContextAndLoadSurvey(chatSDK, dispatch); // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -271,16 +388,7 @@ export const LiveChatWidgetStateful = props => {
271
388
 
272
389
  const initStartChatRelay = (optionalParams, persistedState) => initStartChat(chatSDK, dispatch, setAdapter, optionalParams, persistedState);
273
390
 
274
- const confirmationPaneProps = initConfirmationPropsComposer(props); // publish chat widget state
275
-
276
- useEffect(() => {
277
- const chatWidgetStateChangeEvent = {
278
- eventName: BroadcastEvent.ChatWidgetStateChanged,
279
- payload: { ...state
280
- }
281
- };
282
- BroadcastService.postMessage(chatWidgetStateChangeEvent);
283
- }, [state]);
391
+ const confirmationPaneProps = initConfirmationPropsComposer(props);
284
392
  return /*#__PURE__*/React.createElement(Composer, _extends({}, webChatProps, {
285
393
  styleOptions: webChatStyles,
286
394
  directLine: ((_props$webChatContain4 = props.webChatContainerProps) === null || _props$webChatContain4 === void 0 ? void 0 : _props$webChatContain4.directLine) ?? adapter ?? defaultWebChatContainerStatefulProps.directLine
@@ -1,7 +1,7 @@
1
- import { Constants, HtmlAttributeNames, Regex } from "../../common/Constants";
1
+ import { HtmlAttributeNames, Regex } from "../../common/Constants";
2
2
  import { LogLevel, TelemetryEvent } from "../../common/telemetry/TelemetryConstants";
3
3
  import React, { useEffect } from "react";
4
- import { extractPreChatSurveyResponseValues, findAllFocusableElement, parseAdaptiveCardPayload } from "../../common/utils";
4
+ import { extractPreChatSurveyResponseValues, findAllFocusableElement, getWidgetCacheId, parseAdaptiveCardPayload } from "../../common/utils";
5
5
  import { ConversationState } from "../../contexts/common/ConversationState";
6
6
  import { DataStoreManager } from "../../common/contextDataStore/DataStoreManager";
7
7
  import { LiveChatWidgetActionType } from "../../contexts/common/LiveChatWidgetActionType";
@@ -67,9 +67,10 @@ export const PreChatSurveyPaneStateful = props => {
67
67
  });
68
68
 
69
69
  try {
70
- var _DataStoreManager$cli, _persistedState$domai;
70
+ var _state$domainStates, _state$domainStates$t, _state$domainStates$t2, _DataStoreManager$cli, _persistedState$domai;
71
71
 
72
- const widgetStateFromCache = (_DataStoreManager$cli = DataStoreManager.clientDataStore) === null || _DataStoreManager$cli === void 0 ? void 0 : _DataStoreManager$cli.getData(Constants.widgetStateDataKey, "localStorage");
72
+ const widgetStateCacheId = getWidgetCacheId(((_state$domainStates = state.domainStates) === null || _state$domainStates === void 0 ? void 0 : (_state$domainStates$t = _state$domainStates.telemetryInternalData) === null || _state$domainStates$t === void 0 ? void 0 : _state$domainStates$t.orgId) ?? "", ((_state$domainStates$t2 = state.domainStates.telemetryInternalData) === null || _state$domainStates$t2 === void 0 ? void 0 : _state$domainStates$t2.widgetId) ?? "");
73
+ const widgetStateFromCache = (_DataStoreManager$cli = DataStoreManager.clientDataStore) === null || _DataStoreManager$cli === void 0 ? void 0 : _DataStoreManager$cli.getData(widgetStateCacheId, "localStorage");
73
74
  const persistedState = widgetStateFromCache ? JSON.parse(widgetStateFromCache) : undefined;
74
75
  let optionalParams = {};
75
76
 
@@ -83,9 +84,7 @@ export const PreChatSurveyPaneStateful = props => {
83
84
  } else {
84
85
  const prechatResponseValues = extractPreChatSurveyResponseValues(state.domainStates.preChatSurveyResponse, values);
85
86
  optionalParams = {
86
- initContext: {
87
- preChatResponse: prechatResponseValues
88
- }
87
+ preChatResponse: prechatResponseValues
89
88
  };
90
89
  setPreChatResponseEmail(values);
91
90
  await initStartChat(optionalParams);
@@ -24,6 +24,14 @@ export const ProactiveChatPaneStateful = props => {
24
24
  const handleProactiveChatInviteTimeout = () => {
25
25
  if (!timeoutRemoved) {
26
26
  setTimeoutRemoved(true);
27
+ dispatch({
28
+ type: LiveChatWidgetActionType.SET_PROACTIVE_CHAT_PARAMS,
29
+ payload: {
30
+ proactiveChatBodyTitle: "",
31
+ proactiveChatEnablePrechat: false,
32
+ proactiveChatInNewWindow: false
33
+ }
34
+ });
27
35
  dispatch({
28
36
  type: LiveChatWidgetActionType.SET_CONVERSATION_STATE,
29
37
  payload: ConversationState.Closed
@@ -81,6 +89,14 @@ export const ProactiveChatPaneStateful = props => {
81
89
  Event: TelemetryEvent.ProactiveChatClosed,
82
90
  Description: "Proactive chat closed."
83
91
  });
92
+ dispatch({
93
+ type: LiveChatWidgetActionType.SET_PROACTIVE_CHAT_PARAMS,
94
+ payload: {
95
+ proactiveChatBodyTitle: "",
96
+ proactiveChatEnablePrechat: false,
97
+ proactiveChatInNewWindow: false
98
+ }
99
+ });
84
100
  dispatch({
85
101
  type: LiveChatWidgetActionType.SET_CONVERSATION_STATE,
86
102
  payload: ConversationState.Closed
@@ -8,11 +8,45 @@ import { defaultMiddlewareLocalizedTexts } from "./common/defaultProps/defaultMi
8
8
  import { defaultWebChatContainerStatefulProps } from "./common/defaultProps/defaultWebChatContainerStatefulProps";
9
9
  import { setFocusOnSendBox } from "../../common/utils";
10
10
  import { useChatContextStore } from "../..";
11
+ import { WebChatActionType } from "./webchatcontroller/enums/WebChatActionType";
12
+ import { WebChatStoreLoader } from "./webchatcontroller/WebChatStoreLoader";
13
+ import { Constants } from "../../common/Constants";
14
+ import { BotMagicCodeStore } from "./webchatcontroller/BotMagicCodeStore";
15
+ const broadcastChannelMessageEvent = "message";
16
+
17
+ const postActivity = activity => {
18
+ // eslint-disable-line @typescript-eslint/no-explicit-any
19
+ return {
20
+ type: WebChatActionType.DIRECT_LINE_POST_ACTIVITY,
21
+ meta: {
22
+ method: "keyboard"
23
+ },
24
+ payload: {
25
+ activity: {
26
+ channelData: undefined,
27
+ text: "",
28
+ textFormat: "plain",
29
+ type: Constants.message,
30
+ ...activity
31
+ }
32
+ }
33
+ };
34
+ };
35
+
36
+ const createMagicCodeSuccessResponse = signin => {
37
+ return {
38
+ signin,
39
+ result: "Success"
40
+ };
41
+ };
42
+
11
43
  export const WebChatContainerStateful = props => {
12
44
  const {
13
45
  BasicWebChat
14
46
  } = Components;
15
47
  const [state, dispatch] = useChatContextStore();
48
+ const magicCodeBroadcastChannel = new BroadcastChannel(Constants.magicCodeBroadcastChannel);
49
+ const magicCodeResponseBroadcastChannel = new BroadcastChannel(Constants.magicCodeResponseBroadcastChannel);
16
50
  const containerStyles = {
17
51
  root: Object.assign({}, defaultWebChatContainerStatefulProps.containerStyles, props === null || props === void 0 ? void 0 : props.containerStyles, {
18
52
  display: state.appStates.isMinimized ? "none" : ""
@@ -36,6 +70,44 @@ export const WebChatContainerStateful = props => {
36
70
  Event: TelemetryEvent.WebChatLoaded
37
71
  });
38
72
  }, []);
73
+ useEffect(() => {
74
+ const eventListener = event => {
75
+ // eslint-disable-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-empty-function
76
+ const {
77
+ data
78
+ } = event;
79
+
80
+ if (BotMagicCodeStore.botOAuthSignInId === data.signin) {
81
+ const {
82
+ signin,
83
+ code
84
+ } = data;
85
+ const text = `${code}`;
86
+ const action = postActivity({
87
+ text,
88
+ channelData: {
89
+ tags: [Constants.hiddenTag]
90
+ }
91
+ });
92
+ WebChatStoreLoader.store.dispatch(action);
93
+ const response = createMagicCodeSuccessResponse(signin);
94
+ magicCodeResponseBroadcastChannel.postMessage(response);
95
+ TelemetryHelper.logActionEvent(LogLevel.INFO, {
96
+ Event: TelemetryEvent.SuppressBotMagicCodeSucceeded
97
+ });
98
+ BotMagicCodeStore.botOAuthSignInId = "";
99
+ magicCodeBroadcastChannel.close();
100
+ magicCodeResponseBroadcastChannel.close();
101
+ } else {
102
+ TelemetryHelper.logActionEvent(LogLevel.ERROR, {
103
+ Event: TelemetryEvent.SuppressBotMagicCodeFailed,
104
+ Description: "Signin does not match"
105
+ });
106
+ }
107
+ };
108
+
109
+ magicCodeBroadcastChannel.addEventListener(broadcastChannelMessageEvent, eventListener);
110
+ }, []);
39
111
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("style", null, `
40
112
  .ms_lcw_webchat_received_message img.webchat__markdown__external-link-icon {
41
113
  background-image : url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIzIDMgMTggMTgiICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik03LjI1MDEgNC41MDAxN0gxMC43NDk1QzExLjE2MzcgNC41MDAxNyAxMS40OTk1IDQuODM1OTYgMTEuNDk5NSA1LjI1MDE3QzExLjQ5OTUgNS42Mjk4NiAxMS4yMTczIDUuOTQzNjYgMTAuODUxMyA1Ljk5MzMyTDEwLjc0OTUgNi4wMDAxN0g3LjI0OTc0QzYuMDcwNzkgNS45OTk2MSA1LjEwMzQ5IDYuOTA2NTYgNS4wMDc4NiA4LjA2MTEyTDUuMDAwMjggOC4yMjAwM0w1LjAwMzEyIDE2Ljc1MDdDNS4wMDM0MyAxNy45NDE1IDUuOTI4ODUgMTguOTE2MSA3LjA5OTY2IDE4Ljk5NDlMNy4yNTM3MSAxOS4wMDAxTDE1Ljc1MTggMTguOTg4NEMxNi45NDE1IDE4Ljk4NjggMTcuOTE0NSAxOC4wNjIgMTcuOTkzNSAxNi44OTIzTDE3Ljk5ODcgMTYuNzM4NFYxMy4yMzIxQzE3Ljk5ODcgMTIuODE3OSAxOC4zMzQ1IDEyLjQ4MjEgMTguNzQ4NyAxMi40ODIxQzE5LjEyODQgMTIuNDgyMSAxOS40NDIyIDEyLjc2NDMgMTkuNDkxOCAxMy4xMzAzTDE5LjQ5ODcgMTMuMjMyMVYxNi43Mzg0QzE5LjQ5ODcgMTguNzQwNyAxNy45MjkzIDIwLjM3NjkgMTUuOTUyOCAyMC40ODI5TDE1Ljc1MzggMjAuNDg4NEw3LjI1ODI3IDIwLjUwMDFMNy4wNTQ5NSAyMC40OTQ5QzUuMTQyMzkgMjAuMzk1NCAzLjYwODk1IDE4Ljg2MjcgMy41MDgzNyAxNi45NTAyTDMuNTAzMTIgMTYuNzUxMUwzLjUwMDg5IDguMjUyN0wzLjUwNTI5IDguMDUwMkMzLjYwNTM5IDYuMTM3NDkgNS4xMzg2NyA0LjYwNDQ5IDcuMDUwOTYgNC41MDUyN0w3LjI1MDEgNC41MDAxN0gxMC43NDk1SDcuMjUwMVpNMTMuNzQ4MSAzLjAwMTQ2TDIwLjMwMTggMy4wMDE5N0wyMC40MDE0IDMuMDE1NzVMMjAuNTAyMiAzLjA0MzkzTDIwLjU1OSAzLjA2ODAzQzIwLjYxMjIgMy4wOTEyMiAyMC42NjM0IDMuMTIxNjMgMjAuNzExMSAzLjE1ODg1TDIwLjc4MDQgMy4yMjE1NkwyMC44NjQxIDMuMzIwMTRMMjAuOTE4MyAzLjQxMDI1TDIwLjk1NyAzLjUwMDU3TDIwLjk3NjIgMy41NjQ3NkwyMC45ODk4IDMuNjI4NjJMMjAuOTk5MiAzLjcyMjgyTDIwLjk5OTcgMTAuMjU1NEMyMC45OTk3IDEwLjY2OTYgMjAuNjYzOSAxMS4wMDU0IDIwLjI0OTcgMTEuMDA1NEMxOS44NyAxMS4wMDU0IDE5LjU1NjIgMTAuNzIzMiAxOS41MDY1IDEwLjM1NzFMMTkuNDk5NyAxMC4yNTU0TDE5LjQ5ODkgNS41NjE0N0wxMi4yNzk3IDEyLjc4NDdDMTIuMDEzNCAxMy4wNTEgMTEuNTk2OCAxMy4wNzUzIDExLjMwMzEgMTIuODU3NUwxMS4yMTkgMTIuNzg0OUMxMC45NTI3IDEyLjUxODcgMTAuOTI4NCAxMi4xMDIxIDExLjE0NjIgMTEuODA4NEwxMS4yMTg4IDExLjcyNDNMMTguNDM2OSA0LjUwMTQ2SDEzLjc0ODFDMTMuMzY4NCA0LjUwMTQ2IDEzLjA1NDYgNC4yMTkzMSAxMy4wMDUgMy44NTMyNEwxMi45OTgxIDMuNzUxNDZDMTIuOTk4MSAzLjM3MTc3IDEzLjI4MDMgMy4wNTc5NyAxMy42NDY0IDMuMDA4MzFMMTMuNzQ4MSAzLjAwMTQ2WiIgZmlsbD0iI0ZGRkZGRiIgLz48L3N2Zz4) !important;
@@ -0,0 +1,5 @@
1
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
2
+
3
+ export class BotMagicCodeStore {}
4
+
5
+ _defineProperty(BotMagicCodeStore, "botOAuthSignInId", "");
@@ -54,6 +54,16 @@ const handleSystemMessage = (next, args, card, systemMessageStyleProps) => {
54
54
  }; // eslint-disable-next-line @typescript-eslint/no-explicit-any
55
55
 
56
56
 
57
+ const isTagIncluded = (card, tag) => {
58
+ return isDataTagsPresent(card) && card.activity.channelData.tags.includes(tag);
59
+ }; // eslint-disable-next-line @typescript-eslint/no-explicit-any
60
+
61
+
62
+ const isDataTagsPresent = card => {
63
+ return card && card.activity && card.activity.channelData && card.activity.channelData.tags && card.activity.channelData.tags.length > 0;
64
+ }; // eslint-disable-next-line @typescript-eslint/no-explicit-any
65
+
66
+
57
67
  export const createActivityMiddleware = (systemMessageStyleProps, userMessageStyleProps) => () => next => function () {
58
68
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
59
69
  args[_key] = arguments[_key];
@@ -62,7 +72,7 @@ export const createActivityMiddleware = (systemMessageStyleProps, userMessageSty
62
72
  const [card] = args;
63
73
 
64
74
  if (card.activity) {
65
- var _card$activity$from, _card$activity$channe4, _card$activity$channe5;
75
+ var _card$activity$from;
66
76
 
67
77
  if (((_card$activity$from = card.activity.from) === null || _card$activity$from === void 0 ? void 0 : _card$activity$from.role) === DirectLineSenderRole.Channel) {
68
78
  var _card$activity$channe3;
@@ -77,7 +87,11 @@ export const createActivityMiddleware = (systemMessageStyleProps, userMessageSty
77
87
  return () => false;
78
88
  }
79
89
 
80
- if ((_card$activity$channe4 = card.activity.channelData) !== null && _card$activity$channe4 !== void 0 && (_card$activity$channe5 = _card$activity$channe4.tags) !== null && _card$activity$channe5 !== void 0 && _card$activity$channe5.includes(Constants.systemMessageTag)) {
90
+ if (isTagIncluded(card, Constants.hiddenTag)) {
91
+ return () => false;
92
+ }
93
+
94
+ if (isTagIncluded(card, Constants.systemMessageTag)) {
81
95
  return handleSystemMessage(next, args, card, systemMessageStyleProps);
82
96
  } else if (card.activity.text && card.activity.type === DirectLineActivityType.Message) {
83
97
  if (!card.activity.channelData.isHtmlEncoded && card.activity.channelId === Constants.webchatChannelId) {
@@ -0,0 +1,41 @@
1
+ import { BotMagicCodeStore } from "../../BotMagicCodeStore";
2
+ var CardActionType;
3
+
4
+ (function (CardActionType) {
5
+ CardActionType["OpenUrl"] = "openUrl";
6
+ CardActionType["SignIn"] = "signin";
7
+ })(CardActionType || (CardActionType = {}));
8
+
9
+ const validCardActionTypes = [CardActionType.OpenUrl, CardActionType.SignIn];
10
+ const botOauthUrlRegex = /[\S]+.botframework.com\/api\/oauth\/signin\?signin=([\S]+)/;
11
+ export const createCardActionMiddleware = botMagicCodeConfig => {
12
+ const cardActionMiddleware = () => next => function () {
13
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
14
+ args[_key] = arguments[_key];
15
+ }
16
+
17
+ // eslint-disable-line @typescript-eslint/no-explicit-any
18
+ const [card] = args;
19
+
20
+ if (card.cardAction && validCardActionTypes.indexOf(card.cardAction.type) >= 0 && card.cardAction.value) {
21
+ // Override signin url only if fwdUrl is valid & feature is enabled
22
+ if ((botMagicCodeConfig === null || botMagicCodeConfig === void 0 ? void 0 : botMagicCodeConfig.disabled) === true && botMagicCodeConfig !== null && botMagicCodeConfig !== void 0 && botMagicCodeConfig.fwdUrl) {
23
+ const baseUrl = window.location.origin;
24
+ const result = botOauthUrlRegex.exec(card.cardAction.value);
25
+
26
+ if (result) {
27
+ BotMagicCodeStore.botOAuthSignInId = `${result[1]}`;
28
+ } // fwdUrl must be on the same domain as the chat widget
29
+
30
+
31
+ if (botMagicCodeConfig !== null && botMagicCodeConfig !== void 0 && botMagicCodeConfig.fwdUrl.startsWith(baseUrl)) {
32
+ card.cardAction.value += `&fwdUrl=${botMagicCodeConfig.fwdUrl}`;
33
+ }
34
+ }
35
+ }
36
+
37
+ return next(...args);
38
+ };
39
+
40
+ return cardActionMiddleware;
41
+ };
@@ -0,0 +1,94 @@
1
+ import "@testing-library/jest-dom/extend-expect";
2
+ import { createCardActionMiddleware } from "./cardActionMiddleware";
3
+ describe("cardActionMiddleware test", () => {
4
+ it("createCardActionMiddleware() with undefined botMagicCodeConfig should not change the sign in card url", () => {
5
+ const next = args => args; // eslint-disable-line @typescript-eslint/no-explicit-any
6
+
7
+
8
+ const signInUrl = "https://token.botframework.com/api/oauth/signin?signin=[signin]";
9
+ const args = {
10
+ cardAction: {
11
+ type: "signin",
12
+ value: signInUrl
13
+ }
14
+ };
15
+ const results = createCardActionMiddleware(undefined)()(next)(args);
16
+ expect(signInUrl).toEqual(results.cardAction.value);
17
+ });
18
+ it("createCardActionMiddleware() with botMagicCode enabled should not change the sign in card url", () => {
19
+ const botMagicCodeConfig = {
20
+ disabled: false
21
+ };
22
+
23
+ const next = args => args; // eslint-disable-line @typescript-eslint/no-explicit-any
24
+
25
+
26
+ const signInUrl = "https://token.botframework.com/api/oauth/signin?signin=[signin]";
27
+ const args = {
28
+ cardAction: {
29
+ type: "signin",
30
+ value: signInUrl
31
+ }
32
+ };
33
+ const results = createCardActionMiddleware(botMagicCodeConfig)()(next)(args);
34
+ expect(args.cardAction.value).toEqual(results.cardAction.value);
35
+ });
36
+ it("createCardActionMiddleware() with botMagicCode disabled & no fwdUrl should not change the sign in card url", () => {
37
+ const botMagicCodeConfig = {
38
+ disabled: true
39
+ };
40
+
41
+ const next = args => args; // eslint-disable-line @typescript-eslint/no-explicit-any
42
+
43
+
44
+ const signInUrl = "https://token.botframework.com/api/oauth/signin?signin=[signin]";
45
+ const args = {
46
+ cardAction: {
47
+ type: "signin",
48
+ value: signInUrl
49
+ }
50
+ };
51
+ const results = createCardActionMiddleware(botMagicCodeConfig)()(next)(args);
52
+ expect(args.cardAction.value).toEqual(results.cardAction.value);
53
+ });
54
+ it("createCardActionMiddleware() with botMagicCode disabled & fwdUrl should append the fwdUrl in the sign in card url", () => {
55
+ const botMagicCodeConfig = {
56
+ disabled: true,
57
+ fwdUrl: "http://localhost/forwarder.html"
58
+ };
59
+
60
+ const next = args => args; // eslint-disable-line @typescript-eslint/no-explicit-any
61
+
62
+
63
+ const signInUrl = "https://token.botframework.com/api/oauth/signin?signin=[signin]";
64
+ const args = {
65
+ cardAction: {
66
+ type: "signin",
67
+ value: signInUrl
68
+ }
69
+ };
70
+ const results = createCardActionMiddleware(botMagicCodeConfig)()(next)(args);
71
+ expect(signInUrl === results.cardAction.value).toBe(false);
72
+ expect(results.cardAction.value === `${signInUrl}&fwdUrl=${botMagicCodeConfig.fwdUrl}`).toBe(true);
73
+ });
74
+ it("createCardActionMiddleware() should not append fwdUrl if fwdUrl & sign in card url are not in the same domain", () => {
75
+ const botMagicCodeConfig = {
76
+ disabled: true,
77
+ fwdUrl: "https://localhost/forwarder.html"
78
+ };
79
+
80
+ const next = args => args; // eslint-disable-line @typescript-eslint/no-explicit-any
81
+
82
+
83
+ const signInUrl = "https://token.botframework.com/api/oauth/signin?signin=[signin]";
84
+ const args = {
85
+ cardAction: {
86
+ type: "signin",
87
+ value: signInUrl
88
+ }
89
+ };
90
+ const results = createCardActionMiddleware(botMagicCodeConfig)()(next)(args);
91
+ expect(signInUrl === results.cardAction.value).toBe(true);
92
+ expect(results.cardAction.value === `${signInUrl}&fwdUrl=${botMagicCodeConfig.fwdUrl}`).toBe(false);
93
+ });
94
+ });