@botonic/react 1.0.0-dev.1 → 1.0.0-dev.2

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 (116) hide show
  1. package/lib/components/button.js +2 -0
  2. package/lib/components/button.js.map +1 -1
  3. package/lib/components/components.js +1 -1
  4. package/lib/components/image.js +47 -5
  5. package/lib/components/image.js.map +1 -1
  6. package/lib/components/index.js +6 -6
  7. package/lib/components/markdown.js +1 -1
  8. package/lib/components/multichannel/multichannel-utils.js +8 -6
  9. package/lib/components/multichannel/multichannel-utils.js.map +1 -1
  10. package/lib/components/timestamps.js +1 -1
  11. package/lib/constants.js +2 -1
  12. package/lib/constants.js.map +1 -1
  13. package/lib/dev-app.js +7 -6
  14. package/lib/dev-app.js.map +1 -1
  15. package/lib/index.d.ts +3 -0
  16. package/lib/index.js +20 -20
  17. package/lib/message-utils.js +1 -1
  18. package/lib/util/dom.js +8 -2
  19. package/lib/util/dom.js.map +1 -1
  20. package/lib/util/environment.js +1 -1
  21. package/lib/util/objects.js +1 -1
  22. package/lib/util/react.js +1 -1
  23. package/lib/util/webchat.js +1 -1
  24. package/lib/webchat/actions.js +3 -1
  25. package/lib/webchat/actions.js.map +1 -1
  26. package/lib/webchat/devices/device-adapter.js +14 -4
  27. package/lib/webchat/devices/device-adapter.js.map +1 -1
  28. package/lib/webchat/devices/scrollbar-controller.js +5 -3
  29. package/lib/webchat/devices/scrollbar-controller.js.map +1 -1
  30. package/lib/webchat/header.js +1 -1
  31. package/lib/webchat/hooks.js +14 -4
  32. package/lib/webchat/hooks.js.map +1 -1
  33. package/lib/webchat/index.js +1 -1
  34. package/lib/webchat/webchat-reducer.js +6 -0
  35. package/lib/webchat/webchat-reducer.js.map +1 -1
  36. package/lib/webchat/webchat.js +21 -4
  37. package/lib/webchat/webchat.js.map +1 -1
  38. package/lib/webchat/webview.js +1 -1
  39. package/lib/webchat-app.js +20 -9
  40. package/lib/webchat-app.js.map +1 -1
  41. package/package.json +6 -6
  42. package/src/components/button.jsx +2 -0
  43. package/src/dev-app.jsx +8 -3
  44. package/src/experimental/components/custom-message.jsx +2 -1
  45. package/src/experimental/components/message.jsx +14 -7
  46. package/src/experimental/constants.js +189 -0
  47. package/src/experimental/contexts.jsx +36 -0
  48. package/src/experimental/dev-app.jsx +14 -7
  49. package/src/experimental/index.js +32 -20
  50. package/src/experimental/msg-to-botonic.jsx +9 -9
  51. package/src/experimental/react-bot.jsx +1 -1
  52. package/src/experimental/util/dom.js +55 -0
  53. package/src/experimental/util/objects.js +39 -0
  54. package/src/experimental/util/webchat.js +61 -0
  55. package/src/experimental/webchat/actions.jsx +24 -0
  56. package/src/experimental/webchat/hooks.js +296 -0
  57. package/src/experimental/webchat/messages-reducer.js +86 -0
  58. package/src/experimental/webchat/session-view.jsx +166 -0
  59. package/src/experimental/webchat/webchat-dev.jsx +23 -19
  60. package/src/experimental/webchat/webchat-reducer.js +68 -0
  61. package/src/experimental/webchat/webchat.jsx +107 -75
  62. package/src/experimental/webchat-app.jsx +34 -15
  63. package/src/index.d.ts +1 -0
  64. package/src/util/dom.js +5 -3
  65. package/src/webchat/devices/device-adapter.js +16 -4
  66. package/src/webchat/devices/scrollbar-controller.js +9 -4
  67. package/src/webchat/webchat.jsx +2 -1
  68. package/src/webchat-app.jsx +6 -4
  69. package/lib/experimental/components/audio.js +0 -46
  70. package/lib/experimental/components/audio.js.map +0 -1
  71. package/lib/experimental/components/carousel.js +0 -194
  72. package/lib/experimental/components/carousel.js.map +0 -1
  73. package/lib/experimental/components/custom-message.js +0 -132
  74. package/lib/experimental/components/custom-message.js.map +0 -1
  75. package/lib/experimental/components/document.js +0 -69
  76. package/lib/experimental/components/document.js.map +0 -1
  77. package/lib/experimental/components/image.js +0 -47
  78. package/lib/experimental/components/image.js.map +0 -1
  79. package/lib/experimental/components/index.js +0 -184
  80. package/lib/experimental/components/index.js.map +0 -1
  81. package/lib/experimental/components/location.js +0 -54
  82. package/lib/experimental/components/location.js.map +0 -1
  83. package/lib/experimental/components/markdown.js +0 -103
  84. package/lib/experimental/components/markdown.js.map +0 -1
  85. package/lib/experimental/components/message.js +0 -353
  86. package/lib/experimental/components/message.js.map +0 -1
  87. package/lib/experimental/components/text.js +0 -80
  88. package/lib/experimental/components/text.js.map +0 -1
  89. package/lib/experimental/components/video.js +0 -49
  90. package/lib/experimental/components/video.js.map +0 -1
  91. package/lib/experimental/components/whatsapp-template.js +0 -53
  92. package/lib/experimental/components/whatsapp-template.js.map +0 -1
  93. package/lib/experimental/dev-app.js +0 -240
  94. package/lib/experimental/dev-app.js.map +0 -1
  95. package/lib/experimental/index.js +0 -1022
  96. package/lib/experimental/index.js.map +0 -1
  97. package/lib/experimental/msg-to-botonic.js +0 -162
  98. package/lib/experimental/msg-to-botonic.js.map +0 -1
  99. package/lib/experimental/node-app.js +0 -97
  100. package/lib/experimental/node-app.js.map +0 -1
  101. package/lib/experimental/react-bot.js +0 -167
  102. package/lib/experimental/react-bot.js.map +0 -1
  103. package/lib/experimental/webchat/assets/Inter-VariableFont_slnt,wght.ttf +0 -0
  104. package/lib/experimental/webchat/assets/botonic-logo-white.svg +0 -16
  105. package/lib/experimental/webchat/assets/messenger.svg +0 -10
  106. package/lib/experimental/webchat/assets/open-new-window.svg +0 -3
  107. package/lib/experimental/webchat/assets/open.svg +0 -3
  108. package/lib/experimental/webchat/assets/telegram.svg +0 -10
  109. package/lib/experimental/webchat/assets/webchat.svg +0 -21
  110. package/lib/experimental/webchat/assets/whatsapp.svg +0 -4
  111. package/lib/experimental/webchat/webchat-dev.js +0 -300
  112. package/lib/experimental/webchat/webchat-dev.js.map +0 -1
  113. package/lib/experimental/webchat/webchat.js +0 -1051
  114. package/lib/experimental/webchat/webchat.js.map +0 -1
  115. package/lib/experimental/webchat-app.js +0 -642
  116. package/lib/experimental/webchat-app.js.map +0 -1
@@ -77,8 +77,9 @@ export const customMessage = ({
77
77
  WrappedComponent.customTypeName = name
78
78
  // eslint-disable-next-line react/display-name
79
79
  WrappedComponent.deserialize = msg => {
80
+ const customMessageProps = msg.json
80
81
  return (
81
- <WrappedComponent {...msg}>
82
+ <WrappedComponent {...msg} {...customMessageProps}>
82
83
  {msg.replies.length > 0 &&
83
84
  msg.replies.map((r, i) => (
84
85
  <Reply key={i} payload={r.payload}>
@@ -1,4 +1,5 @@
1
1
  import { INPUT, isBrowser } from '@botonic/core'
2
+ import { MessageEventAck } from '@botonic/core/src/models/events/message'
2
3
  import React, { useContext, useEffect, useState } from 'react'
3
4
  import Fade from 'react-reveal/Fade'
4
5
  import styled from 'styled-components'
@@ -126,14 +127,18 @@ export const Message = props => {
126
127
  timestampStyle,
127
128
  } = resolveMessageTimestamps(getThemeProperty, enabletimestamps)
128
129
 
129
- const getEnvAck = () => {
130
- if (isDev) return 1
131
- if (!isFromUser) return 1
132
- if (props.ack !== undefined) return props.ack
133
- return 0
130
+ const resolveAck = ack => {
131
+ // Browser app version
132
+ // eslint-disable-next-line no-undef
133
+ if (typeof FULLSTACK === 'undefined' || !FULLSTACK) {
134
+ return MessageEventAck.RECEIVED
135
+ }
136
+ if (ack !== undefined) return ack
137
+ if (isFromBot) return MessageEventAck.RECEIVED
138
+ return MessageEventAck.DRAFT
134
139
  }
135
140
 
136
- const ack = getEnvAck()
141
+ const ack = resolveAck(props.ack)
137
142
 
138
143
  if (isBrowser()) {
139
144
  // eslint-disable-next-line react-hooks/rules-of-hooks
@@ -171,6 +176,8 @@ export const Message = props => {
171
176
  display: delay + typing == 0,
172
177
  customTypeName: decomposedChildren.customTypeName,
173
178
  ack: ack,
179
+ channel: props.channel,
180
+ idFromChannel: props.idFromChannel,
174
181
  }
175
182
  addMessage(message)
176
183
  }, [])
@@ -305,7 +312,7 @@ export const Message = props => {
305
312
  style={{
306
313
  ...getMessageStyle(),
307
314
  ...style,
308
- ...{ opacity: ack === 0 ? 0.6 : 1 },
315
+ ...{ opacity: ack === MessageEventAck.DRAFT ? 0.6 : 1 },
309
316
  }}
310
317
  {...otherProps}
311
318
  >
@@ -0,0 +1,189 @@
1
+ import BotonicLogo from '../assets/botonic_react_logo100x100.png'
2
+
3
+ export const SENDERS = {
4
+ bot: 'bot',
5
+ user: 'user',
6
+ }
7
+
8
+ export const COLORS = {
9
+ // http://chir.ag/projects/name-that-color
10
+ APPLE_GREEN: 'rgba(58, 156, 53, 1)',
11
+ BLEACHED_CEDAR_PURPLE: 'rgba(46, 32, 59, 1)',
12
+ BOTONIC_BLUE: 'rgba(0, 153, 255, 1)',
13
+ CACTUS_GREEN: 'rgba(96, 115, 94, 1)',
14
+ CONCRETE_WHITE: 'rgba(243, 243, 243, 1)',
15
+ CURIOUS_BLUE: 'rgba(38, 139, 210, 1)',
16
+ DAINTREE_BLUE: 'rgba(0, 43, 53, 1)',
17
+ ERROR_RED: 'rgba(255, 43, 94)',
18
+ FRINGY_FLOWER_GREEN: 'rgba(198, 231, 192, 1)',
19
+ GRAY: 'rgba(129, 129, 129, 1)',
20
+ LIGHT_GRAY: 'rgba(209, 209, 209, 1)',
21
+ MID_GRAY: 'rgba(105, 105, 115, 1)',
22
+ PIGEON_POST_BLUE_ALPHA_0_5: 'rgba(176, 196, 222, 0.5)',
23
+ SCORPION_GRAY: 'rgba(87, 87, 87, 1)',
24
+ SEASHELL_WHITE: 'rgba(241, 240, 240, 1)',
25
+ SILVER: 'rgba(200, 200, 200, 1)',
26
+ SOLID_BLACK_ALPHA_0_2: 'rgba(0, 0, 0, 0.2)',
27
+ SOLID_BLACK_ALPHA_0_5: 'rgba(0, 0, 0, 0.5)',
28
+ SOLID_BLACK: 'rgba(0, 0, 0, 1)',
29
+ SOLID_WHITE_ALPHA_0_2: 'rgba(255, 255, 255, 0.2)',
30
+ SOLID_WHITE_ALPHA_0_8: 'rgba(255, 255, 255, 0.8)',
31
+ SOLID_WHITE: 'rgba(255, 255, 255, 1)',
32
+ TASMAN_GRAY: 'rgba(209, 216, 207, 1)',
33
+ TRANSPARENT: 'rgba(0, 0, 0, 0)',
34
+ WILD_SAND_WHITE: 'rgba(244, 244, 244, 1)',
35
+ }
36
+
37
+ export const WEBCHAT = {
38
+ DEFAULTS: {
39
+ WIDTH: 300,
40
+ HEIGHT: 450,
41
+ TITLE: 'Botonic',
42
+ LOGO: BotonicLogo,
43
+ PLACEHOLDER: 'Ask me something...',
44
+ FONT_FAMILY: "'Noto Sans JP', sans-serif",
45
+ BORDER_RADIUS_TOP_CORNERS: '6px 6px 0px 0px',
46
+ ELEMENT_WIDTH: 222,
47
+ ELEMENT_MARGIN_RIGHT: 6,
48
+ STORAGE_KEY: 'botonicState',
49
+ HOST_ID: 'root',
50
+ ID: 'botonic-webchat',
51
+ BUTTON_AUTO_DISABLE: false,
52
+ BUTTON_DISABLED_STYLE: {
53
+ opacity: 0.5,
54
+ cursor: 'auto',
55
+ pointerEvents: 'none',
56
+ },
57
+ },
58
+ SELECTORS: {
59
+ SCROLLABLE_CONTENT: '#botonic-scrollable-content',
60
+ SIMPLEBAR_CONTENT: '.simplebar-content',
61
+ SIMPLEBAR_WRAPPER: '.simplebar-content-wrapper',
62
+ },
63
+ CUSTOM_PROPERTIES: {
64
+ // General
65
+ enableAnimations: 'animations.enable',
66
+ markdownStyle: 'markdownStyle',
67
+ scrollbar: 'scrollbar',
68
+ // Mobile
69
+ mobileBreakpoint: 'mobileBreakpoint',
70
+ mobileStyle: 'mobileStyle',
71
+ // Webviews
72
+ webviewHeaderStyle: 'webview.header.style',
73
+ webviewStyle: 'webview.style',
74
+ // Brand
75
+ brandColor: 'brand.color',
76
+ brandImage: 'brand.image',
77
+ // Header
78
+ customHeader: 'header.custom',
79
+ headerImage: 'header.image',
80
+ headerStyle: 'header.style',
81
+ headerSubtitle: 'header.subtitle',
82
+ headerTitle: 'header.title',
83
+ // Bot Message
84
+ botMessageBackground: 'message.bot.style.background',
85
+ botMessageBlobTick: 'message.bot.blobTick',
86
+ botMessageBlobTickStyle: 'message.bot.blobTickStyle',
87
+ botMessageBlobWidth: 'message.bot.blobWidth',
88
+ botMessageBorderColor: 'message.bot.style.borderColor',
89
+ botMessageImage: 'message.bot.image',
90
+ botMessageImageStyle: 'message.bot.imageStyle',
91
+ botMessageStyle: 'message.bot.style',
92
+ // User Message
93
+ customMessageTypes: 'message.customTypes',
94
+ messageStyle: 'message.style',
95
+ userMessageBackground: 'message.user.style.background',
96
+ userMessageBlobTick: 'message.user.blobTick',
97
+ userMessageBlobTickStyle: 'message.user.blobTickStyle',
98
+ userMessageBorderColor: 'message.user.style.borderColor',
99
+ userMessageStyle: 'message.user.style',
100
+ // Timestamps
101
+ enableMessageTimestamps: 'message.timestamps.enable',
102
+ messageTimestampsFormat: 'message.timestamps.format',
103
+ messageTimestampsStyle: 'message.timestamps.style',
104
+ // Intro
105
+ customIntro: 'intro.custom',
106
+ introImage: 'intro.image',
107
+ introStyle: 'intro.style',
108
+ // Buttons
109
+ buttonHoverBackground: 'button.hoverBackground',
110
+ buttonHoverTextColor: 'button.hoverTextColor',
111
+ buttonMessageType: 'button.messageType',
112
+ buttonStyle: 'button.style',
113
+ buttonDisabledStyle: 'button.disabledstyle',
114
+ buttonAutoDisable: 'button.autodisable',
115
+ buttonStyleBackground: 'button.style.background',
116
+ buttonStyleColor: 'button.style.color',
117
+ customButton: 'button.custom',
118
+ // Replies
119
+ alignReplies: 'replies.align',
120
+ customReply: 'reply.custom',
121
+ replyStyle: 'reply.style',
122
+ wrapReplies: 'replies.wrap',
123
+ // TriggerButton
124
+ customTrigger: 'triggerButton.custom',
125
+ triggerButtonImage: 'triggerButton.image',
126
+ triggerButtonStyle: 'triggerButton.style',
127
+ // User Input
128
+ blockInputs: 'userInput.blockInputs',
129
+ documentDownload: 'documentDownload',
130
+ customMenuButton: 'userInput.menuButton.custom',
131
+ customPersistentMenu: 'userInput.menu.custom',
132
+ customSendButton: 'userInput.sendButton.custom',
133
+ darkBackgroundMenu: 'userInput.menu.darkBackground',
134
+ enableAttachments: 'userInput.attachments.enable',
135
+ enableEmojiPicker: 'userInput.emojiPicker.enable',
136
+ enableSendButton: 'userInput.sendButton.enable',
137
+ enableUserInput: 'userInput.enable',
138
+ persistentMenu: 'userInput.persistentMenu',
139
+ textPlaceholder: 'userInput.box.placeholder',
140
+ userInputBoxStyle: 'userInput.box.style',
141
+ userInputStyle: 'userInput.style',
142
+ // Cover Component
143
+ coverComponent: 'coverComponent.component',
144
+ coverComponentProps: 'coverComponent.props',
145
+ // Carousel
146
+ customCarouselLeftArrow: 'carousel.arrow.left',
147
+ customCarouselRightArrow: 'carousel.arrow.right',
148
+ enableCarouselArrows: 'carousel.enableArrows',
149
+ },
150
+ }
151
+
152
+ export const MIME_WHITELIST = {
153
+ audio: ['audio/mpeg', 'audio/mp3'],
154
+ document: ['application/pdf'],
155
+ image: ['image/jpeg', 'image/png'],
156
+ video: ['video/mp4', 'video/quicktime'],
157
+ }
158
+
159
+ export const MAX_ALLOWED_SIZE_MB = 10
160
+
161
+ export const ROLES = {
162
+ ATTACHMENT_ICON: 'attachment-icon',
163
+ EMOJI_PICKER_ICON: 'emoji-picker-icon',
164
+ EMOJI_PICKER: 'emoji-picker',
165
+ HEADER: 'header',
166
+ MESSAGE_LIST: 'message-list',
167
+ PERSISTENT_MENU_ICON: 'persistent-menu-icon',
168
+ PERSISTENT_MENU: 'persistent-menu',
169
+ SEND_BUTTON_ICON: 'send-button-icon',
170
+ WEBCHAT: 'webchat',
171
+ TRIGGER_BUTTON: 'trigger-button',
172
+ TYPING_INDICATOR: 'typing-indicator',
173
+ TEXT_BOX: 'textbox',
174
+ WEBVIEW: 'webview',
175
+ WEBVIEW_HEADER: 'webview-header',
176
+ MESSAGE: 'message',
177
+ IMAGE_MESSAGE: 'image-message',
178
+ AUDIO_MESSAGE: 'audio-message',
179
+ VIDEO_MESSAGE: 'video-message',
180
+ DOCUMENT_MESSAGE: 'document-message',
181
+ RAW_MESSAGE: 'raw-message',
182
+ }
183
+
184
+ export const COMPONENT_TYPE = {
185
+ TEXT: 'Text',
186
+ BUTTON: 'Button',
187
+ REPLY: 'Reply',
188
+ CAROUSEL: 'Carousel',
189
+ }
@@ -0,0 +1,36 @@
1
+ import React from 'react'
2
+
3
+ import { webchatInitialState } from './webchat/hooks'
4
+
5
+ export const RequestContext = React.createContext({
6
+ getString: () => '',
7
+ setLocale: () => '',
8
+ session: {},
9
+ params: {},
10
+ input: {},
11
+ defaultDelay: 0,
12
+ defaultTyping: 0,
13
+ })
14
+
15
+ export const WebchatContext = React.createContext({
16
+ sendText: text => {},
17
+ sendAttachment: attachment => {},
18
+ sendPayload: payload => {},
19
+ sendInput: input => {},
20
+ setReplies: replies => {},
21
+ openWebview: webviewComponent => {},
22
+ addMessage: message => {},
23
+ updateMessage: message => {},
24
+ updateReplies: replies => {},
25
+ updateLatestInput: input => {},
26
+ closeWebview: () => {},
27
+ toggleWebchat: () => {},
28
+ getThemeProperty: property => undefined, // used to retrieve a specific property of the theme defined by the developer in his 'webchat/index.js'
29
+ resolveCase: () => {},
30
+ theme: {},
31
+ webchatState: webchatInitialState,
32
+ updateWebchatDevSettings: settings => {
33
+ return {}
34
+ },
35
+ updateUser: user => {},
36
+ })
@@ -2,9 +2,9 @@ import merge from 'lodash.merge'
2
2
  import React from 'react'
3
3
  import { render } from 'react-dom'
4
4
 
5
- import { SENDERS } from '../constants'
6
- import { onDOMLoaded } from '../util/dom'
5
+ import { SENDERS } from './constants'
7
6
  import { ReactBot } from './react-bot'
7
+ import { onDOMLoaded } from './util/dom'
8
8
  import { WebchatDev } from './webchat/webchat-dev'
9
9
  import { WebchatApp } from './webchat-app'
10
10
 
@@ -51,7 +51,7 @@ export class DevApp extends WebchatApp {
51
51
  })
52
52
  }
53
53
 
54
- getComponent(optionsAtRuntime = {}) {
54
+ getComponent(host, optionsAtRuntime = {}) {
55
55
  let {
56
56
  theme = {},
57
57
  persistentMenu,
@@ -67,6 +67,7 @@ export class DevApp extends WebchatApp {
67
67
  onOpen,
68
68
  onClose,
69
69
  onMessage,
70
+ hostId,
70
71
  ...webchatOptions
71
72
  } = optionsAtRuntime
72
73
  theme = merge(this.theme, theme)
@@ -83,6 +84,8 @@ export class DevApp extends WebchatApp {
83
84
  this.onOpen = onOpen || this.onOpen
84
85
  this.onClose = onClose || this.onClose
85
86
  this.onMessage = onMessage || this.onMessage
87
+ this.hostId = hostId || this.hostId
88
+ this.createRootElement(host)
86
89
  return (
87
90
  <WebchatDev
88
91
  {...webchatOptions}
@@ -99,8 +102,10 @@ export class DevApp extends WebchatApp {
99
102
  enableAnimations={enableAnimations}
100
103
  storage={storage}
101
104
  storageKey={storageKey}
102
- getString={(stringId, session) => this.bot.getString(stringId, session)}
103
- setLocale={(locale, session) => this.bot.setLocale(locale, session)}
105
+ getString={(stringId, botState) =>
106
+ this.bot.getString(stringId, botState)
107
+ }
108
+ setLocale={(locale, botState) => this.bot.setLocale(locale, botState)}
104
109
  onInit={(...args) => this.onInitWebchat(...args)}
105
110
  onOpen={(...args) => this.onOpenWebchat(...args)}
106
111
  onClose={(...args) => this.onCloseWebchat(...args)}
@@ -111,8 +116,10 @@ export class DevApp extends WebchatApp {
111
116
 
112
117
  render(dest, optionsAtRuntime = {}) {
113
118
  onDOMLoaded(() => {
114
- this.createRootElement(dest)
115
- render(this.getComponent(optionsAtRuntime), this.getReactMountNode(dest))
119
+ render(
120
+ this.getComponent(dest, optionsAtRuntime),
121
+ this.getReactMountNode(dest)
122
+ )
116
123
  })
117
124
  }
118
125
 
@@ -38,23 +38,29 @@ class WebsocketBackendService {
38
38
  // On Event Received...
39
39
  this.wsClient.addEventListener('message', event => {
40
40
  console.log(event, this.onEvent)
41
- const message = JSON.parse(decode(event.data))
41
+ const eventData = JSON.parse(decode(event.data))
42
42
  if (this.onEvent && typeof this.onEvent === 'function')
43
- this.onEvent({ message })
43
+ this.onEvent(eventData)
44
44
  })
45
45
  }
46
46
  async doAuthAndUpdateJwt() {
47
- this.jwt = await this.doAuth({ userId: this.user.id })
47
+ this.jwt = await this.doAuth({
48
+ userId: this.user.id,
49
+ channel: this.user.channel,
50
+ idFromChannel: this.user.idFromChannel,
51
+ })
48
52
  this.updateJwt(this.jwt)
49
53
  }
50
54
 
51
- async doAuth({ userId }) {
55
+ async doAuth({ userId, channel, idFromChannel }) {
52
56
  try {
53
57
  const {
54
58
  data: { token },
55
59
  // eslint-disable-next-line no-undef
56
60
  } = await axios.post(`${REST_API_URL}auth/`, {
57
61
  userId,
62
+ channel,
63
+ idFromChannel,
58
64
  })
59
65
  return token
60
66
  } catch (e) {
@@ -72,7 +78,7 @@ class WebsocketBackendService {
72
78
  `${REST_API_URL}events/`,
73
79
  {
74
80
  message,
75
- sender: user,
81
+ sender: user, // TODO: Really needed or we should pass user information through JWT?
76
82
  },
77
83
  { headers: { Authorization: 'Bearer ' + this.jwt } } // Note: Do not use string template as it will convert the token with commas, which will be invalid
78
84
  )
@@ -85,22 +91,22 @@ class WebsocketBackendService {
85
91
  if (hasErrors) {
86
92
  // TODO: Handle rest of errors
87
93
  await this.doAuthAndUpdateJwt()
88
- await this.postMessage(user, message)
94
+ // await this.postMessage(user, message) // Temporary, avoid infinite events loop
89
95
  }
90
96
  }
91
97
  }
92
98
 
93
99
  export class FullstackProdApp extends WebchatApp {
94
- async onUserInput({ user, input }) {
95
- this.onMessage && this.onMessage(this, { from: 'user', message: input })
100
+ async onUserInput({ user, input, session, botState }) {
101
+ this.onMessage && this.onMessage(this, { from: input.from, message: input })
96
102
  this.backendService.postMessage(user, input)
97
103
  }
98
104
 
99
- async doAuth({ userId }) {
100
- return await this.backendService.doAuth({ userId })
105
+ async doAuth(user) {
106
+ return await this.backendService.doAuth(user)
101
107
  }
102
108
 
103
- onStateChange({ session: { user }, messagesJSON, jwt, updateJwt }) {
109
+ onStateChange({ user, messagesJSON, jwt, updateJwt }) {
104
110
  if (!this.backendService && user) {
105
111
  const lastMessage = messagesJSON[messagesJSON.length - 1]
106
112
  this.backendService = new WebsocketBackendService({
@@ -121,12 +127,12 @@ export class FullstackDevApp extends DevApp {
121
127
  console.log('FullstackDevApp ', args.playgroundCode)
122
128
  }
123
129
 
124
- async onUserInput({ user, input }) {
125
- this.onMessage && this.onMessage(this, { from: 'user', message: input })
130
+ async onUserInput({ user, input, session, botState }) {
131
+ this.onMessage && this.onMessage(this, { from: input.from, message: input })
126
132
  this.backendService && this.backendService.postMessage(user, input)
127
133
  }
128
134
 
129
- getComponent(optionsAtRuntime = {}) {
135
+ getComponent(host, optionsAtRuntime = {}) {
130
136
  let {
131
137
  theme = {},
132
138
  persistentMenu,
@@ -142,6 +148,7 @@ export class FullstackDevApp extends DevApp {
142
148
  onOpen,
143
149
  onClose,
144
150
  onMessage,
151
+ hostId,
145
152
  ...webchatOptions
146
153
  } = optionsAtRuntime
147
154
  theme = merge(this.theme, theme)
@@ -158,6 +165,8 @@ export class FullstackDevApp extends DevApp {
158
165
  this.onOpen = onOpen || this.onOpen
159
166
  this.onClose = onClose || this.onClose
160
167
  this.onMessage = onMessage || this.onMessage
168
+ this.hostId = hostId || this.hostId
169
+ this.createRootElement(host)
161
170
  return (
162
171
  <WebchatDev
163
172
  {...webchatOptions}
@@ -176,8 +185,10 @@ export class FullstackDevApp extends DevApp {
176
185
  storageKey={storageKey}
177
186
  playgroundCode={this.playgroundCode}
178
187
  onStateChange={webchatState => this.onStateChange(webchatState)}
179
- getString={(stringId, session) => this.bot.getString(stringId, session)}
180
- setLocale={(locale, session) => this.bot.setLocale(locale, session)}
188
+ getString={(stringId, botState) =>
189
+ this.bot.getString(stringId, botState)
190
+ }
191
+ setLocale={(locale, botState) => this.bot.setLocale(locale, botState)}
181
192
  onInit={(...args) => this.onInitWebchat(...args)}
182
193
  onOpen={(...args) => this.onOpenWebchat(...args)}
183
194
  onClose={(...args) => this.onCloseWebchat(...args)}
@@ -187,11 +198,11 @@ export class FullstackDevApp extends DevApp {
187
198
  )
188
199
  }
189
200
 
190
- async doAuth({ userId }) {
191
- return await this.backendService.doAuth({ userId })
201
+ async doAuth(user) {
202
+ return await this.backendService.doAuth(user)
192
203
  }
193
204
 
194
- onStateChange({ session: { user }, messagesJSON, jwt, updateJwt }) {
205
+ onStateChange({ user, messagesJSON, jwt, updateJwt }) {
195
206
  if (!this.backendService && user) {
196
207
  const lastMessage = messagesJSON[messagesJSON.length - 1]
197
208
  this.backendService = new WebsocketBackendService({
@@ -257,6 +268,7 @@ export class BrowserProdApp extends WebchatApp {
257
268
  ...botOptions,
258
269
  })
259
270
  }
271
+ // TODO: Review how this be done for only browser versions
260
272
  async onUserInput({ input, session, lastRoutePath }) {
261
273
  this.onMessage && this.onMessage(this, { from: 'user', message: input })
262
274
  const resp = await this.bot.input({ input, session, lastRoutePath })
@@ -277,10 +289,10 @@ export { ShareButton } from '../components/share-button'
277
289
  export { Subtitle } from '../components/subtitle'
278
290
  export { Title } from '../components/title'
279
291
  export { WebchatSettings } from '../components/webchat-settings'
280
- export { RequestContext, WebchatContext } from '../contexts'
281
292
  export { staticAsset } from '../util/environment'
282
293
  export { getBotonicApp } from '../webchat'
283
294
  export { WebviewApp } from '../webview'
295
+ export { RequestContext, WebchatContext } from './contexts'
284
296
  // Experimental
285
297
  export { Audio } from './components/audio'
286
298
  export { Carousel } from './components/carousel'
@@ -1,5 +1,12 @@
1
1
  import React from 'react'
2
2
 
3
+ import { Button } from '../components/button'
4
+ import { ButtonsDisabler } from '../components/buttons-disabler'
5
+ import { Element } from '../components/element'
6
+ import { Pic } from '../components/pic'
7
+ import { Reply } from '../components/reply'
8
+ import { Subtitle } from '../components/subtitle'
9
+ import { Title } from '../components/title'
3
10
  import {
4
11
  isAudio,
5
12
  isCarousel,
@@ -9,14 +16,7 @@ import {
9
16
  isLocation,
10
17
  isText,
11
18
  isVideo,
12
- } from '../../src/message-utils'
13
- import { Button } from '../components/button'
14
- import { ButtonsDisabler } from '../components/buttons-disabler'
15
- import { Element } from '../components/element'
16
- import { Pic } from '../components/pic'
17
- import { Reply } from '../components/reply'
18
- import { Subtitle } from '../components/subtitle'
19
- import { Title } from '../components/title'
19
+ } from '../message-utils'
20
20
  // Experimental
21
21
  import { Audio } from './components/audio'
22
22
  import { Carousel } from './components/carousel'
@@ -39,7 +39,7 @@ export function msgToBotonic(msg, customMessageTypes) {
39
39
  if (isCustom(msg)) {
40
40
  try {
41
41
  return customMessageTypes
42
- .find(mt => mt.customTypeName === msg.customTypeName)
42
+ .find(mt => mt.customTypeName === msg.json.customTypeName)
43
43
  .deserialize(msg)
44
44
  } catch (e) {
45
45
  console.log(e)
@@ -1,8 +1,8 @@
1
1
  import { CoreBot } from '@botonic/core'
2
2
  import React from 'react'
3
3
 
4
- import { RequestContext } from '../contexts'
5
4
  import { Text } from './components/text'
5
+ import { RequestContext } from './contexts'
6
6
 
7
7
  export class ReactBot extends CoreBot {
8
8
  constructor(options) {
@@ -0,0 +1,55 @@
1
+ import { WEBCHAT } from '../constants'
2
+
3
+ export const getScrollableArea = webchatElement => {
4
+ const getArea = area => {
5
+ const botonicScrollableContent = webchatElement.querySelector(
6
+ WEBCHAT.SELECTORS.SCROLLABLE_CONTENT
7
+ )
8
+ const scrollableArea =
9
+ botonicScrollableContent && botonicScrollableContent.querySelector(area)
10
+ return scrollableArea
11
+ }
12
+ return {
13
+ full: getArea(WEBCHAT.SELECTORS.SIMPLEBAR_CONTENT),
14
+ visible: getArea(WEBCHAT.SELECTORS.SIMPLEBAR_WRAPPER),
15
+ }
16
+ }
17
+
18
+ export const scrollToBottom = ({
19
+ timeout = 200,
20
+ behavior = 'smooth',
21
+ host,
22
+ } = {}) => {
23
+ const webchatElement = getWebchatElement(host)
24
+ if (!webchatElement) return
25
+ const frame = getScrollableArea(webchatElement).visible
26
+ if (frame) {
27
+ setTimeout(
28
+ () => frame.scrollTo({ top: frame.scrollHeight, behavior: behavior }),
29
+ timeout
30
+ )
31
+ }
32
+ }
33
+
34
+ export const getWebchatElement = host =>
35
+ host && host.querySelector(`#${WEBCHAT.DEFAULTS.ID}`)
36
+
37
+ // https://stackoverflow.com/questions/9457891/how-to-detect-if-domcontentloaded-was-fired
38
+ export const onDOMLoaded = callback => {
39
+ if (/complete|interactive|loaded/.test(document.readyState)) {
40
+ // In case the document has finished parsing, document's readyState will
41
+ // be one of "complete", "interactive" or (non-standard) "loaded".
42
+ callback()
43
+ } else {
44
+ // The document is not ready yet, so wait for the DOMContentLoaded event
45
+ document.addEventListener('DOMContentLoaded', callback, false)
46
+ }
47
+ }
48
+
49
+ export const isShadowDOMSupported = () => {
50
+ try {
51
+ return document.head.createShadowRoot || document.head.attachShadow
52
+ } catch (e) {
53
+ return false
54
+ }
55
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * given an object and a property, returns the property if exists (recursively), else undefined
3
+ * ex:
4
+ * let obj = { a: { b: { c: 5 } } }
5
+ * getProperty(obj, 'a.b.c'), returns 5
6
+ * getProperty(obj, 'a.b.z'), returns undefined
7
+ */
8
+ export const getProperty = (obj, property) => {
9
+ if (!property) return undefined
10
+ const properties = property.split('.')
11
+ for (let i = 0; i < properties.length; i++) {
12
+ const prop = properties[i]
13
+ // eslint-disable-next-line no-prototype-builtins
14
+ if (!obj || !obj.hasOwnProperty(prop)) {
15
+ return undefined
16
+ } else {
17
+ obj = obj[prop]
18
+ }
19
+ }
20
+ return obj
21
+ }
22
+
23
+ export function strToBool(string) {
24
+ const regex = /^\s*(true|1|on)\s*$/i
25
+ string = String(string)
26
+ return regex.test(string)
27
+ }
28
+
29
+ export const mapObject = (obj, conversion = ([key, value]) => [key, value]) => {
30
+ return (
31
+ obj &&
32
+ Object.entries(obj)
33
+ .map(conversion)
34
+ .reduce(function (prev, curr) {
35
+ prev[curr[0]] = curr[1]
36
+ return prev
37
+ }, {})
38
+ )
39
+ }