@botpress/webchat 0.4.0 → 0.5.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.
@@ -8,4 +8,4 @@ declare const _default: React.ForwardRefExoticComponent<import("react-intl").Omi
8
8
  WrappedComponent: React.ComponentType<MessageProps>;
9
9
  } & import("mobx-react").IWrappedComponent<unknown>;
10
10
  export default _default;
11
- declare type MessageProps = Renderer.Message & WrappedComponentProps & Pick<StoreDef, 'intl'>;
11
+ declare type MessageProps = Renderer.Message & WrappedComponentProps & Pick<StoreDef, 'intl' | 'selectedMessageId' | 'config'>;
@@ -27,6 +27,7 @@ const classnames_1 = __importDefault(require("classnames"));
27
27
  const mobx_react_1 = require("mobx-react");
28
28
  const react_1 = __importStar(require("react"));
29
29
  const react_intl_1 = require("react-intl");
30
+ const webchatEvents_1 = require("../../utils/webchatEvents");
30
31
  class Message extends react_1.Component {
31
32
  constructor() {
32
33
  super(...arguments);
@@ -34,6 +35,17 @@ class Message extends react_1.Component {
34
35
  hasError: false,
35
36
  showMore: false
36
37
  };
38
+ this.onMessageClick = () => {
39
+ var _a, _b;
40
+ (_a = this.props.store) === null || _a === void 0 ? void 0 : _a.setSelectedMessage(this.props.messageId);
41
+ (0, webchatEvents_1.postMessageToParent)('MESSAGE.SELECTED', {
42
+ id: this.props.messageId,
43
+ conversationId: (_b = this.props.store) === null || _b === void 0 ? void 0 : _b.currentConversationId,
44
+ sentOn: this.props.sentOn,
45
+ payload: this.props.payload,
46
+ from: this.props.isBotMessage ? 'bot' : 'user'
47
+ }, this.props.config.chatId);
48
+ };
37
49
  }
38
50
  static getDerivedStateFromError(_error) {
39
51
  return { hasError: true };
@@ -70,11 +82,14 @@ class Message extends react_1.Component {
70
82
  return null;
71
83
  }
72
84
  const additionalStyle = (this.props.payload && this.props.payload['web-style']) || {};
85
+ const messageSelectedClass = {
86
+ 'bpw-message-selected': this.props.selectedMessageId === this.props.messageId
87
+ };
73
88
  if (this.props.noBubble || ((_b = (_a = this.props.payload) === null || _a === void 0 ? void 0 : _a.wrapped) === null || _b === void 0 ? void 0 : _b.noBubble)) {
74
- return (react_1.default.createElement("div", { className: (0, classnames_1.default)(this.props.className, wrappedClass), style: additionalStyle }, rendered));
89
+ return (react_1.default.createElement("div", { className: (0, classnames_1.default)(this.props.className, wrappedClass, messageSelectedClass), style: additionalStyle, onClick: this.onMessageClick }, rendered));
75
90
  }
76
91
  return (react_1.default.createElement("div", { className: (0, classnames_1.default)(this.props.className, wrappedClass, 'bpw-chat-bubble', `bpw-bubble-${type}`), "data-from": this.props.fromLabel, tabIndex: -1, style: additionalStyle },
77
- react_1.default.createElement("div", { tabIndex: -1, className: "bpw-chat-bubble-content" },
92
+ react_1.default.createElement("div", { tabIndex: -1, className: (0, classnames_1.default)('bpw-chat-bubble-content', messageSelectedClass), onClick: this.onMessageClick },
78
93
  react_1.default.createElement("span", { className: "sr-only" }, this.props.store.intl.formatMessage({
79
94
  id: this.props.isBotMessage ? 'message.botSaid' : 'message.iSaid',
80
95
  defaultMessage: this.props.isBotMessage ? 'Virtual assistant said : ' : 'I said : '
@@ -85,5 +100,7 @@ class Message extends react_1.Component {
85
100
  }
86
101
  }
87
102
  exports.default = (0, mobx_react_1.inject)(({ store }) => ({
88
- intl: store.intl
103
+ intl: store.intl,
104
+ config: store.config,
105
+ selectedMessageId: store.selectedMessageId
89
106
  }))((0, react_intl_1.injectIntl)((0, mobx_react_1.observer)(Message)));
@@ -20,4 +20,4 @@ declare type Props = {
20
20
  messages: MessageDetails[];
21
21
  isLastGroup: boolean;
22
22
  store?: RootStore;
23
- } & Pick<StoreDef, 'sendFeedback' | 'sendData'>;
23
+ } & Pick<StoreDef, 'sendFeedback' | 'sendData' | 'selectedMessageId'>;
@@ -43,7 +43,9 @@ class MessageGroup extends react_1.default.Component {
43
43
  }) },
44
44
  avatar,
45
45
  react_1.default.createElement("div", { role: "region", className: 'bpw-message-container' },
46
- react_1.default.createElement("div", { "aria-live": "assertive", role: "log", className: 'bpw-message-group' },
46
+ react_1.default.createElement("div", { "aria-live": "assertive", role: "log", className: (0, classnames_1.default)('bpw-message-group', {
47
+ 'bpw-message-group-selected': !!this.props.messages.find((m) => m.id === this.props.selectedMessageId)
48
+ }) },
47
49
  react_1.default.createElement("span", { "data-from": fromLabel, className: "from hidden", "aria-hidden": "true" }, fromLabel),
48
50
  (0, sortBy_1.default)(messages, ['sent_on', 'eventId']).map((message, i, messages) => {
49
51
  const isLastMsg = i === messages.length - 1;
@@ -56,5 +58,6 @@ class MessageGroup extends react_1.default.Component {
56
58
  exports.default = (0, mobx_react_1.inject)(({ store }) => ({
57
59
  store,
58
60
  sendFeedback: store.sendFeedback,
59
- sendData: store.sendData
61
+ sendData: store.sendData,
62
+ selectedMessageId: store.selectedMessageId
60
63
  }))(MessageGroup);
@@ -8,7 +8,6 @@ export default class BpSocket {
8
8
  constructor(config: Config);
9
9
  setup(): void;
10
10
  sendPayload(payload: any): Promise<Message>;
11
- postToParent: (_type: string, payload: any) => void;
12
11
  connect(): Promise<void>;
13
12
  reload(config: Config): Promise<void>;
14
13
  private getCreds;
@@ -10,13 +10,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  const messaging_socket_1 = require("@botpress/messaging-socket");
13
+ const webchatEvents_1 = require("../utils/webchatEvents");
13
14
  class BpSocket {
14
15
  constructor(config) {
15
16
  this.config = config;
16
- this.postToParent = (_type, payload) => {
17
- var _a;
18
- (_a = window.parent) === null || _a === void 0 ? void 0 : _a.postMessage(Object.assign(Object.assign({}, payload), { chatId: this.chatId }), '*');
19
- };
20
17
  this.chatId = config.chatId;
21
18
  this.socket = new messaging_socket_1.MessagingSocket({ url: config.messagingUrl, clientId: config.clientId });
22
19
  window.websocket = this.socket;
@@ -38,7 +35,7 @@ class BpSocket {
38
35
  if (this.socket.userId) {
39
36
  const userId = this.socket.userId;
40
37
  window.BP_STORAGE.set('creds', this.socket.creds);
41
- this.postToParent('', { userId });
38
+ (0, webchatEvents_1.postMessageToParent)('USER.CONNECTED', { userId }, this.chatId);
42
39
  }
43
40
  });
44
41
  }
package/dist/main.d.ts CHANGED
@@ -10,4 +10,4 @@ declare const _default: React.ForwardRefExoticComponent<import("react-intl").Omi
10
10
  export default _default;
11
11
  declare type MainProps = {
12
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' | 'resetConversation'>;
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' | 'createConversation' | 'setIntlProvider' | 'setSocket' | 'currentConversationId' | 'currentConversation' | 'resetConversation'>;
package/dist/main.js CHANGED
@@ -34,7 +34,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
34
34
  exports.DEFAULT_TYPING_DELAY = void 0;
35
35
  const classnames_1 = __importDefault(require("classnames"));
36
36
  const debounce_1 = __importDefault(require("lodash/debounce"));
37
- const set_1 = __importDefault(require("lodash/set"));
38
37
  const mobx_1 = require("mobx");
39
38
  const mobx_react_1 = require("mobx-react");
40
39
  const query_string_1 = __importDefault(require("query-string"));
@@ -46,6 +45,7 @@ const socket_1 = __importDefault(require("./core/socket"));
46
45
  const Chat_1 = __importDefault(require("./icons/Chat"));
47
46
  const utils_1 = require("./utils");
48
47
  const analytics_1 = require("./utils/analytics");
48
+ const webchatEvents_1 = require("./utils/webchatEvents");
49
49
  exports.DEFAULT_TYPING_DELAY = 1000;
50
50
  class Web extends react_1.default.Component {
51
51
  constructor(props) {
@@ -93,12 +93,14 @@ class Web extends react_1.default.Component {
93
93
  (0, analytics_1.trackWebchatState)('toggle');
94
94
  }
95
95
  else if (type === 'message') {
96
- (0, analytics_1.trackMessage)('sent');
97
96
  yield this.props.sendMessage(text);
98
97
  }
99
98
  else if (type === 'loadConversation') {
100
99
  yield this.props.fetchConversation(conversationId);
101
100
  }
101
+ else if (type === 'createConversation') {
102
+ yield this.props.createConversation();
103
+ }
102
104
  else if (type === 'toggleBotInfo') {
103
105
  this.props.toggleBotInfo();
104
106
  }
@@ -110,7 +112,7 @@ class Web extends react_1.default.Component {
110
112
  }
111
113
  });
112
114
  this.handleNewMessage = (event) => __awaiter(this, void 0, void 0, function* () {
113
- var _b;
115
+ var _b, _c, _d;
114
116
  if (!this.isCurrentConversation(event)) {
115
117
  // don't do anything, it's a message from another conversation
116
118
  return;
@@ -123,7 +125,15 @@ class Web extends react_1.default.Component {
123
125
  // don't do anything, it's the system message
124
126
  return;
125
127
  }
126
- (0, analytics_1.trackMessage)('received');
128
+ if (((_c = this.props.currentConversation) === null || _c === void 0 ? void 0 : _c.userId) !== event.authorId) {
129
+ (0, analytics_1.trackMessage)('received');
130
+ (0, webchatEvents_1.postMessageToParent)('MESSAGE.RECEIVED', event, this.props.config.chatId);
131
+ // This is to handle a special case for the emulator, setting the selected css class to the last message group
132
+ // This needs a rethinking
133
+ if (event.id) {
134
+ (_d = this.props.store) === null || _d === void 0 ? void 0 : _d.setSelectedMessage(event.id);
135
+ }
136
+ }
127
137
  this.props.updateLastMessage(event.conversationId, event);
128
138
  yield this.props.addEventToConversation(event);
129
139
  // there's no focus on the actual conversation
@@ -137,8 +147,8 @@ class Web extends react_1.default.Component {
137
147
  yield this.props.updateTyping(event);
138
148
  });
139
149
  this.playSound = (0, debounce_1.default)(() => __awaiter(this, void 0, void 0, function* () {
140
- var _c;
141
- const disableNotificationSound = this.config.disableNotificationSound || ((_c = this.props.config) === null || _c === void 0 ? void 0 : _c.disableNotificationSound);
150
+ var _e;
151
+ const disableNotificationSound = this.config.disableNotificationSound || ((_e = this.props.config) === null || _e === void 0 ? void 0 : _e.disableNotificationSound);
142
152
  if (disableNotificationSound || this.audio.readyState < 2) {
143
153
  return;
144
154
  }
@@ -192,12 +202,9 @@ class Web extends react_1.default.Component {
192
202
  return __awaiter(this, void 0, void 0, function* () {
193
203
  this.config = this.extractConfig();
194
204
  this.props.updateConfig(this.config);
195
- if (this.config.exposeStore) {
196
- const storePath = this.config.chatId ? `${this.config.chatId}.webchat_store` : 'webchat_store';
197
- (0, set_1.default)(window.parent, storePath, this.props.store);
198
- }
205
+ // is this necessary ?
199
206
  if (this.config.containerWidth) {
200
- this.postMessageToParent('setWidth', this.config.containerWidth);
207
+ (0, webchatEvents_1.postMessageToParent)('UI.RESIZE', this.config.containerWidth, this.config.chatId);
201
208
  }
202
209
  yield this.props.fetchBotInfo();
203
210
  if (!this.isLazySocket()) {
@@ -206,10 +213,6 @@ class Web extends react_1.default.Component {
206
213
  this.setupObserver();
207
214
  });
208
215
  }
209
- postMessageToParent(type, value) {
210
- var _a;
211
- (_a = window.parent) === null || _a === void 0 ? void 0 : _a.postMessage({ type, value, chatId: this.config.chatId }, '*');
212
- }
213
216
  extractConfig() {
214
217
  let userConfig = Object.assign({}, constants_1.default.DEFAULT_CONFIG, this.props.config);
215
218
  const { options } = query_string_1.default.parse(location.search);
@@ -239,7 +242,8 @@ class Web extends react_1.default.Component {
239
242
  setupObserver() {
240
243
  (0, mobx_1.observe)(this.props.dimensions, 'container', (data) => {
241
244
  if (data.newValue) {
242
- this.postMessageToParent('setWidth', data.newValue);
245
+ // is this necessary ?
246
+ (0, webchatEvents_1.postMessageToParent)('UI.RESIZE', data.newValue, this.config.chatId);
243
247
  }
244
248
  });
245
249
  }
@@ -267,8 +271,8 @@ class Web extends react_1.default.Component {
267
271
  [(_a = this.props.config) === null || _a === void 0 ? void 0 : _a.className]: !!((_b = this.props.config) === null || _b === void 0 ? void 0 : _b.className)
268
272
  });
269
273
  if (this.parentClass !== parentClass) {
270
- this.postMessageToParent('setClass', parentClass);
271
274
  this.parentClass = parentClass;
275
+ (0, webchatEvents_1.postMessageToParent)('UI.SET-CLASS', parentClass, this.config.chatId);
272
276
  }
273
277
  const stylesheet = this.props.config.stylesheet;
274
278
  const extraStylesheet = (_c = this.props.botInfo) === null || _c === void 0 ? void 0 : _c.extraStylesheet;
@@ -323,8 +327,10 @@ exports.default = (0, mobx_react_1.inject)(({ store }) => ({
323
327
  sendFeedback: store.sendFeedback,
324
328
  updateLastMessage: store.updateLastMessage,
325
329
  fetchConversation: store.fetchConversation,
330
+ createConversation: store.createConversation,
326
331
  setIntlProvider: store.setIntlProvider,
327
332
  setSocket: store.setSocket,
333
+ currentConversation: store.currentConversation,
328
334
  currentConversationId: store.currentConversationId,
329
335
  resetConversation: store.resetConversation
330
336
  }))((0, react_intl_1.injectIntl)((0, mobx_react_1.observer)(Web)));
@@ -13,6 +13,7 @@ declare class RootStore {
13
13
  private api;
14
14
  conversations: RecentConversation[];
15
15
  currentConversation?: CurrentConversation;
16
+ selectedMessageId?: string;
16
17
  botInfo: BotInfo;
17
18
  config: Config;
18
19
  preferredLanguage: string;
@@ -27,6 +28,7 @@ declare class RootStore {
27
28
  }, config?: Config);
28
29
  setIntlProvider(provider: IntlShape): void;
29
30
  setSocket(socket: BpSocket): void;
31
+ setSelectedMessage(messageId: string): void;
30
32
  get isConversationStarted(): boolean;
31
33
  get botName(): string;
32
34
  get hasBotInfoDescription(): boolean;
@@ -35,7 +37,6 @@ declare class RootStore {
35
37
  get escapeHTML(): boolean;
36
38
  get currentMessages(): Message[];
37
39
  get currentConversationId(): uuid | undefined;
38
- postMessage(name: string, payload?: any): void;
39
40
  updateMessages(messages: Message[]): void;
40
41
  updateLastMessage(conversationId: string, message?: Message): void;
41
42
  clearMessages(): void;
@@ -51,7 +52,7 @@ declare class RootStore {
51
52
  /** Fetch the specified conversation ID, or try to fetch a valid one from the list */
52
53
  fetchConversation(convoId?: uuid): Promise<uuid | undefined>;
53
54
  /** Sends the specified message, or fetch the message in the composer */
54
- sendMessage(message?: string): Promise<void>;
55
+ sendMessage(textMessage?: string): Promise<void>;
55
56
  /** Sends an event to start conversation & hide the bot info page */
56
57
  startConversation(): Promise<void>;
57
58
  /** Creates a new conversation and switches to it */
@@ -61,7 +62,7 @@ declare class RootStore {
61
62
  sendFeedback(feedback: number, messageId: string): Promise<void>;
62
63
  downloadConversation(): Promise<void>;
63
64
  /** Sends an event or a message, depending on how the backend manages those types */
64
- sendData(data: any): Promise<void>;
65
+ sendData(data: any): Promise<Message | void>;
65
66
  /** Sends a message of type voice */
66
67
  sendVoiceMessage(voice: Buffer, ext: string): Promise<void>;
67
68
  /** Use this method to replace a value or add a new config */
@@ -69,7 +70,6 @@ declare class RootStore {
69
70
  /** This replaces all the configurations by this object */
70
71
  updateConfig(config: Config): void;
71
72
  private _applyConfig;
72
- publishConfigChanged(): void;
73
73
  updatePreferredLanguage(lang: string): void;
74
74
  /** Starts a timer to remove the typing animation when it's completed */
75
75
  private _startTypingTimer;
@@ -30,6 +30,7 @@ const main_1 = require("../main");
30
30
  const translations_1 = require("../translations");
31
31
  const utils_1 = require("../utils");
32
32
  const analytics_1 = require("../utils/analytics");
33
+ const webchatEvents_1 = require("../utils/webchatEvents");
33
34
  const composer_1 = __importDefault(require("./composer"));
34
35
  const view_1 = __importDefault(require("./view"));
35
36
  class RootStore {
@@ -50,6 +51,9 @@ class RootStore {
50
51
  setSocket(socket) {
51
52
  this.api = new api_1.default(socket);
52
53
  }
54
+ setSelectedMessage(messageId) {
55
+ this.selectedMessageId = messageId;
56
+ }
53
57
  get isConversationStarted() {
54
58
  var _a;
55
59
  return !!((_a = this.currentConversation) === null || _a === void 0 ? void 0 : _a.messages.length);
@@ -81,10 +85,6 @@ class RootStore {
81
85
  var _a;
82
86
  return (_a = this.currentConversation) === null || _a === void 0 ? void 0 : _a.id;
83
87
  }
84
- postMessage(name, payload) {
85
- const chatId = this.config.chatId;
86
- window.parent.postMessage({ name, chatId, payload }, '*');
87
- }
88
88
  updateMessages(messages) {
89
89
  if (this.currentConversation) {
90
90
  this.currentConversation.messages = messages;
@@ -160,7 +160,7 @@ class RootStore {
160
160
  yield this.fetchConversation();
161
161
  (0, mobx_1.runInAction)('-> setInitialized', () => {
162
162
  this.isInitialized = true;
163
- this.postMessage('webchatReady');
163
+ (0, webchatEvents_1.postMessageToParent)('LIFECYCLE.READY', undefined, this.config.chatId);
164
164
  });
165
165
  }
166
166
  catch (err) {
@@ -229,23 +229,24 @@ class RootStore {
229
229
  });
230
230
  }
231
231
  /** Sends the specified message, or fetch the message in the composer */
232
- sendMessage(message) {
232
+ sendMessage(textMessage) {
233
233
  return __awaiter(this, void 0, void 0, function* () {
234
- if (message) {
235
- return this.sendData({ type: 'text', text: message });
236
- }
237
- const userMessage = this.composer.message;
238
- if (!userMessage || !userMessage.length) {
234
+ textMessage = textMessage || this.composer.message;
235
+ if (!textMessage) {
239
236
  return;
240
237
  }
241
238
  this.composer.updateMessage('');
242
239
  try {
243
- yield this.sendData({ type: 'text', text: userMessage });
240
+ const message = yield this.sendData({ type: 'text', text: textMessage });
244
241
  (0, analytics_1.trackMessage)('sent');
245
- this.composer.addMessageToHistory(userMessage);
242
+ if (message) {
243
+ (0, webchatEvents_1.postMessageToParent)('MESSAGE.SENT', message, this.config.chatId);
244
+ }
245
+ this.composer.addMessageToHistory(textMessage);
246
246
  }
247
247
  catch (e) {
248
- this.composer.updateMessage(userMessage);
248
+ this.composer.updateMessage(textMessage);
249
+ console.error('Webchat cloud not send message');
249
250
  throw e;
250
251
  }
251
252
  });
@@ -328,6 +329,7 @@ class RootStore {
328
329
  }
329
330
  const message = yield this.api.sendMessage(data, this.currentConversationId);
330
331
  this.updateLastMessage(this.currentConversationId, message);
332
+ return message;
331
333
  });
332
334
  }
333
335
  /** Sends a message of type voice */
@@ -364,10 +366,7 @@ class RootStore {
364
366
  const locale = (0, translations_1.getUserLocale)(this.config.locale);
365
367
  this.updateBotUILanguage(locale);
366
368
  document.documentElement.setAttribute('lang', locale);
367
- this.publishConfigChanged();
368
- }
369
- publishConfigChanged() {
370
- this.postMessage('configChanged', JSON.stringify(this.config, undefined, 2));
369
+ (0, webchatEvents_1.postMessageToParent)('CONFIG.SET', Object.assign({}, this.config), this.config.chatId);
371
370
  }
372
371
  updatePreferredLanguage(lang) {
373
372
  this.preferredLanguage = lang;
@@ -439,6 +438,9 @@ __decorate([
439
438
  __decorate([
440
439
  mobx_1.observable
441
440
  ], RootStore.prototype, "currentConversation", void 0);
441
+ __decorate([
442
+ mobx_1.observable
443
+ ], RootStore.prototype, "selectedMessageId", void 0);
442
444
  __decorate([
443
445
  mobx_1.observable
444
446
  ], RootStore.prototype, "botInfo", void 0);
@@ -463,6 +465,9 @@ __decorate([
463
465
  __decorate([
464
466
  mobx_1.action.bound
465
467
  ], RootStore.prototype, "setSocket", null);
468
+ __decorate([
469
+ mobx_1.action.bound
470
+ ], RootStore.prototype, "setSelectedMessage", null);
466
471
  __decorate([
467
472
  mobx_1.computed
468
473
  ], RootStore.prototype, "isConversationStarted", null);
@@ -487,9 +492,6 @@ __decorate([
487
492
  __decorate([
488
493
  mobx_1.computed
489
494
  ], RootStore.prototype, "currentConversationId", null);
490
- __decorate([
491
- mobx_1.action.bound
492
- ], RootStore.prototype, "postMessage", null);
493
495
  __decorate([
494
496
  mobx_1.action.bound
495
497
  ], RootStore.prototype, "updateMessages", null);
@@ -556,9 +558,6 @@ __decorate([
556
558
  __decorate([
557
559
  mobx_1.action.bound
558
560
  ], RootStore.prototype, "updateConfig", null);
559
- __decorate([
560
- mobx_1.action.bound
561
- ], RootStore.prototype, "publishConfigChanged", null);
562
561
  __decorate([
563
562
  mobx_1.action.bound
564
563
  ], RootStore.prototype, "updatePreferredLanguage", null);
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  const merge_1 = __importDefault(require("lodash/merge"));
13
13
  const mobx_1 = require("mobx");
14
14
  const constants_1 = __importDefault(require("../core/constants"));
15
+ const webchatEvents_1 = require("../utils/webchatEvents");
15
16
  class ViewStore {
16
17
  constructor(rootStore, fullscreen) {
17
18
  /** If false, probably embedded on a website or on the studio */
@@ -111,7 +112,7 @@ class ViewStore {
111
112
  }
112
113
  setLoadingCompleted() {
113
114
  this._isLoading = false;
114
- this.rootStore.postMessage('webchatLoaded');
115
+ (0, webchatEvents_1.postMessageToParent)('LIFECYCLE.LOADED', undefined, this.rootStore.config.chatId);
115
116
  }
116
117
  showPoweredBy() {
117
118
  this.isPoweredByDisplayed = true;
@@ -157,7 +158,7 @@ class ViewStore {
157
158
  showChat() {
158
159
  if (this.disableAnimations) {
159
160
  this.activeView = 'side';
160
- this.rootStore.postMessage('webchatOpened');
161
+ (0, webchatEvents_1.postMessageToParent)('UI.OPENED', undefined, this.rootStore.config.chatId);
161
162
  return this._updateTransitions({ widgetTransition: undefined, sideTransition: 'none' });
162
163
  }
163
164
  this._updateTransitions({ widgetTransition: 'fadeOut' });
@@ -165,7 +166,7 @@ class ViewStore {
165
166
  this._updateTransitions({ sideTransition: 'fadeIn' });
166
167
  }, constants_1.default.ANIMATION_DURATION + 10);
167
168
  this._endAnimation('side');
168
- this.rootStore.postMessage('webchatOpened');
169
+ (0, webchatEvents_1.postMessageToParent)('UI.OPENED', undefined, this.rootStore.config.chatId);
169
170
  }
170
171
  hideChat() {
171
172
  if (this.isFullscreen) {
@@ -173,7 +174,7 @@ class ViewStore {
173
174
  }
174
175
  if (this.disableAnimations) {
175
176
  this.activeView = 'widget';
176
- this.rootStore.postMessage('webchatClosed');
177
+ (0, webchatEvents_1.postMessageToParent)('UI.CLOSED', undefined, this.rootStore.config.chatId);
177
178
  return this._updateTransitions({ widgetTransition: undefined, sideTransition: undefined });
178
179
  }
179
180
  this._updateTransitions({ sideTransition: 'fadeOut' });
@@ -183,7 +184,7 @@ class ViewStore {
183
184
  }, constants_1.default.ANIMATION_DURATION + 10);
184
185
  }
185
186
  this._endAnimation('widget');
186
- this.rootStore.postMessage('webchatClosed');
187
+ (0, webchatEvents_1.postMessageToParent)('UI.CLOSED', undefined, this.rootStore.config.chatId);
187
188
  }
188
189
  _endAnimation(finalView) {
189
190
  setTimeout(() => {
package/dist/typings.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  /// <reference types="react" />
2
+ import { UserCredentials } from '@botpress/messaging-socket';
2
3
  import { RootStore } from './store';
3
4
  import { BPStorage } from './utils/storage';
4
5
  declare global {
@@ -35,7 +36,7 @@ export declare namespace Renderer {
35
36
  isLastMessage?: boolean;
36
37
  sentOn?: Date;
37
38
  inlineFeedback?: any;
38
- onSendData?: (data: any) => Promise<void>;
39
+ onSendData?: (data: any) => Promise<Message | void>;
39
40
  onFileUpload?: (label: string, payload: any, file: File) => Promise<void>;
40
41
  /** Allows to autoplay voice messages coming from the bot */
41
42
  onAudioEnded?: () => void;
@@ -135,11 +136,27 @@ export interface StudioConnector {
135
136
  getModuleInjector: any;
136
137
  loadModuleView: any;
137
138
  }
139
+ export declare type WebchatEventType = 'LIFECYCLE.LOADED' | 'LIFECYCLE.READY' | 'UI.OPENED' | 'UI.CLOSED' | 'UI.RESIZE' | 'UI.SET-CLASS' | 'CONFIG.SET' | 'MESSAGE.SENT' | 'MESSAGE.RECEIVED' | 'MESSAGE.SELECTED' | 'USER.CONNECTED';
140
+ export interface WebchatEvent {
141
+ type: WebchatEventType;
142
+ value: any;
143
+ chatId: string;
144
+ }
138
145
  export interface Config {
139
146
  /** Url of the messaging server */
140
147
  messagingUrl: string;
141
148
  /** Id of your messaging client */
142
149
  clientId: string;
150
+ /**
151
+ * Refers to a specific webchat reference in parent window. Useful when using multiple chat window
152
+ * @default 'bp-web-widget'
153
+ */
154
+ chatId: string;
155
+ /**
156
+ * Url where the webchat bundle is hosted
157
+ * @default: '/'
158
+ */
159
+ hostUrl?: string;
143
160
  /**
144
161
  * Url of the Media File Service where we fetch the bot info
145
162
  * @default ''
@@ -250,22 +267,12 @@ export interface Config {
250
267
  * Experimental: expose the store to the parent frame for more control on the webchat's behavior
251
268
  * @default false
252
269
  */
253
- exposeStore?: boolean;
254
- /**
255
- * If true, Websocket is created when the Webchat is opened. Bot cannot be proactive.
256
- * @default false
257
- */
258
270
  lazySocket?: boolean;
259
271
  /**
260
272
  * If true, chat will no longer play the notification sound for new messages.
261
273
  * @default false
262
274
  */
263
275
  disableNotificationSound?: boolean;
264
- /**
265
- * Refers to a specific webchat reference in parent window. Useful when using multiple chat window
266
- * @default ''
267
- */
268
- chatId?: string;
269
276
  /**
270
277
  * CSS class to be applied to iframe
271
278
  * @default ''
@@ -280,10 +287,7 @@ export interface Config {
280
287
  /**
281
288
  * Allows setting a custom user id
282
289
  */
283
- customUser?: {
284
- userId: string;
285
- userToken: string;
286
- };
290
+ customUser?: UserCredentials;
287
291
  }
288
292
  export interface BotDetails {
289
293
  website?: string;
@@ -0,0 +1,2 @@
1
+ import { WebchatEventType } from '../typings';
2
+ export declare const postMessageToParent: (type: WebchatEventType, value: any, chatId: string) => void;
@@ -0,0 +1,14 @@
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
+ exports.postMessageToParent = void 0;
7
+ const cloneDeep_1 = __importDefault(require("lodash/cloneDeep"));
8
+ const postMessageToParent = (type, value, chatId) => {
9
+ var _a;
10
+ //cloneDeep necessary because of potentially nested mobx proxy object isn't serializable
11
+ const evt = { type, value: (0, cloneDeep_1.default)(value), chatId };
12
+ (_a = window.parent) === null || _a === void 0 ? void 0 : _a.postMessage(evt, '*');
13
+ };
14
+ exports.postMessageToParent = postMessageToParent;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botpress/webchat",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "source": "src/index.tsx",
@@ -29,7 +29,7 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "@blueprintjs/core": "^3.23.1",
32
- "@botpress/messaging-components": "0.4.0",
32
+ "@botpress/messaging-components": "0.4.2",
33
33
  "@botpress/messaging-socket": "1.2.0",
34
34
  "@formatjs/intl-pluralrules": "^4.1.6",
35
35
  "@formatjs/intl-utils": "^3.8.4",