@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.
- package/lib/components/button.js +2 -0
- package/lib/components/button.js.map +1 -1
- package/lib/components/components.js +1 -1
- package/lib/components/image.js +47 -5
- package/lib/components/image.js.map +1 -1
- package/lib/components/index.js +6 -6
- package/lib/components/markdown.js +1 -1
- package/lib/components/multichannel/multichannel-utils.js +8 -6
- package/lib/components/multichannel/multichannel-utils.js.map +1 -1
- package/lib/components/timestamps.js +1 -1
- package/lib/constants.js +2 -1
- package/lib/constants.js.map +1 -1
- package/lib/dev-app.js +7 -6
- package/lib/dev-app.js.map +1 -1
- package/lib/index.d.ts +3 -0
- package/lib/index.js +20 -20
- package/lib/message-utils.js +1 -1
- package/lib/util/dom.js +8 -2
- package/lib/util/dom.js.map +1 -1
- package/lib/util/environment.js +1 -1
- package/lib/util/objects.js +1 -1
- package/lib/util/react.js +1 -1
- package/lib/util/webchat.js +1 -1
- package/lib/webchat/actions.js +3 -1
- package/lib/webchat/actions.js.map +1 -1
- package/lib/webchat/devices/device-adapter.js +14 -4
- package/lib/webchat/devices/device-adapter.js.map +1 -1
- package/lib/webchat/devices/scrollbar-controller.js +5 -3
- package/lib/webchat/devices/scrollbar-controller.js.map +1 -1
- package/lib/webchat/header.js +1 -1
- package/lib/webchat/hooks.js +14 -4
- package/lib/webchat/hooks.js.map +1 -1
- package/lib/webchat/index.js +1 -1
- package/lib/webchat/webchat-reducer.js +6 -0
- package/lib/webchat/webchat-reducer.js.map +1 -1
- package/lib/webchat/webchat.js +21 -4
- package/lib/webchat/webchat.js.map +1 -1
- package/lib/webchat/webview.js +1 -1
- package/lib/webchat-app.js +20 -9
- package/lib/webchat-app.js.map +1 -1
- package/package.json +6 -6
- package/src/components/button.jsx +2 -0
- package/src/dev-app.jsx +8 -3
- package/src/experimental/components/custom-message.jsx +2 -1
- package/src/experimental/components/message.jsx +14 -7
- package/src/experimental/constants.js +189 -0
- package/src/experimental/contexts.jsx +36 -0
- package/src/experimental/dev-app.jsx +14 -7
- package/src/experimental/index.js +32 -20
- package/src/experimental/msg-to-botonic.jsx +9 -9
- package/src/experimental/react-bot.jsx +1 -1
- package/src/experimental/util/dom.js +55 -0
- package/src/experimental/util/objects.js +39 -0
- package/src/experimental/util/webchat.js +61 -0
- package/src/experimental/webchat/actions.jsx +24 -0
- package/src/experimental/webchat/hooks.js +296 -0
- package/src/experimental/webchat/messages-reducer.js +86 -0
- package/src/experimental/webchat/session-view.jsx +166 -0
- package/src/experimental/webchat/webchat-dev.jsx +23 -19
- package/src/experimental/webchat/webchat-reducer.js +68 -0
- package/src/experimental/webchat/webchat.jsx +107 -75
- package/src/experimental/webchat-app.jsx +34 -15
- package/src/index.d.ts +1 -0
- package/src/util/dom.js +5 -3
- package/src/webchat/devices/device-adapter.js +16 -4
- package/src/webchat/devices/scrollbar-controller.js +9 -4
- package/src/webchat/webchat.jsx +2 -1
- package/src/webchat-app.jsx +6 -4
- package/lib/experimental/components/audio.js +0 -46
- package/lib/experimental/components/audio.js.map +0 -1
- package/lib/experimental/components/carousel.js +0 -194
- package/lib/experimental/components/carousel.js.map +0 -1
- package/lib/experimental/components/custom-message.js +0 -132
- package/lib/experimental/components/custom-message.js.map +0 -1
- package/lib/experimental/components/document.js +0 -69
- package/lib/experimental/components/document.js.map +0 -1
- package/lib/experimental/components/image.js +0 -47
- package/lib/experimental/components/image.js.map +0 -1
- package/lib/experimental/components/index.js +0 -184
- package/lib/experimental/components/index.js.map +0 -1
- package/lib/experimental/components/location.js +0 -54
- package/lib/experimental/components/location.js.map +0 -1
- package/lib/experimental/components/markdown.js +0 -103
- package/lib/experimental/components/markdown.js.map +0 -1
- package/lib/experimental/components/message.js +0 -353
- package/lib/experimental/components/message.js.map +0 -1
- package/lib/experimental/components/text.js +0 -80
- package/lib/experimental/components/text.js.map +0 -1
- package/lib/experimental/components/video.js +0 -49
- package/lib/experimental/components/video.js.map +0 -1
- package/lib/experimental/components/whatsapp-template.js +0 -53
- package/lib/experimental/components/whatsapp-template.js.map +0 -1
- package/lib/experimental/dev-app.js +0 -240
- package/lib/experimental/dev-app.js.map +0 -1
- package/lib/experimental/index.js +0 -1022
- package/lib/experimental/index.js.map +0 -1
- package/lib/experimental/msg-to-botonic.js +0 -162
- package/lib/experimental/msg-to-botonic.js.map +0 -1
- package/lib/experimental/node-app.js +0 -97
- package/lib/experimental/node-app.js.map +0 -1
- package/lib/experimental/react-bot.js +0 -167
- package/lib/experimental/react-bot.js.map +0 -1
- package/lib/experimental/webchat/assets/Inter-VariableFont_slnt,wght.ttf +0 -0
- package/lib/experimental/webchat/assets/botonic-logo-white.svg +0 -16
- package/lib/experimental/webchat/assets/messenger.svg +0 -10
- package/lib/experimental/webchat/assets/open-new-window.svg +0 -3
- package/lib/experimental/webchat/assets/open.svg +0 -3
- package/lib/experimental/webchat/assets/telegram.svg +0 -10
- package/lib/experimental/webchat/assets/webchat.svg +0 -21
- package/lib/experimental/webchat/assets/whatsapp.svg +0 -4
- package/lib/experimental/webchat/webchat-dev.js +0 -300
- package/lib/experimental/webchat/webchat-dev.js.map +0 -1
- package/lib/experimental/webchat/webchat.js +0 -1051
- package/lib/experimental/webchat/webchat.js.map +0 -1
- package/lib/experimental/webchat-app.js +0 -642
- package/lib/experimental/webchat-app.js.map +0 -1
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SET_CURRENT_ATTACHMENT,
|
|
3
|
+
SET_ERROR,
|
|
4
|
+
SET_ONLINE,
|
|
5
|
+
TOGGLE_COVER_COMPONENT,
|
|
6
|
+
TOGGLE_EMOJI_PICKER,
|
|
7
|
+
TOGGLE_PERSISTENT_MENU,
|
|
8
|
+
TOGGLE_WEBCHAT,
|
|
9
|
+
UPDATE_BOT_STATE,
|
|
10
|
+
UPDATE_DEV_SETTINGS,
|
|
11
|
+
UPDATE_HANDOFF,
|
|
12
|
+
UPDATE_JWT,
|
|
13
|
+
UPDATE_LAST_ROUTE_PATH,
|
|
14
|
+
UPDATE_LATEST_INPUT,
|
|
15
|
+
UPDATE_SESSION,
|
|
16
|
+
UPDATE_THEME,
|
|
17
|
+
UPDATE_TYPING,
|
|
18
|
+
UPDATE_USER,
|
|
19
|
+
UPDATE_WEBVIEW,
|
|
20
|
+
} from './actions'
|
|
21
|
+
import { messagesReducer } from './messages-reducer'
|
|
22
|
+
|
|
23
|
+
// eslint-disable-next-line complexity
|
|
24
|
+
export function webchatReducer(state, action) {
|
|
25
|
+
switch (action.type) {
|
|
26
|
+
case UPDATE_WEBVIEW:
|
|
27
|
+
return { ...state, ...action.payload }
|
|
28
|
+
case UPDATE_TYPING:
|
|
29
|
+
return { ...state, typing: action.payload }
|
|
30
|
+
case UPDATE_THEME:
|
|
31
|
+
return {
|
|
32
|
+
...state,
|
|
33
|
+
...action.payload,
|
|
34
|
+
}
|
|
35
|
+
case UPDATE_HANDOFF:
|
|
36
|
+
return { ...state, handoff: action.payload }
|
|
37
|
+
case TOGGLE_WEBCHAT:
|
|
38
|
+
return { ...state, isWebchatOpen: action.payload }
|
|
39
|
+
case TOGGLE_EMOJI_PICKER:
|
|
40
|
+
return { ...state, isEmojiPickerOpen: action.payload }
|
|
41
|
+
case TOGGLE_PERSISTENT_MENU:
|
|
42
|
+
return { ...state, isPersistentMenuOpen: action.payload }
|
|
43
|
+
case TOGGLE_COVER_COMPONENT:
|
|
44
|
+
return { ...state, isCoverComponentOpen: action.payload }
|
|
45
|
+
case SET_ERROR:
|
|
46
|
+
return { ...state, error: action.payload || {} }
|
|
47
|
+
case SET_ONLINE:
|
|
48
|
+
return { ...state, online: action.payload }
|
|
49
|
+
case UPDATE_DEV_SETTINGS:
|
|
50
|
+
return { ...state, devSettings: { ...action.payload } }
|
|
51
|
+
case UPDATE_LATEST_INPUT:
|
|
52
|
+
return { ...state, latestInput: action.payload }
|
|
53
|
+
case UPDATE_LAST_ROUTE_PATH:
|
|
54
|
+
return { ...state, lastRoutePath: action.payload }
|
|
55
|
+
case SET_CURRENT_ATTACHMENT:
|
|
56
|
+
return { ...state, currentAttachment: action.payload }
|
|
57
|
+
case UPDATE_JWT:
|
|
58
|
+
return { ...state, jwt: action.payload }
|
|
59
|
+
case UPDATE_USER:
|
|
60
|
+
return { ...state, user: action.payload }
|
|
61
|
+
case UPDATE_SESSION:
|
|
62
|
+
return { ...state, session: action.payload }
|
|
63
|
+
case UPDATE_BOT_STATE:
|
|
64
|
+
return { ...state, botState: action.payload }
|
|
65
|
+
default:
|
|
66
|
+
return messagesReducer(state, action)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { INPUT, isMobile, params2queryString } from '@botonic/core'
|
|
2
|
+
import {
|
|
3
|
+
MessageEventAck,
|
|
4
|
+
MessageEventFrom,
|
|
5
|
+
} from '@botonic/core/src/models/events/message'
|
|
2
6
|
import { motion } from 'framer-motion'
|
|
3
7
|
import merge from 'lodash.merge'
|
|
4
8
|
import React, {
|
|
@@ -38,12 +42,6 @@ import { scrollToBottom } from '../../util/dom'
|
|
|
38
42
|
import { isDev, resolveImage } from '../../util/environment'
|
|
39
43
|
import { ConditionalWrapper } from '../../util/react'
|
|
40
44
|
import { deserializeRegex, stringifyWithRegexs } from '../../util/regexs'
|
|
41
|
-
import {
|
|
42
|
-
_getThemeProperty,
|
|
43
|
-
getServerErrorMessage,
|
|
44
|
-
initSession,
|
|
45
|
-
shouldKeepSessionOnReload,
|
|
46
|
-
} from '../../util/webchat'
|
|
47
45
|
import { Attachment } from '../../webchat/components/attachment'
|
|
48
46
|
import {
|
|
49
47
|
EmojiPicker,
|
|
@@ -57,12 +55,6 @@ import { SendButton } from '../../webchat/components/send-button'
|
|
|
57
55
|
import { TypingIndicator } from '../../webchat/components/typing-indicator'
|
|
58
56
|
import { DeviceAdapter } from '../../webchat/devices/device-adapter'
|
|
59
57
|
import { StyledWebchatHeader } from '../../webchat/header'
|
|
60
|
-
import {
|
|
61
|
-
useComponentWillMount,
|
|
62
|
-
usePrevious,
|
|
63
|
-
useTyping,
|
|
64
|
-
useWebchat,
|
|
65
|
-
} from '../../webchat/hooks'
|
|
66
58
|
import { WebchatMessageList } from '../../webchat/message-list'
|
|
67
59
|
import { WebchatReplies } from '../../webchat/replies'
|
|
68
60
|
import { useStorageState } from '../../webchat/use-storage-state-hook'
|
|
@@ -70,6 +62,18 @@ import { WebviewContainer } from '../../webchat/webview'
|
|
|
70
62
|
import { Audio, Document, Image, Video } from '../components'
|
|
71
63
|
import { Text } from '../components/text'
|
|
72
64
|
import { msgToBotonic } from '../msg-to-botonic'
|
|
65
|
+
import {
|
|
66
|
+
_getThemeProperty,
|
|
67
|
+
getServerErrorMessage,
|
|
68
|
+
initUser,
|
|
69
|
+
shouldKeepSessionOnReload,
|
|
70
|
+
} from '../util/webchat'
|
|
71
|
+
import {
|
|
72
|
+
useComponentWillMount,
|
|
73
|
+
usePrevious,
|
|
74
|
+
useTyping,
|
|
75
|
+
useWebchat,
|
|
76
|
+
} from '../webchat/hooks'
|
|
73
77
|
export const getParsedAction = botonicAction => {
|
|
74
78
|
const splittedAction = botonicAction.split('create_case:')
|
|
75
79
|
if (splittedAction.length <= 1) return undefined
|
|
@@ -177,7 +181,6 @@ export const Webchat = forwardRef((props, ref) => {
|
|
|
177
181
|
updateLatestInput,
|
|
178
182
|
updateTyping,
|
|
179
183
|
updateWebview,
|
|
180
|
-
updateSession,
|
|
181
184
|
updateLastRoutePath,
|
|
182
185
|
updateHandoff,
|
|
183
186
|
updateTheme,
|
|
@@ -194,14 +197,23 @@ export const Webchat = forwardRef((props, ref) => {
|
|
|
194
197
|
updateLastMessageDate,
|
|
195
198
|
setCurrentAttachment,
|
|
196
199
|
updateJwt,
|
|
200
|
+
updateUser,
|
|
201
|
+
updateSession,
|
|
202
|
+
updateBotState,
|
|
197
203
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
198
204
|
} = props.webchatHooks || useWebchat()
|
|
199
205
|
|
|
200
206
|
const firstUpdate = useRef(true)
|
|
201
|
-
const isOnline = () => webchatState.
|
|
207
|
+
const isOnline = () => webchatState.isWebchatOnline
|
|
202
208
|
const currentDateString = () => new Date().toISOString()
|
|
203
209
|
const theme = merge(webchatState.theme, props.theme)
|
|
204
|
-
const {
|
|
210
|
+
const {
|
|
211
|
+
initialUser,
|
|
212
|
+
initialSession,
|
|
213
|
+
initialBotState,
|
|
214
|
+
initialDevSettings,
|
|
215
|
+
onStateChange,
|
|
216
|
+
} = props
|
|
205
217
|
const getThemeProperty = _getThemeProperty(theme)
|
|
206
218
|
|
|
207
219
|
const storage = props.storage === undefined ? localStorage : props.storage
|
|
@@ -223,12 +235,13 @@ export const Webchat = forwardRef((props, ref) => {
|
|
|
223
235
|
JSON.parse(
|
|
224
236
|
stringifyWithRegexs({
|
|
225
237
|
messages: webchatState.messagesJSON,
|
|
226
|
-
session: webchatState.session,
|
|
227
|
-
lastRoutePath: webchatState.lastRoutePath,
|
|
228
238
|
devSettings: webchatState.devSettings,
|
|
229
239
|
lastMessageUpdate: webchatState.lastMessageUpdate,
|
|
230
240
|
themeUpdates: webchatState.themeUpdates,
|
|
231
241
|
jwt: webchatState.jwt,
|
|
242
|
+
user: webchatState.user,
|
|
243
|
+
session: webchatState.session,
|
|
244
|
+
botState: webchatState.botState,
|
|
232
245
|
})
|
|
233
246
|
)
|
|
234
247
|
)
|
|
@@ -256,10 +269,10 @@ export const Webchat = forwardRef((props, ref) => {
|
|
|
256
269
|
const sendUserInput = async input => {
|
|
257
270
|
props.onUserInput &&
|
|
258
271
|
props.onUserInput({
|
|
259
|
-
user: webchatState.
|
|
260
|
-
input
|
|
272
|
+
user: webchatState.user,
|
|
273
|
+
input,
|
|
261
274
|
session: webchatState.session,
|
|
262
|
-
|
|
275
|
+
botState: webchatState.botState,
|
|
263
276
|
})
|
|
264
277
|
}
|
|
265
278
|
|
|
@@ -293,16 +306,18 @@ export const Webchat = forwardRef((props, ref) => {
|
|
|
293
306
|
|
|
294
307
|
// Load initial state from storage
|
|
295
308
|
useEffect(() => {
|
|
296
|
-
|
|
309
|
+
const {
|
|
297
310
|
messages,
|
|
298
|
-
session,
|
|
299
311
|
lastRoutePath,
|
|
300
312
|
devSettings,
|
|
301
313
|
lastMessageUpdate,
|
|
302
314
|
themeUpdates,
|
|
315
|
+
user,
|
|
316
|
+
session,
|
|
317
|
+
botState,
|
|
303
318
|
} = botonicState || {}
|
|
304
|
-
|
|
305
|
-
|
|
319
|
+
updateUser(merge(initialUser, initUser(user)))
|
|
320
|
+
|
|
306
321
|
if (shouldKeepSessionOnReload({ initialDevSettings, devSettings })) {
|
|
307
322
|
if (messages) {
|
|
308
323
|
messages.forEach(m => {
|
|
@@ -315,9 +330,16 @@ export const Webchat = forwardRef((props, ref) => {
|
|
|
315
330
|
if (newComponent) addMessageComponent(newComponent)
|
|
316
331
|
})
|
|
317
332
|
}
|
|
318
|
-
if (initialSession)
|
|
319
|
-
|
|
320
|
-
|
|
333
|
+
if (initialSession) {
|
|
334
|
+
updateSession(merge(initialSession, session))
|
|
335
|
+
}
|
|
336
|
+
if (initialBotState) {
|
|
337
|
+
updateBotState(merge(initialBotState, botState))
|
|
338
|
+
}
|
|
339
|
+
} else {
|
|
340
|
+
updateSession(merge(initialSession, session))
|
|
341
|
+
updateBotState(merge(initialBotState, botState))
|
|
342
|
+
}
|
|
321
343
|
if (devSettings) updateDevSettings(devSettings)
|
|
322
344
|
else if (initialDevSettings) updateDevSettings(initialDevSettings)
|
|
323
345
|
if (lastMessageUpdate) updateLastMessageDate(lastMessageUpdate)
|
|
@@ -333,21 +355,26 @@ export const Webchat = forwardRef((props, ref) => {
|
|
|
333
355
|
}, [webchatState.isWebchatOpen])
|
|
334
356
|
|
|
335
357
|
useEffect(() => {
|
|
336
|
-
if (
|
|
358
|
+
if (
|
|
359
|
+
onStateChange &&
|
|
360
|
+
typeof onStateChange === 'function' &&
|
|
361
|
+
webchatState.user.id
|
|
362
|
+
) {
|
|
337
363
|
onStateChange({ ...webchatState, updateJwt })
|
|
338
364
|
}
|
|
339
365
|
saveWebchatState(webchatState)
|
|
340
366
|
}, [
|
|
341
367
|
webchatState.messagesJSON,
|
|
342
|
-
webchatState.session,
|
|
343
|
-
webchatState.lastRoutePath,
|
|
344
368
|
webchatState.devSettings,
|
|
345
369
|
webchatState.lastMessageUpdate,
|
|
346
370
|
webchatState.jwt,
|
|
371
|
+
webchatState.user,
|
|
372
|
+
webchatState.session,
|
|
373
|
+
webchatState.botState,
|
|
347
374
|
])
|
|
348
375
|
|
|
349
376
|
useAsyncEffect(async () => {
|
|
350
|
-
if (!webchatState.
|
|
377
|
+
if (!webchatState.isWebchatOnline) {
|
|
351
378
|
setError({
|
|
352
379
|
message: getServerErrorMessage(props.server),
|
|
353
380
|
})
|
|
@@ -356,7 +383,7 @@ export const Webchat = forwardRef((props, ref) => {
|
|
|
356
383
|
setError(undefined)
|
|
357
384
|
}
|
|
358
385
|
}
|
|
359
|
-
}, [webchatState.
|
|
386
|
+
}, [webchatState.isWebchatOnline])
|
|
360
387
|
|
|
361
388
|
useTyping({ webchatState, updateTyping, updateMessage, host })
|
|
362
389
|
|
|
@@ -423,7 +450,7 @@ export const Webchat = forwardRef((props, ref) => {
|
|
|
423
450
|
)
|
|
424
451
|
if (!Array.isArray(blockInputs)) return false
|
|
425
452
|
for (const rule of blockInputs) {
|
|
426
|
-
if (getBlockInputs(rule, input.
|
|
453
|
+
if (getBlockInputs(rule, input.text)) {
|
|
427
454
|
addMessageComponent(
|
|
428
455
|
<Text
|
|
429
456
|
id={input.id}
|
|
@@ -498,36 +525,36 @@ export const Webchat = forwardRef((props, ref) => {
|
|
|
498
525
|
|
|
499
526
|
const messageComponentFromInput = input => {
|
|
500
527
|
let messageComponent = null
|
|
528
|
+
let props = { ...input }
|
|
501
529
|
if (isText(input)) {
|
|
502
|
-
messageComponent =
|
|
503
|
-
<Text id={input.id} payload={input.payload} from={SENDERS.user}>
|
|
504
|
-
{input.data}
|
|
505
|
-
</Text>
|
|
506
|
-
)
|
|
530
|
+
messageComponent = <Text {...props}>{input.text}</Text>
|
|
507
531
|
} else if (isMedia(input)) {
|
|
508
|
-
const temporaryDisplayUrl = URL.createObjectURL(input.
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
}
|
|
514
|
-
if (isImage(input)) messageComponent = <Image {...mediaProps} />
|
|
515
|
-
else if (isAudio(input)) messageComponent = <Audio {...mediaProps} />
|
|
516
|
-
else if (isVideo(input)) messageComponent = <Video {...mediaProps} />
|
|
517
|
-
else if (isDocument(input))
|
|
518
|
-
messageComponent = <Document {...mediaProps} />
|
|
532
|
+
const temporaryDisplayUrl = URL.createObjectURL(input.src)
|
|
533
|
+
props = { ...props, src: temporaryDisplayUrl }
|
|
534
|
+
if (isImage(input)) messageComponent = <Image {...props} />
|
|
535
|
+
else if (isAudio(input)) messageComponent = <Audio {...props} />
|
|
536
|
+
else if (isVideo(input)) messageComponent = <Video {...props} />
|
|
537
|
+
else if (isDocument(input)) messageComponent = <Document {...props} />
|
|
519
538
|
}
|
|
520
539
|
return messageComponent
|
|
521
540
|
}
|
|
522
541
|
|
|
523
542
|
const sendInput = async input => {
|
|
524
543
|
if (!input || Object.keys(input).length == 0) return
|
|
525
|
-
if (isText(input) && (!input.
|
|
544
|
+
if (isText(input) && (!input.text || !input.text.trim())) return // in case trim() doesn't work in a browser we can use !/\S/.test(input.text)
|
|
526
545
|
if (isText(input) && checkBlockInput(input)) return
|
|
527
546
|
if (!input.id) input.id = uuidv4()
|
|
547
|
+
const { idFromChannel, channel } = webchatState.user
|
|
548
|
+
input = {
|
|
549
|
+
idFromChannel,
|
|
550
|
+
channel,
|
|
551
|
+
ack: MessageEventAck.DRAFT,
|
|
552
|
+
from: MessageEventFrom.USER,
|
|
553
|
+
...input,
|
|
554
|
+
}
|
|
528
555
|
const messageComponent = messageComponentFromInput(input)
|
|
529
556
|
if (messageComponent) addMessageComponent(messageComponent)
|
|
530
|
-
if (isMedia(input)) input.
|
|
557
|
+
if (isMedia(input)) input.src = await readDataURL(input.src)
|
|
531
558
|
sendUserInput(input)
|
|
532
559
|
updateLatestInput(input)
|
|
533
560
|
isOnline() && updateLastMessageDate(currentDateString())
|
|
@@ -540,27 +567,28 @@ export const Webchat = forwardRef((props, ref) => {
|
|
|
540
567
|
https://stackoverflow.com/questions/37949981/call-child-method-from-parent
|
|
541
568
|
*/
|
|
542
569
|
|
|
543
|
-
const
|
|
544
|
-
|
|
570
|
+
const mergeAndUpdateUser = userToUpdate =>
|
|
571
|
+
updateUser(merge(webchatState.user, userToUpdate))
|
|
545
572
|
|
|
546
573
|
useImperativeHandle(ref, () => ({
|
|
547
574
|
addBotResponse: ({ response, session, lastRoutePath }) => {
|
|
548
575
|
updateTyping(false)
|
|
549
576
|
if (Array.isArray(response)) response.map(r => addMessageComponent(r))
|
|
550
577
|
else if (response) addMessageComponent(response)
|
|
551
|
-
if (session) {
|
|
552
|
-
updateSession(merge(session, { user: webchatState.session.user }))
|
|
553
|
-
const action = session._botonic_action || ''
|
|
554
|
-
const handoff = action.startsWith('create_case')
|
|
555
|
-
if (handoff && isDev) addMessageComponent(<Handoff />)
|
|
556
|
-
updateHandoff(handoff)
|
|
557
|
-
}
|
|
558
|
-
if (lastRoutePath) updateLastRoutePath(lastRoutePath)
|
|
559
578
|
updateLastMessageDate(currentDateString())
|
|
560
579
|
},
|
|
561
580
|
setTyping: typing => updateTyping(typing),
|
|
562
581
|
addUserMessage: message => sendInput(message),
|
|
563
|
-
updateUser:
|
|
582
|
+
updateUser: mergeAndUpdateUser,
|
|
583
|
+
updateBotState: botState => {
|
|
584
|
+
// TODO: Review handoff logic for 1.0
|
|
585
|
+
// const action = botState.botonicAction || ''
|
|
586
|
+
// // const isHandoff = action.startsWith('create_case')
|
|
587
|
+
if (botState.isHandoff && isDev) addMessageComponent(<Handoff />)
|
|
588
|
+
updateBotState(botState)
|
|
589
|
+
// updateHandoff(botState.isHandoff)
|
|
590
|
+
},
|
|
591
|
+
updateSession: updateSession,
|
|
564
592
|
openWebchat: () => toggleWebchat(true),
|
|
565
593
|
closeWebchat: () => toggleWebchat(false),
|
|
566
594
|
toggleWebchat: () => toggleWebchat(!webchatState.isWebchatOpen),
|
|
@@ -593,26 +621,30 @@ export const Webchat = forwardRef((props, ref) => {
|
|
|
593
621
|
}))
|
|
594
622
|
|
|
595
623
|
const resolveCase = () => {
|
|
596
|
-
updateHandoff(false)
|
|
597
|
-
|
|
624
|
+
// updateHandoff(false)
|
|
625
|
+
updateBotState({
|
|
626
|
+
...webchatState.botState,
|
|
627
|
+
isHandoff: false,
|
|
628
|
+
botonicAction: null,
|
|
629
|
+
})
|
|
598
630
|
}
|
|
599
631
|
|
|
600
|
-
const
|
|
632
|
+
const previousBotState = usePrevious(webchatState.botState)
|
|
601
633
|
useEffect(() => {
|
|
602
634
|
// Resume conversation after handoff
|
|
603
635
|
if (
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
!webchatState.
|
|
636
|
+
previousBotState &&
|
|
637
|
+
previousBotState.botonicAction &&
|
|
638
|
+
!webchatState.botState.botonicAction
|
|
607
639
|
) {
|
|
608
|
-
const action = getParsedAction(
|
|
640
|
+
const action = getParsedAction(previousBotState.botonicAction)
|
|
609
641
|
if (action && action.on_finish) sendPayload(action.on_finish)
|
|
610
642
|
}
|
|
611
|
-
}, [webchatState.
|
|
643
|
+
}, [webchatState.botState.botonicAction])
|
|
612
644
|
|
|
613
645
|
const sendText = async (text, payload) => {
|
|
614
646
|
if (!text) return
|
|
615
|
-
const input = { type: INPUT.TEXT,
|
|
647
|
+
const input = { type: INPUT.TEXT, text, payload }
|
|
616
648
|
await sendInput(input)
|
|
617
649
|
}
|
|
618
650
|
|
|
@@ -628,7 +660,7 @@ export const Webchat = forwardRef((props, ref) => {
|
|
|
628
660
|
if (!attachmentType) return
|
|
629
661
|
const input = {
|
|
630
662
|
type: attachmentType,
|
|
631
|
-
|
|
663
|
+
src: attachment.file,
|
|
632
664
|
}
|
|
633
665
|
await sendInput(input)
|
|
634
666
|
setCurrentAttachment(undefined)
|
|
@@ -648,8 +680,8 @@ export const Webchat = forwardRef((props, ref) => {
|
|
|
648
680
|
}
|
|
649
681
|
|
|
650
682
|
const webviewRequestContext = {
|
|
651
|
-
getString: stringId => props.getString(stringId, webchatState.
|
|
652
|
-
setLocale: locale => props.getString(locale, webchatState.
|
|
683
|
+
getString: stringId => props.getString(stringId, webchatState.botState),
|
|
684
|
+
setLocale: locale => props.getString(locale, webchatState.botState),
|
|
653
685
|
session: webchatState.session || {},
|
|
654
686
|
params: webchatState.webviewParams || {},
|
|
655
687
|
closeWebview: closeWebview,
|
|
@@ -909,7 +941,7 @@ export const Webchat = forwardRef((props, ref) => {
|
|
|
909
941
|
updateMessage,
|
|
910
942
|
updateReplies,
|
|
911
943
|
updateLatestInput,
|
|
912
|
-
updateUser:
|
|
944
|
+
updateUser: mergeAndUpdateUser,
|
|
913
945
|
updateWebchatDevSettings: updateWebchatDevSettings,
|
|
914
946
|
}}
|
|
915
947
|
>
|
|
@@ -3,9 +3,9 @@ import merge from 'lodash.merge'
|
|
|
3
3
|
import React, { createRef } from 'react'
|
|
4
4
|
import { render } from 'react-dom'
|
|
5
5
|
|
|
6
|
-
import { SENDERS, WEBCHAT } from '
|
|
7
|
-
import { isShadowDOMSupported, onDOMLoaded } from '../util/dom'
|
|
6
|
+
import { SENDERS, WEBCHAT } from './constants'
|
|
8
7
|
import { msgToBotonic } from './msg-to-botonic'
|
|
8
|
+
import { isShadowDOMSupported, onDOMLoaded } from './util/dom'
|
|
9
9
|
import { Webchat } from './webchat/webchat'
|
|
10
10
|
|
|
11
11
|
export class WebchatApp {
|
|
@@ -139,18 +139,27 @@ export class WebchatApp {
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
onServiceEvent(event) {
|
|
142
|
-
|
|
142
|
+
const { action, ...eventData } = event
|
|
143
|
+
if (action === 'connection_change')
|
|
143
144
|
this.webchatRef.current.setOnline(event.online)
|
|
144
|
-
else if (
|
|
145
|
-
this.updateMessageInfo(
|
|
146
|
-
else if (
|
|
147
|
-
this.
|
|
148
|
-
else if (
|
|
149
|
-
this.
|
|
150
|
-
else {
|
|
145
|
+
else if (action === 'update_message_info') {
|
|
146
|
+
this.updateMessageInfo(eventData.id, eventData)
|
|
147
|
+
} else if (action === 'update_user') {
|
|
148
|
+
this.updateUser(eventData)
|
|
149
|
+
} else if (action === 'update_session') {
|
|
150
|
+
this.updateSession(eventData.session)
|
|
151
|
+
} else if (action === 'update_bot_state') {
|
|
152
|
+
this.updateBotState(eventData.botState)
|
|
153
|
+
}
|
|
154
|
+
// TODO: Discuss how this updates to be done
|
|
155
|
+
else if (eventData.type === 'update_webchat_settings')
|
|
156
|
+
this.updateWebchatSettings(event.data)
|
|
157
|
+
else if (eventData.type === 'sender_action')
|
|
158
|
+
this.setTyping(event.data === 'typing_on')
|
|
159
|
+
else if (eventData.eventType === 'message') {
|
|
151
160
|
this.onMessage &&
|
|
152
|
-
this.onMessage(this, { from: SENDERS.bot, message:
|
|
153
|
-
this.addBotMessage(
|
|
161
|
+
this.onMessage(this, { from: SENDERS.bot, message: eventData })
|
|
162
|
+
this.addBotMessage(eventData)
|
|
154
163
|
}
|
|
155
164
|
}
|
|
156
165
|
|
|
@@ -158,6 +167,14 @@ export class WebchatApp {
|
|
|
158
167
|
this.webchatRef.current.updateUser(user)
|
|
159
168
|
}
|
|
160
169
|
|
|
170
|
+
updateSession(session) {
|
|
171
|
+
this.webchatRef.current.updateSession(session)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
updateBotState(botState) {
|
|
175
|
+
this.webchatRef.current.updateBotState(botState)
|
|
176
|
+
}
|
|
177
|
+
|
|
161
178
|
addBotMessage(message) {
|
|
162
179
|
this.webchatRef.current.addBotResponse({
|
|
163
180
|
response: msgToBotonic(
|
|
@@ -240,7 +257,7 @@ export class WebchatApp {
|
|
|
240
257
|
}
|
|
241
258
|
|
|
242
259
|
// eslint-disable-next-line complexity
|
|
243
|
-
getComponent(optionsAtRuntime = {}) {
|
|
260
|
+
getComponent(host, optionsAtRuntime = {}) {
|
|
244
261
|
let {
|
|
245
262
|
theme = {},
|
|
246
263
|
persistentMenu,
|
|
@@ -258,6 +275,7 @@ export class WebchatApp {
|
|
|
258
275
|
onOpen,
|
|
259
276
|
onClose,
|
|
260
277
|
onMessage,
|
|
278
|
+
hostId,
|
|
261
279
|
appId,
|
|
262
280
|
visibility,
|
|
263
281
|
server,
|
|
@@ -282,6 +300,8 @@ export class WebchatApp {
|
|
|
282
300
|
this.onMessage = onMessage || this.onMessage
|
|
283
301
|
this.visibility = visibility || this.visibility
|
|
284
302
|
this.appId = appId || this.appId
|
|
303
|
+
this.hostId = hostId || this.hostId
|
|
304
|
+
this.createRootElement(host)
|
|
285
305
|
return (
|
|
286
306
|
<Webchat
|
|
287
307
|
{...webchatOptions}
|
|
@@ -342,11 +362,10 @@ export class WebchatApp {
|
|
|
342
362
|
|
|
343
363
|
async render(dest, optionsAtRuntime = {}) {
|
|
344
364
|
onDOMLoaded(async () => {
|
|
345
|
-
this.createRootElement(dest)
|
|
346
365
|
const isVisible = await this.resolveWebchatVisibility(optionsAtRuntime)
|
|
347
366
|
if (isVisible)
|
|
348
367
|
render(
|
|
349
|
-
this.getComponent(optionsAtRuntime),
|
|
368
|
+
this.getComponent(dest, optionsAtRuntime),
|
|
350
369
|
this.getReactMountNode(dest)
|
|
351
370
|
)
|
|
352
371
|
})
|
package/src/index.d.ts
CHANGED
package/src/util/dom.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { WEBCHAT } from '../constants'
|
|
2
2
|
|
|
3
|
+
export const getScrollableContent = webchatElement => {
|
|
4
|
+
return webchatElement.querySelector(WEBCHAT.SELECTORS.SCROLLABLE_CONTENT)
|
|
5
|
+
}
|
|
6
|
+
|
|
3
7
|
export const getScrollableArea = webchatElement => {
|
|
4
8
|
const getArea = area => {
|
|
5
|
-
const botonicScrollableContent = webchatElement
|
|
6
|
-
WEBCHAT.SELECTORS.SCROLLABLE_CONTENT
|
|
7
|
-
)
|
|
9
|
+
const botonicScrollableContent = getScrollableContent(webchatElement)
|
|
8
10
|
const scrollableArea =
|
|
9
11
|
botonicScrollableContent && botonicScrollableContent.querySelector(area)
|
|
10
12
|
return scrollableArea
|
|
@@ -4,21 +4,33 @@ import { ScrollbarController } from './scrollbar-controller'
|
|
|
4
4
|
import { WebchatResizer } from './webchat-resizer'
|
|
5
5
|
|
|
6
6
|
export class DeviceAdapter {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.currentDevice = this.getCurrentDevice()
|
|
9
|
+
}
|
|
10
|
+
|
|
7
11
|
init(host) {
|
|
8
|
-
this.currentDevice = navigator.platform
|
|
9
12
|
this.webchatResizer = new WebchatResizer(this.currentDevice, host)
|
|
10
13
|
this.scrollbarController = new ScrollbarController(this.currentDevice, host)
|
|
11
14
|
this.scrollbarController.handleScrollEvents()
|
|
12
15
|
}
|
|
13
16
|
|
|
17
|
+
getCurrentDevice() {
|
|
18
|
+
// navigator.platform deprecated. Ref: (https://erikmartinjordan.com/navigator-platform-deprecated-alternative)
|
|
19
|
+
if (navigator.userAgentData) return navigator.userAgentData.platform
|
|
20
|
+
return navigator.platform
|
|
21
|
+
}
|
|
22
|
+
|
|
14
23
|
onFocus(host) {
|
|
15
24
|
if (this.currentDevice !== DEVICES.MOBILE.IPHONE) {
|
|
16
25
|
scrollToBottom({ host, timeout: 800 })
|
|
17
26
|
return
|
|
18
27
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
28
|
+
setTimeout(() => {
|
|
29
|
+
// Place onFocus logic to be run the last on the queue of asynchronous events to give enough time to init method to be called. Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#zero_delays
|
|
30
|
+
this.webchatResizer.onFocus(() =>
|
|
31
|
+
this.scrollbarController.handleOnTouchMoveEvents()
|
|
32
|
+
)
|
|
33
|
+
}, 0)
|
|
22
34
|
}
|
|
23
35
|
|
|
24
36
|
onBlur() {
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
getScrollableArea,
|
|
3
|
+
getScrollableContent,
|
|
4
|
+
getWebchatElement,
|
|
5
|
+
} from '../../util/dom'
|
|
2
6
|
import { DEVICES, isMobileDevice } from '.'
|
|
3
7
|
|
|
4
8
|
const debounced = (delay, fn) => {
|
|
@@ -28,7 +32,7 @@ export class ScrollbarController {
|
|
|
28
32
|
|
|
29
33
|
handleScrollEvents() {
|
|
30
34
|
/*
|
|
31
|
-
It handles scroll events for Mobile/Desktop.
|
|
35
|
+
It handles scroll events for Mobile/Desktop.
|
|
32
36
|
"ontouchmove" is the phone equivalent for "onmouseover"
|
|
33
37
|
*/
|
|
34
38
|
if (isMobileDevice()) {
|
|
@@ -61,11 +65,12 @@ export class ScrollbarController {
|
|
|
61
65
|
}
|
|
62
66
|
|
|
63
67
|
toggleOnMouseWheelEvents() {
|
|
68
|
+
const scrollableContent = getScrollableContent(this.webchat)
|
|
64
69
|
if (this.hasScrollbar()) {
|
|
65
|
-
|
|
70
|
+
scrollableContent.onmousewheel = {}
|
|
66
71
|
return
|
|
67
72
|
}
|
|
68
|
-
|
|
73
|
+
scrollableContent.onmousewheel = e => e.preventDefault()
|
|
69
74
|
}
|
|
70
75
|
|
|
71
76
|
handleOnTouchMoveEvents(e) {
|
package/src/webchat/webchat.jsx
CHANGED
|
@@ -212,6 +212,8 @@ export const Webchat = forwardRef((props, ref) => {
|
|
|
212
212
|
|
|
213
213
|
const host = props.host || document.body
|
|
214
214
|
|
|
215
|
+
const deviceAdapter = new DeviceAdapter()
|
|
216
|
+
|
|
215
217
|
const saveWebchatState = webchatState => {
|
|
216
218
|
storage &&
|
|
217
219
|
saveState(
|
|
@@ -227,7 +229,6 @@ export const Webchat = forwardRef((props, ref) => {
|
|
|
227
229
|
)
|
|
228
230
|
)
|
|
229
231
|
}
|
|
230
|
-
const deviceAdapter = new DeviceAdapter()
|
|
231
232
|
|
|
232
233
|
const handleAttachment = event => {
|
|
233
234
|
if (!isAllowedSize(event.target.files[0].size)) {
|