@botonic/react 0.31.0-alpha.5 → 0.31.0-alpha.7
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/cjs/components/index-types.d.ts +4 -131
- package/lib/cjs/components/index.d.ts +7 -1
- package/lib/cjs/components/index.js +14 -1
- package/lib/cjs/components/index.js.map +1 -1
- package/lib/cjs/components/webchat-settings.d.ts +15 -2
- package/lib/cjs/components/webchat-settings.js.map +1 -1
- package/lib/cjs/components/whatsapp-catalog.d.ts +6 -0
- package/lib/cjs/components/whatsapp-catalog.js +25 -0
- package/lib/cjs/components/whatsapp-catalog.js.map +1 -0
- package/lib/cjs/components/whatsapp-media-carousel.d.ts +46 -0
- package/lib/cjs/components/whatsapp-media-carousel.js +40 -0
- package/lib/cjs/components/whatsapp-media-carousel.js.map +1 -0
- package/lib/cjs/components/whatsapp-product-carousel.d.ts +32 -0
- package/lib/cjs/components/whatsapp-product-carousel.js +34 -0
- package/lib/cjs/components/whatsapp-product-carousel.js.map +1 -0
- package/lib/cjs/components/whatsapp-product-list.d.ts +15 -0
- package/lib/cjs/components/whatsapp-product-list.js +26 -0
- package/lib/cjs/components/whatsapp-product-list.js.map +1 -0
- package/lib/cjs/components/whatsapp-product.d.ts +7 -0
- package/lib/cjs/components/whatsapp-product.js +25 -0
- package/lib/cjs/components/whatsapp-product.js.map +1 -0
- package/lib/cjs/index-types.d.ts +4 -3
- package/lib/cjs/index-types.js.map +1 -1
- package/lib/cjs/util/functional.d.ts +3 -0
- package/lib/cjs/util/functional.js +30 -0
- package/lib/cjs/util/functional.js.map +1 -0
- package/lib/cjs/util/webchat.d.ts +1 -1
- package/lib/cjs/util/webchat.js.map +1 -1
- package/lib/cjs/webchat/context/types.d.ts +2 -2
- package/lib/cjs/webchat/context/use-webchat.d.ts +2 -1
- package/lib/cjs/webchat/context/use-webchat.js +1 -0
- package/lib/cjs/webchat/context/use-webchat.js.map +1 -1
- package/lib/cjs/webchat/index-types.d.ts +0 -3
- package/lib/cjs/webchat/input-panel/textarea.d.ts +2 -2
- package/lib/cjs/webchat/input-panel/textarea.js.map +1 -1
- package/lib/cjs/webchat/theme/types.d.ts +167 -0
- package/lib/cjs/webchat/theme/types.js +3 -0
- package/lib/cjs/webchat/theme/types.js.map +1 -0
- package/lib/cjs/webchat/webchat.js +3 -5
- package/lib/cjs/webchat/webchat.js.map +1 -1
- package/lib/cjs/webchat-app.d.ts +3 -2
- package/lib/cjs/webchat-app.js.map +1 -1
- package/lib/esm/components/index-types.d.ts +4 -131
- package/lib/esm/components/index.d.ts +7 -1
- package/lib/esm/components/index.js +7 -1
- package/lib/esm/components/index.js.map +1 -1
- package/lib/esm/components/webchat-settings.d.ts +15 -2
- package/lib/esm/components/webchat-settings.js.map +1 -1
- package/lib/esm/components/whatsapp-catalog.d.ts +6 -0
- package/lib/esm/components/whatsapp-catalog.js +21 -0
- package/lib/esm/components/whatsapp-catalog.js.map +1 -0
- package/lib/esm/components/whatsapp-media-carousel.d.ts +46 -0
- package/lib/esm/components/whatsapp-media-carousel.js +36 -0
- package/lib/esm/components/whatsapp-media-carousel.js.map +1 -0
- package/lib/esm/components/whatsapp-product-carousel.d.ts +32 -0
- package/lib/esm/components/whatsapp-product-carousel.js +30 -0
- package/lib/esm/components/whatsapp-product-carousel.js.map +1 -0
- package/lib/esm/components/whatsapp-product-list.d.ts +15 -0
- package/lib/esm/components/whatsapp-product-list.js +22 -0
- package/lib/esm/components/whatsapp-product-list.js.map +1 -0
- package/lib/esm/components/whatsapp-product.d.ts +7 -0
- package/lib/esm/components/whatsapp-product.js +21 -0
- package/lib/esm/components/whatsapp-product.js.map +1 -0
- package/lib/esm/index-types.d.ts +4 -3
- package/lib/esm/index-types.js.map +1 -1
- package/lib/esm/util/functional.d.ts +3 -0
- package/lib/esm/util/functional.js +26 -0
- package/lib/esm/util/functional.js.map +1 -0
- package/lib/esm/util/webchat.d.ts +1 -1
- package/lib/esm/util/webchat.js.map +1 -1
- package/lib/esm/webchat/context/types.d.ts +2 -2
- package/lib/esm/webchat/context/use-webchat.d.ts +2 -1
- package/lib/esm/webchat/context/use-webchat.js +1 -0
- package/lib/esm/webchat/context/use-webchat.js.map +1 -1
- package/lib/esm/webchat/index-types.d.ts +0 -3
- package/lib/esm/webchat/input-panel/textarea.d.ts +2 -2
- package/lib/esm/webchat/input-panel/textarea.js.map +1 -1
- package/lib/esm/webchat/theme/types.d.ts +167 -0
- package/lib/esm/webchat/theme/types.js +2 -0
- package/lib/esm/webchat/theme/types.js.map +1 -0
- package/lib/esm/webchat/webchat.js +1 -3
- package/lib/esm/webchat/webchat.js.map +1 -1
- package/lib/esm/webchat-app.d.ts +3 -2
- package/lib/esm/webchat-app.js.map +1 -1
- package/package.json +9 -8
- package/src/components/index-types.ts +4 -121
- package/src/components/index.ts +22 -1
- package/src/components/webchat-settings.tsx +13 -1
- package/src/components/whatsapp-catalog.tsx +42 -0
- package/src/components/whatsapp-media-carousel.tsx +104 -0
- package/src/components/whatsapp-product-carousel.tsx +83 -0
- package/src/components/whatsapp-product-list.tsx +56 -0
- package/src/components/whatsapp-product.tsx +44 -0
- package/src/index-types.ts +8 -6
- package/src/util/functional.ts +31 -0
- package/src/util/webchat.ts +1 -1
- package/src/webchat/context/index.tsx +1 -1
- package/src/webchat/context/types.ts +7 -11
- package/src/webchat/context/use-webchat.ts +3 -1
- package/src/webchat/index-types.ts +0 -4
- package/src/webchat/input-panel/textarea.tsx +2 -2
- package/src/webchat/theme/types.ts +119 -0
- package/src/webchat/webchat.tsx +2 -2
- package/src/webchat-app.tsx +7 -8
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { INPUT } from '@botonic/core'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
import { toSnakeCaseKeys } from '../util/functional'
|
|
5
|
+
import { renderComponent } from '../util/react'
|
|
6
|
+
import { Message } from './message'
|
|
7
|
+
|
|
8
|
+
type Parameters = TextParameter | CurrencyParameter | DateTimeParameter
|
|
9
|
+
|
|
10
|
+
interface TextParameter {
|
|
11
|
+
type: 'text'
|
|
12
|
+
text: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface CurrencyParameter {
|
|
16
|
+
type: 'currency'
|
|
17
|
+
currency: {
|
|
18
|
+
fallbackValue: string
|
|
19
|
+
code: string
|
|
20
|
+
amount1000: number
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface DateTimeParameter {
|
|
25
|
+
type: 'date_time'
|
|
26
|
+
dateTime: { fallbackValue: string }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
type CardButton = QuickReplyButton | UrlButton
|
|
30
|
+
|
|
31
|
+
interface Button {
|
|
32
|
+
type: 'quick_reply' | 'url'
|
|
33
|
+
buttonIndex?: number
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface QuickReplyButton extends Button {
|
|
37
|
+
payload: string
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface UrlButton extends Button {
|
|
41
|
+
urlVariable: string
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface Card {
|
|
45
|
+
fileType: 'image' | 'video'
|
|
46
|
+
fileId: string
|
|
47
|
+
cardIndex?: number
|
|
48
|
+
bodyParameters?: Parameters[]
|
|
49
|
+
buttons?: CardButton[]
|
|
50
|
+
extraComponents?: Record<string, any>[]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface WhatsappMediaCarouselProps {
|
|
54
|
+
templateName: string
|
|
55
|
+
templateLanguage: string
|
|
56
|
+
cards: Card[]
|
|
57
|
+
bodyParameters?: Parameters[]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const serialize = (message: string) => {
|
|
61
|
+
return { text: message }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const WhatsappMediaCarousel = (props: WhatsappMediaCarouselProps) => {
|
|
65
|
+
const renderBrowser = () => {
|
|
66
|
+
// Return a dummy message for browser
|
|
67
|
+
const message = `WhatsApp Media Carousel would be sent to the user.`
|
|
68
|
+
return (
|
|
69
|
+
<Message json={serialize(message)} {...props} type={INPUT.TEXT}>
|
|
70
|
+
{message}
|
|
71
|
+
</Message>
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const getCards = (cards: Card[]) => {
|
|
76
|
+
cards.forEach((card, index) => {
|
|
77
|
+
if (!card.cardIndex) {
|
|
78
|
+
card.cardIndex = index
|
|
79
|
+
}
|
|
80
|
+
card.buttons?.forEach((button, index) => {
|
|
81
|
+
if (!button.buttonIndex) {
|
|
82
|
+
button.buttonIndex = index
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
})
|
|
86
|
+
return toSnakeCaseKeys(cards)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const renderNode = () => {
|
|
90
|
+
return (
|
|
91
|
+
// @ts-ignore Property 'message' does not exist on type 'JSX.IntrinsicElements'.
|
|
92
|
+
<message
|
|
93
|
+
{...props}
|
|
94
|
+
bodyParameters={JSON.stringify(toSnakeCaseKeys(props.bodyParameters))}
|
|
95
|
+
cards={JSON.stringify(getCards(props.cards))}
|
|
96
|
+
templateName={props.templateName}
|
|
97
|
+
templateLanguage={props.templateLanguage}
|
|
98
|
+
type={INPUT.WHATSAPP_MEDIA_CAROUSEL}
|
|
99
|
+
/>
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return renderComponent({ renderBrowser, renderNode })
|
|
104
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { INPUT } from '@botonic/core'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
import { toSnakeCaseKeys } from '../util/functional'
|
|
5
|
+
import { renderComponent } from '../util/react'
|
|
6
|
+
import { Message } from './message'
|
|
7
|
+
|
|
8
|
+
type Parameters = TextParameter | CurrencyParameter | DateTimeParameter
|
|
9
|
+
|
|
10
|
+
interface TextParameter {
|
|
11
|
+
type: 'text'
|
|
12
|
+
text: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface CurrencyParameter {
|
|
16
|
+
type: 'currency'
|
|
17
|
+
currency: {
|
|
18
|
+
fallbackValue: string
|
|
19
|
+
code: string
|
|
20
|
+
amount1000: number
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface DateTimeParameter {
|
|
25
|
+
type: 'date_time'
|
|
26
|
+
dateTime: { fallbackValue: string }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface Card {
|
|
30
|
+
productRetailerId: string
|
|
31
|
+
catalogId: string
|
|
32
|
+
cardIndex?: number
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface WhatsappProductCarouselProps {
|
|
36
|
+
templateName: string
|
|
37
|
+
templateLanguage: string
|
|
38
|
+
cards: Card[]
|
|
39
|
+
bodyParameters?: Parameters[]
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const serialize = (message: string) => {
|
|
43
|
+
return { text: message }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const WhatsappProductCarousel = (
|
|
47
|
+
props: WhatsappProductCarouselProps
|
|
48
|
+
) => {
|
|
49
|
+
const renderBrowser = () => {
|
|
50
|
+
// Return a dummy message for browser
|
|
51
|
+
const message = `WhatsApp Product Carousel would be sent to the user.`
|
|
52
|
+
return (
|
|
53
|
+
<Message json={serialize(message)} {...props} type={INPUT.TEXT}>
|
|
54
|
+
{message}
|
|
55
|
+
</Message>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const getCards = (cards: Card[]) => {
|
|
60
|
+
cards.forEach((card, index) => {
|
|
61
|
+
if (!card.cardIndex) {
|
|
62
|
+
card.cardIndex = index
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
return toSnakeCaseKeys(cards)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const renderNode = () => {
|
|
69
|
+
return (
|
|
70
|
+
// @ts-ignore Property 'message' does not exist on type 'JSX.IntrinsicElements'.
|
|
71
|
+
<message
|
|
72
|
+
{...props}
|
|
73
|
+
bodyParameters={JSON.stringify(toSnakeCaseKeys(props.bodyParameters))}
|
|
74
|
+
cards={JSON.stringify(getCards(props.cards))}
|
|
75
|
+
templateName={props.templateName}
|
|
76
|
+
templateLanguage={props.templateLanguage}
|
|
77
|
+
type={INPUT.WHATSAPP_PRODUCT_CAROUSEL}
|
|
78
|
+
/>
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return renderComponent({ renderBrowser, renderNode })
|
|
83
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { INPUT } from '@botonic/core'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
import { toSnakeCaseKeys } from '../util/functional'
|
|
5
|
+
import { renderComponent } from '../util/react'
|
|
6
|
+
import { Message } from './message'
|
|
7
|
+
|
|
8
|
+
export interface ProductItem {
|
|
9
|
+
productRetailerId: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface WhatsappProductListSection {
|
|
13
|
+
title: string
|
|
14
|
+
productItems: ProductItem[]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface WhatsappProductListProps {
|
|
18
|
+
body: string
|
|
19
|
+
header: string
|
|
20
|
+
catalogId: string
|
|
21
|
+
sections: WhatsappProductListSection[]
|
|
22
|
+
footer?: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const serialize = (message: string) => {
|
|
26
|
+
return { text: message }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const WhatsappProductList = (props: WhatsappProductListProps) => {
|
|
30
|
+
const renderBrowser = () => {
|
|
31
|
+
// Return a dummy message for browser
|
|
32
|
+
const message = `WhatsApp Product List would be sent to the user.`
|
|
33
|
+
return (
|
|
34
|
+
<Message json={serialize(message)} {...props} type={INPUT.TEXT}>
|
|
35
|
+
{message}
|
|
36
|
+
</Message>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const renderNode = () => {
|
|
41
|
+
return (
|
|
42
|
+
// @ts-ignore Property 'message' does not exist on type 'JSX.IntrinsicElements'.
|
|
43
|
+
<message
|
|
44
|
+
{...props}
|
|
45
|
+
body={props.body}
|
|
46
|
+
footer={props.footer}
|
|
47
|
+
header={props.header}
|
|
48
|
+
sections={JSON.stringify(toSnakeCaseKeys(props.sections))}
|
|
49
|
+
catalogId={props.catalogId}
|
|
50
|
+
type={INPUT.WHATSAPP_PRODUCT_LIST}
|
|
51
|
+
/>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return renderComponent({ renderBrowser, renderNode })
|
|
56
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { INPUT } from '@botonic/core'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
import { renderComponent } from '../util/react'
|
|
5
|
+
import { Message } from './message'
|
|
6
|
+
|
|
7
|
+
export interface WhatsappProductProps {
|
|
8
|
+
body: string
|
|
9
|
+
catalogId: string
|
|
10
|
+
productId: string
|
|
11
|
+
footer?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const serialize = (message: string) => {
|
|
15
|
+
return { text: message }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const WhatsappProduct = (props: WhatsappProductProps) => {
|
|
19
|
+
const renderBrowser = () => {
|
|
20
|
+
// Return a dummy message for browser
|
|
21
|
+
const message = `WhatsApp Product would be sent to the user.`
|
|
22
|
+
return (
|
|
23
|
+
<Message json={serialize(message)} {...props} type={INPUT.TEXT}>
|
|
24
|
+
{message}
|
|
25
|
+
</Message>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const renderNode = () => {
|
|
30
|
+
return (
|
|
31
|
+
// @ts-ignore Property 'message' does not exist on type 'JSX.IntrinsicElements'.
|
|
32
|
+
<message
|
|
33
|
+
{...props}
|
|
34
|
+
body={props.body}
|
|
35
|
+
footer={props.footer}
|
|
36
|
+
catalogId={props.catalogId}
|
|
37
|
+
productId={props.productId}
|
|
38
|
+
type={INPUT.WHATSAPP_PRODUCT}
|
|
39
|
+
/>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return renderComponent({ renderBrowser, renderNode })
|
|
44
|
+
}
|
package/src/index-types.ts
CHANGED
|
@@ -14,14 +14,16 @@ import React from 'react'
|
|
|
14
14
|
import {
|
|
15
15
|
BlockInputOption,
|
|
16
16
|
ButtonProps,
|
|
17
|
-
CoverComponentOptions,
|
|
18
|
-
PersistentMenuTheme,
|
|
19
17
|
ReplyProps,
|
|
20
|
-
ThemeProps,
|
|
21
18
|
WebchatSettingsProps,
|
|
22
|
-
} from './components
|
|
19
|
+
} from './components'
|
|
23
20
|
import { CloseWebviewOptions } from './contexts'
|
|
24
21
|
import { UseWebchat } from './webchat/context/use-webchat'
|
|
22
|
+
import {
|
|
23
|
+
CoverComponentOptions,
|
|
24
|
+
PersistentMenuOptionsTheme,
|
|
25
|
+
ThemeProps,
|
|
26
|
+
} from './webchat/theme/types'
|
|
25
27
|
import { WebchatApp } from './webchat-app'
|
|
26
28
|
|
|
27
29
|
/**
|
|
@@ -87,7 +89,7 @@ interface AddBotResponseArgs {
|
|
|
87
89
|
|
|
88
90
|
export interface WebchatArgs {
|
|
89
91
|
theme?: ThemeProps
|
|
90
|
-
persistentMenu?:
|
|
92
|
+
persistentMenu?: PersistentMenuOptionsTheme
|
|
91
93
|
coverComponent?: CoverComponentOptions
|
|
92
94
|
blockInputs?: BlockInputOption[]
|
|
93
95
|
enableEmojiPicker?: boolean
|
|
@@ -119,7 +121,7 @@ export interface WebchatProps {
|
|
|
119
121
|
|
|
120
122
|
shadowDOM?: any
|
|
121
123
|
theme?: ThemeProps
|
|
122
|
-
persistentMenu?:
|
|
124
|
+
persistentMenu?: PersistentMenuOptionsTheme
|
|
123
125
|
coverComponent?: CoverComponentOptions
|
|
124
126
|
blockInputs?: BlockInputOption[]
|
|
125
127
|
enableEmojiPicker?: boolean
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
function camelCaseToSnake(str: string): string {
|
|
2
|
+
return str
|
|
3
|
+
.replace(/([a-z])([A-Z])/g, '$1_$2')
|
|
4
|
+
.replace(/([A-Za-z])(\d)/g, '$1_$2')
|
|
5
|
+
.replace(/(\d)([A-Za-z])/g, '$1_$2')
|
|
6
|
+
.toLowerCase()
|
|
7
|
+
}
|
|
8
|
+
type Input = Record<string, any> | Record<string, any>[] | undefined
|
|
9
|
+
|
|
10
|
+
export function toSnakeCaseKeys(input: Input): Input {
|
|
11
|
+
if (Array.isArray(input)) {
|
|
12
|
+
return input.map(item => toSnakeCaseKeys(item))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (typeof input === 'object' && input !== null) {
|
|
16
|
+
const result = Object.keys(input).reduce((acc, key) => {
|
|
17
|
+
const snakeKey = camelCaseToSnake(key)
|
|
18
|
+
const value = input[key]
|
|
19
|
+
acc[snakeKey] =
|
|
20
|
+
typeof value === 'object' && value !== null
|
|
21
|
+
? toSnakeCaseKeys(value)
|
|
22
|
+
: value
|
|
23
|
+
|
|
24
|
+
return acc
|
|
25
|
+
}, {})
|
|
26
|
+
|
|
27
|
+
return result
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return input
|
|
31
|
+
}
|
package/src/util/webchat.ts
CHANGED
|
@@ -2,8 +2,8 @@ import merge from 'lodash.merge'
|
|
|
2
2
|
import UAParser from 'ua-parser-js'
|
|
3
3
|
import { v7 as uuidv7 } from 'uuid'
|
|
4
4
|
|
|
5
|
-
import { ThemeProps } from '../components'
|
|
6
5
|
import { WEBCHAT } from '../constants'
|
|
6
|
+
import { ThemeProps } from '../webchat/theme/types'
|
|
7
7
|
import { getProperty } from './objects'
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -4,14 +4,10 @@ import {
|
|
|
4
4
|
SessionUser as CoreSessionUser,
|
|
5
5
|
} from '@botonic/core'
|
|
6
6
|
|
|
7
|
-
import { Reply } from '../../components'
|
|
8
|
-
import {
|
|
9
|
-
ThemeProps,
|
|
10
|
-
WebchatSettingsProps,
|
|
11
|
-
Webview,
|
|
12
|
-
} from '../../components/index-types'
|
|
7
|
+
import { Reply, WebchatSettingsProps, Webview } from '../../components'
|
|
13
8
|
import { TrackEventFunction, WebchatMessage } from '../../index-types'
|
|
14
9
|
import { WebchatStateTheme } from '../index-types'
|
|
10
|
+
import { ThemeProps } from '../theme/types'
|
|
15
11
|
|
|
16
12
|
export interface ErrorMessage {
|
|
17
13
|
message?: string
|
|
@@ -23,8 +19,8 @@ export interface DevSettings {
|
|
|
23
19
|
}
|
|
24
20
|
|
|
25
21
|
export interface WebchatState {
|
|
26
|
-
width: number
|
|
27
|
-
height: number
|
|
22
|
+
width: number // TODO: move this inside webchatState.theme.style
|
|
23
|
+
height: number // TODO: move this inside webchatState.theme.style
|
|
28
24
|
messagesJSON: any[]
|
|
29
25
|
messagesComponents: any[]
|
|
30
26
|
replies?: (typeof Reply)[]
|
|
@@ -35,8 +31,8 @@ export interface WebchatState {
|
|
|
35
31
|
session: Partial<CoreSession>
|
|
36
32
|
lastRoutePath?: string
|
|
37
33
|
handoff: boolean
|
|
38
|
-
theme: WebchatStateTheme
|
|
39
|
-
themeUpdates: Partial<WebchatStateTheme>
|
|
34
|
+
theme: WebchatStateTheme // TODO: type this as ThemeProps
|
|
35
|
+
themeUpdates: Partial<WebchatStateTheme> // TODO: type this as Partial<ThemeProps>
|
|
40
36
|
error: ErrorMessage
|
|
41
37
|
online: boolean
|
|
42
38
|
devSettings: DevSettings
|
|
@@ -67,7 +63,7 @@ export interface WebchatContextProps {
|
|
|
67
63
|
sendText: (text: string, payload?: string) => Promise<void>
|
|
68
64
|
setIsInputFocused: (isInputFocused: boolean) => void
|
|
69
65
|
setLastMessageVisible: (isLastMessageVisible: boolean) => void
|
|
70
|
-
theme: ThemeProps // TODO:
|
|
66
|
+
theme: ThemeProps // TODO: Remove this attribute and use allways webchatState.theme
|
|
71
67
|
toggleWebchat: (toggle: boolean) => void
|
|
72
68
|
toggleEmojiPicker: (toggle: boolean) => void
|
|
73
69
|
togglePersistentMenu: (toggle: boolean) => void
|
|
@@ -2,9 +2,10 @@ import { Session } from '@botonic/core'
|
|
|
2
2
|
import { useReducer, useRef } from 'react'
|
|
3
3
|
|
|
4
4
|
import { Reply } from '../../components'
|
|
5
|
-
import {
|
|
5
|
+
import { Webview } from '../../components/index-types'
|
|
6
6
|
import { COLORS, WEBCHAT } from '../../constants'
|
|
7
7
|
import { WebchatMessage } from '../../index-types'
|
|
8
|
+
import { ThemeProps } from '../theme/types'
|
|
8
9
|
import { WebchatAction } from './actions'
|
|
9
10
|
import { ClientInput, DevSettings, ErrorMessage, WebchatState } from './types'
|
|
10
11
|
import { webchatReducer } from './webchat-reducer'
|
|
@@ -22,6 +23,7 @@ export const webchatInitialState: WebchatState = {
|
|
|
22
23
|
session: { user: undefined },
|
|
23
24
|
lastRoutePath: undefined,
|
|
24
25
|
handoff: false,
|
|
26
|
+
// TODO: type create a defaultTheme using ThemeProps, and put this in initialState
|
|
25
27
|
theme: {
|
|
26
28
|
headerTitle: WEBCHAT.DEFAULTS.TITLE,
|
|
27
29
|
brandColor: COLORS.BOTONIC_BLUE,
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import React, { useContext } from 'react'
|
|
2
2
|
import TextareaAutosize from 'react-textarea-autosize'
|
|
3
3
|
|
|
4
|
-
import { PersistentMenuTheme } from '../../components/index-types'
|
|
5
4
|
import { WEBCHAT } from '../../constants'
|
|
6
5
|
import { Typing } from '../../index-types'
|
|
7
6
|
import { WebchatContext } from '../../webchat/context'
|
|
8
7
|
import { useDeviceAdapter } from '../hooks'
|
|
8
|
+
import { PersistentMenuOptionsTheme } from '../theme/types'
|
|
9
9
|
import { TextAreaContainer } from './styles'
|
|
10
10
|
|
|
11
11
|
interface TextareaProps {
|
|
12
12
|
host: HTMLElement
|
|
13
|
-
persistentMenu:
|
|
13
|
+
persistentMenu: PersistentMenuOptionsTheme
|
|
14
14
|
textareaRef: React.MutableRefObject<HTMLTextAreaElement | undefined>
|
|
15
15
|
sendChatEvent: (event: string) => Promise<void>
|
|
16
16
|
sendTextAreaText: () => Promise<void>
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BlockInputOption,
|
|
3
|
+
ButtonProps,
|
|
4
|
+
CustomMessageType,
|
|
5
|
+
} from '../../components/index-types'
|
|
6
|
+
|
|
7
|
+
interface ImagePreviewerProps {
|
|
8
|
+
src: string
|
|
9
|
+
isPreviewerOpened: boolean
|
|
10
|
+
closePreviewer: () => void
|
|
11
|
+
}
|
|
12
|
+
export interface CoverComponentProps {
|
|
13
|
+
closeComponent: () => void
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface CoverComponentOptions {
|
|
17
|
+
component: React.ComponentType<CoverComponentProps>
|
|
18
|
+
props?: any
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type PersistentMenuCloseOption = { closeLabel: string }
|
|
22
|
+
export type PersistentMenuOption = { label: string } & ButtonProps
|
|
23
|
+
|
|
24
|
+
export type PersistentMenuOptionsTheme = (
|
|
25
|
+
| PersistentMenuCloseOption
|
|
26
|
+
| PersistentMenuOption
|
|
27
|
+
)[]
|
|
28
|
+
|
|
29
|
+
export interface PersistentMenuOptionsProps {
|
|
30
|
+
onClick: () => void
|
|
31
|
+
options: any
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface BlobProps {
|
|
35
|
+
blobTick?: boolean
|
|
36
|
+
blobTickStyle?: any
|
|
37
|
+
blobWidth?: string
|
|
38
|
+
imageStyle?: any
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ThemeProps {
|
|
42
|
+
style?: any
|
|
43
|
+
coverComponent?: CoverComponentOptions
|
|
44
|
+
mobileBreakpoint?: number
|
|
45
|
+
mobileStyle?: any
|
|
46
|
+
webview?: { style?: any; header?: { style?: any } }
|
|
47
|
+
animations?: { enable?: boolean }
|
|
48
|
+
intro?: { style?: any; image?: string; custom?: React.ComponentType }
|
|
49
|
+
brand?: { color?: string; image?: string }
|
|
50
|
+
header?: {
|
|
51
|
+
title?: string
|
|
52
|
+
subtitle?: string
|
|
53
|
+
image?: string
|
|
54
|
+
style?: any
|
|
55
|
+
custom?: React.ComponentType
|
|
56
|
+
}
|
|
57
|
+
// TODO: Review if this is needed hear, or only in message.customTypes? use the same type in both places
|
|
58
|
+
customMessageTypes?: CustomMessageType[]
|
|
59
|
+
message?: {
|
|
60
|
+
bot?: BlobProps & { image?: string; style?: any }
|
|
61
|
+
agent?: { image?: string }
|
|
62
|
+
user?: BlobProps & { style?: any }
|
|
63
|
+
// TODO: Review type used in cutomTypes should be a component exported by default with customMessage function
|
|
64
|
+
customTypes?: CustomMessageType[]
|
|
65
|
+
style?: any
|
|
66
|
+
timestamps?: {
|
|
67
|
+
withImage?: boolean
|
|
68
|
+
format: () => string
|
|
69
|
+
style?: any
|
|
70
|
+
enable?: boolean
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
button?: {
|
|
74
|
+
autodisable?: boolean
|
|
75
|
+
disabledstyle?: any
|
|
76
|
+
hoverBackground?: string
|
|
77
|
+
hoverTextColor?: string
|
|
78
|
+
messageType?: 'text' | 'payload'
|
|
79
|
+
urlIcon?: { image?: string; enable?: boolean }
|
|
80
|
+
style?: any
|
|
81
|
+
custom?: React.ComponentType
|
|
82
|
+
}
|
|
83
|
+
replies?: {
|
|
84
|
+
align?: 'left' | 'center' | 'right'
|
|
85
|
+
wrap?: 'wrap' | 'nowrap'
|
|
86
|
+
}
|
|
87
|
+
carousel?: {
|
|
88
|
+
arrow?: {
|
|
89
|
+
left: { custom?: React.ComponentType }
|
|
90
|
+
right: { custom?: React.ComponentType }
|
|
91
|
+
}
|
|
92
|
+
enableArrows?: boolean
|
|
93
|
+
}
|
|
94
|
+
reply?: { style?: any; custom?: React.ComponentType }
|
|
95
|
+
triggerButton?: { image?: string; style?: any; custom?: React.ComponentType }
|
|
96
|
+
notifications?: {
|
|
97
|
+
enable?: boolean
|
|
98
|
+
banner?: { custom?: React.ComponentType; enable?: boolean; text?: string }
|
|
99
|
+
triggerButton?: { enable?: boolean }
|
|
100
|
+
}
|
|
101
|
+
scrollButton?: { enable?: boolean; custom?: React.ComponentType }
|
|
102
|
+
markdownStyle?: string // string template with css styles
|
|
103
|
+
userInput?: {
|
|
104
|
+
attachments?: { enable?: boolean; custom?: React.ComponentType }
|
|
105
|
+
blockInputs?: BlockInputOption[]
|
|
106
|
+
box?: { placeholder: string; style?: any }
|
|
107
|
+
emojiPicker?: { enable?: boolean; custom?: React.ComponentType }
|
|
108
|
+
menu?: {
|
|
109
|
+
darkBackground?: boolean
|
|
110
|
+
custom?: React.ComponentType<PersistentMenuOptionsProps>
|
|
111
|
+
}
|
|
112
|
+
menuButton?: { custom?: React.ComponentType }
|
|
113
|
+
persistentMenu?: PersistentMenuOptionsTheme
|
|
114
|
+
sendButton?: { enable?: boolean; custom?: React.ComponentType }
|
|
115
|
+
enable?: boolean
|
|
116
|
+
style?: any
|
|
117
|
+
}
|
|
118
|
+
imagePreviewer?: React.ComponentType<ImagePreviewerProps>
|
|
119
|
+
}
|
package/src/webchat/webchat.tsx
CHANGED
|
@@ -19,13 +19,13 @@ import { v7 as uuidv7 } from 'uuid'
|
|
|
19
19
|
import {
|
|
20
20
|
Audio,
|
|
21
21
|
Document,
|
|
22
|
+
Handoff,
|
|
22
23
|
Image,
|
|
24
|
+
normalizeWebchatSettings,
|
|
23
25
|
Text,
|
|
24
26
|
Video,
|
|
25
27
|
WebchatSettingsProps,
|
|
26
28
|
} from '../components'
|
|
27
|
-
import { Handoff } from '../components/handoff'
|
|
28
|
-
import { normalizeWebchatSettings } from '../components/webchat-settings'
|
|
29
29
|
import { COLORS, MAX_ALLOWED_SIZE_MB, ROLES, WEBCHAT } from '../constants'
|
|
30
30
|
import { CloseWebviewOptions, WebviewRequestContext } from '../contexts'
|
|
31
31
|
import { SENDERS, WebchatProps, WebchatRef } from '../index-types'
|
package/src/webchat-app.tsx
CHANGED
|
@@ -3,13 +3,7 @@ import merge from 'lodash.merge'
|
|
|
3
3
|
import React, { createRef } from 'react'
|
|
4
4
|
import { createRoot, Root } from 'react-dom/client'
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
BlockInputOption,
|
|
8
|
-
CoverComponentOptions,
|
|
9
|
-
PersistentMenuTheme,
|
|
10
|
-
ThemeProps,
|
|
11
|
-
WebchatSettingsProps,
|
|
12
|
-
} from './components/index-types'
|
|
6
|
+
import { BlockInputOption, WebchatSettingsProps } from './components'
|
|
13
7
|
import { WEBCHAT } from './constants'
|
|
14
8
|
import { CloseWebviewOptions } from './contexts'
|
|
15
9
|
import {
|
|
@@ -26,11 +20,16 @@ import {
|
|
|
26
20
|
} from './index-types'
|
|
27
21
|
import { msgToBotonic } from './msg-to-botonic'
|
|
28
22
|
import { isShadowDOMSupported, onDOMLoaded } from './util/dom'
|
|
23
|
+
import {
|
|
24
|
+
CoverComponentOptions,
|
|
25
|
+
PersistentMenuOptionsTheme,
|
|
26
|
+
ThemeProps,
|
|
27
|
+
} from './webchat/theme/types'
|
|
29
28
|
import { Webchat } from './webchat/webchat'
|
|
30
29
|
|
|
31
30
|
export class WebchatApp {
|
|
32
31
|
public theme?: ThemeProps
|
|
33
|
-
public persistentMenu?:
|
|
32
|
+
public persistentMenu?: PersistentMenuOptionsTheme
|
|
34
33
|
public coverComponent?: CoverComponentOptions
|
|
35
34
|
public blockInputs?: BlockInputOption[]
|
|
36
35
|
public enableEmojiPicker?: boolean
|