@botonic/react 0.23.3 → 0.24.0-alpha.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.
- package/index.d.ts +1 -1
- package/lib/cjs/assets/arrow-down.svg +3 -0
- package/lib/cjs/assets/arrow-scroll-down.svg +3 -0
- package/lib/cjs/assets/index-types.d.ts +4 -0
- package/lib/cjs/assets/index-types.js +2 -0
- package/lib/cjs/assets/index-types.js.map +1 -0
- package/lib/cjs/components/custom-message.js +2 -2
- package/lib/cjs/components/custom-message.js.map +1 -1
- package/lib/cjs/components/index-types.d.ts +10 -4
- package/lib/cjs/components/index-types.js.map +1 -1
- package/lib/cjs/components/message.js +21 -17
- package/lib/cjs/components/message.js.map +1 -1
- package/lib/cjs/components/timestamps.d.ts +2 -2
- package/lib/cjs/components/timestamps.js +5 -5
- package/lib/cjs/components/timestamps.js.map +1 -1
- package/lib/cjs/constants.d.ts +7 -5
- package/lib/cjs/constants.js +10 -6
- package/lib/cjs/constants.js.map +1 -1
- package/lib/cjs/contexts.js +6 -0
- package/lib/cjs/contexts.js.map +1 -1
- package/lib/cjs/dev-app.js +9 -3
- package/lib/cjs/dev-app.js.map +1 -1
- package/lib/cjs/index-types.d.ts +16 -2
- package/lib/cjs/index-types.js +7 -0
- package/lib/cjs/index-types.js.map +1 -1
- package/lib/cjs/msg-to-botonic.js +5 -2
- package/lib/cjs/msg-to-botonic.js.map +1 -1
- package/lib/cjs/webchat/actions.d.ts +19 -17
- package/lib/cjs/webchat/actions.js +19 -17
- package/lib/cjs/webchat/actions.js.map +1 -1
- package/lib/cjs/webchat/components/styled-scrollbar.js +1 -1
- package/lib/cjs/webchat/devices/device-adapter.js +1 -1
- package/lib/cjs/webchat/devices/device-adapter.js.map +1 -1
- package/lib/cjs/webchat/devices/webchat-resizer.js +1 -1
- package/lib/cjs/webchat/devices/webchat-resizer.js.map +1 -1
- package/lib/cjs/webchat/hooks/use-typing.d.ts +1 -1
- package/lib/cjs/webchat/hooks/use-typing.js +2 -3
- package/lib/cjs/webchat/hooks/use-typing.js.map +1 -1
- package/lib/cjs/webchat/hooks/use-webchat.d.ts +5 -1
- package/lib/cjs/webchat/hooks/use-webchat.js +15 -1
- package/lib/cjs/webchat/hooks/use-webchat.js.map +1 -1
- package/lib/cjs/webchat/index-types.d.ts +2 -1
- package/lib/cjs/webchat/message-list/index.d.ts +1 -0
- package/lib/cjs/webchat/message-list/index.js +58 -0
- package/lib/cjs/webchat/message-list/index.js.map +1 -0
- package/lib/cjs/webchat/message-list/intro-message.d.ts +1 -0
- package/lib/cjs/webchat/message-list/intro-message.js +23 -0
- package/lib/cjs/webchat/message-list/intro-message.js.map +1 -0
- package/lib/cjs/webchat/message-list/scroll-button.d.ts +5 -0
- package/lib/cjs/webchat/message-list/scroll-button.js +19 -0
- package/lib/cjs/webchat/message-list/scroll-button.js.map +1 -0
- package/lib/cjs/webchat/message-list/styles.d.ts +4 -0
- package/lib/cjs/webchat/message-list/styles.js +48 -0
- package/lib/cjs/webchat/message-list/styles.js.map +1 -0
- package/lib/cjs/webchat/message-list/unread-messages-banner.d.ts +5 -0
- package/lib/cjs/webchat/message-list/unread-messages-banner.js +30 -0
- package/lib/cjs/webchat/message-list/unread-messages-banner.js.map +1 -0
- package/lib/cjs/webchat/messages-reducer.js +31 -9
- package/lib/cjs/webchat/messages-reducer.js.map +1 -1
- package/lib/cjs/webchat/trigger-button/index.js +3 -2
- package/lib/cjs/webchat/trigger-button/index.js.map +1 -1
- package/lib/cjs/webchat/webchat-reducer.js +1 -1
- package/lib/cjs/webchat/webchat-reducer.js.map +1 -1
- package/lib/cjs/webchat/webchat.js +39 -21
- package/lib/cjs/webchat/webchat.js.map +1 -1
- package/lib/cjs/webchat-app.js +24 -9
- package/lib/cjs/webchat-app.js.map +1 -1
- package/lib/esm/assets/arrow-down.svg +3 -0
- package/lib/esm/assets/arrow-scroll-down.svg +3 -0
- package/lib/esm/assets/index-types.d.ts +4 -0
- package/lib/esm/assets/index-types.js +2 -0
- package/lib/esm/assets/index-types.js.map +1 -0
- package/lib/esm/components/custom-message.js +2 -2
- package/lib/esm/components/custom-message.js.map +1 -1
- package/lib/esm/components/index-types.d.ts +10 -4
- package/lib/esm/components/index-types.js.map +1 -1
- package/lib/esm/components/message.js +22 -18
- package/lib/esm/components/message.js.map +1 -1
- package/lib/esm/components/timestamps.d.ts +2 -2
- package/lib/esm/components/timestamps.js +5 -5
- package/lib/esm/components/timestamps.js.map +1 -1
- package/lib/esm/constants.d.ts +7 -5
- package/lib/esm/constants.js +9 -5
- package/lib/esm/constants.js.map +1 -1
- package/lib/esm/contexts.js +6 -0
- package/lib/esm/contexts.js.map +1 -1
- package/lib/esm/dev-app.js +9 -3
- package/lib/esm/dev-app.js.map +1 -1
- package/lib/esm/index-types.d.ts +16 -2
- package/lib/esm/index-types.js +6 -1
- package/lib/esm/index-types.js.map +1 -1
- package/lib/esm/msg-to-botonic.js +6 -3
- package/lib/esm/msg-to-botonic.js.map +1 -1
- package/lib/esm/webchat/actions.d.ts +19 -17
- package/lib/esm/webchat/actions.js +19 -17
- package/lib/esm/webchat/actions.js.map +1 -1
- package/lib/esm/webchat/components/styled-scrollbar.js +1 -1
- package/lib/esm/webchat/devices/device-adapter.js +1 -1
- package/lib/esm/webchat/devices/device-adapter.js.map +1 -1
- package/lib/esm/webchat/devices/webchat-resizer.js +1 -1
- package/lib/esm/webchat/devices/webchat-resizer.js.map +1 -1
- package/lib/esm/webchat/hooks/use-typing.d.ts +1 -1
- package/lib/esm/webchat/hooks/use-typing.js +2 -3
- package/lib/esm/webchat/hooks/use-typing.js.map +1 -1
- package/lib/esm/webchat/hooks/use-webchat.d.ts +5 -1
- package/lib/esm/webchat/hooks/use-webchat.js +15 -1
- package/lib/esm/webchat/hooks/use-webchat.js.map +1 -1
- package/lib/esm/webchat/index-types.d.ts +2 -1
- package/lib/esm/webchat/message-list/index.d.ts +1 -0
- package/lib/esm/webchat/message-list/index.js +54 -0
- package/lib/esm/webchat/message-list/index.js.map +1 -0
- package/lib/esm/webchat/message-list/intro-message.d.ts +1 -0
- package/lib/esm/webchat/message-list/intro-message.js +18 -0
- package/lib/esm/webchat/message-list/intro-message.js.map +1 -0
- package/lib/esm/webchat/message-list/scroll-button.d.ts +5 -0
- package/lib/esm/webchat/message-list/scroll-button.js +14 -0
- package/lib/esm/webchat/message-list/scroll-button.js.map +1 -0
- package/lib/esm/webchat/message-list/styles.d.ts +4 -0
- package/lib/esm/webchat/message-list/styles.js +44 -0
- package/lib/esm/webchat/message-list/styles.js.map +1 -0
- package/lib/esm/webchat/message-list/unread-messages-banner.d.ts +5 -0
- package/lib/esm/webchat/message-list/unread-messages-banner.js +25 -0
- package/lib/esm/webchat/message-list/unread-messages-banner.js.map +1 -0
- package/lib/esm/webchat/messages-reducer.js +31 -9
- package/lib/esm/webchat/messages-reducer.js.map +1 -1
- package/lib/esm/webchat/trigger-button/index.js +3 -2
- package/lib/esm/webchat/trigger-button/index.js.map +1 -1
- package/lib/esm/webchat/webchat-reducer.js +1 -1
- package/lib/esm/webchat/webchat-reducer.js.map +1 -1
- package/lib/esm/webchat/webchat.js +40 -22
- package/lib/esm/webchat/webchat.js.map +1 -1
- package/lib/esm/webchat-app.js +25 -10
- package/lib/esm/webchat-app.js.map +1 -1
- package/package.json +7 -5
- package/src/assets/arrow-down.svg +3 -0
- package/src/assets/arrow-scroll-down.svg +3 -0
- package/src/assets/index-types.ts +4 -0
- package/src/components/custom-message.jsx +2 -2
- package/src/components/index-types.ts +8 -4
- package/src/components/message.jsx +29 -21
- package/src/components/timestamps.jsx +5 -5
- package/src/constants.js +9 -6
- package/src/contexts.tsx +6 -0
- package/src/dev-app.jsx +9 -3
- package/src/index-types.ts +18 -3
- package/src/msg-to-botonic.jsx +2 -3
- package/src/webchat/actions.ts +19 -17
- package/src/webchat/components/styled-scrollbar.jsx +1 -1
- package/src/webchat/devices/device-adapter.js +1 -1
- package/src/webchat/devices/webchat-resizer.js +1 -1
- package/src/webchat/hooks/use-typing.ts +3 -3
- package/src/webchat/hooks/use-webchat.ts +18 -2
- package/src/webchat/index-types.ts +2 -1
- package/src/webchat/message-list/index.tsx +103 -0
- package/src/webchat/message-list/intro-message.tsx +38 -0
- package/src/webchat/message-list/scroll-button.tsx +41 -0
- package/src/webchat/message-list/styles.ts +47 -0
- package/src/webchat/message-list/unread-messages-banner.tsx +62 -0
- package/src/webchat/messages-reducer.ts +42 -5
- package/src/webchat/trigger-button/index.tsx +9 -4
- package/src/webchat/webchat-reducer.ts +0 -1
- package/src/webchat/webchat.jsx +71 -49
- package/src/webchat-app.jsx +25 -14
- package/lib/cjs/webchat/message-list.d.ts +0 -1
- package/lib/cjs/webchat/message-list.js +0 -39
- package/lib/cjs/webchat/message-list.js.map +0 -1
- package/lib/esm/webchat/message-list.d.ts +0 -1
- package/lib/esm/webchat/message-list.js +0 -34
- package/lib/esm/webchat/message-list.js.map +0 -1
- package/src/webchat/message-list.jsx +0 -77
|
@@ -4,8 +4,9 @@ import Fade from 'react-reveal/Fade'
|
|
|
4
4
|
import styled from 'styled-components'
|
|
5
5
|
import { v4 as uuidv4 } from 'uuid'
|
|
6
6
|
|
|
7
|
-
import { COLORS,
|
|
7
|
+
import { COLORS, WEBCHAT } from '../constants'
|
|
8
8
|
import { RequestContext, WebchatContext } from '../contexts'
|
|
9
|
+
import { SENDERS } from '../index-types'
|
|
9
10
|
import { isDev, resolveImage } from '../util/environment'
|
|
10
11
|
import { ConditionalWrapper, renderComponent } from '../util/react'
|
|
11
12
|
import { Button } from './button'
|
|
@@ -16,7 +17,7 @@ import { MessageTimestamp, resolveMessageTimestamps } from './timestamps'
|
|
|
16
17
|
|
|
17
18
|
const MessageContainer = styled.div`
|
|
18
19
|
display: flex;
|
|
19
|
-
justify-content: ${props => (props.
|
|
20
|
+
justify-content: ${props => (props.isSentByUser ? 'flex-end' : 'flex-start')};
|
|
20
21
|
position: relative;
|
|
21
22
|
padding: 0px 6px;
|
|
22
23
|
`
|
|
@@ -72,7 +73,7 @@ export const Message = props => {
|
|
|
72
73
|
let {
|
|
73
74
|
type = '',
|
|
74
75
|
blob = true,
|
|
75
|
-
|
|
76
|
+
sentBy,
|
|
76
77
|
delay = defaultDelay,
|
|
77
78
|
typing = defaultTyping,
|
|
78
79
|
children,
|
|
@@ -80,10 +81,13 @@ export const Message = props => {
|
|
|
80
81
|
json,
|
|
81
82
|
style,
|
|
82
83
|
imagestyle = props.imagestyle || props.imageStyle,
|
|
84
|
+
isUnread = true,
|
|
83
85
|
...otherProps
|
|
84
86
|
} = props
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
+
|
|
88
|
+
const isSentByUser = sentBy === SENDERS.user
|
|
89
|
+
const isSentByBot = sentBy === SENDERS.bot
|
|
90
|
+
const isSentByAgent = sentBy === SENDERS.agent
|
|
87
91
|
const markdown = props.markdown
|
|
88
92
|
const { webchatState, addMessage, updateReplies, getThemeProperty } =
|
|
89
93
|
useContext(WebchatContext)
|
|
@@ -105,7 +109,7 @@ export const Message = props => {
|
|
|
105
109
|
let textChildren = React.Children.toArray(children).filter(
|
|
106
110
|
e => ![Button, Reply].includes(e.type)
|
|
107
111
|
)
|
|
108
|
-
if (
|
|
112
|
+
if (isSentByUser)
|
|
109
113
|
textChildren = textChildren.map(e =>
|
|
110
114
|
typeof e === 'string' ? renderLinks(e) : e
|
|
111
115
|
)
|
|
@@ -115,7 +119,7 @@ export const Message = props => {
|
|
|
115
119
|
|
|
116
120
|
const getEnvAck = () => {
|
|
117
121
|
if (isDev) return 1
|
|
118
|
-
if (!
|
|
122
|
+
if (!isSentByUser) return 1
|
|
119
123
|
if (props.ack !== undefined) return props.ack
|
|
120
124
|
return 0
|
|
121
125
|
}
|
|
@@ -131,7 +135,7 @@ export const Message = props => {
|
|
|
131
135
|
data: decomposedChildren ? decomposedChildren : textChildren,
|
|
132
136
|
timestamp: props.timestamp || getFormattedTimestamp,
|
|
133
137
|
markdown,
|
|
134
|
-
|
|
138
|
+
sentBy,
|
|
135
139
|
buttons: buttons.map(b => ({
|
|
136
140
|
parentId: b.props.parentId,
|
|
137
141
|
payload: b.props.payload,
|
|
@@ -153,6 +157,7 @@ export const Message = props => {
|
|
|
153
157
|
display: delay + typing == 0,
|
|
154
158
|
customTypeName: decomposedChildren.customTypeName,
|
|
155
159
|
ack: ack,
|
|
160
|
+
isUnread: isUnread === 1 || isUnread === true,
|
|
156
161
|
}
|
|
157
162
|
addMessage(message)
|
|
158
163
|
}
|
|
@@ -178,7 +183,7 @@ export const Message = props => {
|
|
|
178
183
|
|
|
179
184
|
const getBgColor = () => {
|
|
180
185
|
if (!blob) return COLORS.TRANSPARENT
|
|
181
|
-
if (
|
|
186
|
+
if (isSentByUser) {
|
|
182
187
|
return getThemeProperty(
|
|
183
188
|
WEBCHAT.CUSTOM_PROPERTIES.userMessageBackground,
|
|
184
189
|
brandColor
|
|
@@ -191,11 +196,13 @@ export const Message = props => {
|
|
|
191
196
|
}
|
|
192
197
|
|
|
193
198
|
const getMessageStyle = () =>
|
|
194
|
-
|
|
199
|
+
isSentByBot
|
|
195
200
|
? getThemeProperty(WEBCHAT.CUSTOM_PROPERTIES.botMessageStyle)
|
|
196
201
|
: getThemeProperty(WEBCHAT.CUSTOM_PROPERTIES.userMessageStyle)
|
|
197
202
|
|
|
198
|
-
const
|
|
203
|
+
const userOrBotMessage = isSentByUser ? SENDERS.user : SENDERS.bot
|
|
204
|
+
const hasBlobTick = () =>
|
|
205
|
+
getThemeProperty(`message.${userOrBotMessage}.blobTick`, true)
|
|
199
206
|
|
|
200
207
|
const renderBrowser = () => {
|
|
201
208
|
const m = webchatState.messagesJSON.find(m => m.id === state.id)
|
|
@@ -209,14 +216,14 @@ export const Message = props => {
|
|
|
209
216
|
pointerSize == 5
|
|
210
217
|
? getBgColor()
|
|
211
218
|
: getThemeProperty(
|
|
212
|
-
`message.${
|
|
219
|
+
`message.${userOrBotMessage}.style.borderColor`,
|
|
213
220
|
COLORS.TRANSPARENT
|
|
214
221
|
)
|
|
215
222
|
const containerStyle = {
|
|
216
|
-
...getThemeProperty(`message.${
|
|
223
|
+
...getThemeProperty(`message.${userOrBotMessage}.blobTickStyle`),
|
|
217
224
|
}
|
|
218
225
|
const blobTickStyle = {}
|
|
219
|
-
if (
|
|
226
|
+
if (isSentByUser) {
|
|
220
227
|
containerStyle.right = 0
|
|
221
228
|
containerStyle.marginRight = -pointerSize
|
|
222
229
|
blobTickStyle.borderRight = 0
|
|
@@ -247,9 +254,10 @@ export const Message = props => {
|
|
|
247
254
|
)
|
|
248
255
|
|
|
249
256
|
const resolveCustomTypeName = () =>
|
|
250
|
-
|
|
257
|
+
isSentByBot && type === INPUT.CUSTOM ? ` ${m.customTypeName}` : ''
|
|
258
|
+
|
|
259
|
+
const className = `${type}-${userOrBotMessage}${resolveCustomTypeName()}`
|
|
251
260
|
|
|
252
|
-
const className = `${type}-${from}${resolveCustomTypeName()}`
|
|
253
261
|
return (
|
|
254
262
|
<ConditionalWrapper
|
|
255
263
|
condition={animationsEnabled}
|
|
@@ -257,12 +265,12 @@ export const Message = props => {
|
|
|
257
265
|
>
|
|
258
266
|
<>
|
|
259
267
|
<MessageContainer
|
|
260
|
-
|
|
268
|
+
isSentByUser={isSentByUser}
|
|
261
269
|
style={{
|
|
262
270
|
...getThemeProperty(WEBCHAT.CUSTOM_PROPERTIES.messageStyle),
|
|
263
271
|
}}
|
|
264
272
|
>
|
|
265
|
-
{
|
|
273
|
+
{isSentByBot && BotMessageImage && (
|
|
266
274
|
<BotMessageImageContainer
|
|
267
275
|
style={{
|
|
268
276
|
...getThemeProperty(
|
|
@@ -280,7 +288,7 @@ export const Message = props => {
|
|
|
280
288
|
<Blob
|
|
281
289
|
className={className}
|
|
282
290
|
bgcolor={getBgColor()}
|
|
283
|
-
color={
|
|
291
|
+
color={isSentByUser ? COLORS.SOLID_WHITE : COLORS.SOLID_BLACK}
|
|
284
292
|
blobwidth={getThemeProperty(
|
|
285
293
|
WEBCHAT.CUSTOM_PROPERTIES.botMessageBlobWidth
|
|
286
294
|
)}
|
|
@@ -300,7 +308,7 @@ export const Message = props => {
|
|
|
300
308
|
}}
|
|
301
309
|
markdownstyle={getMarkdownStyle(
|
|
302
310
|
getThemeProperty,
|
|
303
|
-
|
|
311
|
+
isSentByUser ? COLORS.SEASHELL_WHITE : brandColor
|
|
304
312
|
)}
|
|
305
313
|
/>
|
|
306
314
|
) : (
|
|
@@ -317,7 +325,7 @@ export const Message = props => {
|
|
|
317
325
|
<MessageTimestamp
|
|
318
326
|
timestamp={m.timestamp}
|
|
319
327
|
style={timestampStyle}
|
|
320
|
-
|
|
328
|
+
isSentByUser={isSentByUser}
|
|
321
329
|
/>
|
|
322
330
|
)}
|
|
323
331
|
</>
|
|
@@ -46,17 +46,17 @@ const TimestampText = styled.div`
|
|
|
46
46
|
font-size: 10px;
|
|
47
47
|
color: ${COLORS.SOLID_BLACK};
|
|
48
48
|
width: 100%;
|
|
49
|
-
text-align: ${props => (props.
|
|
50
|
-
padding: ${props => (props.
|
|
49
|
+
text-align: ${props => (props.isSentByUser ? 'right' : 'left')};
|
|
50
|
+
padding: ${props => (props.isSentByUser ? '0px 15px' : '0px 50px')};
|
|
51
51
|
margin-bottom: 5px;
|
|
52
52
|
`
|
|
53
53
|
|
|
54
|
-
export const MessageTimestamp = ({ timestamp, style,
|
|
55
|
-
const classSufix =
|
|
54
|
+
export const MessageTimestamp = ({ timestamp, style, isSentByUser }) => {
|
|
55
|
+
const classSufix = isSentByUser ? 'user' : 'bot'
|
|
56
56
|
return (
|
|
57
57
|
<TimestampContainer className={`botonic-timestamp-${classSufix}`}>
|
|
58
58
|
<TimestampText
|
|
59
|
-
|
|
59
|
+
isSentByUser={isSentByUser}
|
|
60
60
|
style={{
|
|
61
61
|
...style,
|
|
62
62
|
}}
|
package/src/constants.js
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import BotonicLogo from './assets/botonic_react_logo100x100.png'
|
|
2
2
|
|
|
3
|
-
export const SENDERS = {
|
|
4
|
-
bot: 'bot',
|
|
5
|
-
user: 'user',
|
|
6
|
-
}
|
|
7
|
-
|
|
8
3
|
export const COLORS = {
|
|
9
4
|
// http://chir.ag/projects/name-that-color
|
|
10
5
|
APPLE_GREEN: 'rgba(58, 156, 53, 1)',
|
|
@@ -125,8 +120,16 @@ export const WEBCHAT = {
|
|
|
125
120
|
// TriggerButton
|
|
126
121
|
customTrigger: 'triggerButton.custom',
|
|
127
122
|
triggerButtonImage: 'triggerButton.image',
|
|
128
|
-
triggerButtonNotificationsEnabled: 'triggerButton.notificationsEnabled',
|
|
129
123
|
triggerButtonStyle: 'triggerButton.style',
|
|
124
|
+
// Notifications
|
|
125
|
+
notificationsEnabled: 'notifications.enable',
|
|
126
|
+
notificationsBannerEnabled: 'notifications.banner.enable',
|
|
127
|
+
notificationsBannerCustom: 'notifications.banner.custom',
|
|
128
|
+
notificationsBannerText: 'notifications.banner.text',
|
|
129
|
+
notificationsTriggerButtonEnabled: 'notifications.triggerButton.enable',
|
|
130
|
+
// Scroll Button
|
|
131
|
+
scrollButtonEnabled: 'scrollButton.enable',
|
|
132
|
+
scrollButtonCustom: 'scrollButton.custom',
|
|
130
133
|
// User Input
|
|
131
134
|
blockInputs: 'userInput.blockInputs',
|
|
132
135
|
documentDownload: 'documentDownload',
|
package/src/contexts.tsx
CHANGED
package/src/dev-app.jsx
CHANGED
|
@@ -2,7 +2,7 @@ import merge from 'lodash.merge'
|
|
|
2
2
|
import React from 'react'
|
|
3
3
|
import { render } from 'react-dom'
|
|
4
4
|
|
|
5
|
-
import { SENDERS } from './
|
|
5
|
+
import { SENDERS } from './index-types'
|
|
6
6
|
import { ReactBot } from './react-bot'
|
|
7
7
|
import { onDOMLoaded } from './util/dom'
|
|
8
8
|
import { WebchatDev } from './webchat/webchat-dev'
|
|
@@ -123,11 +123,17 @@ export class DevApp extends WebchatApp {
|
|
|
123
123
|
|
|
124
124
|
async onUserInput({ input, session, lastRoutePath }) {
|
|
125
125
|
this.onMessage &&
|
|
126
|
-
this.onMessage(this, {
|
|
126
|
+
this.onMessage(this, {
|
|
127
|
+
sentBy: SENDERS.user,
|
|
128
|
+
message: input,
|
|
129
|
+
})
|
|
127
130
|
const resp = await this.bot.input({ input, session, lastRoutePath })
|
|
128
131
|
this.onMessage &&
|
|
129
132
|
resp.response.map(r =>
|
|
130
|
-
this.onMessage(this, {
|
|
133
|
+
this.onMessage(this, {
|
|
134
|
+
sentBy: SENDERS.bot,
|
|
135
|
+
message: r,
|
|
136
|
+
})
|
|
131
137
|
)
|
|
132
138
|
this.webchatRef.current.addBotResponse(resp)
|
|
133
139
|
}
|
package/src/index-types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
2
|
BotRequest as CoreBotRequest,
|
|
3
3
|
Input as CoreInput,
|
|
4
4
|
InputType as CoreInputType,
|
|
@@ -7,7 +7,7 @@ import type {
|
|
|
7
7
|
Routes as CoreRoutes,
|
|
8
8
|
Session as CoreSession,
|
|
9
9
|
SessionUser as CoreSessionUser,
|
|
10
|
-
} from '@botonic/core/
|
|
10
|
+
} from '@botonic/core/src'
|
|
11
11
|
import React from 'react'
|
|
12
12
|
|
|
13
13
|
import {
|
|
@@ -129,16 +129,29 @@ export interface WebchatAppArgs {
|
|
|
129
129
|
visibility?: () => boolean
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
export enum SENDERS {
|
|
133
|
+
bot = 'bot',
|
|
134
|
+
user = 'user',
|
|
135
|
+
agent = 'agent',
|
|
136
|
+
}
|
|
137
|
+
|
|
132
138
|
export interface WebchatMessage {
|
|
133
139
|
ack: 0 | 1
|
|
140
|
+
blob: boolean
|
|
134
141
|
buttons: ButtonProps[]
|
|
142
|
+
children: any
|
|
135
143
|
data: any
|
|
136
144
|
delay: number
|
|
137
145
|
display: boolean
|
|
138
|
-
|
|
146
|
+
enabletimestamps: boolean
|
|
139
147
|
id: string
|
|
148
|
+
imagestyle: any
|
|
149
|
+
isUnread: boolean
|
|
150
|
+
json: any
|
|
140
151
|
markdown: boolean
|
|
141
152
|
replies: ReplyProps[]
|
|
153
|
+
sentBy: SENDERS
|
|
154
|
+
style: any
|
|
142
155
|
timestamp: string
|
|
143
156
|
type: CoreInputType
|
|
144
157
|
typing: number
|
|
@@ -173,11 +186,13 @@ export interface WebchatContextProps {
|
|
|
173
186
|
closeWebview: () => void
|
|
174
187
|
getThemeProperty: (property: string, defaultValue?: string | boolean) => any
|
|
175
188
|
openWebview: (webviewComponent: Webview) => void
|
|
189
|
+
resetUnreadMessages: () => void
|
|
176
190
|
resolveCase: () => void
|
|
177
191
|
sendAttachment: (attachment: File) => void
|
|
178
192
|
sendInput: (input: CoreInput) => void
|
|
179
193
|
sendPayload: (payload: string) => void
|
|
180
194
|
sendText: (text: string, payload?: string) => void
|
|
195
|
+
setLastMessageVisible: (isLastMessageVisible: boolean) => void
|
|
181
196
|
theme: ThemeProps
|
|
182
197
|
toggleWebchat: (toggle: boolean) => void
|
|
183
198
|
updateLatestInput: (input: CoreInput) => void
|
package/src/msg-to-botonic.jsx
CHANGED
|
@@ -88,7 +88,7 @@ export function msgToBotonic(msg, customMessageTypes) {
|
|
|
88
88
|
const buttons = buttonsParse(msg.buttons)
|
|
89
89
|
return (
|
|
90
90
|
<>
|
|
91
|
-
<Text {...msg}>
|
|
91
|
+
<Text {...msg} key={msg.key}>
|
|
92
92
|
{msg.text}
|
|
93
93
|
{buttons}
|
|
94
94
|
</Text>
|
|
@@ -125,8 +125,7 @@ export function msgsToBotonic(msgs, customMessageTypes) {
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
function textToBotonic(msg) {
|
|
128
|
-
const txt =
|
|
129
|
-
msg.data && msg.data.text != undefined ? msg.data.text : String(msg.data)
|
|
128
|
+
const txt = msg.data?.text ?? String(msg.data)
|
|
130
129
|
if (
|
|
131
130
|
(msg.replies && msg.replies.length) ||
|
|
132
131
|
(msg.keyboard && msg.keyboard.length)
|
package/src/webchat/actions.ts
CHANGED
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
export enum WebchatAction {
|
|
2
2
|
ADD_MESSAGE = 'addMessage',
|
|
3
3
|
ADD_MESSAGE_COMPONENT = 'addMessageComponent',
|
|
4
|
-
UPDATE_MESSAGE = 'updateMessage',
|
|
5
|
-
UPDATE_REPLIES = 'updateReplies',
|
|
6
|
-
UPDATE_LATEST_INPUT = 'updateLatestInput',
|
|
7
|
-
UPDATE_TYPING = 'updateTyping',
|
|
8
|
-
UPDATE_WEBVIEW = 'updateWebview',
|
|
9
|
-
UPDATE_SESSION = 'updateSession',
|
|
10
|
-
UPDATE_LAST_ROUTE_PATH = 'updateLastRoutePath',
|
|
11
|
-
UPDATE_HANDOFF = 'updateHandoff',
|
|
12
|
-
UPDATE_THEME = 'updateTheme',
|
|
13
|
-
UPDATE_DEV_SETTINGS = 'updateDevSettings',
|
|
14
|
-
TOGGLE_WEBCHAT = 'toggleWebchat',
|
|
15
|
-
TOGGLE_EMOJI_PICKER = 'toggleEmojiPicker',
|
|
16
|
-
TOGGLE_PERSISTENT_MENU = 'togglePersistentMenu',
|
|
17
|
-
TOGGLE_COVER_COMPONENT = 'toggleCoverComponent',
|
|
18
|
-
DO_RENDER_CUSTOM_COMPONENT = 'doRenderCustomComponent',
|
|
19
|
-
SET_ERROR = 'setError',
|
|
20
4
|
CLEAR_MESSAGES = 'clearMessages',
|
|
21
|
-
|
|
5
|
+
DO_RENDER_CUSTOM_COMPONENT = 'doRenderCustomComponent',
|
|
6
|
+
RESET_UNREAD_MESSAGES = 'resetUnreadMessages',
|
|
22
7
|
SET_CURRENT_ATTACHMENT = 'setCurrentAttachment',
|
|
8
|
+
SET_ERROR = 'setError',
|
|
9
|
+
SET_LAST_MESSAGE_VISIBLE = 'setlastMessageVisible',
|
|
23
10
|
SET_ONLINE = 'setOnline',
|
|
11
|
+
TOGGLE_COVER_COMPONENT = 'toggleCoverComponent',
|
|
12
|
+
TOGGLE_EMOJI_PICKER = 'toggleEmojiPicker',
|
|
13
|
+
TOGGLE_PERSISTENT_MENU = 'togglePersistentMenu',
|
|
14
|
+
TOGGLE_WEBCHAT = 'toggleWebchat',
|
|
15
|
+
UPDATE_DEV_SETTINGS = 'updateDevSettings',
|
|
16
|
+
UPDATE_HANDOFF = 'updateHandoff',
|
|
24
17
|
UPDATE_JWT = 'updateJwt',
|
|
18
|
+
UPDATE_LAST_MESSAGE_DATE = 'updateLastMessageDate',
|
|
19
|
+
UPDATE_LAST_ROUTE_PATH = 'updateLastRoutePath',
|
|
20
|
+
UPDATE_LATEST_INPUT = 'updateLatestInput',
|
|
21
|
+
UPDATE_MESSAGE = 'updateMessage',
|
|
22
|
+
UPDATE_REPLIES = 'updateReplies',
|
|
23
|
+
UPDATE_SESSION = 'updateSession',
|
|
24
|
+
UPDATE_THEME = 'updateTheme',
|
|
25
|
+
UPDATE_TYPING = 'updateTyping',
|
|
26
|
+
UPDATE_WEBVIEW = 'updateWebview',
|
|
25
27
|
}
|
|
@@ -15,11 +15,11 @@ export function useTyping({
|
|
|
15
15
|
webchatState,
|
|
16
16
|
updateTyping,
|
|
17
17
|
updateMessage,
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
}: // host,
|
|
19
|
+
UseTyping): void {
|
|
20
20
|
useEffect(() => {
|
|
21
21
|
let delayTimeout, typingTimeout
|
|
22
|
-
scrollToBottom({ host })
|
|
22
|
+
// scrollToBottom({ host })
|
|
23
23
|
try {
|
|
24
24
|
const nextMsg = webchatState.messagesJSON.filter(m => !m.display)[0]
|
|
25
25
|
if (nextMsg.delay && nextMsg.typing) {
|
|
@@ -43,7 +43,8 @@ export const webchatInitialState: WebchatState = {
|
|
|
43
43
|
lastMessageUpdate: undefined,
|
|
44
44
|
currentAttachment: undefined,
|
|
45
45
|
jwt: undefined,
|
|
46
|
-
|
|
46
|
+
numUnreadMessages: 0,
|
|
47
|
+
isLastMessageVisible: true,
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
export function useWebchat() {
|
|
@@ -55,7 +56,7 @@ export function useWebchat() {
|
|
|
55
56
|
const addMessage = (message: WebchatMessage) =>
|
|
56
57
|
webchatDispatch({ type: WebchatAction.ADD_MESSAGE, payload: message })
|
|
57
58
|
|
|
58
|
-
const addMessageComponent = (message: WebchatMessage) =>
|
|
59
|
+
const addMessageComponent = (message: { props: WebchatMessage }) =>
|
|
59
60
|
webchatDispatch({
|
|
60
61
|
type: WebchatAction.ADD_MESSAGE_COMPONENT,
|
|
61
62
|
payload: message,
|
|
@@ -183,13 +184,28 @@ export function useWebchat() {
|
|
|
183
184
|
})
|
|
184
185
|
}
|
|
185
186
|
|
|
187
|
+
const resetUnreadMessages = () => {
|
|
188
|
+
webchatDispatch({
|
|
189
|
+
type: WebchatAction.RESET_UNREAD_MESSAGES,
|
|
190
|
+
})
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const setLastMessageVisible = (isLastMessageVisible: boolean) => {
|
|
194
|
+
webchatDispatch({
|
|
195
|
+
type: WebchatAction.SET_LAST_MESSAGE_VISIBLE,
|
|
196
|
+
payload: isLastMessageVisible,
|
|
197
|
+
})
|
|
198
|
+
}
|
|
199
|
+
|
|
186
200
|
return {
|
|
187
201
|
addMessage,
|
|
188
202
|
addMessageComponent,
|
|
189
203
|
clearMessages,
|
|
190
204
|
doRenderCustomComponent,
|
|
205
|
+
resetUnreadMessages,
|
|
191
206
|
setCurrentAttachment,
|
|
192
207
|
setError,
|
|
208
|
+
setLastMessageVisible,
|
|
193
209
|
setOnline,
|
|
194
210
|
toggleCoverComponent,
|
|
195
211
|
toggleEmojiPicker,
|
|
@@ -48,7 +48,8 @@ export interface WebchatState {
|
|
|
48
48
|
lastMessageUpdate?: string
|
|
49
49
|
currentAttachment?: File
|
|
50
50
|
jwt?: string
|
|
51
|
-
|
|
51
|
+
numUnreadMessages: number
|
|
52
|
+
isLastMessageVisible: boolean
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
// export interface WebchatProps extends WebchatArgs {
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import React, { useContext, useEffect, useRef, useState } from 'react'
|
|
2
|
+
|
|
3
|
+
import { ROLES, WEBCHAT } from '../../constants'
|
|
4
|
+
import { WebchatContext } from '../../contexts'
|
|
5
|
+
import { scrollToBottom } from '../../util'
|
|
6
|
+
import { StyledScrollbar } from '../components/styled-scrollbar'
|
|
7
|
+
import { TypingIndicator } from '../components/typing-indicator'
|
|
8
|
+
import { IntroMessage } from './intro-message'
|
|
9
|
+
import { ScrollButton } from './scroll-button'
|
|
10
|
+
import { ContainerMessage } from './styles'
|
|
11
|
+
import { UnreadMessagesBanner } from './unread-messages-banner'
|
|
12
|
+
|
|
13
|
+
export const WebchatMessageList = props => {
|
|
14
|
+
const {
|
|
15
|
+
webchatState,
|
|
16
|
+
getThemeProperty,
|
|
17
|
+
resetUnreadMessages,
|
|
18
|
+
setLastMessageVisible,
|
|
19
|
+
} = useContext(WebchatContext)
|
|
20
|
+
|
|
21
|
+
const scrollbarOptions = {
|
|
22
|
+
...{ enable: true, autoHide: true },
|
|
23
|
+
...getThemeProperty(WEBCHAT.CUSTOM_PROPERTIES.scrollbar),
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const [firstUnreadMessageId, setFirstUnreadMessageId] = useState()
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
const firstUnreadMessage = webchatState.messagesComponents.find(
|
|
29
|
+
message => message.props.isUnread
|
|
30
|
+
)
|
|
31
|
+
setFirstUnreadMessageId(firstUnreadMessage?.props?.id)
|
|
32
|
+
}, [webchatState.messagesComponents])
|
|
33
|
+
|
|
34
|
+
const lastMessageRef = useRef(null)
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (webchatState.messagesComponents.length > 0 && lastMessageRef.current) {
|
|
37
|
+
const observer = new IntersectionObserver(entries => {
|
|
38
|
+
entries.forEach(entry => {
|
|
39
|
+
setLastMessageVisible(entry.isIntersecting)
|
|
40
|
+
})
|
|
41
|
+
})
|
|
42
|
+
observer.observe(lastMessageRef.current)
|
|
43
|
+
}
|
|
44
|
+
}, [webchatState.messagesComponents])
|
|
45
|
+
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
if (webchatState.isLastMessageVisible && webchatState.typing) {
|
|
48
|
+
scrollToBottom({ host: props.host })
|
|
49
|
+
}
|
|
50
|
+
if (webchatState.isLastMessageVisible) {
|
|
51
|
+
scrollToBottom({ host: props.host })
|
|
52
|
+
}
|
|
53
|
+
}, [webchatState.typing, webchatState.isLastMessageVisible])
|
|
54
|
+
|
|
55
|
+
const handleScrollToBottom = () => {
|
|
56
|
+
resetUnreadMessages()
|
|
57
|
+
scrollToBottom({ host: props.host })
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const showUnreadMessagesBanner = (messageComponentId: string) =>
|
|
61
|
+
firstUnreadMessageId &&
|
|
62
|
+
messageComponentId === firstUnreadMessageId &&
|
|
63
|
+
webchatState.numUnreadMessages > 0
|
|
64
|
+
|
|
65
|
+
const showScrollButton =
|
|
66
|
+
webchatState.numUnreadMessages > 0 && !webchatState.isLastMessageVisible
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<>
|
|
70
|
+
<StyledScrollbar
|
|
71
|
+
role={ROLES.MESSAGE_LIST}
|
|
72
|
+
// TODO: Distinguis between multiple instances of webchat, e.g. `${uniqueId}-botonic-scrollable`
|
|
73
|
+
id='botonic-scrollable-content'
|
|
74
|
+
scrollbar={scrollbarOptions}
|
|
75
|
+
autoHide={scrollbarOptions.autoHide}
|
|
76
|
+
isMessagesContainer={true}
|
|
77
|
+
style={{
|
|
78
|
+
...props.style,
|
|
79
|
+
}}
|
|
80
|
+
>
|
|
81
|
+
<IntroMessage />
|
|
82
|
+
{webchatState.messagesComponents.map((messageComponent, index) => {
|
|
83
|
+
return (
|
|
84
|
+
<ContainerMessage role={ROLES.MESSAGE} key={index}>
|
|
85
|
+
{showUnreadMessagesBanner(messageComponent.props.id) && (
|
|
86
|
+
<UnreadMessagesBanner
|
|
87
|
+
numUnreadMessages={webchatState.numUnreadMessages}
|
|
88
|
+
/>
|
|
89
|
+
)}
|
|
90
|
+
|
|
91
|
+
{index === webchatState.messagesComponents.length - 1 && (
|
|
92
|
+
<div ref={lastMessageRef} style={{ content: '' }}></div>
|
|
93
|
+
)}
|
|
94
|
+
{messageComponent}
|
|
95
|
+
</ContainerMessage>
|
|
96
|
+
)
|
|
97
|
+
})}
|
|
98
|
+
{webchatState.typing && <TypingIndicator />}
|
|
99
|
+
</StyledScrollbar>
|
|
100
|
+
{showScrollButton && <ScrollButton handleClick={handleScrollToBottom} />}
|
|
101
|
+
</>
|
|
102
|
+
)
|
|
103
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React, { useContext } from 'react'
|
|
2
|
+
import Fade from 'react-reveal/Fade'
|
|
3
|
+
|
|
4
|
+
import { WEBCHAT } from '../../constants'
|
|
5
|
+
import { WebchatContext } from '../../contexts'
|
|
6
|
+
import { resolveImage } from '../../util/environment'
|
|
7
|
+
import { ConditionalWrapper } from '../../util/react'
|
|
8
|
+
import { DefaultIntroImage } from './styles'
|
|
9
|
+
|
|
10
|
+
export const IntroMessage = () => {
|
|
11
|
+
const { getThemeProperty } = useContext(WebchatContext)
|
|
12
|
+
|
|
13
|
+
const animationsEnabled = getThemeProperty(
|
|
14
|
+
WEBCHAT.CUSTOM_PROPERTIES.enableAnimations,
|
|
15
|
+
true
|
|
16
|
+
)
|
|
17
|
+
const CustomIntro = getThemeProperty(WEBCHAT.CUSTOM_PROPERTIES.customIntro)
|
|
18
|
+
const introImage = getThemeProperty(WEBCHAT.CUSTOM_PROPERTIES.introImage)
|
|
19
|
+
const introStyle = getThemeProperty(WEBCHAT.CUSTOM_PROPERTIES.introStyle)
|
|
20
|
+
|
|
21
|
+
const DefaultIntro = introImage && (
|
|
22
|
+
<DefaultIntroImage
|
|
23
|
+
style={{
|
|
24
|
+
...introStyle,
|
|
25
|
+
}}
|
|
26
|
+
src={resolveImage(introImage)}
|
|
27
|
+
/>
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
return CustomIntro || DefaultIntro ? (
|
|
31
|
+
<ConditionalWrapper
|
|
32
|
+
condition={animationsEnabled}
|
|
33
|
+
wrapper={children => <Fade>{children}</Fade>}
|
|
34
|
+
>
|
|
35
|
+
{CustomIntro ? <CustomIntro /> : DefaultIntro}
|
|
36
|
+
</ConditionalWrapper>
|
|
37
|
+
) : null
|
|
38
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React, { useContext, useEffect, useState } from 'react'
|
|
2
|
+
|
|
3
|
+
import ArrowScrollDown from '../../assets/arrow-scroll-down.svg'
|
|
4
|
+
import { WEBCHAT } from '../../constants'
|
|
5
|
+
import { WebchatContext } from '../../contexts'
|
|
6
|
+
import { resolveImage } from '../../util/environment'
|
|
7
|
+
import { ContainerScrollButton } from './styles'
|
|
8
|
+
|
|
9
|
+
interface ScrollButtonProps {
|
|
10
|
+
handleClick: () => void
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const ScrollButton = ({
|
|
14
|
+
handleClick,
|
|
15
|
+
}: ScrollButtonProps): JSX.Element => {
|
|
16
|
+
const { getThemeProperty } = useContext(WebchatContext)
|
|
17
|
+
|
|
18
|
+
const CustomScrollButton = getThemeProperty(
|
|
19
|
+
WEBCHAT.CUSTOM_PROPERTIES.scrollButtonCustom,
|
|
20
|
+
undefined
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
const scrollButtonEnabled = getThemeProperty(
|
|
24
|
+
WEBCHAT.CUSTOM_PROPERTIES.scrollButtonEnabled,
|
|
25
|
+
false
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
scrollButtonEnabled && (
|
|
30
|
+
<>
|
|
31
|
+
{CustomScrollButton ? (
|
|
32
|
+
<CustomScrollButton />
|
|
33
|
+
) : (
|
|
34
|
+
<ContainerScrollButton onClick={handleClick}>
|
|
35
|
+
<img src={resolveImage(ArrowScrollDown)} />
|
|
36
|
+
</ContainerScrollButton>
|
|
37
|
+
)}
|
|
38
|
+
</>
|
|
39
|
+
)
|
|
40
|
+
)
|
|
41
|
+
}
|