@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.
Files changed (57) hide show
  1. package/README.md +31 -0
  2. package/dist/components/Composer.d.ts +4 -5
  3. package/dist/components/Composer.js +16 -25
  4. package/dist/components/Container.js +1 -4
  5. package/dist/components/ConversationList.d.ts +1 -1
  6. package/dist/components/ConversationList.js +5 -46
  7. package/dist/components/Header.d.ts +1 -3
  8. package/dist/components/Header.js +7 -37
  9. package/dist/components/common/BotInfo/index.d.ts +1 -1
  10. package/dist/components/common/BotInfo/index.js +4 -14
  11. package/dist/components/messages/InlineFeedback.d.ts +2 -1
  12. package/dist/components/messages/Message.js +3 -6
  13. package/dist/components/messages/MessageGroup.d.ts +1 -5
  14. package/dist/components/messages/MessageGroup.js +4 -7
  15. package/dist/components/messages/MessageList.d.ts +1 -1
  16. package/dist/components/messages/MessageList.js +7 -29
  17. package/dist/core/api.d.ts +2 -7
  18. package/dist/core/api.js +5 -29
  19. package/dist/core/constants.d.ts +4 -32
  20. package/dist/core/constants.js +18 -32
  21. package/dist/core/socket.d.ts +1 -7
  22. package/dist/core/socket.js +8 -30
  23. package/dist/index.d.ts +3 -9
  24. package/dist/index.js +8 -35
  25. package/dist/main.d.ts +2 -2
  26. package/dist/main.js +84 -135
  27. package/dist/store/composer.js +1 -1
  28. package/dist/store/index.d.ts +5 -9
  29. package/dist/store/index.js +43 -66
  30. package/dist/store/view.d.ts +3 -4
  31. package/dist/store/view.js +6 -13
  32. package/dist/translations/index.d.ts +2 -1
  33. package/dist/translations/index.js +36 -1
  34. package/dist/typings.d.ts +123 -55
  35. package/dist/utils/analytics.d.ts +5 -0
  36. package/dist/utils/analytics.js +37 -0
  37. package/dist/utils/index.d.ts +3 -0
  38. package/dist/utils/index.js +27 -0
  39. package/dist/utils/storage.d.ts +4 -5
  40. package/dist/utils/storage.js +23 -11
  41. package/package.json +4 -4
  42. package/dist/components/ContextMenu.d.ts +0 -2
  43. package/dist/components/ContextMenu.js +0 -24
  44. package/dist/components/OverridableComponent.d.ts +0 -24
  45. package/dist/components/OverridableComponent.js +0 -50
  46. package/dist/components/Stylesheet.d.ts +0 -5
  47. package/dist/components/Stylesheet.js +0 -7
  48. package/dist/components/common/MoreOptions/index.d.ts +0 -21
  49. package/dist/components/common/MoreOptions/index.js +0 -60
  50. package/dist/components/common/Overlay/index.d.ts +0 -7
  51. package/dist/components/common/Overlay/index.js +0 -36
  52. package/dist/icons/CloseChat.d.ts +0 -6
  53. package/dist/icons/CloseChat.js +0 -9
  54. package/dist/icons/Send.d.ts +0 -6
  55. package/dist/icons/Send.js +0 -8
  56. package/dist/utils.d.ts +0 -8
  57. 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
- var _a, _b;
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: { action, payload } }) => __awaiter(this, void 0, void 0, function* () {
68
- if (action === 'configure') {
69
- this.props.updateConfig(Object.assign({}, constants_1.default.DEFAULT_CONFIG, payload));
70
- }
71
- else if (action === 'mergeConfig') {
72
- this.props.mergeConfig(payload);
73
- }
74
- else if (action === 'sendPayload') {
75
- yield this.props.sendData(payload);
76
- }
77
- else if (action === 'event') {
78
- const { type, text } = payload;
79
- if (type === 'show') {
80
- this.props.showChat();
81
- (0, utils_1.trackWebchatState)('show');
82
- }
83
- else if (type === 'hide') {
84
- this.props.hideChat();
85
- (0, utils_1.trackWebchatState)('hide');
86
- }
87
- else if (type === 'toggle') {
88
- this.props.displayWidgetView ? this.props.showChat() : this.props.hideChat();
89
- (0, utils_1.trackWebchatState)('toggle');
90
- }
91
- else if (type === 'message') {
92
- (0, utils_1.trackMessage)('sent');
93
- yield this.props.sendMessage(text);
94
- }
95
- else if (type === 'loadConversation') {
96
- yield this.props.store.fetchConversation(payload.conversationId);
97
- }
98
- else if (type === 'toggleBotInfo') {
99
- this.props.toggleBotInfo();
100
- }
101
- else {
102
- yield this.props.sendData({ type, payload });
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
- if (!this.isCurrentConversation(event)) {
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
- // Preference for config object
154
- const disableNotificationSound = this.config.disableNotificationSound === undefined
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, utils_1.checkLocationOrigin)();
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.store.setIntlProvider(this.props.intl);
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.load();
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.waitForUserId();
202
- this.props.store.setSocket(this.socket);
178
+ yield this.socket.connect();
179
+ this.props.setSocket(this.socket);
203
180
  yield this.props.initializeChat();
204
181
  }
205
182
  });
206
183
  }
207
- load() {
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
- // TODO: replace this by frontend configuration
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, _b;
230
- (_a = window.parent) === null || _a === void 0 ? void 0 : _a.postMessage({ type, value, chatId: (_b = this.config) === null || _b === void 0 ? void 0 : _b.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
- const decodeIfRequired = (options) => {
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
- const { config } = JSON.parse(decodeIfRequired(options || '{}'));
243
- const userConfig = Object.assign({}, constants_1.default.DEFAULT_CONFIG, this.props.config, config);
244
- this.props.updateConfig(userConfig);
245
- return userConfig;
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.waitForUserId();
259
- this.props.store.setSocket(this.socket);
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 && window.parent) {
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 { stylesheet, extraStylesheet } = this.props.config;
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(Stylesheet_1.default, { href: stylesheet }),
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(Stylesheet_1.default, { href: extraStylesheet })));
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)));
@@ -56,7 +56,7 @@ class ComposerStore {
56
56
  this._sentHistoryIndex = newIndex;
57
57
  }
58
58
  setLocked(locked) {
59
- this.locked = locked;
59
+ this.locked = !!locked;
60
60
  }
61
61
  setHidden(hidden) {
62
62
  this.hidden = hidden;
@@ -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, StudioConnector, uuid } from '../typings';
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 partial definitions of all classes */
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: 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, bp?: StudioConnector): void;
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 if it didn't expired. Otherwise, returns nothing. */
79
+ /** Returns the current conversation ID, or the last one. */
84
80
  private _getCurrentConvoId;
85
81
  }
86
82
  export { RootStore };
@@ -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
- this.updateConfig(config);
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 || ((_a = this.botInfo) === null || _a === void 0 ? void 0 : _a.name) || 'Bot';
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.botConvoDescription) === null || _a === void 0 ? void 0 : _a.length);
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, utils_1.isRTLLocale)(this.preferredLanguage);
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(this.config.conversationId);
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
- const botInfo = yield this.api.fetchBotInfo(this.config.mediaFileServiceUrl);
175
- if (!botInfo) {
176
- return;
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, utils_1.trackMessage)('sent');
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
- for (const message of (0, orderBy_1.default)(conversation.messages, 'sentOn', 'desc')) {
301
- info += `\n[${formatDate(message.sentOn)}] ${message.authorId ? 'User' : this.config.botId || 'Bot'}: ${message.payload.text}`;
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, bp) {
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 if it didn't expired. Otherwise, returns nothing. */
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);