@microsoft/omnichannel-chat-widget 1.7.3-main.7a38853 → 1.7.3-main.aa696dc
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 +1 -0
- package/lib/cjs/components/livechatwidget/LiveChatWidget.js +6 -1
- package/lib/cjs/components/livechatwidget/common/endChat.js +20 -5
- package/lib/cjs/components/livechatwidget/common/getMockChatSDKIfApplicable.js +26 -0
- package/lib/cjs/components/livechatwidget/common/overridePropsOnMockIfApplicable.js +41 -0
- package/lib/cjs/components/livechatwidget/common/startChat.js +52 -37
- package/lib/cjs/components/livechatwidget/common/startChatErrorHandler.js +6 -6
- package/lib/cjs/components/livechatwidget/common/updateSessionDataForTelemetry.js +8 -3
- package/lib/cjs/components/livechatwidget/interfaces/IMockProps.js +7 -0
- package/lib/cjs/components/webchatcontainerstateful/common/DemoChatAdapter.js +87 -0
- package/lib/cjs/components/webchatcontainerstateful/common/DemoChatSDK.js +17 -0
- package/lib/cjs/components/webchatcontainerstateful/common/DesignerChatAdapter.js +41 -0
- package/lib/cjs/components/webchatcontainerstateful/common/DesignerChatSDK.js +17 -0
- package/lib/cjs/components/webchatcontainerstateful/common/MockBotCardCommandType.js +14 -0
- package/lib/cjs/components/webchatcontainerstateful/common/MockBotCommand.js +19 -0
- package/lib/cjs/components/webchatcontainerstateful/common/mockchatsdk.js +3 -0
- package/lib/cjs/components/webchatcontainerstateful/common/utils/attachmentActivityUtils.js +71 -0
- package/lib/cjs/components/webchatcontainerstateful/common/utils/chatAdapterUtils.js +90 -0
- package/lib/cjs/plugins/newMessageEventHandler.js +4 -2
- package/lib/esm/common/telemetry/TelemetryConstants.js +1 -0
- package/lib/esm/components/livechatwidget/LiveChatWidget.js +6 -1
- package/lib/esm/components/livechatwidget/common/endChat.js +20 -5
- package/lib/esm/components/livechatwidget/common/getMockChatSDKIfApplicable.js +20 -0
- package/lib/esm/components/livechatwidget/common/overridePropsOnMockIfApplicable.js +34 -0
- package/lib/esm/components/livechatwidget/common/startChat.js +52 -37
- package/lib/esm/components/livechatwidget/common/startChatErrorHandler.js +7 -7
- package/lib/esm/components/livechatwidget/common/updateSessionDataForTelemetry.js +7 -2
- package/lib/esm/components/livechatwidget/interfaces/IMockProps.js +6 -0
- package/lib/esm/components/webchatcontainerstateful/common/DemoChatAdapter.js +79 -0
- package/lib/esm/components/webchatcontainerstateful/common/DemoChatSDK.js +10 -0
- package/lib/esm/components/webchatcontainerstateful/common/DesignerChatAdapter.js +33 -0
- package/lib/esm/components/webchatcontainerstateful/common/DesignerChatSDK.js +10 -0
- package/lib/esm/components/webchatcontainerstateful/common/MockBotCardCommandType.js +7 -0
- package/lib/esm/components/webchatcontainerstateful/common/MockBotCommand.js +12 -0
- package/lib/esm/components/webchatcontainerstateful/common/mockchatsdk.js +3 -0
- package/lib/esm/components/webchatcontainerstateful/common/utils/attachmentActivityUtils.js +61 -0
- package/lib/esm/components/webchatcontainerstateful/common/utils/chatAdapterUtils.js +77 -0
- package/lib/esm/plugins/newMessageEventHandler.js +4 -2
- package/lib/types/common/telemetry/TelemetryConstants.d.ts +1 -0
- package/lib/types/components/livechatwidget/common/getMockChatSDKIfApplicable.d.ts +1 -0
- package/lib/types/components/livechatwidget/common/overridePropsOnMockIfApplicable.d.ts +3 -0
- package/lib/types/components/livechatwidget/common/updateSessionDataForTelemetry.d.ts +1 -1
- package/lib/types/components/livechatwidget/interfaces/ILiveChatWidgetProps.d.ts +2 -0
- package/lib/types/components/livechatwidget/interfaces/IMockProps.d.ts +8 -0
- package/lib/types/components/webchatcontainerstateful/common/DemoChatAdapter.d.ts +10 -0
- package/lib/types/components/webchatcontainerstateful/common/DemoChatSDK.d.ts +6 -0
- package/lib/types/components/webchatcontainerstateful/common/DesignerChatAdapter.d.ts +8 -0
- package/lib/types/components/webchatcontainerstateful/common/DesignerChatSDK.d.ts +6 -0
- package/lib/types/components/webchatcontainerstateful/common/MockBotCardCommandType.d.ts +6 -0
- package/lib/types/components/webchatcontainerstateful/common/MockBotCommand.d.ts +11 -0
- package/lib/types/components/webchatcontainerstateful/common/mockadapter.d.ts +2 -1
- package/lib/types/components/webchatcontainerstateful/common/mockchatsdk.d.ts +6 -0
- package/lib/types/components/webchatcontainerstateful/common/utils/attachmentActivityUtils.d.ts +9 -0
- package/lib/types/components/webchatcontainerstateful/common/utils/chatAdapterUtils.d.ts +9 -0
- package/package.json +3 -3
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.createThumbnailCardAttachment = exports.createSigninCardAttachment = exports.createJpgFileAttachment = exports.createHeroCardAttachment = void 0;
|
|
7
|
+
const createJpgFileAttachment = () => {
|
|
8
|
+
return {
|
|
9
|
+
contentType: "image/jpeg",
|
|
10
|
+
name: "600x400.jpg",
|
|
11
|
+
contentUrl: "https://raw.githubusercontent.com/microsoft/omnichannel-chat-sdk/e7e75d4ede351e1cf2e52f13860d2284848c4af0/playwright/public/images/600x400.jpg"
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
exports.createJpgFileAttachment = createJpgFileAttachment;
|
|
15
|
+
const createHeroCardAttachment = () => {
|
|
16
|
+
return {
|
|
17
|
+
contentType: "application/vnd.microsoft.card.hero",
|
|
18
|
+
content: {
|
|
19
|
+
buttons: [{
|
|
20
|
+
title: "Bellevue",
|
|
21
|
+
type: "imBack",
|
|
22
|
+
value: "Bellevue"
|
|
23
|
+
}, {
|
|
24
|
+
title: "Redmond",
|
|
25
|
+
type: "imBack",
|
|
26
|
+
value: "Redmond"
|
|
27
|
+
}, {
|
|
28
|
+
title: "Seattle",
|
|
29
|
+
type: "imBack",
|
|
30
|
+
value: "Seattle"
|
|
31
|
+
}],
|
|
32
|
+
title: "Choose your location"
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
exports.createHeroCardAttachment = createHeroCardAttachment;
|
|
37
|
+
const createThumbnailCardAttachment = () => {
|
|
38
|
+
return {
|
|
39
|
+
contentType: "application/vnd.microsoft.card.thumbnail",
|
|
40
|
+
content: {
|
|
41
|
+
title: "Microsoft",
|
|
42
|
+
subtitle: "Our mission is to empower every person and every organization on the planet to achieve more.",
|
|
43
|
+
text: "Microsoft creates platforms and tools powered by AI to deliver innovative solutions that meet the evolving needs of our customers. The technology company is committed to making AI available broadly and doing so responsibly, with a mission to empower every person and every organization on the planet to achieve more.",
|
|
44
|
+
images: [{
|
|
45
|
+
alt: "Microsoft logo",
|
|
46
|
+
url: "https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1Mu3b?ver=5c31" // logo from https://microsoft.com
|
|
47
|
+
}],
|
|
48
|
+
|
|
49
|
+
buttons: [{
|
|
50
|
+
title: "Learn more",
|
|
51
|
+
type: "openUrl",
|
|
52
|
+
value: "https://www.microsoft.com/"
|
|
53
|
+
}]
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
exports.createThumbnailCardAttachment = createThumbnailCardAttachment;
|
|
58
|
+
const createSigninCardAttachment = () => {
|
|
59
|
+
return {
|
|
60
|
+
contentType: "application/vnd.microsoft.card.signin",
|
|
61
|
+
content: {
|
|
62
|
+
text: "Please login",
|
|
63
|
+
buttons: [{
|
|
64
|
+
type: "signin",
|
|
65
|
+
title: "Signin",
|
|
66
|
+
value: "https://login.live.com/"
|
|
67
|
+
}]
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
exports.createSigninCardAttachment = createSigninCardAttachment;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.postSystemMessageActivity = exports.postEchoActivity = exports.postBotTypingActivity = exports.postBotMessageActivity = exports.postBotAttachmentActivity = exports.customerUser = exports.botUser = void 0;
|
|
7
|
+
var _omnichannelChatSdk = require("@microsoft/omnichannel-chat-sdk");
|
|
8
|
+
const customerUser = {
|
|
9
|
+
id: "usedId",
|
|
10
|
+
name: "User",
|
|
11
|
+
role: "user"
|
|
12
|
+
};
|
|
13
|
+
exports.customerUser = customerUser;
|
|
14
|
+
const botUser = {
|
|
15
|
+
id: "botId",
|
|
16
|
+
name: "Bot",
|
|
17
|
+
role: "bot"
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// WebChat expects an "echo" activity to confirm the message has been sent successfully
|
|
21
|
+
exports.botUser = botUser;
|
|
22
|
+
const postEchoActivity = function (activityObserver, activity, user) {
|
|
23
|
+
let delay = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1000;
|
|
24
|
+
const echoActivity = {
|
|
25
|
+
...activity,
|
|
26
|
+
id: (0, _omnichannelChatSdk.uuidv4)(),
|
|
27
|
+
from: {
|
|
28
|
+
...activity.from,
|
|
29
|
+
...user
|
|
30
|
+
},
|
|
31
|
+
timestamp: new Date().toISOString()
|
|
32
|
+
};
|
|
33
|
+
setTimeout(() => {
|
|
34
|
+
activityObserver === null || activityObserver === void 0 ? void 0 : activityObserver.next(echoActivity); // mock message sent activity
|
|
35
|
+
}, delay);
|
|
36
|
+
};
|
|
37
|
+
exports.postEchoActivity = postEchoActivity;
|
|
38
|
+
const postBotMessageActivity = function (activityObserver, text) {
|
|
39
|
+
let tags = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "";
|
|
40
|
+
let delay = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1000;
|
|
41
|
+
setTimeout(() => {
|
|
42
|
+
activityObserver === null || activityObserver === void 0 ? void 0 : activityObserver.next({
|
|
43
|
+
id: (0, _omnichannelChatSdk.uuidv4)(),
|
|
44
|
+
from: {
|
|
45
|
+
...botUser
|
|
46
|
+
},
|
|
47
|
+
text,
|
|
48
|
+
type: "message",
|
|
49
|
+
channelData: {
|
|
50
|
+
tags
|
|
51
|
+
},
|
|
52
|
+
timestamp: new Date().toISOString()
|
|
53
|
+
});
|
|
54
|
+
}, delay);
|
|
55
|
+
};
|
|
56
|
+
exports.postBotMessageActivity = postBotMessageActivity;
|
|
57
|
+
const postSystemMessageActivity = function (activityObserver, text) {
|
|
58
|
+
let delay = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1000;
|
|
59
|
+
postBotMessageActivity(activityObserver, text, "system", delay);
|
|
60
|
+
};
|
|
61
|
+
exports.postSystemMessageActivity = postSystemMessageActivity;
|
|
62
|
+
const postBotTypingActivity = function (activityObserver) {
|
|
63
|
+
let delay = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1000;
|
|
64
|
+
setTimeout(() => {
|
|
65
|
+
activityObserver === null || activityObserver === void 0 ? void 0 : activityObserver.next({
|
|
66
|
+
id: (0, _omnichannelChatSdk.uuidv4)(),
|
|
67
|
+
from: {
|
|
68
|
+
...botUser
|
|
69
|
+
},
|
|
70
|
+
type: "typing"
|
|
71
|
+
});
|
|
72
|
+
}, delay);
|
|
73
|
+
};
|
|
74
|
+
exports.postBotTypingActivity = postBotTypingActivity;
|
|
75
|
+
const postBotAttachmentActivity = function (activityObserver) {
|
|
76
|
+
let attachments = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
77
|
+
let delay = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1000;
|
|
78
|
+
setTimeout(() => {
|
|
79
|
+
activityObserver === null || activityObserver === void 0 ? void 0 : activityObserver.next({
|
|
80
|
+
id: (0, _omnichannelChatSdk.uuidv4)(),
|
|
81
|
+
from: {
|
|
82
|
+
...botUser
|
|
83
|
+
},
|
|
84
|
+
attachments,
|
|
85
|
+
type: "message",
|
|
86
|
+
timestamp: new Date().toISOString()
|
|
87
|
+
});
|
|
88
|
+
}, delay);
|
|
89
|
+
};
|
|
90
|
+
exports.postBotAttachmentActivity = postBotAttachmentActivity;
|
|
@@ -20,7 +20,7 @@ const createOnNewAdapterActivityHandler = (chatId, userId) => {
|
|
|
20
20
|
const raiseMessageEvent = (activity, isHistoryMessage) => {
|
|
21
21
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
22
|
const polyfillMessagePayloadForEvent = payload => {
|
|
23
|
-
var _activity$conversatio, _TelemetryManager$Int;
|
|
23
|
+
var _activity$conversatio, _TelemetryManager$Int, _attachments;
|
|
24
24
|
return {
|
|
25
25
|
...payload,
|
|
26
26
|
channelData: activity === null || activity === void 0 ? void 0 : activity.channelData,
|
|
@@ -29,7 +29,9 @@ const createOnNewAdapterActivityHandler = (chatId, userId) => {
|
|
|
29
29
|
id: activity === null || activity === void 0 ? void 0 : activity.id,
|
|
30
30
|
isChatComplete: false,
|
|
31
31
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
32
|
-
text: activity === null || activity === void 0 ? void 0 : activity.text
|
|
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 : []
|
|
33
35
|
};
|
|
34
36
|
};
|
|
35
37
|
if ((activity === null || activity === void 0 ? void 0 : activity.type) === _Constants.Constants.message) {
|
|
@@ -95,6 +95,7 @@ export let TelemetryEvent;
|
|
|
95
95
|
TelemetryEvent["GetConversationDetailsCallStarted"] = "GetConversationDetailsCallStarted";
|
|
96
96
|
TelemetryEvent["GetConversationDetailsCallFailed"] = "GetConversationDetailsCallFailed";
|
|
97
97
|
TelemetryEvent["EndChatSDKCallFailed"] = "EndChatSDKCallFailed";
|
|
98
|
+
TelemetryEvent["DisconnectEndChatSDKCallFailed"] = "DisconnectEndChatSDKCallFailed";
|
|
98
99
|
TelemetryEvent["GetChatReconnectContextSDKCallStarted"] = "GetChatReconnectContextSDKCallStarted";
|
|
99
100
|
TelemetryEvent["GetChatReconnectContextSDKCallFailed"] = "GetChatReconnectContextSDKCallFailed";
|
|
100
101
|
TelemetryEvent["ParseAdaptiveCardFailed"] = "ParseAdaptiveCardFailed";
|
|
@@ -5,13 +5,18 @@ import { ChatSDKStore } from "../../contexts/ChatSDKStore";
|
|
|
5
5
|
import LiveChatWidgetStateful from "./livechatwidgetstateful/LiveChatWidgetStateful";
|
|
6
6
|
import { createReducer } from "../../contexts/createReducer";
|
|
7
7
|
import { getLiveChatWidgetContextInitialState } from "../../contexts/common/LiveChatWidgetContextInitialState";
|
|
8
|
+
import { getMockChatSDKIfApplicable } from "./common/getMockChatSDKIfApplicable";
|
|
9
|
+
import overridePropsOnMockIfApplicable from "./common/overridePropsOnMockIfApplicable";
|
|
8
10
|
export const LiveChatWidget = props => {
|
|
11
|
+
var _props$mock;
|
|
9
12
|
const reducer = createReducer();
|
|
10
13
|
const [state, dispatch] = useReducer(reducer, getLiveChatWidgetContextInitialState(props));
|
|
11
14
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12
15
|
const [adapter, setAdapter] = useState(undefined);
|
|
16
|
+
const chatSDK = getMockChatSDKIfApplicable(props.chatSDK, props === null || props === void 0 ? void 0 : (_props$mock = props.mock) === null || _props$mock === void 0 ? void 0 : _props$mock.type);
|
|
17
|
+
overridePropsOnMockIfApplicable(props);
|
|
13
18
|
return /*#__PURE__*/React.createElement(ChatSDKStore.Provider, {
|
|
14
|
-
value:
|
|
19
|
+
value: chatSDK
|
|
15
20
|
}, /*#__PURE__*/React.createElement(ChatAdapterStore.Provider, {
|
|
16
21
|
value: [adapter, setAdapter]
|
|
17
22
|
}, /*#__PURE__*/React.createElement(ChatContextStore.Provider, {
|
|
@@ -135,12 +135,27 @@ const endChat = async (props, chatSDK, state, dispatch, setAdapter, setWebChatSt
|
|
|
135
135
|
await handleAuthentication(chatSDK, props.chatConfig, props.getAuthToken);
|
|
136
136
|
await (chatSDK === null || chatSDK === void 0 ? void 0 : chatSDK.endChat());
|
|
137
137
|
} catch (ex) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
138
|
+
var _inMemoryState$appSta;
|
|
139
|
+
const inMemoryState = executeReducer(state, {
|
|
140
|
+
type: LiveChatWidgetActionType.GET_IN_MEMORY_STATE,
|
|
141
|
+
payload: null
|
|
143
142
|
});
|
|
143
|
+
// if the chat was disconnected or ended by the agent, we don't want to log the error
|
|
144
|
+
if (!(inMemoryState !== null && inMemoryState !== void 0 && (_inMemoryState$appSta = inMemoryState.appStates) !== null && _inMemoryState$appSta !== void 0 && _inMemoryState$appSta.chatDisconnectEventReceived)) {
|
|
145
|
+
TelemetryHelper.logSDKEvent(LogLevel.ERROR, {
|
|
146
|
+
Event: TelemetryEvent.EndChatSDKCallFailed,
|
|
147
|
+
ExceptionDetails: {
|
|
148
|
+
exception: ex
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
} else {
|
|
152
|
+
TelemetryHelper.logSDKEvent(LogLevel.WARN, {
|
|
153
|
+
Event: TelemetryEvent.DisconnectEndChatSDKCallFailed,
|
|
154
|
+
ExceptionDetails: {
|
|
155
|
+
exception: ex
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
144
159
|
postMessageToOtherTab = false;
|
|
145
160
|
} finally {
|
|
146
161
|
await endChatStateCleanUp(dispatch);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { DemoChatSDK } from "../../webchatcontainerstateful/common/DemoChatSDK";
|
|
2
|
+
import { DesignerChatSDK } from "../../webchatcontainerstateful/common/DesignerChatSDK";
|
|
3
|
+
import { MockChatSDK } from "../../webchatcontainerstateful/common/mockchatsdk";
|
|
4
|
+
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6
|
+
export const getMockChatSDKIfApplicable = (chatSDK, type) => {
|
|
7
|
+
if (type) {
|
|
8
|
+
switch (type.toLowerCase()) {
|
|
9
|
+
case "demo":
|
|
10
|
+
chatSDK = new DemoChatSDK();
|
|
11
|
+
break;
|
|
12
|
+
case "designer":
|
|
13
|
+
chatSDK = new DesignerChatSDK();
|
|
14
|
+
break;
|
|
15
|
+
default:
|
|
16
|
+
chatSDK = new MockChatSDK();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return chatSDK;
|
|
20
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const overridePropsOnMockIfApplicable = props => {
|
|
2
|
+
var _props$mock, _props$mock2;
|
|
3
|
+
if (props !== null && props !== void 0 && (_props$mock = props.mock) !== null && _props$mock !== void 0 && _props$mock.type && (props === null || props === void 0 ? void 0 : (_props$mock2 = props.mock) === null || _props$mock2 === void 0 ? void 0 : _props$mock2.type.toLowerCase()) === "designer") {
|
|
4
|
+
if (!props.webChatContainerProps) {
|
|
5
|
+
props.webChatContainerProps = {};
|
|
6
|
+
}
|
|
7
|
+
if (!props.webChatContainerProps.webChatProps) {
|
|
8
|
+
props.webChatContainerProps.webChatProps = {};
|
|
9
|
+
}
|
|
10
|
+
if (!props.webChatContainerProps.webChatStyles) {
|
|
11
|
+
props.webChatContainerProps.webChatStyles = {};
|
|
12
|
+
}
|
|
13
|
+
if (!props.webChatContainerProps.webChatProps.overrideLocalizedStrings) {
|
|
14
|
+
props.webChatContainerProps.webChatProps.overrideLocalizedStrings = {};
|
|
15
|
+
}
|
|
16
|
+
props.webChatContainerProps = {
|
|
17
|
+
...props.webChatContainerProps,
|
|
18
|
+
webChatProps: {
|
|
19
|
+
disabled: true,
|
|
20
|
+
...props.webChatContainerProps.webChatProps,
|
|
21
|
+
overrideLocalizedStrings: {
|
|
22
|
+
TEXT_INPUT_PLACEHOLDER: "Send a message . . .",
|
|
23
|
+
...props.webChatContainerProps.webChatProps.overrideLocalizedStrings
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
webChatStyles: {
|
|
27
|
+
hideUploadButton: false,
|
|
28
|
+
sendBoxBackground: "rgb(243, 242, 241)",
|
|
29
|
+
...props.webChatContainerProps.webChatStyles
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
export default overridePropsOnMockIfApplicable;
|
|
@@ -2,21 +2,21 @@ import { BroadcastEvent, LogLevel, TelemetryEvent } from "../../../common/teleme
|
|
|
2
2
|
import { Constants, LiveWorkItemState, WidgetLoadCustomErrorString, WidgetLoadTelemetryMessage } from "../../../common/Constants";
|
|
3
3
|
import { checkContactIdError, createTimer, getConversationDetailsCall, getStateFromCache, getWidgetCacheIdfromProps, isNullOrEmptyString, isUndefinedOrEmpty } from "../../../common/utils";
|
|
4
4
|
import { getAuthClientFunction, handleAuthentication } from "./authHelper";
|
|
5
|
+
import { handleChatReconnect, isPersistentEnabled, isReconnectEnabled } from "./reconnectChatHelper";
|
|
6
|
+
import { handleStartChatError, logWidgetLoadComplete } from "./startChatErrorHandler";
|
|
5
7
|
import { ActivityStreamHandler } from "./ActivityStreamHandler";
|
|
6
8
|
import { BroadcastService } from "@microsoft/omnichannel-chat-components";
|
|
7
9
|
import { ConversationState } from "../../../contexts/common/ConversationState";
|
|
8
10
|
import { LiveChatWidgetActionType } from "../../../contexts/common/LiveChatWidgetActionType";
|
|
9
11
|
import { TelemetryHelper } from "../../../common/telemetry/TelemetryHelper";
|
|
10
12
|
import { TelemetryTimers } from "../../../common/telemetry/TelemetryManager";
|
|
13
|
+
import { chatSDKStateCleanUp } from "./endChat";
|
|
11
14
|
import { createAdapter } from "./createAdapter";
|
|
12
15
|
import { createOnNewAdapterActivityHandler } from "../../../plugins/newMessageEventHandler";
|
|
13
|
-
import { handleChatReconnect, isPersistentEnabled, isReconnectEnabled } from "./reconnectChatHelper";
|
|
14
|
-
import { setPostChatContextAndLoadSurvey } from "./setPostChatContextAndLoadSurvey";
|
|
15
|
-
import { updateSessionDataForTelemetry } from "./updateSessionDataForTelemetry";
|
|
16
|
-
import { logWidgetLoadComplete, handleStartChatError } from "./startChatErrorHandler";
|
|
17
|
-
import { chatSDKStateCleanUp } from "./endChat";
|
|
18
16
|
import { isPersistentChatEnabled } from "./liveChatConfigUtils";
|
|
17
|
+
import { setPostChatContextAndLoadSurvey } from "./setPostChatContextAndLoadSurvey";
|
|
19
18
|
import { shouldSetPreChatIfPersistentChat } from "./persistentChatHelper";
|
|
19
|
+
import { updateTelemetryData } from "./updateSessionDataForTelemetry";
|
|
20
20
|
|
|
21
21
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
22
|
let optionalParams = {};
|
|
@@ -25,10 +25,25 @@ let widgetInstanceId;
|
|
|
25
25
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
26
|
let popoutWidgetInstanceId;
|
|
27
27
|
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
29
|
+
const setAuthenticationIfApplicable = async (props, chatSDK) => {
|
|
30
|
+
const chatConfig = props === null || props === void 0 ? void 0 : props.chatConfig;
|
|
31
|
+
const getAuthToken = props === null || props === void 0 ? void 0 : props.getAuthToken;
|
|
32
|
+
const authClientFunction = getAuthClientFunction(chatConfig);
|
|
33
|
+
if (getAuthToken && authClientFunction) {
|
|
34
|
+
// set auth token to chat sdk before start chat
|
|
35
|
+
const authSuccess = await handleAuthentication(chatSDK, chatConfig, getAuthToken);
|
|
36
|
+
if (!authSuccess) {
|
|
37
|
+
throw new Error(WidgetLoadCustomErrorString.AuthenticationFailedErrorString);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
28
42
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
29
43
|
const prepareStartChat = async (props, chatSDK, state, dispatch, setAdapter) => {
|
|
30
44
|
optionalParams = {}; //Resetting to ensure no stale values
|
|
31
45
|
widgetInstanceId = getWidgetCacheIdfromProps(props);
|
|
46
|
+
|
|
32
47
|
// reconnect > chat from cache
|
|
33
48
|
if (isReconnectEnabled(props.chatConfig) === true && !isPersistentEnabled(props.chatConfig)) {
|
|
34
49
|
const shouldStartChatNormally = await handleChatReconnect(chatSDK, props, dispatch, setAdapter, initStartChat, state);
|
|
@@ -51,6 +66,11 @@ const prepareStartChat = async (props, chatSDK, state, dispatch, setAdapter) =>
|
|
|
51
66
|
const isProactiveChat = state.appStates.conversationState === ConversationState.ProactiveChat;
|
|
52
67
|
const isPreChatEnabledInProactiveChat = state.appStates.proactiveChatStates.proactiveChatEnablePrechat;
|
|
53
68
|
|
|
69
|
+
// Setting auth settings to OC API to retrieve existing persistent chat session before start chat if any
|
|
70
|
+
if (isPersistentEnabled(props.chatConfig)) {
|
|
71
|
+
await setAuthenticationIfApplicable(props, chatSDK);
|
|
72
|
+
}
|
|
73
|
+
|
|
54
74
|
//Setting PreChat and intiate chat
|
|
55
75
|
await setPreChatAndInitiateChat(chatSDK, dispatch, setAdapter, isProactiveChat, isPreChatEnabledInProactiveChat, state, props);
|
|
56
76
|
};
|
|
@@ -125,15 +145,13 @@ const setPreChatAndInitiateChat = async (chatSDK, dispatch, setAdapter, isProact
|
|
|
125
145
|
const initStartChat = async (chatSDK, dispatch, setAdapter, state, props, params, persistedState) => {
|
|
126
146
|
var _state$domainStates5, _state$domainStates5$, _state$domainStates5$2;
|
|
127
147
|
let isStartChatSuccessful = false;
|
|
128
|
-
const chatConfig = props === null || props === void 0 ? void 0 : props.chatConfig;
|
|
129
|
-
const getAuthToken = props === null || props === void 0 ? void 0 : props.getAuthToken;
|
|
130
148
|
const persistentChatEnabled = await isPersistentChatEnabled(state === null || state === void 0 ? void 0 : (_state$domainStates5 = state.domainStates) === null || _state$domainStates5 === void 0 ? void 0 : (_state$domainStates5$ = _state$domainStates5.liveChatConfig) === null || _state$domainStates5$ === void 0 ? void 0 : (_state$domainStates5$2 = _state$domainStates5$.LiveWSAndLiveChatEngJoin) === null || _state$domainStates5$2 === void 0 ? void 0 : _state$domainStates5$2.msdyn_conversationmode);
|
|
131
149
|
if ((state === null || state === void 0 ? void 0 : state.appStates.conversationState) === ConversationState.Closed) {
|
|
132
150
|
// Preventive reset to avoid starting chat with previous requestId which could potentially cause problems
|
|
133
151
|
chatSDKStateCleanUp(chatSDK);
|
|
134
152
|
}
|
|
135
153
|
try {
|
|
136
|
-
var _state$appStates2
|
|
154
|
+
var _state$appStates2;
|
|
137
155
|
// Clear disconnect state on start chat
|
|
138
156
|
(state === null || state === void 0 ? void 0 : (_state$appStates2 = state.appStates) === null || _state$appStates2 === void 0 ? void 0 : _state$appStates2.chatDisconnectEventReceived) && dispatch({
|
|
139
157
|
type: LiveChatWidgetActionType.SET_CHAT_DISCONNECT_EVENT_RECEIVED,
|
|
@@ -146,14 +164,9 @@ const initStartChat = async (chatSDK, dispatch, setAdapter, state, props, params
|
|
|
146
164
|
Event: TelemetryEvent.WidgetLoadStarted,
|
|
147
165
|
Description: "Widget loading started"
|
|
148
166
|
});
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const authSuccess = await handleAuthentication(chatSDK, chatConfig, getAuthToken);
|
|
153
|
-
if (!authSuccess) {
|
|
154
|
-
throw new Error(WidgetLoadCustomErrorString.AuthenticationFailedErrorString);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
167
|
+
|
|
168
|
+
// Auth token retrieval needs to happen during start chat to support pop-out chat
|
|
169
|
+
await setAuthenticationIfApplicable(props, chatSDK);
|
|
157
170
|
|
|
158
171
|
//Check if chat retrieved from cache
|
|
159
172
|
if (persistedState || params !== null && params !== void 0 && params.liveChatContext) {
|
|
@@ -190,16 +203,6 @@ const initStartChat = async (chatSDK, dispatch, setAdapter, state, props, params
|
|
|
190
203
|
throw error;
|
|
191
204
|
}
|
|
192
205
|
|
|
193
|
-
// New adapter creation
|
|
194
|
-
const newAdapter = await createAdapter(chatSDK);
|
|
195
|
-
setAdapter(newAdapter);
|
|
196
|
-
const chatToken = await chatSDK.getChatToken();
|
|
197
|
-
dispatch({
|
|
198
|
-
type: LiveChatWidgetActionType.SET_CHAT_TOKEN,
|
|
199
|
-
payload: chatToken
|
|
200
|
-
});
|
|
201
|
-
newAdapter === null || newAdapter === void 0 ? void 0 : (_newAdapter$activity$ = newAdapter.activity$) === null || _newAdapter$activity$ === void 0 ? void 0 : _newAdapter$activity$.subscribe(createOnNewAdapterActivityHandler(chatToken === null || chatToken === void 0 ? void 0 : chatToken.chatId, chatToken === null || chatToken === void 0 ? void 0 : chatToken.visitorId));
|
|
202
|
-
|
|
203
206
|
// Set app state to Active
|
|
204
207
|
if (isStartChatSuccessful) {
|
|
205
208
|
ActivityStreamHandler.uncork();
|
|
@@ -219,27 +222,26 @@ const initStartChat = async (chatSDK, dispatch, setAdapter, state, props, params
|
|
|
219
222
|
payload: persistedState
|
|
220
223
|
});
|
|
221
224
|
logWidgetLoadComplete(WidgetLoadTelemetryMessage.PersistedStateRetrievedMessage);
|
|
222
|
-
|
|
225
|
+
// Set post chat context in state, load in background to do not block the load
|
|
226
|
+
setPostChatContextAndLoadSurvey(chatSDK, dispatch, true);
|
|
223
227
|
return;
|
|
224
228
|
}
|
|
225
|
-
|
|
226
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
227
|
-
const liveChatContext = await (chatSDK === null || chatSDK === void 0 ? void 0 : chatSDK.getCurrentLiveChatContext());
|
|
229
|
+
await createAdapterAndSubscribe(chatSDK, dispatch, setAdapter);
|
|
228
230
|
|
|
229
231
|
// Persistent Chat relies on the `reconnectId` retrieved from reconnectablechats API to reconnect upon start chat and not `liveChatContext`
|
|
230
232
|
if (!persistentChatEnabled) {
|
|
233
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
234
|
+
const liveChatContext = await (chatSDK === null || chatSDK === void 0 ? void 0 : chatSDK.getCurrentLiveChatContext());
|
|
231
235
|
dispatch({
|
|
232
236
|
type: LiveChatWidgetActionType.SET_LIVE_CHAT_CONTEXT,
|
|
233
237
|
payload: liveChatContext
|
|
234
238
|
});
|
|
235
239
|
}
|
|
236
240
|
logWidgetLoadComplete();
|
|
237
|
-
// Set post chat context in state
|
|
238
|
-
|
|
239
|
-
await setPostChatContextAndLoadSurvey(chatSDK, dispatch);
|
|
240
|
-
|
|
241
|
+
// Set post chat context in state, load in background to do not block the load
|
|
242
|
+
setPostChatContextAndLoadSurvey(chatSDK, dispatch);
|
|
241
243
|
// Updating chat session detail for telemetry
|
|
242
|
-
await
|
|
244
|
+
await updateTelemetryData(chatSDK, dispatch);
|
|
243
245
|
} catch (ex) {
|
|
244
246
|
handleStartChatError(dispatch, chatSDK, props, ex, isStartChatSuccessful);
|
|
245
247
|
} finally {
|
|
@@ -248,6 +250,21 @@ const initStartChat = async (chatSDK, dispatch, setAdapter, state, props, params
|
|
|
248
250
|
}
|
|
249
251
|
};
|
|
250
252
|
|
|
253
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
254
|
+
const createAdapterAndSubscribe = async (chatSDK, dispatch, setAdapter) => {
|
|
255
|
+
var _newAdapter$activity$;
|
|
256
|
+
// New adapter creation
|
|
257
|
+
const newAdapter = await createAdapter(chatSDK);
|
|
258
|
+
setAdapter(newAdapter);
|
|
259
|
+
|
|
260
|
+
//start chat is already seeding the chat token, so no need to get it again
|
|
261
|
+
const chatToken = await chatSDK.getChatToken(true);
|
|
262
|
+
dispatch({
|
|
263
|
+
type: LiveChatWidgetActionType.SET_CHAT_TOKEN,
|
|
264
|
+
payload: chatToken
|
|
265
|
+
});
|
|
266
|
+
newAdapter === null || newAdapter === void 0 ? void 0 : (_newAdapter$activity$ = newAdapter.activity$) === null || _newAdapter$activity$ === void 0 ? void 0 : _newAdapter$activity$.subscribe(createOnNewAdapterActivityHandler(chatToken === null || chatToken === void 0 ? void 0 : chatToken.chatId, chatToken === null || chatToken === void 0 ? void 0 : chatToken.visitorId));
|
|
267
|
+
};
|
|
251
268
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
252
269
|
const canConnectToExistingChat = async (props, chatSDK, state, dispatch, setAdapter) => {
|
|
253
270
|
var _state$appStates3, _persistedState$domai6, _persistedState$appSt;
|
|
@@ -336,10 +353,8 @@ const checkIfConversationStillValid = async (chatSDK, dispatch, state) => {
|
|
|
336
353
|
var _state$domainStates8, _state$domainStates8$, _state$domainStates9;
|
|
337
354
|
const requestIdFromCache = (_state$domainStates8 = state.domainStates) === null || _state$domainStates8 === void 0 ? void 0 : (_state$domainStates8$ = _state$domainStates8.liveChatContext) === null || _state$domainStates8$ === void 0 ? void 0 : _state$domainStates8$.requestId;
|
|
338
355
|
const liveChatContext = state === null || state === void 0 ? void 0 : (_state$domainStates9 = state.domainStates) === null || _state$domainStates9 === void 0 ? void 0 : _state$domainStates9.liveChatContext;
|
|
339
|
-
|
|
340
356
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
341
357
|
let conversationDetails = undefined;
|
|
342
|
-
|
|
343
358
|
// Preserve current requestId
|
|
344
359
|
const currentRequestId = chatSDK.requestId ?? "";
|
|
345
360
|
dispatch({
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ChatSDKError, ChatSDKErrorName } from "@microsoft/omnichannel-chat-sdk";
|
|
2
2
|
import { LogLevel, TelemetryEvent } from "../../../common/telemetry/TelemetryConstants";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { PrepareEndChatDescriptionConstants, WidgetLoadCustomErrorString, WidgetLoadTelemetryMessage } from "../../../common/Constants";
|
|
4
|
+
import { callingStateCleanUp, chatSDKStateCleanUp, closeChatStateCleanUp, endChatStateCleanUp } from "./endChat";
|
|
5
5
|
import { ConversationState } from "../../../contexts/common/ConversationState";
|
|
6
|
-
import { LiveChatWidgetActionType } from "../../../contexts/common/LiveChatWidgetActionType";
|
|
7
|
-
import { callingStateCleanUp, endChatStateCleanUp, closeChatStateCleanUp, chatSDKStateCleanUp } from "./endChat";
|
|
8
6
|
import { DataStoreManager } from "../../../common/contextDataStore/DataStoreManager";
|
|
9
|
-
import {
|
|
10
|
-
import { PrepareEndChatDescriptionConstants, WidgetLoadCustomErrorString, WidgetLoadTelemetryMessage } from "../../../common/Constants";
|
|
7
|
+
import { LiveChatWidgetActionType } from "../../../contexts/common/LiveChatWidgetActionType";
|
|
11
8
|
import { StartChatFailureType } from "../../../contexts/common/StartChatFailureType";
|
|
9
|
+
import { TelemetryHelper } from "../../../common/telemetry/TelemetryHelper";
|
|
10
|
+
import { TelemetryTimers } from "../../../common/telemetry/TelemetryManager";
|
|
11
|
+
import { getWidgetCacheIdfromProps } from "../../../common/utils";
|
|
12
12
|
|
|
13
13
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
14
|
export const handleStartChatError = (dispatch, chatSDK, props, ex, isStartChatSuccessful) => {
|
|
@@ -6,7 +6,13 @@ import { TelemetryManager } from "../../../common/telemetry/TelemetryManager";
|
|
|
6
6
|
import { getConversationDetailsCall } from "../../../common/utils";
|
|
7
7
|
|
|
8
8
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9
|
-
export const
|
|
9
|
+
export const updateTelemetryData = async (chatSDK, dispatch) => {
|
|
10
|
+
// load it concurrently, this will reduce the load time
|
|
11
|
+
await Promise.all([updateSessionDataForTelemetry(chatSDK, dispatch), updateConversationDataForTelemetry(chatSDK, dispatch)]);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
15
|
+
const updateSessionDataForTelemetry = async (chatSDK, dispatch) => {
|
|
10
16
|
if (chatSDK) {
|
|
11
17
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12
18
|
const chatSession = await chatSDK.getCurrentLiveChatContext();
|
|
@@ -21,7 +27,6 @@ export const updateSessionDataForTelemetry = async (chatSDK, dispatch) => {
|
|
|
21
27
|
chatSession
|
|
22
28
|
}
|
|
23
29
|
});
|
|
24
|
-
await updateConversationDataForTelemetry(chatSDK, dispatch);
|
|
25
30
|
}
|
|
26
31
|
};
|
|
27
32
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import "rxjs/add/operator/share";
|
|
2
|
+
import "rxjs/add/observable/of";
|
|
3
|
+
import { Observable } from "rxjs/Observable";
|
|
4
|
+
import MockAdapter from "./mockadapter";
|
|
5
|
+
import { customerUser, postBotMessageActivity, postBotAttachmentActivity, postBotTypingActivity, postEchoActivity, postSystemMessageActivity } from "./utils/chatAdapterUtils";
|
|
6
|
+
import { createHeroCardAttachment, createJpgFileAttachment, createSigninCardAttachment, createThumbnailCardAttachment } from "./utils/attachmentActivityUtils";
|
|
7
|
+
import MockBotCommand from "./MockBotCommand";
|
|
8
|
+
import MockBotCardCommandType from "./MockBotCardCommandType";
|
|
9
|
+
export class DemoChatAdapter extends MockAdapter {
|
|
10
|
+
constructor() {
|
|
11
|
+
super();
|
|
12
|
+
setTimeout(() => {
|
|
13
|
+
postSystemMessageActivity(this.activityObserver, "You're currently using a demo.", 0);
|
|
14
|
+
postBotMessageActivity(this.activityObserver, "Type `/help` to learn more", undefined, 0); // send init message from bot
|
|
15
|
+
}, 1000);
|
|
16
|
+
}
|
|
17
|
+
postBotCommandsActivity() {
|
|
18
|
+
let delay = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1000;
|
|
19
|
+
postBotAttachmentActivity(this.activityObserver, [{
|
|
20
|
+
contentType: "application/vnd.microsoft.card.thumbnail",
|
|
21
|
+
content: {
|
|
22
|
+
buttons: [{
|
|
23
|
+
title: "Send system message",
|
|
24
|
+
type: "imBack",
|
|
25
|
+
value: "send system message"
|
|
26
|
+
}, {
|
|
27
|
+
title: "Send typing",
|
|
28
|
+
type: "imBack",
|
|
29
|
+
value: "send typing"
|
|
30
|
+
}, {
|
|
31
|
+
title: "Send bot message",
|
|
32
|
+
type: "imBack",
|
|
33
|
+
value: "send bot message"
|
|
34
|
+
}],
|
|
35
|
+
title: "Commands"
|
|
36
|
+
}
|
|
37
|
+
}], delay);
|
|
38
|
+
}
|
|
39
|
+
postActivity(activity) {
|
|
40
|
+
if (activity) {
|
|
41
|
+
postEchoActivity(this.activityObserver, activity, customerUser);
|
|
42
|
+
if (activity.text) {
|
|
43
|
+
switch (true) {
|
|
44
|
+
case activity.text === MockBotCommand.Help:
|
|
45
|
+
this.postBotCommandsActivity();
|
|
46
|
+
break;
|
|
47
|
+
case activity.text === MockBotCommand.SendSystemMessage:
|
|
48
|
+
postSystemMessageActivity(this.activityObserver, "Contoso has joined the chat.");
|
|
49
|
+
break;
|
|
50
|
+
case activity.text === MockBotCommand.SendTyping:
|
|
51
|
+
postBotTypingActivity(this.activityObserver);
|
|
52
|
+
break;
|
|
53
|
+
case activity.text === MockBotCommand.SendAttachment:
|
|
54
|
+
postBotAttachmentActivity(this.activityObserver, [createJpgFileAttachment()]);
|
|
55
|
+
break;
|
|
56
|
+
case activity.text === MockBotCommand.SendBotMessage:
|
|
57
|
+
postBotMessageActivity(this.activityObserver, "Hi, how can I help you?");
|
|
58
|
+
break;
|
|
59
|
+
case activity.text === `${MockBotCommand.Card} ${MockBotCardCommandType.Signin}`:
|
|
60
|
+
postBotAttachmentActivity(this.activityObserver, [createSigninCardAttachment()]);
|
|
61
|
+
break;
|
|
62
|
+
case activity.text === `${MockBotCommand.Card} ${MockBotCardCommandType.Hero}`:
|
|
63
|
+
postBotAttachmentActivity(this.activityObserver, [createHeroCardAttachment()]);
|
|
64
|
+
break;
|
|
65
|
+
case activity.text === `${MockBotCommand.Card} ${MockBotCardCommandType.Thumbnail}`:
|
|
66
|
+
postBotAttachmentActivity(this.activityObserver, [createThumbnailCardAttachment()]);
|
|
67
|
+
break;
|
|
68
|
+
case activity.text.startsWith(`${MockBotCommand.Bot} `):
|
|
69
|
+
postBotMessageActivity(this.activityObserver, activity.text.substring(5));
|
|
70
|
+
break;
|
|
71
|
+
case activity.text.startsWith(`${MockBotCommand.System} `):
|
|
72
|
+
postSystemMessageActivity(this.activityObserver, activity.text.substring(8));
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return Observable.of(activity.id || "");
|
|
78
|
+
}
|
|
79
|
+
}
|