@botonic/react 0.27.2 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/lib/cjs/assets/thumbs-down.svg +3 -0
  2. package/lib/cjs/assets/thumbs-up.svg +3 -0
  3. package/lib/cjs/components/index-types.d.ts +2 -0
  4. package/lib/cjs/components/index-types.js +0 -14
  5. package/lib/cjs/components/index-types.js.map +1 -1
  6. package/lib/cjs/components/message/index.js +6 -3
  7. package/lib/cjs/components/message/index.js.map +1 -1
  8. package/lib/cjs/components/message/message-feedback.d.ts +6 -0
  9. package/lib/cjs/components/message/message-feedback.js +60 -0
  10. package/lib/cjs/components/message/message-feedback.js.map +1 -0
  11. package/lib/cjs/components/message/message-footer.d.ts +10 -0
  12. package/lib/cjs/components/message/message-footer.js +21 -0
  13. package/lib/cjs/components/message/message-footer.js.map +1 -0
  14. package/lib/cjs/components/message/styles.d.ts +3 -0
  15. package/lib/cjs/components/message/styles.js +48 -3
  16. package/lib/cjs/components/message/styles.js.map +1 -1
  17. package/lib/cjs/components/text.d.ts +6 -7
  18. package/lib/cjs/components/text.js +5 -9
  19. package/lib/cjs/components/text.js.map +1 -1
  20. package/lib/cjs/contexts.js +4 -0
  21. package/lib/cjs/contexts.js.map +1 -1
  22. package/lib/cjs/dev-app.d.ts +2 -1
  23. package/lib/cjs/dev-app.js +5 -3
  24. package/lib/cjs/dev-app.js.map +1 -1
  25. package/lib/cjs/index-types.d.ts +7 -0
  26. package/lib/cjs/index-types.js.map +1 -1
  27. package/lib/cjs/webchat/tracking.d.ts +7 -0
  28. package/lib/cjs/webchat/tracking.js +13 -0
  29. package/lib/cjs/webchat/tracking.js.map +1 -0
  30. package/lib/cjs/webchat/webchat.js +1 -0
  31. package/lib/cjs/webchat/webchat.js.map +1 -1
  32. package/lib/cjs/webchat-app.d.ts +3 -1
  33. package/lib/cjs/webchat-app.js +5 -3
  34. package/lib/cjs/webchat-app.js.map +1 -1
  35. package/lib/esm/assets/thumbs-down.svg +3 -0
  36. package/lib/esm/assets/thumbs-up.svg +3 -0
  37. package/lib/esm/components/index-types.d.ts +2 -0
  38. package/lib/esm/components/index-types.js +0 -14
  39. package/lib/esm/components/index-types.js.map +1 -1
  40. package/lib/esm/components/message/index.js +7 -4
  41. package/lib/esm/components/message/index.js.map +1 -1
  42. package/lib/esm/components/message/message-feedback.d.ts +6 -0
  43. package/lib/esm/components/message/message-feedback.js +56 -0
  44. package/lib/esm/components/message/message-feedback.js.map +1 -0
  45. package/lib/esm/components/message/message-footer.d.ts +10 -0
  46. package/lib/esm/components/message/message-footer.js +17 -0
  47. package/lib/esm/components/message/message-footer.js.map +1 -0
  48. package/lib/esm/components/message/styles.d.ts +3 -0
  49. package/lib/esm/components/message/styles.js +47 -2
  50. package/lib/esm/components/message/styles.js.map +1 -1
  51. package/lib/esm/components/text.d.ts +6 -7
  52. package/lib/esm/components/text.js +5 -8
  53. package/lib/esm/components/text.js.map +1 -1
  54. package/lib/esm/contexts.js +4 -0
  55. package/lib/esm/contexts.js.map +1 -1
  56. package/lib/esm/dev-app.d.ts +2 -1
  57. package/lib/esm/dev-app.js +5 -3
  58. package/lib/esm/dev-app.js.map +1 -1
  59. package/lib/esm/index-types.d.ts +7 -0
  60. package/lib/esm/index-types.js.map +1 -1
  61. package/lib/esm/webchat/tracking.d.ts +7 -0
  62. package/lib/esm/webchat/tracking.js +10 -0
  63. package/lib/esm/webchat/tracking.js.map +1 -0
  64. package/lib/esm/webchat/webchat.js +1 -0
  65. package/lib/esm/webchat/webchat.js.map +1 -1
  66. package/lib/esm/webchat-app.d.ts +3 -1
  67. package/lib/esm/webchat-app.js +5 -3
  68. package/lib/esm/webchat-app.js.map +1 -1
  69. package/package.json +3 -3
  70. package/src/assets/thumbs-down.svg +3 -0
  71. package/src/assets/thumbs-up.svg +3 -0
  72. package/src/components/index-types.ts +3 -19
  73. package/src/components/message/index.jsx +17 -8
  74. package/src/components/message/message-feedback.tsx +99 -0
  75. package/src/components/message/message-footer.tsx +52 -0
  76. package/src/components/message/styles.ts +50 -2
  77. package/src/components/{text.jsx → text.tsx} +7 -7
  78. package/src/contexts.tsx +3 -0
  79. package/src/dev-app.jsx +5 -0
  80. package/src/index-types.ts +9 -1
  81. package/src/webchat/tracking.ts +8 -0
  82. package/src/webchat/webchat.jsx +1 -0
  83. package/src/webchat-app.jsx +5 -0
@@ -0,0 +1,99 @@
1
+ import React, { useContext, useEffect, useState } from 'react'
2
+ import { v4 as uuid } from 'uuid'
3
+
4
+ import ThumbsDown from '../../assets/thumbs-down.svg'
5
+ import ThumbsUp from '../../assets/thumbs-up.svg'
6
+ import { RequestContext, WebchatContext } from '../../contexts'
7
+ import { ActionRequest } from '../../index-types'
8
+ import { resolveImage } from '../../util'
9
+ import { EventAction, FeedbackOption } from '../../webchat/tracking'
10
+ import { FeedbackButton, FeedbackMessageContainer } from './styles'
11
+
12
+ interface ButtonsState {
13
+ positive: boolean
14
+ negative: boolean
15
+ }
16
+
17
+ interface RatingProps {
18
+ inferenceId?: string
19
+ messageId: string
20
+ }
21
+
22
+ export const MessageFeedback = ({ inferenceId, messageId }: RatingProps) => {
23
+ const { webchatState, updateMessage, trackEvent } = useContext(WebchatContext)
24
+ const request = useContext(RequestContext)
25
+
26
+ const [className, setClassName] = useState('')
27
+ const [disabled, setDisabled] = useState<ButtonsState>({
28
+ positive: false,
29
+ negative: false,
30
+ })
31
+
32
+ const updateMsgWithFeedback = (feedbackEnabled: boolean) => {
33
+ const message = webchatState.messagesJSON.find(
34
+ message => message.id === messageId
35
+ )
36
+ const updatedMsg = {
37
+ ...message,
38
+ feedbackEnabled,
39
+ }
40
+ updateMessage(updatedMsg)
41
+ }
42
+
43
+ useEffect(() => {
44
+ updateMsgWithFeedback(true)
45
+ }, [])
46
+
47
+ useEffect(() => {
48
+ if (disabled.positive || disabled.negative) {
49
+ setClassName('clicked')
50
+ updateMsgWithFeedback(false)
51
+ }
52
+ }, [disabled])
53
+
54
+ const handleClick = async (isUseful: boolean) => {
55
+ if (!trackEvent) {
56
+ return
57
+ }
58
+
59
+ if (isUseful) {
60
+ setDisabled({ positive: false, negative: true })
61
+ } else {
62
+ setDisabled({ positive: true, negative: false })
63
+ }
64
+
65
+ const args = {
66
+ knowledgebaseInferenceId: inferenceId,
67
+ feedbackTargetId: messageId,
68
+ feedbackGroupId: uuid(),
69
+ possibleOptions: [FeedbackOption.ThumbsUp, FeedbackOption.ThumbsDown],
70
+ possibleValues: [0, 1],
71
+ option: isUseful ? FeedbackOption.ThumbsUp : FeedbackOption.ThumbsDown,
72
+ value: isUseful ? 1 : 0,
73
+ }
74
+ await trackEvent(
75
+ request as ActionRequest,
76
+ EventAction.FeedbackKnowledgebase,
77
+ args
78
+ )
79
+ }
80
+
81
+ return (
82
+ <FeedbackMessageContainer>
83
+ <FeedbackButton
84
+ className={className}
85
+ disabled={disabled.positive}
86
+ onClick={() => handleClick(true)}
87
+ >
88
+ <img src={resolveImage(ThumbsUp)} />
89
+ </FeedbackButton>
90
+ <FeedbackButton
91
+ className={className}
92
+ disabled={disabled.negative}
93
+ onClick={() => handleClick(false)}
94
+ >
95
+ <img src={resolveImage(ThumbsDown)} />
96
+ </FeedbackButton>
97
+ </FeedbackMessageContainer>
98
+ )
99
+ }
@@ -0,0 +1,52 @@
1
+ import React, { useContext } from 'react'
2
+
3
+ import { WebchatContext } from '../../contexts'
4
+ import { SENDERS } from '../../index-types'
5
+ import { MessageFeedback } from './message-feedback'
6
+ import { MessageFooterContainer } from './styles'
7
+ import { MessageTimestamp, resolveMessageTimestamps } from './timestamps'
8
+
9
+ interface MessageFooterProps {
10
+ enabletimestamps: boolean
11
+ messageJSON: any
12
+ sentBy: SENDERS
13
+ feedbackEnabled: boolean
14
+ inferenceId?: string
15
+ }
16
+
17
+ export const MessageFooter = ({
18
+ enabletimestamps,
19
+ messageJSON,
20
+ sentBy,
21
+ feedbackEnabled,
22
+ inferenceId,
23
+ }: MessageFooterProps) => {
24
+ const { getThemeProperty } = useContext(WebchatContext)
25
+
26
+ const { timestampsEnabled, timestampStyle } = resolveMessageTimestamps(
27
+ getThemeProperty,
28
+ enabletimestamps
29
+ )
30
+ const isSentByUser = sentBy === SENDERS.user
31
+ const messageFotterClass = isSentByUser
32
+ ? 'message-footer-user'
33
+ : 'message-footer-bot'
34
+
35
+ return (
36
+ <MessageFooterContainer
37
+ className={messageFotterClass}
38
+ isSentByUser={isSentByUser}
39
+ >
40
+ {timestampsEnabled ? (
41
+ <MessageTimestamp
42
+ sentBy={sentBy}
43
+ style={timestampStyle}
44
+ timestamp={messageJSON.timestamp}
45
+ />
46
+ ) : null}
47
+ {feedbackEnabled ? (
48
+ <MessageFeedback inferenceId={inferenceId} messageId={messageJSON.id} />
49
+ ) : null}
50
+ </MessageFooterContainer>
51
+ )
52
+ }
@@ -85,8 +85,6 @@ export const TimestampContainer = styled.div<TimestampContainerProps>`
85
85
 
86
86
  box-sizing: border-box;
87
87
  width: 100%;
88
- padding: 0px 15px 4px 15px;
89
- padding-top: ${props => (props.isSentByUser ? '0px' : '4px')};
90
88
 
91
89
  img {
92
90
  max-width: 20px;
@@ -103,3 +101,53 @@ export const TimestampText = styled.div<TimestampTextProps>`
103
101
  color: ${COLORS.SOLID_BLACK};
104
102
  text-align: ${props => (props.isSentByUser ? 'right' : 'left')};
105
103
  `
104
+
105
+ export const MessageFooterContainer = styled.div<TimestampContainerProps>`
106
+ display: flex;
107
+ justify-content: space-between;
108
+ align-items: center;
109
+
110
+ box-sizing: border-box;
111
+ padding: 0px 15px 4px 15px;
112
+ padding-top: ${props => (props.isSentByUser ? '0px' : '4px')};
113
+ width: 100%;
114
+ `
115
+
116
+ export const FeedbackMessageContainer = styled.div`
117
+ display: flex;
118
+ justify-content: space-between;
119
+ align-items: center;
120
+ gap: 4px;
121
+
122
+ box-sizing: border-box;
123
+ `
124
+
125
+ export const FeedbackButton = styled.button`
126
+ display: flex;
127
+ justify-content: center;
128
+ align-items: center;
129
+
130
+ background: none;
131
+ box-sizing: border-box;
132
+ border: none;
133
+ border-radius: 4px;
134
+ padding: 8px 8px;
135
+ height: 24px;
136
+ width: 24px;
137
+
138
+ &:hover {
139
+ cursor: pointer;
140
+ background-color: #f4f3f4;
141
+ }
142
+
143
+ &:disabled {
144
+ cursor: default;
145
+ background: none;
146
+ opacity: 0.3;
147
+ }
148
+
149
+ &.clicked {
150
+ opacity: 0;
151
+ transition: 1s 1s;
152
+ }
153
+ `
@@ -2,6 +2,7 @@ import { INPUT } from '@botonic/core'
2
2
  import React, { Children } from 'react'
3
3
 
4
4
  import { mapObjectNonBooleanValues } from '../util/react'
5
+ import { TextProps } from './index-types'
5
6
  import { serializeMarkdown, toMarkdownChildren } from './markdown'
6
7
  import { Message } from './message'
7
8
 
@@ -17,7 +18,7 @@ const serializeText = children => {
17
18
  return text
18
19
  }
19
20
 
20
- const serialize = textProps => {
21
+ const serialize = (textProps: TextProps) => {
21
22
  if (!textProps.markdown)
22
23
  return {
23
24
  text: serializeText(textProps.children),
@@ -25,20 +26,19 @@ const serialize = textProps => {
25
26
  return { text: serializeMarkdown(textProps.children) }
26
27
  }
27
28
 
28
- /**
29
- *
30
- * @param {TextProps} props
31
- * @returns {JSX.Element}
32
- */
33
- export const Text = props => {
29
+ export const Text = (props: TextProps) => {
34
30
  const defaultTextProps = {
35
31
  markdown: props.markdown === undefined ? true : props.markdown,
32
+ feedbackEnabled: props.feedbackEnabled,
33
+ inferenceId: props.inferenceId,
36
34
  }
35
+
37
36
  const textProps = mapObjectNonBooleanValues({
38
37
  ...props,
39
38
  ...defaultTextProps,
40
39
  ...{ children: Children.toArray(props.children) },
41
40
  })
41
+
42
42
  if (!textProps.markdown)
43
43
  return (
44
44
  <Message json={serialize(textProps)} {...textProps} type={INPUT.TEXT}>
package/src/contexts.tsx CHANGED
@@ -91,4 +91,7 @@ export const WebchatContext = createContext<WebchatContextProps>({
91
91
  return
92
92
  },
93
93
  webchatState: webchatInitialState,
94
+ trackEvent: async () => {
95
+ return
96
+ },
94
97
  })
package/src/dev-app.jsx CHANGED
@@ -26,6 +26,7 @@ export class DevApp extends WebchatApp {
26
26
  onOpen,
27
27
  onClose,
28
28
  onMessage,
29
+ onTrackEvent,
29
30
  ...botOptions
30
31
  }) {
31
32
  super({
@@ -45,6 +46,7 @@ export class DevApp extends WebchatApp {
45
46
  onOpen,
46
47
  onClose,
47
48
  onMessage,
49
+ onTrackEvent,
48
50
  })
49
51
  this.bot = new ReactBot({
50
52
  ...botOptions,
@@ -67,6 +69,7 @@ export class DevApp extends WebchatApp {
67
69
  onOpen,
68
70
  onClose,
69
71
  onMessage,
72
+ onTrackEvent,
70
73
  hostId,
71
74
  ...webchatOptions
72
75
  } = optionsAtRuntime
@@ -84,6 +87,7 @@ export class DevApp extends WebchatApp {
84
87
  this.onOpen = onOpen || this.onOpen
85
88
  this.onClose = onClose || this.onClose
86
89
  this.onMessage = onMessage || this.onMessage
90
+ this.onTrackEvent = onTrackEvent || this.onTrackEvent
87
91
  this.hostId = hostId || this.hostId
88
92
  this.createRootElement(host)
89
93
  return (
@@ -108,6 +112,7 @@ export class DevApp extends WebchatApp {
108
112
  onOpen={(...args) => this.onOpenWebchat(...args)}
109
113
  onClose={(...args) => this.onCloseWebchat(...args)}
110
114
  onUserInput={(...args) => this.onUserInput(...args)}
115
+ onTrackEvent={(...args) => this.onTrackEvent(...args)}
111
116
  />
112
117
  )
113
118
  }
@@ -117,13 +117,20 @@ export interface WebchatArgs {
117
117
  onMessage?: (app: WebchatApp, message: WebchatMessage) => void
118
118
  onOpen?: (app: WebchatApp, args: any) => void
119
119
  onConnectionChange?: (app: WebchatApp, isOnline: boolean) => void
120
+ onTrackEvent?: TrackEventFunction
120
121
  persistentMenu?: PersistentMenuTheme
121
122
  storage?: Storage | null
122
123
  storageKey?: any
123
124
  theme?: ThemeProps
124
125
  }
125
126
 
126
- // export interface WebchatAppArgs extends WebchatArgs {
127
+ type EventArgs = { [key: string]: any }
128
+ type TrackEventFunction = (
129
+ request: ActionRequest,
130
+ eventName: string,
131
+ args?: EventArgs
132
+ ) => Promise<void>
133
+
127
134
  export interface WebchatAppArgs {
128
135
  appId?: string
129
136
  visibility?: () => boolean
@@ -201,6 +208,7 @@ export interface WebchatContextProps {
201
208
  updateUser: (user: Partial<CoreSessionUser>) => void
202
209
  updateWebchatDevSettings: (settings: WebchatSettingsProps) => void
203
210
  webchatState: WebchatState
211
+ trackEvent: TrackEventFunction
204
212
  }
205
213
 
206
214
  // export class DevApp extends WebchatApp {
@@ -0,0 +1,8 @@
1
+ export enum EventAction {
2
+ FeedbackKnowledgebase = 'feedback_knowledgebase',
3
+ }
4
+
5
+ export enum FeedbackOption {
6
+ ThumbsUp = 'thumbsUp',
7
+ ThumbsDown = 'thumbsDown',
8
+ }
@@ -880,6 +880,7 @@ export const Webchat = forwardRef((props, ref) => {
880
880
  updateUser: updateSessionWithUser,
881
881
  updateWebchatDevSettings: updateWebchatDevSettings,
882
882
  webchatState,
883
+ trackEvent: props.onTrackEvent,
883
884
  }}
884
885
  >
885
886
  {!webchatState.isWebchatOpen && <TriggerButton />}
@@ -29,6 +29,7 @@ export class WebchatApp {
29
29
  onOpen,
30
30
  onClose,
31
31
  onMessage,
32
+ onTrackEvent,
32
33
  onConnectionChange,
33
34
  appId,
34
35
  visibility,
@@ -58,6 +59,7 @@ export class WebchatApp {
58
59
  this.onOpen = onOpen
59
60
  this.onClose = onClose
60
61
  this.onMessage = onMessage
62
+ this.onTrackEvent = onTrackEvent
61
63
  this.onConnectionChange = onConnectionChange
62
64
  this.visibility = visibility
63
65
  this.server = server
@@ -284,6 +286,7 @@ export class WebchatApp {
284
286
  onClose,
285
287
  onMessage,
286
288
  onConnectionChange,
289
+ onTrackEvent,
287
290
  appId,
288
291
  visibility,
289
292
  server,
@@ -307,6 +310,7 @@ export class WebchatApp {
307
310
  this.onOpen = onOpen || this.onOpen
308
311
  this.onClose = onClose || this.onClose
309
312
  this.onMessage = onMessage || this.onMessage
313
+ this.onTrackEvent = onTrackEvent || this.onTrackEvent
310
314
  this.onConnectionChange = onConnectionChange || this.onConnectionChange
311
315
  this.visibility = visibility || this.visibility
312
316
  this.appId = appId || this.appId
@@ -335,6 +339,7 @@ export class WebchatApp {
335
339
  onClose={(...args) => this.onCloseWebchat(...args)}
336
340
  onUserInput={(...args) => this.onUserInput(...args)}
337
341
  onStateChange={webchatState => this.onStateChange(webchatState)}
342
+ onTrackEvent={(...args) => this.onTrackEvent(...args)}
338
343
  server={server}
339
344
  />
340
345
  )