@botpress/webchat 0.2.4 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -0
- package/dist/components/Composer.d.ts +4 -5
- package/dist/components/Composer.js +16 -25
- package/dist/components/Container.js +1 -4
- package/dist/components/ConversationList.d.ts +1 -1
- package/dist/components/ConversationList.js +5 -46
- package/dist/components/Header.d.ts +1 -3
- package/dist/components/Header.js +7 -37
- package/dist/components/common/BotInfo/index.d.ts +1 -1
- package/dist/components/common/BotInfo/index.js +4 -14
- package/dist/components/messages/InlineFeedback.d.ts +2 -1
- package/dist/components/messages/Message.js +3 -6
- package/dist/components/messages/MessageGroup.d.ts +1 -5
- package/dist/components/messages/MessageGroup.js +4 -7
- package/dist/components/messages/MessageList.d.ts +1 -1
- package/dist/components/messages/MessageList.js +7 -29
- package/dist/core/api.d.ts +2 -7
- package/dist/core/api.js +5 -29
- package/dist/core/constants.d.ts +4 -32
- package/dist/core/constants.js +18 -32
- package/dist/core/socket.d.ts +1 -7
- package/dist/core/socket.js +8 -30
- package/dist/index.d.ts +3 -9
- package/dist/index.js +8 -35
- package/dist/main.d.ts +2 -2
- package/dist/main.js +84 -135
- package/dist/store/composer.js +1 -1
- package/dist/store/index.d.ts +5 -9
- package/dist/store/index.js +43 -66
- package/dist/store/view.d.ts +3 -4
- package/dist/store/view.js +6 -13
- package/dist/translations/index.d.ts +2 -1
- package/dist/translations/index.js +36 -1
- package/dist/typings.d.ts +123 -55
- package/dist/utils/analytics.d.ts +5 -0
- package/dist/utils/analytics.js +37 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.js +27 -0
- package/dist/utils/storage.d.ts +4 -5
- package/dist/utils/storage.js +23 -11
- package/package.json +4 -4
- package/dist/components/ContextMenu.d.ts +0 -2
- package/dist/components/ContextMenu.js +0 -24
- package/dist/components/OverridableComponent.d.ts +0 -24
- package/dist/components/OverridableComponent.js +0 -50
- package/dist/components/Stylesheet.d.ts +0 -5
- package/dist/components/Stylesheet.js +0 -7
- package/dist/components/common/MoreOptions/index.d.ts +0 -21
- package/dist/components/common/MoreOptions/index.js +0 -60
- package/dist/components/common/Overlay/index.d.ts +0 -7
- package/dist/components/common/Overlay/index.js +0 -36
- package/dist/icons/CloseChat.d.ts +0 -6
- package/dist/icons/CloseChat.js +0 -9
- package/dist/icons/Send.d.ts +0 -6
- package/dist/icons/Send.js +0 -8
- package/dist/utils.d.ts +0 -8
- package/dist/utils.js +0 -111
package/dist/main.js
CHANGED
|
@@ -41,19 +41,18 @@ const query_string_1 = __importDefault(require("query-string"));
|
|
|
41
41
|
const react_1 = __importDefault(require("react"));
|
|
42
42
|
const react_intl_1 = require("react-intl");
|
|
43
43
|
const Container_1 = __importDefault(require("./components/Container"));
|
|
44
|
-
const Stylesheet_1 = __importDefault(require("./components/Stylesheet"));
|
|
45
44
|
const constants_1 = __importDefault(require("./core/constants"));
|
|
46
45
|
const socket_1 = __importDefault(require("./core/socket"));
|
|
47
46
|
const Chat_1 = __importDefault(require("./icons/Chat"));
|
|
48
47
|
const utils_1 = require("./utils");
|
|
48
|
+
const analytics_1 = require("./utils/analytics");
|
|
49
49
|
exports.DEFAULT_TYPING_DELAY = 1000;
|
|
50
50
|
class Web extends react_1.default.Component {
|
|
51
51
|
constructor(props) {
|
|
52
52
|
super(props);
|
|
53
53
|
this.hasBeenInitialized = false;
|
|
54
54
|
this.isCurrentConversation = (event) => {
|
|
55
|
-
|
|
56
|
-
return !((_a = this.props.config) === null || _a === void 0 ? void 0 : _a.conversationId) || ((_b = this.props.config) === null || _b === void 0 ? void 0 : _b.conversationId) === event.conversationId;
|
|
55
|
+
return this.props.currentConversationId === event.conversationId;
|
|
57
56
|
};
|
|
58
57
|
this.handleKeyDown = (e) => __awaiter(this, void 0, void 0, function* () {
|
|
59
58
|
var _a;
|
|
@@ -64,52 +63,51 @@ class Web extends react_1.default.Component {
|
|
|
64
63
|
this.props.hideChat();
|
|
65
64
|
}
|
|
66
65
|
});
|
|
67
|
-
this.handleIframeApi = ({ data
|
|
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
|
-
|
|
66
|
+
this.handleIframeApi = ({ data }) => __awaiter(this, void 0, void 0, function* () {
|
|
67
|
+
switch (data.action) {
|
|
68
|
+
case 'configure':
|
|
69
|
+
return this.props.updateConfig(Object.assign({}, constants_1.default.DEFAULT_CONFIG, data.payload));
|
|
70
|
+
case 'mergeConfig':
|
|
71
|
+
return this.props.mergeConfig(data.payload);
|
|
72
|
+
case 'sendPayload':
|
|
73
|
+
return this.props.sendData(data.payload);
|
|
74
|
+
case 'event':
|
|
75
|
+
const { type, text, conversationId } = data.payload;
|
|
76
|
+
if (type === 'show') {
|
|
77
|
+
this.props.showChat();
|
|
78
|
+
(0, analytics_1.trackWebchatState)('show');
|
|
79
|
+
}
|
|
80
|
+
else if (type === 'hide') {
|
|
81
|
+
this.props.hideChat();
|
|
82
|
+
(0, analytics_1.trackWebchatState)('hide');
|
|
83
|
+
}
|
|
84
|
+
else if (type === 'toggle') {
|
|
85
|
+
this.props.displayWidgetView ? this.props.showChat() : this.props.hideChat();
|
|
86
|
+
(0, analytics_1.trackWebchatState)('toggle');
|
|
87
|
+
}
|
|
88
|
+
else if (type === 'message') {
|
|
89
|
+
(0, analytics_1.trackMessage)('sent');
|
|
90
|
+
yield this.props.sendMessage(text);
|
|
91
|
+
}
|
|
92
|
+
else if (type === 'loadConversation') {
|
|
93
|
+
yield this.props.fetchConversation(conversationId);
|
|
94
|
+
}
|
|
95
|
+
else if (type === 'toggleBotInfo') {
|
|
96
|
+
this.props.toggleBotInfo();
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
yield this.props.sendData({ type, payload: data.payload });
|
|
100
|
+
}
|
|
101
|
+
default:
|
|
102
|
+
break;
|
|
104
103
|
}
|
|
105
104
|
});
|
|
106
|
-
this.handleClearMessages = (event) => {
|
|
107
|
-
if (this.isCurrentConversation(event)) {
|
|
108
|
-
this.props.clearMessages();
|
|
109
|
-
}
|
|
110
|
-
};
|
|
111
105
|
this.handleNewMessage = (event) => __awaiter(this, void 0, void 0, function* () {
|
|
112
106
|
var _b;
|
|
107
|
+
if (!this.isCurrentConversation(event)) {
|
|
108
|
+
// don't do anything, it's a message from another conversation
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
113
111
|
if (event.authorId === undefined) {
|
|
114
112
|
const value = (event.payload.type === 'typing' ? event.payload.value : undefined) || exports.DEFAULT_TYPING_DELAY;
|
|
115
113
|
yield this.handleTyping(Object.assign(Object.assign({}, event), { timeInMs: value }));
|
|
@@ -118,11 +116,7 @@ class Web extends react_1.default.Component {
|
|
|
118
116
|
// don't do anything, it's the system message
|
|
119
117
|
return;
|
|
120
118
|
}
|
|
121
|
-
|
|
122
|
-
// don't do anything, it's a message from another conversation
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
(0, utils_1.trackMessage)('received');
|
|
119
|
+
(0, analytics_1.trackMessage)('received');
|
|
126
120
|
this.props.updateLastMessage(event.conversationId, event);
|
|
127
121
|
yield this.props.addEventToConversation(event);
|
|
128
122
|
// there's no focus on the actual conversation
|
|
@@ -133,27 +127,11 @@ class Web extends react_1.default.Component {
|
|
|
133
127
|
this.handleResetUnreadCount();
|
|
134
128
|
});
|
|
135
129
|
this.handleTyping = (event) => __awaiter(this, void 0, void 0, function* () {
|
|
136
|
-
if (!this.isCurrentConversation(event)) {
|
|
137
|
-
// don't do anything, it's a message from another conversation
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
130
|
yield this.props.updateTyping(event);
|
|
141
131
|
});
|
|
142
|
-
this.handleDataMessage = (event) => {
|
|
143
|
-
if (!event || !event.payload) {
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
const { language } = event.payload;
|
|
147
|
-
if (!language) {
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
this.props.updateBotUILanguage(language);
|
|
151
|
-
};
|
|
152
132
|
this.playSound = (0, debounce_1.default)(() => __awaiter(this, void 0, void 0, function* () {
|
|
153
|
-
|
|
154
|
-
const disableNotificationSound = this.config.disableNotificationSound ===
|
|
155
|
-
? this.props.config.disableNotificationSound
|
|
156
|
-
: this.config.disableNotificationSound;
|
|
133
|
+
var _c;
|
|
134
|
+
const disableNotificationSound = this.config.disableNotificationSound || ((_c = this.props.config) === null || _c === void 0 ? void 0 : _c.disableNotificationSound);
|
|
157
135
|
if (disableNotificationSound || this.audio.readyState < 2) {
|
|
158
136
|
return;
|
|
159
137
|
}
|
|
@@ -164,17 +142,16 @@ class Web extends react_1.default.Component {
|
|
|
164
142
|
this.props.resetUnread();
|
|
165
143
|
}
|
|
166
144
|
};
|
|
167
|
-
(0,
|
|
168
|
-
(0, utils_1.initializeAnalytics)();
|
|
145
|
+
(0, analytics_1.initializeAnalytics)();
|
|
169
146
|
}
|
|
170
147
|
componentDidMount() {
|
|
171
148
|
return __awaiter(this, void 0, void 0, function* () {
|
|
172
149
|
this.audio = new Audio(require('url:../assets/notification.mp3'));
|
|
173
|
-
this.props.
|
|
150
|
+
this.props.setIntlProvider(this.props.intl);
|
|
174
151
|
window.store = this.props.store;
|
|
175
152
|
window.addEventListener('message', this.handleIframeApi);
|
|
176
153
|
window.addEventListener('keydown', this.handleKeyDown);
|
|
177
|
-
yield this.
|
|
154
|
+
yield this.loadConfig();
|
|
178
155
|
yield this.initializeIfChatDisplayed();
|
|
179
156
|
this.props.setLoadingCompleted();
|
|
180
157
|
});
|
|
@@ -198,27 +175,24 @@ class Web extends react_1.default.Component {
|
|
|
198
175
|
if (this.isLazySocket() || !this.socket) {
|
|
199
176
|
yield this.initializeSocket();
|
|
200
177
|
}
|
|
201
|
-
yield this.socket.
|
|
202
|
-
this.props.
|
|
178
|
+
yield this.socket.connect();
|
|
179
|
+
this.props.setSocket(this.socket);
|
|
203
180
|
yield this.props.initializeChat();
|
|
204
181
|
}
|
|
205
182
|
});
|
|
206
183
|
}
|
|
207
|
-
|
|
184
|
+
loadConfig() {
|
|
208
185
|
return __awaiter(this, void 0, void 0, function* () {
|
|
209
186
|
this.config = this.extractConfig();
|
|
187
|
+
this.props.updateConfig(this.config);
|
|
210
188
|
if (this.config.exposeStore) {
|
|
211
189
|
const storePath = this.config.chatId ? `${this.config.chatId}.webchat_store` : 'webchat_store';
|
|
212
190
|
(0, set_1.default)(window.parent, storePath, this.props.store);
|
|
213
191
|
}
|
|
214
|
-
if (this.config.overrides) {
|
|
215
|
-
this.loadOverrides(this.config.overrides);
|
|
216
|
-
}
|
|
217
192
|
if (this.config.containerWidth) {
|
|
218
193
|
this.postMessageToParent('setWidth', this.config.containerWidth);
|
|
219
194
|
}
|
|
220
|
-
|
|
221
|
-
// await this.props.fetchBotInfo!()
|
|
195
|
+
yield this.props.fetchBotInfo();
|
|
222
196
|
if (!this.isLazySocket()) {
|
|
223
197
|
yield this.initializeSocket();
|
|
224
198
|
}
|
|
@@ -226,68 +200,38 @@ class Web extends react_1.default.Component {
|
|
|
226
200
|
});
|
|
227
201
|
}
|
|
228
202
|
postMessageToParent(type, value) {
|
|
229
|
-
var _a
|
|
230
|
-
(_a = window.parent) === null || _a === void 0 ? void 0 : _a.postMessage({ type, value, chatId:
|
|
203
|
+
var _a;
|
|
204
|
+
(_a = window.parent) === null || _a === void 0 ? void 0 : _a.postMessage({ type, value, chatId: this.config.chatId }, '*');
|
|
231
205
|
}
|
|
232
206
|
extractConfig() {
|
|
233
|
-
|
|
234
|
-
try {
|
|
235
|
-
return decodeURIComponent(options);
|
|
236
|
-
}
|
|
237
|
-
catch (_a) {
|
|
238
|
-
return options;
|
|
239
|
-
}
|
|
240
|
-
};
|
|
207
|
+
let userConfig = Object.assign({}, constants_1.default.DEFAULT_CONFIG, this.props.config);
|
|
241
208
|
const { options } = query_string_1.default.parse(location.search);
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
209
|
+
if (!options || typeof options !== 'string') {
|
|
210
|
+
console.warn(`Cannot decode option. Invalid format: ${typeof options}, expecting 'string'.`);
|
|
211
|
+
return userConfig;
|
|
212
|
+
}
|
|
213
|
+
try {
|
|
214
|
+
const parsedOptions = JSON.parse(decodeURIComponent(options));
|
|
215
|
+
userConfig = Object.assign(userConfig, parsedOptions.config);
|
|
216
|
+
return userConfig;
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
// TODO: Handle those errors so they don't directly bubble up to the users
|
|
220
|
+
throw new Error(`An error occurred while extracting the configurations ${err}`);
|
|
221
|
+
}
|
|
246
222
|
}
|
|
247
223
|
initializeSocket() {
|
|
248
224
|
return __awaiter(this, void 0, void 0, function* () {
|
|
249
225
|
this.socket = new socket_1.default(this.config);
|
|
250
|
-
this.socket.onClear = this.handleClearMessages;
|
|
251
226
|
this.socket.onMessage = this.handleNewMessage;
|
|
252
|
-
this.socket.onTyping = this.handleTyping;
|
|
253
|
-
this.socket.onData = this.handleDataMessage;
|
|
254
|
-
this.socket.onUserIdChanged = this.props.setUserId;
|
|
255
|
-
// TODO: Can't do that
|
|
256
|
-
// this.config.userId && this.socket.changeUserId(this.config.userId)
|
|
257
227
|
this.socket.setup();
|
|
258
|
-
yield this.socket.
|
|
259
|
-
this.props.
|
|
228
|
+
yield this.socket.connect();
|
|
229
|
+
this.props.setSocket(this.socket);
|
|
260
230
|
});
|
|
261
231
|
}
|
|
262
|
-
loadOverrides(overrides) {
|
|
263
|
-
try {
|
|
264
|
-
for (const override of Object.values(overrides)) {
|
|
265
|
-
// TODO: load module view this can't work
|
|
266
|
-
// override.map(({ module }) => this.props.bp!.loadModuleView(module, true))
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
catch (err) {
|
|
270
|
-
console.error('Error while loading overrides', err.message);
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
232
|
setupObserver() {
|
|
274
|
-
(0, mobx_1.observe)(this.props.config, 'userId', (data) => __awaiter(this, void 0, void 0, function* () {
|
|
275
|
-
if (!data.oldValue || data.oldValue === data.newValue) {
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
// TODO: Can't work right now
|
|
279
|
-
// this.socket.changeUserId(data.newValue)
|
|
280
|
-
this.socket.setup();
|
|
281
|
-
yield this.socket.waitForUserId();
|
|
282
|
-
yield this.props.initializeChat();
|
|
283
|
-
}));
|
|
284
|
-
(0, mobx_1.observe)(this.props.config, 'overrides', (data) => {
|
|
285
|
-
if (data.newValue && window.parent) {
|
|
286
|
-
this.loadOverrides(data.newValue);
|
|
287
|
-
}
|
|
288
|
-
});
|
|
289
233
|
(0, mobx_1.observe)(this.props.dimensions, 'container', (data) => {
|
|
290
|
-
if (data.newValue
|
|
234
|
+
if (data.newValue) {
|
|
291
235
|
this.postMessageToParent('setWidth', data.newValue);
|
|
292
236
|
}
|
|
293
237
|
});
|
|
@@ -310,20 +254,22 @@ class Web extends react_1.default.Component {
|
|
|
310
254
|
this.props.hasUnreadMessages && react_1.default.createElement("span", { className: 'bpw-floating-button-unread' }, this.props.unreadCount)));
|
|
311
255
|
}
|
|
312
256
|
applyAndRenderStyle() {
|
|
257
|
+
var _a, _b, _c;
|
|
313
258
|
const parentClass = (0, classnames_1.default)(`bp-widget-web bp-widget-${this.props.activeView}`, {
|
|
314
259
|
'bp-widget-hidden': !this.props.showWidgetButton && this.props.displayWidgetView,
|
|
315
|
-
[this.props.config.className]: !!this.props.config.className
|
|
260
|
+
[(_a = this.props.config) === null || _a === void 0 ? void 0 : _a.className]: !!((_b = this.props.config) === null || _b === void 0 ? void 0 : _b.className)
|
|
316
261
|
});
|
|
317
262
|
if (this.parentClass !== parentClass) {
|
|
318
263
|
this.postMessageToParent('setClass', parentClass);
|
|
319
264
|
this.parentClass = parentClass;
|
|
320
265
|
}
|
|
321
|
-
const
|
|
266
|
+
const stylesheet = this.props.config.stylesheet;
|
|
267
|
+
const extraStylesheet = (_c = this.props.botInfo) === null || _c === void 0 ? void 0 : _c.extraStylesheet;
|
|
322
268
|
const RobotoFont = react_1.default.lazy(() => Promise.resolve().then(() => __importStar(require('./fonts/roboto'))));
|
|
323
269
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
324
|
-
!!(stylesheet === null || stylesheet === void 0 ? void 0 : stylesheet.length) && react_1.default.createElement(
|
|
270
|
+
!!(stylesheet === null || stylesheet === void 0 ? void 0 : stylesheet.length) && react_1.default.createElement("link", { rel: "stylesheet", type: "text/css", href: stylesheet }),
|
|
325
271
|
react_1.default.createElement(react_1.default.Suspense, { fallback: react_1.default.createElement(react_1.default.Fragment, null) }, !utils_1.isIE && react_1.default.createElement(RobotoFont, null)),
|
|
326
|
-
!!(extraStylesheet === null || extraStylesheet === void 0 ? void 0 : extraStylesheet.length) && react_1.default.createElement(
|
|
272
|
+
!!(extraStylesheet === null || extraStylesheet === void 0 ? void 0 : extraStylesheet.length) && react_1.default.createElement("link", { rel: "stylesheet", type: "text/css", href: extraStylesheet })));
|
|
327
273
|
}
|
|
328
274
|
render() {
|
|
329
275
|
if (!this.props.isWebchatReady) {
|
|
@@ -349,7 +295,6 @@ exports.default = (0, mobx_react_1.inject)(({ store }) => ({
|
|
|
349
295
|
mergeConfig: store.mergeConfig,
|
|
350
296
|
addEventToConversation: store.addEventToConversation,
|
|
351
297
|
clearMessages: store.clearMessages,
|
|
352
|
-
setUserId: store.setUserId,
|
|
353
298
|
updateTyping: store.updateTyping,
|
|
354
299
|
sendMessage: store.sendMessage,
|
|
355
300
|
updateBotUILanguage: store.updateBotUILanguage,
|
|
@@ -369,5 +314,9 @@ exports.default = (0, mobx_react_1.inject)(({ store }) => ({
|
|
|
369
314
|
displayWidgetView: store.view.displayWidgetView,
|
|
370
315
|
setLoadingCompleted: store.view.setLoadingCompleted,
|
|
371
316
|
sendFeedback: store.sendFeedback,
|
|
372
|
-
updateLastMessage: store.updateLastMessage
|
|
317
|
+
updateLastMessage: store.updateLastMessage,
|
|
318
|
+
fetchConversation: store.fetchConversation,
|
|
319
|
+
setIntlProvider: store.setIntlProvider,
|
|
320
|
+
setSocket: store.setSocket,
|
|
321
|
+
currentConversationId: store.currentConversationId
|
|
373
322
|
}))((0, react_intl_1.injectIntl)((0, mobx_react_1.observer)(Web)));
|
package/dist/store/composer.js
CHANGED
package/dist/store/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { IntlShape } from 'react-intl';
|
|
3
3
|
import BpSocket from '../core/socket';
|
|
4
|
-
import { BotInfo, Config, CurrentConversation, EventFeedback, Message, QueuedMessage, RecentConversation,
|
|
4
|
+
import { BotInfo, Config, CurrentConversation, EventFeedback, Message, QueuedMessage, RecentConversation, uuid } from '../typings';
|
|
5
5
|
import ComposerStore from './composer';
|
|
6
6
|
import ViewStore from './view';
|
|
7
|
-
/** Includes the
|
|
7
|
+
/** Includes the definitions of all store classes */
|
|
8
8
|
export declare type StoreDef = Partial<RootStore> & Partial<ViewStore> & Partial<ComposerStore> & Partial<Config>;
|
|
9
9
|
declare class RootStore {
|
|
10
10
|
composer: ComposerStore;
|
|
@@ -24,7 +24,7 @@ declare class RootStore {
|
|
|
24
24
|
delayedMessages: QueuedMessage[];
|
|
25
25
|
constructor(options: {
|
|
26
26
|
fullscreen: boolean;
|
|
27
|
-
}, config
|
|
27
|
+
}, config?: Config);
|
|
28
28
|
setIntlProvider(provider: IntlShape): void;
|
|
29
29
|
setSocket(socket: BpSocket): void;
|
|
30
30
|
get isConversationStarted(): boolean;
|
|
@@ -57,22 +57,18 @@ declare class RootStore {
|
|
|
57
57
|
/** Creates a new conversation and switches to it */
|
|
58
58
|
createConversation(): Promise<uuid>;
|
|
59
59
|
resetConversation(): void;
|
|
60
|
-
resetSession(): Promise<void>;
|
|
61
60
|
extractFeedback(messages: Message[]): Promise<void>;
|
|
62
61
|
sendFeedback(feedback: number, messageId: string): Promise<void>;
|
|
63
62
|
downloadConversation(): Promise<void>;
|
|
64
63
|
/** Sends an event or a message, depending on how the backend manages those types */
|
|
65
64
|
sendData(data: any): Promise<void>;
|
|
66
|
-
uploadFile(title: string, payload: string, file: File): Promise<void>;
|
|
67
65
|
/** Sends a message of type voice */
|
|
68
66
|
sendVoiceMessage(voice: Buffer, ext: string): Promise<void>;
|
|
69
67
|
/** Use this method to replace a value or add a new config */
|
|
70
68
|
mergeConfig(config: Partial<Config>): void;
|
|
71
69
|
/** This replaces all the configurations by this object */
|
|
72
|
-
updateConfig(config: Config
|
|
70
|
+
updateConfig(config: Config): void;
|
|
73
71
|
private _applyConfig;
|
|
74
|
-
/** When this method is used, the user ID is changed in the configuration, then the socket is updated */
|
|
75
|
-
setUserId(userId: string): void;
|
|
76
72
|
publishConfigChanged(): void;
|
|
77
73
|
updatePreferredLanguage(lang: string): void;
|
|
78
74
|
/** Starts a timer to remove the typing animation when it's completed */
|
|
@@ -80,7 +76,7 @@ declare class RootStore {
|
|
|
80
76
|
private _expireTyping;
|
|
81
77
|
updateBotUILanguage(lang: string): void;
|
|
82
78
|
private emptyDelayedMessagesQueue;
|
|
83
|
-
/** Returns the current conversation ID, or the last one
|
|
79
|
+
/** Returns the current conversation ID, or the last one. */
|
|
84
80
|
private _getCurrentConvoId;
|
|
85
81
|
}
|
|
86
82
|
export { RootStore };
|
package/dist/store/index.js
CHANGED
|
@@ -19,6 +19,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
19
19
|
};
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
21
|
exports.RootStore = void 0;
|
|
22
|
+
const axios_1 = __importDefault(require("axios"));
|
|
22
23
|
const is_before_1 = __importDefault(require("date-fns/is_before"));
|
|
23
24
|
const is_valid_1 = __importDefault(require("date-fns/is_valid"));
|
|
24
25
|
const merge_1 = __importDefault(require("lodash/merge"));
|
|
@@ -28,6 +29,7 @@ const api_1 = __importDefault(require("../core/api"));
|
|
|
28
29
|
const main_1 = require("../main");
|
|
29
30
|
const translations_1 = require("../translations");
|
|
30
31
|
const utils_1 = require("../utils");
|
|
32
|
+
const analytics_1 = require("../utils/analytics");
|
|
31
33
|
const composer_1 = __importDefault(require("./composer"));
|
|
32
34
|
const view_1 = __importDefault(require("./view"));
|
|
33
35
|
class RootStore {
|
|
@@ -37,7 +39,9 @@ class RootStore {
|
|
|
37
39
|
this.delayedMessages = [];
|
|
38
40
|
this.composer = new composer_1.default(this);
|
|
39
41
|
this.view = new view_1.default(this, options.fullscreen);
|
|
40
|
-
|
|
42
|
+
if (config) {
|
|
43
|
+
this.updateConfig(config);
|
|
44
|
+
}
|
|
41
45
|
this.botUILanguage = (0, translations_1.getUserLocale)();
|
|
42
46
|
}
|
|
43
47
|
setIntlProvider(provider) {
|
|
@@ -51,19 +55,19 @@ class RootStore {
|
|
|
51
55
|
return !!((_a = this.currentConversation) === null || _a === void 0 ? void 0 : _a.messages.length);
|
|
52
56
|
}
|
|
53
57
|
get botName() {
|
|
54
|
-
var _a;
|
|
55
|
-
return this.config.botName || ((
|
|
58
|
+
var _a, _b;
|
|
59
|
+
return ((_a = this.config) === null || _a === void 0 ? void 0 : _a.botName) || ((_b = this.botInfo) === null || _b === void 0 ? void 0 : _b.name) || 'Bot';
|
|
56
60
|
}
|
|
57
61
|
get hasBotInfoDescription() {
|
|
58
62
|
var _a;
|
|
59
|
-
return !!((_a = this.config.
|
|
63
|
+
return !!((_a = this.config.botConversationDescription) === null || _a === void 0 ? void 0 : _a.length);
|
|
60
64
|
}
|
|
61
65
|
get botAvatarUrl() {
|
|
62
66
|
var _a, _b, _c;
|
|
63
67
|
return ((_b = (_a = this.botInfo) === null || _a === void 0 ? void 0 : _a.details) === null || _b === void 0 ? void 0 : _b.avatarUrl) || ((_c = this.config) === null || _c === void 0 ? void 0 : _c.avatarUrl) || undefined;
|
|
64
68
|
}
|
|
65
69
|
get rtl() {
|
|
66
|
-
return (0,
|
|
70
|
+
return (0, translations_1.isRTLLocale)(this.preferredLanguage);
|
|
67
71
|
}
|
|
68
72
|
get escapeHTML() {
|
|
69
73
|
var _a, _b;
|
|
@@ -153,7 +157,7 @@ class RootStore {
|
|
|
153
157
|
return __awaiter(this, void 0, void 0, function* () {
|
|
154
158
|
try {
|
|
155
159
|
yield this.fetchConversations();
|
|
156
|
-
yield this.fetchConversation(
|
|
160
|
+
yield this.fetchConversation();
|
|
157
161
|
(0, mobx_1.runInAction)('-> setInitialized', () => {
|
|
158
162
|
this.isInitialized = true;
|
|
159
163
|
this.postMessage('webchatReady');
|
|
@@ -171,17 +175,21 @@ class RootStore {
|
|
|
171
175
|
if (!this.config.mediaFileServiceUrl) {
|
|
172
176
|
return;
|
|
173
177
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
178
|
+
try {
|
|
179
|
+
const { data } = yield axios_1.default.get(this.config.mediaFileServiceUrl);
|
|
180
|
+
if (!data) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
(0, mobx_1.runInAction)('-> setBotInfo', () => {
|
|
184
|
+
this.botInfo = data;
|
|
185
|
+
});
|
|
186
|
+
this.mergeConfig({
|
|
187
|
+
disableNotificationSound: data.disableNotificationSound
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
catch (err) {
|
|
191
|
+
console.error('Error while loading bot info', err);
|
|
177
192
|
}
|
|
178
|
-
(0, mobx_1.runInAction)('-> setBotInfo', () => {
|
|
179
|
-
this.botInfo = botInfo;
|
|
180
|
-
});
|
|
181
|
-
this.mergeConfig({
|
|
182
|
-
extraStylesheet: botInfo.extraStylesheet,
|
|
183
|
-
disableNotificationSound: botInfo.disableNotificationSound
|
|
184
|
-
});
|
|
185
193
|
});
|
|
186
194
|
}
|
|
187
195
|
fetchLanguage() {
|
|
@@ -233,7 +241,7 @@ class RootStore {
|
|
|
233
241
|
this.composer.updateMessage('');
|
|
234
242
|
try {
|
|
235
243
|
yield this.sendData({ type: 'text', text: userMessage });
|
|
236
|
-
(0,
|
|
244
|
+
(0, analytics_1.trackMessage)('sent');
|
|
237
245
|
this.composer.addMessageToHistory(userMessage);
|
|
238
246
|
}
|
|
239
247
|
catch (e) {
|
|
@@ -262,18 +270,9 @@ class RootStore {
|
|
|
262
270
|
resetConversation() {
|
|
263
271
|
this.currentConversation = undefined;
|
|
264
272
|
}
|
|
265
|
-
resetSession() {
|
|
266
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
267
|
-
if (this.currentConversationId) {
|
|
268
|
-
this.composer.setLocked(false);
|
|
269
|
-
return this.api.resetSession(this.currentConversationId);
|
|
270
|
-
}
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
273
|
extractFeedback(messages) {
|
|
274
274
|
return __awaiter(this, void 0, void 0, function* () {
|
|
275
275
|
const feedbackMessageIds = messages.filter((x) => x.payload && x.payload.collectFeedback).map((x) => x.id);
|
|
276
|
-
// TODO: store feedback somewhere
|
|
277
276
|
const feedbackInfo = feedbackMessageIds.map((x) => ({ messageId: x, feedback: 1 }));
|
|
278
277
|
(0, mobx_1.runInAction)('-> setFeedbackInfo', () => {
|
|
279
278
|
this.messageFeedbacks = feedbackInfo;
|
|
@@ -297,8 +296,20 @@ class RootStore {
|
|
|
297
296
|
return;
|
|
298
297
|
}
|
|
299
298
|
let info = `Conversation Id: ${conversation.id}\nCreated on: ${formatDate(conversation.createdOn)}\nUser: ${conversation.userId}\n-----------------`;
|
|
300
|
-
|
|
301
|
-
|
|
299
|
+
const messages = yield this.api.listCurrentConversationMessages(500);
|
|
300
|
+
for (const message of (0, orderBy_1.default)(messages, 'sentOn', 'desc')) {
|
|
301
|
+
const payload = message.payload;
|
|
302
|
+
if (payload.type === 'session_reset') {
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
info += `\n[${formatDate(message.sentOn)}] ${message.authorId ? 'User' : this.config.botName || 'Bot'}: Event (${payload.type}): ${payload.text ||
|
|
306
|
+
payload.audio ||
|
|
307
|
+
payload.image ||
|
|
308
|
+
payload.video ||
|
|
309
|
+
payload.file ||
|
|
310
|
+
payload.message ||
|
|
311
|
+
payload.title ||
|
|
312
|
+
''}`;
|
|
302
313
|
}
|
|
303
314
|
const blobFile = new Blob([info]);
|
|
304
315
|
(0, utils_1.downloadFile)(`conversation-${conversation.id}`, blobFile);
|
|
@@ -319,13 +330,6 @@ class RootStore {
|
|
|
319
330
|
this.updateLastMessage(this.currentConversationId, message);
|
|
320
331
|
});
|
|
321
332
|
}
|
|
322
|
-
uploadFile(title, payload, file) {
|
|
323
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
324
|
-
if (this.currentConversationId) {
|
|
325
|
-
yield this.api.uploadFile(file, payload, this.currentConversationId);
|
|
326
|
-
}
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
333
|
/** Sends a message of type voice */
|
|
330
334
|
sendVoiceMessage(voice, ext) {
|
|
331
335
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -340,7 +344,7 @@ class RootStore {
|
|
|
340
344
|
this._applyConfig();
|
|
341
345
|
}
|
|
342
346
|
/** This replaces all the configurations by this object */
|
|
343
|
-
updateConfig(config
|
|
347
|
+
updateConfig(config) {
|
|
344
348
|
this.config = config;
|
|
345
349
|
this._applyConfig();
|
|
346
350
|
}
|
|
@@ -348,13 +352,11 @@ class RootStore {
|
|
|
348
352
|
window.BP_STORAGE.config = this.config;
|
|
349
353
|
this.config.layoutWidth && this.view.setLayoutWidth(this.config.layoutWidth);
|
|
350
354
|
this.config.containerWidth && this.view.setContainerWidth(this.config.containerWidth);
|
|
351
|
-
this.view.disableAnimations = this.config.disableAnimations;
|
|
355
|
+
this.view.disableAnimations = !!this.config.disableAnimations;
|
|
352
356
|
this.config.showPoweredBy ? this.view.showPoweredBy() : this.view.hidePoweredBy();
|
|
353
357
|
document.title = this.config.botName || 'Botpress Webchat';
|
|
354
|
-
// TODO: can't work at the moment
|
|
355
|
-
// this.api.updateUserId(this.config.userId!)
|
|
356
358
|
if (!this.isInitialized) {
|
|
357
|
-
window.USE_SESSION_STORAGE = this.config.useSessionStorage;
|
|
359
|
+
window.USE_SESSION_STORAGE = !!this.config.useSessionStorage;
|
|
358
360
|
}
|
|
359
361
|
else if (window.USE_SESSION_STORAGE !== this.config.useSessionStorage) {
|
|
360
362
|
console.warn('[WebChat] "useSessionStorage" value cannot be altered once the webchat is initialized');
|
|
@@ -364,13 +366,6 @@ class RootStore {
|
|
|
364
366
|
document.documentElement.setAttribute('lang', locale);
|
|
365
367
|
this.publishConfigChanged();
|
|
366
368
|
}
|
|
367
|
-
/** When this method is used, the user ID is changed in the configuration, then the socket is updated */
|
|
368
|
-
setUserId(userId) {
|
|
369
|
-
this.config.userId = userId;
|
|
370
|
-
this.resetConversation();
|
|
371
|
-
// this.api.updateUserId(userId)
|
|
372
|
-
this.publishConfigChanged();
|
|
373
|
-
}
|
|
374
369
|
publishConfigChanged() {
|
|
375
370
|
this.postMessage('configChanged', JSON.stringify(this.config, undefined, 2));
|
|
376
371
|
}
|
|
@@ -427,7 +422,7 @@ class RootStore {
|
|
|
427
422
|
}
|
|
428
423
|
}
|
|
429
424
|
}
|
|
430
|
-
/** Returns the current conversation ID, or the last one
|
|
425
|
+
/** Returns the current conversation ID, or the last one. */
|
|
431
426
|
_getCurrentConvoId() {
|
|
432
427
|
if (this.currentConversationId) {
|
|
433
428
|
return this.currentConversationId;
|
|
@@ -435,15 +430,6 @@ class RootStore {
|
|
|
435
430
|
if (!this.conversations.length) {
|
|
436
431
|
return;
|
|
437
432
|
}
|
|
438
|
-
// TODO: these settings need to be set in the frontend
|
|
439
|
-
/*
|
|
440
|
-
const lifeTimeMargin = Date.now() - ms(this.config.recentConversationLifetime)
|
|
441
|
-
const isConversationExpired =
|
|
442
|
-
new Date(this.conversations[0].lastMessage?.sentOn || this.conversations[0].createdOn).getTime() < lifeTimeMargin
|
|
443
|
-
if (isConversationExpired && this.config.startNewConvoOnTimeout) {
|
|
444
|
-
return
|
|
445
|
-
}
|
|
446
|
-
*/
|
|
447
433
|
return this.conversations[0].id;
|
|
448
434
|
}
|
|
449
435
|
}
|
|
@@ -549,9 +535,6 @@ __decorate([
|
|
|
549
535
|
__decorate([
|
|
550
536
|
mobx_1.action.bound
|
|
551
537
|
], RootStore.prototype, "resetConversation", null);
|
|
552
|
-
__decorate([
|
|
553
|
-
mobx_1.action.bound
|
|
554
|
-
], RootStore.prototype, "resetSession", null);
|
|
555
538
|
__decorate([
|
|
556
539
|
mobx_1.action.bound
|
|
557
540
|
], RootStore.prototype, "extractFeedback", null);
|
|
@@ -564,9 +547,6 @@ __decorate([
|
|
|
564
547
|
__decorate([
|
|
565
548
|
mobx_1.action.bound
|
|
566
549
|
], RootStore.prototype, "sendData", null);
|
|
567
|
-
__decorate([
|
|
568
|
-
mobx_1.action.bound
|
|
569
|
-
], RootStore.prototype, "uploadFile", null);
|
|
570
550
|
__decorate([
|
|
571
551
|
mobx_1.action.bound
|
|
572
552
|
], RootStore.prototype, "sendVoiceMessage", null);
|
|
@@ -576,9 +556,6 @@ __decorate([
|
|
|
576
556
|
__decorate([
|
|
577
557
|
mobx_1.action.bound
|
|
578
558
|
], RootStore.prototype, "updateConfig", null);
|
|
579
|
-
__decorate([
|
|
580
|
-
mobx_1.action.bound
|
|
581
|
-
], RootStore.prototype, "setUserId", null);
|
|
582
559
|
__decorate([
|
|
583
560
|
mobx_1.action.bound
|
|
584
561
|
], RootStore.prototype, "publishConfigChanged", null);
|