@botpress/webchat 0.2.3 → 0.3.0

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 (70) hide show
  1. package/README.md +31 -0
  2. package/dist/components/Composer.d.ts +4 -5
  3. package/dist/components/Composer.js +13 -23
  4. package/dist/components/Container.d.ts +1 -1
  5. package/dist/components/Container.js +1 -6
  6. package/dist/components/ConversationList.d.ts +1 -1
  7. package/dist/components/ConversationList.js +5 -46
  8. package/dist/components/Header.d.ts +1 -3
  9. package/dist/components/Header.js +17 -64
  10. package/dist/components/VoiceRecorder.js +6 -2
  11. package/dist/components/common/{Avatar.d.ts → Avatar/index.d.ts} +0 -0
  12. package/dist/components/common/Avatar/index.js +13 -0
  13. package/dist/components/common/{BotInfo.d.ts → BotInfo/index.d.ts} +3 -3
  14. package/dist/components/common/BotInfo/index.js +102 -0
  15. package/dist/components/common/ConfirmDialog/index.d.ts +11 -0
  16. package/dist/components/common/ConfirmDialog/index.js +78 -0
  17. package/dist/components/common/Dialog/index.d.ts +17 -0
  18. package/dist/components/common/Dialog/index.js +57 -0
  19. package/dist/components/common/ToolTip/index.d.ts +10 -0
  20. package/dist/components/common/ToolTip/index.js +163 -0
  21. package/dist/components/common/ToolTip/utils.d.ts +15 -0
  22. package/dist/components/common/ToolTip/utils.js +78 -0
  23. package/dist/components/messages/InlineFeedback.d.ts +2 -1
  24. package/dist/components/messages/Message.js +2 -25
  25. package/dist/components/messages/MessageGroup.d.ts +1 -13
  26. package/dist/components/messages/MessageGroup.js +6 -40
  27. package/dist/components/messages/MessageList.d.ts +1 -1
  28. package/dist/components/messages/MessageList.js +8 -31
  29. package/dist/core/api.d.ts +4 -18
  30. package/dist/core/api.js +25 -150
  31. package/dist/core/constants.d.ts +4 -32
  32. package/dist/core/constants.js +18 -32
  33. package/dist/core/socket.d.ts +1 -12
  34. package/dist/core/socket.js +7 -73
  35. package/dist/{components/Stylesheet.d.ts → icons/Cancel.d.ts} +2 -2
  36. package/dist/icons/Cancel.js +10 -0
  37. package/dist/icons/Microphone.d.ts +5 -0
  38. package/dist/icons/Microphone.js +12 -0
  39. package/dist/index.d.ts +2 -8
  40. package/dist/index.js +9 -29
  41. package/dist/main.d.ts +2 -2
  42. package/dist/main.js +100 -168
  43. package/dist/store/composer.js +3 -6
  44. package/dist/store/index.d.ts +8 -18
  45. package/dist/store/index.js +98 -136
  46. package/dist/store/view.d.ts +3 -6
  47. package/dist/store/view.js +6 -23
  48. package/dist/translations/index.d.ts +3 -1
  49. package/dist/translations/index.js +44 -4
  50. package/dist/typings.d.ts +121 -71
  51. package/dist/utils/analytics.d.ts +5 -0
  52. package/dist/utils/analytics.js +37 -0
  53. package/dist/utils/index.d.ts +3 -0
  54. package/dist/utils/index.js +27 -0
  55. package/dist/utils/storage.d.ts +16 -0
  56. package/dist/utils/storage.js +129 -0
  57. package/package.json +4 -3
  58. package/dist/components/ContextMenu.d.ts +0 -2
  59. package/dist/components/ContextMenu.js +0 -33
  60. package/dist/components/OverridableComponent.d.ts +0 -24
  61. package/dist/components/OverridableComponent.js +0 -50
  62. package/dist/components/Stylesheet.js +0 -7
  63. package/dist/components/common/Avatar.js +0 -29
  64. package/dist/components/common/BotInfo.js +0 -110
  65. package/dist/icons/CloseChat.d.ts +0 -6
  66. package/dist/icons/CloseChat.js +0 -9
  67. package/dist/icons/Send.d.ts +0 -6
  68. package/dist/icons/Send.js +0 -8
  69. package/dist/utils.d.ts +0 -8
  70. package/dist/utils.js +0 -111
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const react_1 = __importDefault(require("react"));
7
+ exports.default = ({ fill = 'black' }) => (react_1.default.createElement("i", null,
8
+ react_1.default.createElement("svg", { version: "1.1", xmlns: "http://www.w3.org/2000/svg", x: "0px", y: "0px", width: "16px", height: "16px", viewBox: "0 0 475.085 475.085", fill: `${fill}` },
9
+ react_1.default.createElement("g", null,
10
+ react_1.default.createElement("g", null,
11
+ react_1.default.createElement("path", { d: "M237.541,328.897c25.128,0,46.632-8.946,64.523-26.83c17.888-17.884,26.833-39.399,26.833-64.525V91.365\n c0-25.126-8.938-46.632-26.833-64.525C284.173,8.951,262.669,0,237.541,0c-25.125,0-46.632,8.951-64.524,26.84\n c-17.893,17.89-26.838,39.399-26.838,64.525v146.177c0,25.125,8.949,46.641,26.838,64.525\n C190.906,319.951,212.416,328.897,237.541,328.897z" }),
12
+ react_1.default.createElement("path", { d: "M396.563,188.15c-3.606-3.617-7.898-5.426-12.847-5.426c-4.944,0-9.226,1.809-12.847,5.426\n c-3.613,3.616-5.421,7.898-5.421,12.845v36.547c0,35.214-12.518,65.333-37.548,90.362c-25.022,25.03-55.145,37.545-90.36,37.545\n c-35.214,0-65.334-12.515-90.365-37.545c-25.028-25.022-37.541-55.147-37.541-90.362v-36.547c0-4.947-1.809-9.229-5.424-12.845\n c-3.617-3.617-7.895-5.426-12.847-5.426c-4.952,0-9.235,1.809-12.85,5.426c-3.618,3.616-5.426,7.898-5.426,12.845v36.547\n c0,42.065,14.04,78.659,42.112,109.776c28.073,31.118,62.762,48.961,104.068,53.526v37.691h-73.089\n c-4.949,0-9.231,1.811-12.847,5.428c-3.617,3.614-5.426,7.898-5.426,12.847c0,4.941,1.809,9.233,5.426,12.847\n c3.616,3.614,7.898,5.428,12.847,5.428h182.719c4.948,0,9.236-1.813,12.847-5.428c3.621-3.613,5.431-7.905,5.431-12.847\n c0-4.948-1.81-9.232-5.431-12.847c-3.61-3.617-7.898-5.428-12.847-5.428h-73.08v-37.691\n c41.299-4.565,75.985-22.408,104.061-53.526c28.076-31.117,42.12-67.711,42.12-109.776v-36.547\n C401.998,196.049,400.185,191.77,396.563,188.15z" }))))));
package/dist/index.d.ts CHANGED
@@ -1,8 +1,6 @@
1
1
  import React from 'react';
2
2
  import { RootStore } from './store';
3
3
  import { Config } from './typings';
4
- export declare const Embedded: (props: any) => ExposedWebChat;
5
- export declare const Fullscreen: (props: any) => ExposedWebChat;
6
4
  interface State {
7
5
  store: RootStore;
8
6
  }
@@ -14,10 +12,6 @@ export declare class ExposedWebChat extends React.Component<Props, State> {
14
12
  constructor(props: Props);
15
13
  render(): JSX.Element;
16
14
  }
17
- /**
18
- * @deprecated Since the way views are handled has changed, we're also exporting views in lowercase.
19
- * https://botpress.com/docs/developers/migrate/
20
- */
21
- export { Embedded as embedded } from '.';
22
- export { Fullscreen as fullscreen } from '.';
15
+ export declare const Embedded: (props: Props) => ExposedWebChat;
16
+ export declare const Fullscreen: (props: Props) => ExposedWebChat;
23
17
  export * from './typings';
package/dist/index.js CHANGED
@@ -13,7 +13,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
13
13
  return (mod && mod.__esModule) ? mod : { "default": mod };
14
14
  };
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.fullscreen = exports.embedded = exports.ExposedWebChat = exports.Fullscreen = exports.Embedded = void 0;
16
+ exports.Fullscreen = exports.Embedded = exports.ExposedWebChat = void 0;
17
17
  const mobx_1 = require("mobx");
18
18
  const mobx_react_1 = require("mobx-react");
19
19
  const react_1 = __importDefault(require("react"));
@@ -21,14 +21,12 @@ const react_intl_1 = require("react-intl");
21
21
  const main_1 = __importDefault(require("./main"));
22
22
  const store_1 = require("./store");
23
23
  const translations_1 = require("./translations");
24
+ const storage_1 = __importDefault(require("./utils/storage"));
24
25
  (0, mobx_1.configure)({ enforceActions: 'observed' });
25
- const Embedded = (props) => new Wrapper(Object.assign(Object.assign({}, props), { fullscreen: false }));
26
- exports.Embedded = Embedded;
27
- const Fullscreen = (props) => new Wrapper(Object.assign(Object.assign({}, props), { fullscreen: true }));
28
- exports.Fullscreen = Fullscreen;
29
26
  class ExposedWebChat extends react_1.default.Component {
30
27
  constructor(props) {
31
28
  super(props);
29
+ window.BP_STORAGE = new storage_1.default(props.config);
32
30
  this.state = {
33
31
  store: new store_1.RootStore({ fullscreen: props.fullscreen }, props.config)
34
32
  };
@@ -37,32 +35,14 @@ class ExposedWebChat extends react_1.default.Component {
37
35
  const store = this.state.store;
38
36
  const { botUILanguage: locale } = store;
39
37
  return (react_1.default.createElement(mobx_react_1.Provider, { store: store },
40
- react_1.default.createElement(react_intl_1.IntlProvider, { locale: locale, messages: translations_1.translations[locale], defaultLocale: translations_1.defaultLocale },
41
- react_1.default.createElement(react_1.default.Fragment, null,
42
- react_1.default.createElement(main_1.default, Object.assign({ store: store }, this.props))))));
38
+ react_1.default.createElement(react_intl_1.IntlProvider, { locale: locale, messages: translations_1.translations[locale || translations_1.defaultLocale], defaultLocale: translations_1.defaultLocale },
39
+ react_1.default.createElement(main_1.default, Object.assign({}, this.props)))));
43
40
  }
44
41
  }
45
42
  exports.ExposedWebChat = ExposedWebChat;
46
- // TODO: what does this observer do?
47
43
  const Wrapper = (0, mobx_react_1.observer)(ExposedWebChat);
48
- /**
49
- * @deprecated Since the way views are handled has changed, we're also exporting views in lowercase.
50
- * https://botpress.com/docs/developers/migrate/
51
- */
52
- var _1 = require(".");
53
- Object.defineProperty(exports, "embedded", { enumerable: true, get: function () { return _1.Embedded; } });
54
- var _2 = require(".");
55
- Object.defineProperty(exports, "fullscreen", { enumerable: true, get: function () { return _2.Fullscreen; } });
44
+ const Embedded = (props) => new Wrapper(Object.assign(Object.assign({}, props), { fullscreen: false }));
45
+ exports.Embedded = Embedded;
46
+ const Fullscreen = (props) => new Wrapper(Object.assign(Object.assign({}, props), { fullscreen: true }));
47
+ exports.Fullscreen = Fullscreen;
56
48
  __exportStar(require("./typings"), exports);
57
- // TODO: export this
58
- /*
59
- export {
60
- Carousel,
61
- QuickReplies,
62
- LoginPrompt,
63
- Text,
64
- FileMessage,
65
- FileInput,
66
- Button
67
- } from './components/messages/renderer'
68
- */
package/dist/main.d.ts CHANGED
@@ -9,5 +9,5 @@ declare const _default: React.ForwardRefExoticComponent<import("react-intl").Omi
9
9
  } & import("mobx-react").IWrappedComponent<unknown>;
10
10
  export default _default;
11
11
  declare type MainProps = {
12
- store: RootStore;
13
- } & WrappedComponentProps & Pick<StoreDef, 'config' | 'initializeChat' | 'botInfo' | 'fetchBotInfo' | 'sendMessage' | 'setUserId' | 'sendData' | 'intl' | 'isEmulator' | 'updateTyping' | 'setReference' | 'updateBotUILanguage' | 'hideChat' | 'showChat' | 'toggleBotInfo' | 'widgetTransition' | 'activeView' | 'isFullscreen' | 'unreadCount' | 'hasUnreadMessages' | 'showWidgetButton' | 'addEventToConversation' | 'clearMessages' | 'updateConfig' | 'mergeConfig' | 'isWebchatReady' | 'incrementUnread' | 'displayWidgetView' | 'resetUnread' | 'setLoadingCompleted' | 'dimensions' | 'updateLastMessage'>;
12
+ store?: RootStore;
13
+ } & WrappedComponentProps & Pick<StoreDef, 'config' | 'initializeChat' | 'botInfo' | 'fetchBotInfo' | 'sendMessage' | 'sendData' | 'intl' | 'updateTyping' | 'updateBotUILanguage' | 'hideChat' | 'showChat' | 'toggleBotInfo' | 'widgetTransition' | 'activeView' | 'isFullscreen' | 'unreadCount' | 'hasUnreadMessages' | 'showWidgetButton' | 'addEventToConversation' | 'clearMessages' | 'updateConfig' | 'mergeConfig' | 'isWebchatReady' | 'incrementUnread' | 'displayWidgetView' | 'resetUnread' | 'setLoadingCompleted' | 'dimensions' | 'updateLastMessage' | 'fetchConversation' | 'setIntlProvider' | 'setSocket' | 'currentConversationId'>;
package/dist/main.js CHANGED
@@ -41,161 +41,128 @@ 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;
56
- return !((_a = this.props.config) === null || _a === void 0 ? void 0 : _a.conversationId) || this.props.config.conversationId === event.conversationId;
55
+ return this.props.currentConversationId === event.conversationId;
57
56
  };
58
- this.handleIframeApi = ({ data: { action, payload } }) => __awaiter(this, void 0, void 0, function* () {
59
- if (action === 'configure') {
60
- this.props.updateConfig(Object.assign({}, constants_1.default.DEFAULT_CONFIG, payload));
61
- }
62
- else if (action === 'mergeConfig') {
63
- this.props.mergeConfig(payload);
64
- }
65
- else if (action === 'sendPayload') {
66
- yield this.props.sendData(payload);
57
+ this.handleKeyDown = (e) => __awaiter(this, void 0, void 0, function* () {
58
+ var _a;
59
+ if (!((_a = this.props.config) === null || _a === void 0 ? void 0 : _a.closeOnEscape)) {
60
+ return;
67
61
  }
68
- else if (action === 'change-user-id') {
69
- this.props.store.setUserId(payload);
70
- }
71
- else if (action === 'event') {
72
- const { type, text } = payload;
73
- if (type === 'show') {
74
- this.props.showChat();
75
- (0, utils_1.trackWebchatState)('show');
76
- }
77
- else if (type === 'hide') {
78
- this.props.hideChat();
79
- (0, utils_1.trackWebchatState)('hide');
80
- }
81
- else if (type === 'toggle') {
82
- this.props.displayWidgetView ? this.props.showChat() : this.props.hideChat();
83
- (0, utils_1.trackWebchatState)('toggle');
84
- }
85
- else if (type === 'message') {
86
- (0, utils_1.trackMessage)('sent');
87
- yield this.props.sendMessage(text);
88
- }
89
- else if (type === 'loadConversation') {
90
- yield this.props.store.fetchConversation(payload.conversationId);
91
- }
92
- else if (type === 'toggleBotInfo') {
93
- this.props.toggleBotInfo();
94
- }
95
- else {
96
- yield this.props.sendData({ type, payload });
97
- }
62
+ if (e.key === 'Escape') {
63
+ this.props.hideChat();
98
64
  }
99
65
  });
100
- this.handleClearMessages = (event) => {
101
- if (this.isCurrentConversation(event)) {
102
- this.props.clearMessages();
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;
103
103
  }
104
- };
104
+ });
105
105
  this.handleNewMessage = (event) => __awaiter(this, void 0, void 0, function* () {
106
- var _a;
106
+ var _b;
107
+ if (!this.isCurrentConversation(event)) {
108
+ // don't do anything, it's a message from another conversation
109
+ return;
110
+ }
107
111
  if (event.authorId === undefined) {
108
112
  const value = (event.payload.type === 'typing' ? event.payload.value : undefined) || exports.DEFAULT_TYPING_DELAY;
109
113
  yield this.handleTyping(Object.assign(Object.assign({}, event), { timeInMs: value }));
110
114
  }
111
- if (((_a = event.payload) === null || _a === void 0 ? void 0 : _a.type) === 'visit') {
115
+ if (((_b = event.payload) === null || _b === void 0 ? void 0 : _b.type) === 'visit') {
112
116
  // don't do anything, it's the system message
113
117
  return;
114
118
  }
115
- if (!this.isCurrentConversation(event)) {
116
- // don't do anything, it's a message from another conversation
117
- return;
118
- }
119
- (0, utils_1.trackMessage)('received');
119
+ (0, analytics_1.trackMessage)('received');
120
120
  this.props.updateLastMessage(event.conversationId, event);
121
121
  yield this.props.addEventToConversation(event);
122
122
  // there's no focus on the actual conversation
123
- if ((document.hasFocus && !document.hasFocus()) || this.props.activeView !== 'side') {
123
+ if (!document.hasFocus() || this.props.activeView !== 'side') {
124
124
  yield this.playSound();
125
125
  this.props.incrementUnread();
126
126
  }
127
127
  this.handleResetUnreadCount();
128
- if (!['session_reset'].includes(event.payload.type) && event.id !== this.lastMessageId) {
129
- this.lastMessageId = event.id;
130
- yield this.props.store.loadEventInDebugger(event.id);
131
- }
132
128
  });
133
129
  this.handleTyping = (event) => __awaiter(this, void 0, void 0, function* () {
134
- if (!this.isCurrentConversation(event)) {
135
- // don't do anything, it's a message from another conversation
136
- return;
137
- }
138
130
  yield this.props.updateTyping(event);
139
131
  });
140
- this.handleDataMessage = (event) => {
141
- if (!event || !event.payload) {
142
- return;
143
- }
144
- const { language } = event.payload;
145
- if (!language) {
146
- return;
147
- }
148
- this.props.updateBotUILanguage(language);
149
- };
150
132
  this.playSound = (0, debounce_1.default)(() => __awaiter(this, void 0, void 0, function* () {
151
- // Preference for config object
152
- const disableNotificationSound = this.config.disableNotificationSound === undefined
153
- ? this.props.config.disableNotificationSound
154
- : this.config.disableNotificationSound;
133
+ var _c;
134
+ const disableNotificationSound = this.config.disableNotificationSound || ((_c = this.props.config) === null || _c === void 0 ? void 0 : _c.disableNotificationSound);
155
135
  if (disableNotificationSound || this.audio.readyState < 2) {
156
136
  return;
157
137
  }
158
138
  yield this.audio.play();
159
139
  }), constants_1.default.MIN_TIME_BETWEEN_SOUNDS);
160
140
  this.handleResetUnreadCount = () => {
161
- var _a;
162
- if (((_a = document.hasFocus) === null || _a === void 0 ? void 0 : _a.call(document)) && this.props.activeView === 'side') {
141
+ if (document.hasFocus() && this.props.activeView === 'side') {
163
142
  this.props.resetUnread();
164
143
  }
165
144
  };
166
- (0, utils_1.checkLocationOrigin)();
167
- (0, utils_1.initializeAnalytics)();
145
+ (0, analytics_1.initializeAnalytics)();
168
146
  }
169
147
  componentDidMount() {
170
148
  return __awaiter(this, void 0, void 0, function* () {
171
149
  this.audio = new Audio(require('url:../assets/notification.mp3'));
172
- this.props.store.setIntlProvider(this.props.intl);
150
+ this.props.setIntlProvider(this.props.intl);
173
151
  window.store = this.props.store;
174
152
  window.addEventListener('message', this.handleIframeApi);
175
- window.addEventListener('keydown', (e) => {
176
- if (!this.props.config.closeOnEscape) {
177
- return;
178
- }
179
- if (e.key === 'Escape') {
180
- this.props.hideChat();
181
- // TODO: what to do with emulator mode?
182
- if (this.props.config.isEmulator) {
183
- window.parent.document.getElementById('mainLayout').focus();
184
- }
185
- }
186
- });
187
- yield this.load();
153
+ window.addEventListener('keydown', this.handleKeyDown);
154
+ yield this.loadConfig();
188
155
  yield this.initializeIfChatDisplayed();
189
156
  this.props.setLoadingCompleted();
190
157
  });
191
158
  }
192
159
  componentWillUnmount() {
193
160
  window.removeEventListener('message', this.handleIframeApi);
161
+ window.removeEventListener('keydown', this.handleKeyDown);
194
162
  }
195
163
  componentDidUpdate() {
196
164
  if (this.config) {
197
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
198
- this.initializeIfChatDisplayed();
165
+ void this.initializeIfChatDisplayed();
199
166
  }
200
167
  }
201
168
  initializeIfChatDisplayed() {
@@ -208,30 +175,24 @@ class Web extends react_1.default.Component {
208
175
  if (this.isLazySocket() || !this.socket) {
209
176
  yield this.initializeSocket();
210
177
  }
211
- yield this.socket.waitForUserId();
212
- this.props.store.setSocket(this.socket);
178
+ yield this.socket.connect();
179
+ this.props.setSocket(this.socket);
213
180
  yield this.props.initializeChat();
214
181
  }
215
182
  });
216
183
  }
217
- load() {
184
+ loadConfig() {
218
185
  return __awaiter(this, void 0, void 0, function* () {
219
186
  this.config = this.extractConfig();
187
+ this.props.updateConfig(this.config);
220
188
  if (this.config.exposeStore) {
221
189
  const storePath = this.config.chatId ? `${this.config.chatId}.webchat_store` : 'webchat_store';
222
190
  (0, set_1.default)(window.parent, storePath, this.props.store);
223
191
  }
224
- if (this.config.overrides) {
225
- this.loadOverrides(this.config.overrides);
226
- }
227
192
  if (this.config.containerWidth) {
228
193
  this.postMessageToParent('setWidth', this.config.containerWidth);
229
194
  }
230
- if (this.config.reference) {
231
- yield this.props.setReference();
232
- }
233
- // TODO: replace this by frontend configuration
234
- // await this.props.fetchBotInfo!()
195
+ yield this.props.fetchBotInfo();
235
196
  if (!this.isLazySocket()) {
236
197
  yield this.initializeSocket();
237
198
  }
@@ -239,69 +200,38 @@ class Web extends react_1.default.Component {
239
200
  });
240
201
  }
241
202
  postMessageToParent(type, value) {
242
- var _a, _b;
243
- (_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 }, '*');
244
205
  }
245
206
  extractConfig() {
246
- const decodeIfRequired = (options) => {
247
- try {
248
- return decodeURIComponent(options);
249
- }
250
- catch (_a) {
251
- return options;
252
- }
253
- };
254
- const { options, ref } = query_string_1.default.parse(location.search);
255
- const { config } = JSON.parse(decodeIfRequired(options || '{}'));
256
- const userConfig = Object.assign({}, constants_1.default.DEFAULT_CONFIG, this.props.config, config);
257
- userConfig.reference = (config === null || config === void 0 ? void 0 : config.ref) || ref;
258
- this.props.updateConfig(userConfig);
259
- return userConfig;
207
+ let userConfig = Object.assign({}, constants_1.default.DEFAULT_CONFIG, this.props.config);
208
+ const { options } = query_string_1.default.parse(location.search);
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
+ }
260
222
  }
261
223
  initializeSocket() {
262
224
  return __awaiter(this, void 0, void 0, function* () {
263
225
  this.socket = new socket_1.default(this.config);
264
- this.socket.onClear = this.handleClearMessages;
265
226
  this.socket.onMessage = this.handleNewMessage;
266
- this.socket.onTyping = this.handleTyping;
267
- this.socket.onData = this.handleDataMessage;
268
- this.socket.onUserIdChanged = this.props.setUserId;
269
- // TODO: Can't do that
270
- // this.config.userId && this.socket.changeUserId(this.config.userId)
271
227
  this.socket.setup();
272
- yield this.socket.waitForUserId();
273
- this.props.store.setSocket(this.socket);
228
+ yield this.socket.connect();
229
+ this.props.setSocket(this.socket);
274
230
  });
275
231
  }
276
- loadOverrides(overrides) {
277
- try {
278
- for (const override of Object.values(overrides)) {
279
- // TODO: load module view this can't work
280
- // override.map(({ module }) => this.props.bp!.loadModuleView(module, true))
281
- }
282
- }
283
- catch (err) {
284
- console.error('Error while loading overrides', err.message);
285
- }
286
- }
287
232
  setupObserver() {
288
- (0, mobx_1.observe)(this.props.config, 'userId', (data) => __awaiter(this, void 0, void 0, function* () {
289
- if (!data.oldValue || data.oldValue === data.newValue) {
290
- return;
291
- }
292
- // TODO: Can't work right now
293
- // this.socket.changeUserId(data.newValue)
294
- this.socket.setup();
295
- yield this.socket.waitForUserId();
296
- yield this.props.initializeChat();
297
- }));
298
- (0, mobx_1.observe)(this.props.config, 'overrides', (data) => {
299
- if (data.newValue && window.parent) {
300
- this.loadOverrides(data.newValue);
301
- }
302
- });
303
233
  (0, mobx_1.observe)(this.props.dimensions, 'container', (data) => {
304
- if (data.newValue && window.parent) {
234
+ if (data.newValue) {
305
235
  this.postMessageToParent('setWidth', data.newValue);
306
236
  }
307
237
  });
@@ -324,21 +254,22 @@ class Web extends react_1.default.Component {
324
254
  this.props.hasUnreadMessages && react_1.default.createElement("span", { className: 'bpw-floating-button-unread' }, this.props.unreadCount)));
325
255
  }
326
256
  applyAndRenderStyle() {
327
- const emulatorClass = this.props.isEmulator ? ' emulator' : '';
328
- const parentClass = (0, classnames_1.default)(`bp-widget-web bp-widget-${this.props.activeView}${emulatorClass}`, {
257
+ var _a, _b, _c;
258
+ const parentClass = (0, classnames_1.default)(`bp-widget-web bp-widget-${this.props.activeView}`, {
329
259
  'bp-widget-hidden': !this.props.showWidgetButton && this.props.displayWidgetView,
330
- [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)
331
261
  });
332
262
  if (this.parentClass !== parentClass) {
333
263
  this.postMessageToParent('setClass', parentClass);
334
264
  this.parentClass = parentClass;
335
265
  }
336
- 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;
337
268
  const RobotoFont = react_1.default.lazy(() => Promise.resolve().then(() => __importStar(require('./fonts/roboto'))));
338
269
  return (react_1.default.createElement(react_1.default.Fragment, null,
339
- !!(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 }),
340
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)),
341
- !!(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 })));
342
273
  }
343
274
  render() {
344
275
  if (!this.props.isWebchatReady) {
@@ -364,11 +295,8 @@ exports.default = (0, mobx_react_1.inject)(({ store }) => ({
364
295
  mergeConfig: store.mergeConfig,
365
296
  addEventToConversation: store.addEventToConversation,
366
297
  clearMessages: store.clearMessages,
367
- setUserId: store.setUserId,
368
298
  updateTyping: store.updateTyping,
369
299
  sendMessage: store.sendMessage,
370
- setReference: store.setReference,
371
- isEmulator: store.isEmulator,
372
300
  updateBotUILanguage: store.updateBotUILanguage,
373
301
  isWebchatReady: store.view.isWebchatReady,
374
302
  showWidgetButton: store.view.showWidgetButton,
@@ -386,5 +314,9 @@ exports.default = (0, mobx_react_1.inject)(({ store }) => ({
386
314
  displayWidgetView: store.view.displayWidgetView,
387
315
  setLoadingCompleted: store.view.setLoadingCompleted,
388
316
  sendFeedback: store.sendFeedback,
389
- updateLastMessage: store.updateLastMessage
317
+ updateLastMessage: store.updateLastMessage,
318
+ fetchConversation: store.fetchConversation,
319
+ setIntlProvider: store.setIntlProvider,
320
+ setSocket: store.setSocket,
321
+ currentConversationId: store.currentConversationId
390
322
  }))((0, react_intl_1.injectIntl)((0, mobx_react_1.observer)(Web)));
@@ -14,7 +14,7 @@ const takeRight_1 = __importDefault(require("lodash/takeRight"));
14
14
  const mobx_1 = require("mobx");
15
15
  const constants_1 = __importDefault(require("../core/constants"));
16
16
  const HISTORY_UP = 'ArrowUp';
17
- const SENT_HISTORY_KEY = `bp::${window.BOT_ID}::sentHistory`;
17
+ const SENT_HISTORY_KEY = 'sent-history';
18
18
  class ComposerStore {
19
19
  constructor(rootStore) {
20
20
  this.message = '';
@@ -23,9 +23,7 @@ class ComposerStore {
23
23
  this._sentHistory = [];
24
24
  this._sentHistoryIndex = 0;
25
25
  this.rootStore = rootStore;
26
- if (window.BP_STORAGE) {
27
- this._sentHistory = window.BP_STORAGE.get(SENT_HISTORY_KEY) || [];
28
- }
26
+ this._sentHistory = window.BP_STORAGE.get(SENT_HISTORY_KEY) || [];
29
27
  }
30
28
  get composerPlaceholder() {
31
29
  var _a;
@@ -35,12 +33,11 @@ class ComposerStore {
35
33
  this.message = msg;
36
34
  }
37
35
  addMessageToHistory(text) {
38
- var _a;
39
36
  if ((0, last_1.default)(this._sentHistory) !== text) {
40
37
  this._sentHistory.push(text);
41
38
  this._sentHistoryIndex = 0;
42
39
  if (this.rootStore.config.enablePersistHistory) {
43
- (_a = window.BP_STORAGE) === null || _a === void 0 ? void 0 : _a.set(SENT_HISTORY_KEY, (0, takeRight_1.default)(this._sentHistory, constants_1.default.SENT_HISTORY_SIZE));
40
+ window.BP_STORAGE.set(SENT_HISTORY_KEY, (0, takeRight_1.default)(this._sentHistory, constants_1.default.SENT_HISTORY_SIZE));
44
41
  }
45
42
  }
46
43
  }
@@ -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, MessageWrapper, 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;
@@ -12,7 +12,7 @@ declare class RootStore {
12
12
  private _typingInterval;
13
13
  private api;
14
14
  conversations: RecentConversation[];
15
- currentConversation: CurrentConversation;
15
+ currentConversation?: CurrentConversation;
16
16
  botInfo: BotInfo;
17
17
  config: Config;
18
18
  preferredLanguage: string;
@@ -20,8 +20,6 @@ declare class RootStore {
20
20
  messageFeedbacks: EventFeedback[];
21
21
  intl: IntlShape;
22
22
  isBotTyping: import("mobx").IObservableValue<boolean>;
23
- /** When a wrapper is defined, every messages are wrapped by the specified component */
24
- messageWrapper: MessageWrapper | undefined;
25
23
  botUILanguage: string;
26
24
  delayedMessages: QueuedMessage[];
27
25
  constructor(options: {
@@ -31,25 +29,23 @@ declare class RootStore {
31
29
  setSocket(socket: BpSocket): void;
32
30
  get isConversationStarted(): boolean;
33
31
  get botName(): string;
34
- get isEmulator(): boolean;
35
32
  get hasBotInfoDescription(): boolean;
36
33
  get botAvatarUrl(): string | undefined;
37
34
  get rtl(): boolean;
38
35
  get escapeHTML(): boolean;
39
36
  get currentMessages(): Message[];
40
- get currentConversationId(): uuid;
37
+ get currentConversationId(): uuid | undefined;
41
38
  postMessage(name: string, payload?: any): void;
42
39
  updateMessages(messages: Message[]): void;
43
40
  updateLastMessage(conversationId: string, message?: Message): void;
44
41
  clearMessages(): void;
45
42
  deleteConversation(): Promise<void>;
46
- loadEventInDebugger(messageId: uuid, isManual?: boolean): Promise<void>;
47
43
  addEventToConversation(event: Message): Promise<void>;
48
44
  updateTyping(event: Message): Promise<void>;
49
45
  /** Loads the initial state, for the first time or when the user ID is changed. */
50
46
  initializeChat(): Promise<void>;
51
47
  fetchBotInfo(): Promise<void>;
52
- fetchPreferences(): Promise<void>;
48
+ fetchLanguage(): void;
53
49
  /** Fetches the list of conversation, and update the corresponding config values */
54
50
  fetchConversations(): Promise<void>;
55
51
  /** Fetch the specified conversation ID, or try to fetch a valid one from the list */
@@ -60,33 +56,27 @@ declare class RootStore {
60
56
  startConversation(): Promise<void>;
61
57
  /** Creates a new conversation and switches to it */
62
58
  createConversation(): Promise<uuid>;
63
- setReference(): Promise<void>;
64
59
  resetConversation(): void;
65
- resetSession(): Promise<void>;
66
60
  extractFeedback(messages: Message[]): Promise<void>;
67
61
  sendFeedback(feedback: number, messageId: string): Promise<void>;
68
62
  downloadConversation(): Promise<void>;
69
63
  /** Sends an event or a message, depending on how the backend manages those types */
70
64
  sendData(data: any): Promise<void>;
71
- uploadFile(title: string, payload: string, file: File): Promise<void>;
72
65
  /** Sends a message of type voice */
73
66
  sendVoiceMessage(voice: Buffer, ext: string): Promise<void>;
74
67
  /** Use this method to replace a value or add a new config */
75
68
  mergeConfig(config: Partial<Config>): void;
76
69
  /** This replaces all the configurations by this object */
77
- updateConfig(config: Config, bp?: StudioConnector): void;
70
+ updateConfig(config: Config): void;
78
71
  private _applyConfig;
79
- /** When this method is used, the user ID is changed in the configuration, then the socket is updated */
80
- setUserId(userId: string): void;
81
72
  publishConfigChanged(): void;
82
- setMessageWrapper(messageWrapper: MessageWrapper): void;
83
- updatePreferredLanguage(lang: string): Promise<void>;
73
+ updatePreferredLanguage(lang: string): void;
84
74
  /** Starts a timer to remove the typing animation when it's completed */
85
75
  private _startTypingTimer;
86
76
  private _expireTyping;
87
77
  updateBotUILanguage(lang: string): void;
88
78
  private emptyDelayedMessagesQueue;
89
- /** 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. */
90
80
  private _getCurrentConvoId;
91
81
  }
92
82
  export { RootStore };