@botonic/react 0.32.0-alpha.0 → 0.33.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/lib/cjs/components/carousel.d.ts +8 -9
- package/lib/cjs/components/carousel.js +25 -21
- package/lib/cjs/components/carousel.js.map +1 -1
- package/lib/cjs/components/element.d.ts +7 -3
- package/lib/cjs/components/element.js +6 -6
- package/lib/cjs/components/element.js.map +1 -1
- package/lib/cjs/components/index-types.d.ts +3 -8
- package/lib/cjs/components/message/message-footer.js +2 -2
- package/lib/cjs/components/multichannel/index-types.d.ts +0 -4
- package/lib/cjs/components/multichannel/multichannel-carousel.d.ts +1 -1
- package/lib/cjs/components/multichannel/multichannel-carousel.js +59 -62
- package/lib/cjs/components/multichannel/multichannel-carousel.js.map +1 -1
- package/lib/cjs/components/multichannel/multichannel-context.d.ts +0 -3
- package/lib/cjs/components/multichannel/multichannel-context.js +0 -3
- package/lib/cjs/components/multichannel/multichannel-context.js.map +1 -1
- package/lib/cjs/components/pic.d.ts +8 -5
- package/lib/cjs/components/pic.js +8 -8
- package/lib/cjs/components/pic.js.map +1 -1
- package/lib/cjs/components/subtitle.d.ts +9 -5
- package/lib/cjs/components/subtitle.js +6 -7
- package/lib/cjs/components/subtitle.js.map +1 -1
- package/lib/cjs/components/title.d.ts +9 -5
- package/lib/cjs/components/title.js +6 -7
- package/lib/cjs/components/title.js.map +1 -1
- package/lib/cjs/components/whatsapp-button-list.js +5 -5
- package/lib/cjs/components/whatsapp-button-list.js.map +1 -1
- package/lib/cjs/components/whatsapp-cta-url-button.js +2 -2
- package/lib/cjs/components/whatsapp-cta-url-button.js.map +1 -1
- package/lib/cjs/index-types.d.ts +1 -1
- package/lib/cjs/msg-to-botonic.js +2 -2
- package/lib/cjs/webchat-app.js +1 -1
- package/lib/cjs/webchat-app.js.map +1 -1
- package/lib/esm/components/carousel.d.ts +8 -9
- package/lib/esm/components/carousel.js +25 -21
- package/lib/esm/components/carousel.js.map +1 -1
- package/lib/esm/components/element.d.ts +7 -3
- package/lib/esm/components/element.js +4 -4
- package/lib/esm/components/element.js.map +1 -1
- package/lib/esm/components/index-types.d.ts +3 -8
- package/lib/esm/components/message/message-footer.js +2 -2
- package/lib/esm/components/multichannel/index-types.d.ts +0 -4
- package/lib/esm/components/multichannel/multichannel-carousel.d.ts +1 -1
- package/lib/esm/components/multichannel/multichannel-carousel.js +61 -64
- package/lib/esm/components/multichannel/multichannel-carousel.js.map +1 -1
- package/lib/esm/components/multichannel/multichannel-context.d.ts +0 -3
- package/lib/esm/components/multichannel/multichannel-context.js +0 -3
- package/lib/esm/components/multichannel/multichannel-context.js.map +1 -1
- package/lib/esm/components/pic.d.ts +8 -5
- package/lib/esm/components/pic.js +6 -6
- package/lib/esm/components/pic.js.map +1 -1
- package/lib/esm/components/subtitle.d.ts +9 -5
- package/lib/esm/components/subtitle.js +4 -5
- package/lib/esm/components/subtitle.js.map +1 -1
- package/lib/esm/components/title.d.ts +9 -5
- package/lib/esm/components/title.js +4 -5
- package/lib/esm/components/title.js.map +1 -1
- package/lib/esm/components/whatsapp-button-list.js +5 -5
- package/lib/esm/components/whatsapp-button-list.js.map +1 -1
- package/lib/esm/components/whatsapp-cta-url-button.js +2 -2
- package/lib/esm/components/whatsapp-cta-url-button.js.map +1 -1
- package/lib/esm/index-types.d.ts +1 -1
- package/lib/esm/msg-to-botonic.js +2 -2
- package/lib/esm/webchat-app.js +1 -1
- package/lib/esm/webchat-app.js.map +1 -1
- package/package.json +2 -2
- package/src/components/{carousel.jsx → carousel.tsx} +58 -33
- package/src/components/{element.jsx → element.tsx} +8 -3
- package/src/components/index-types.ts +4 -11
- package/src/components/message/message-footer.tsx +2 -2
- package/src/components/multichannel/index-types.ts +0 -4
- package/src/components/multichannel/multichannel-carousel.jsx +93 -93
- package/src/components/multichannel/multichannel-context.jsx +0 -3
- package/src/components/{pic.jsx → pic.tsx} +12 -5
- package/src/components/{subtitle.jsx → subtitle.tsx} +10 -10
- package/src/components/{title.jsx → title.tsx} +8 -6
- package/src/components/whatsapp-button-list.tsx +5 -5
- package/src/components/whatsapp-cta-url-button.tsx +5 -2
- package/src/index-types.ts +2 -0
- package/src/msg-to-botonic.jsx +2 -2
- package/src/webchat-app.tsx +1 -1
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import { isWhatsapp } from '@botonic/core'
|
|
1
|
+
import { isDev, isFacebook, isWebchat, isWhatsapp } from '@botonic/core'
|
|
2
2
|
import React, { useContext } from 'react'
|
|
3
3
|
|
|
4
4
|
import { RequestContext } from '../../contexts'
|
|
5
|
+
import { Button } from '../button'
|
|
5
6
|
import { Carousel } from '../carousel'
|
|
6
|
-
import {
|
|
7
|
+
import { Image } from '../image'
|
|
8
|
+
import { Text } from '../text'
|
|
9
|
+
import { WhatsappCTAUrlButton } from '../whatsapp-cta-url-button'
|
|
7
10
|
import {
|
|
8
11
|
getFilteredElements,
|
|
9
12
|
isMultichannelButton,
|
|
@@ -11,102 +14,99 @@ import {
|
|
|
11
14
|
isNodeSubtitle,
|
|
12
15
|
isNodeTitle,
|
|
13
16
|
} from './multichannel-utils'
|
|
17
|
+
import { convertToMarkdownMeta } from './whatsapp/markdown-meta'
|
|
14
18
|
|
|
15
19
|
export const MultichannelCarousel = props => {
|
|
16
20
|
const requestContext = useContext(RequestContext)
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
[].concat(getFilteredElements(node, isMultichannelButton))
|
|
20
|
-
|
|
21
|
-
if (isWhatsapp(requestContext.session)) {
|
|
22
|
-
const elements = props.children
|
|
23
|
-
.map(e => e.props.children)
|
|
24
|
-
.map((element, i) => {
|
|
25
|
-
let imageProps = undefined
|
|
26
|
-
let title = undefined
|
|
27
|
-
let subtitle = undefined
|
|
28
|
-
const buttons = []
|
|
29
|
-
|
|
30
|
-
for (const node of element) {
|
|
31
|
-
if (isNodePic(node)) {
|
|
32
|
-
imageProps = node.props
|
|
33
|
-
}
|
|
34
|
-
if (isNodeTitle(node)) {
|
|
35
|
-
title = node.props.children
|
|
36
|
-
}
|
|
37
|
-
if (isNodeSubtitle(node)) {
|
|
38
|
-
subtitle = node.props.children
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (isMultichannelButton(node)) {
|
|
42
|
-
buttons.push(node)
|
|
43
|
-
}
|
|
44
|
-
//TODO support fragment containing an array
|
|
45
|
-
if (Array.isArray(node)) {
|
|
46
|
-
buttons.push(getButtons(node))
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
let header = ''
|
|
51
|
-
if (props.showTitle && title) {
|
|
52
|
-
header += `${title ? `**${title}**` : ''}`
|
|
53
|
-
if (title && subtitle) {
|
|
54
|
-
header += ' '
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
if (props.showSubtitle && subtitle) {
|
|
58
|
-
header += `_${subtitle}_`
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return (
|
|
62
|
-
// TODO: newkey only for 1 nested button
|
|
63
|
-
<MultichannelText
|
|
64
|
-
key={i}
|
|
65
|
-
newkey={i}
|
|
66
|
-
indexMode={props.indexMode}
|
|
67
|
-
buttonsAsText={props.buttonsAsText}
|
|
68
|
-
>
|
|
69
|
-
{header || null}
|
|
70
|
-
{buttons}
|
|
71
|
-
</MultichannelText>
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
// TODO: in the future, this would be the default mode
|
|
75
|
-
// } else {
|
|
76
|
-
// return (
|
|
77
|
-
// <React.Fragment key={i}>
|
|
78
|
-
// <Image
|
|
79
|
-
// src={imageSrc}
|
|
80
|
-
// caption={carouselToCaption(
|
|
81
|
-
// i + 1,
|
|
82
|
-
// title,
|
|
83
|
-
// subtitle,
|
|
84
|
-
// imageSrc,
|
|
85
|
-
// buttonProps
|
|
86
|
-
// )}
|
|
87
|
-
// ></Image>
|
|
88
|
-
// </React.Fragment>
|
|
89
|
-
// )
|
|
90
|
-
// }
|
|
91
|
-
})
|
|
92
|
-
return elements
|
|
93
|
-
} else {
|
|
22
|
+
if (isDev(requestContext.session) || isWebchat(requestContext.session)) {
|
|
94
23
|
return <Carousel {...props}>{props.children}</Carousel>
|
|
95
24
|
}
|
|
25
|
+
|
|
26
|
+
const messages = []
|
|
27
|
+
const childrenElements = props.children.map(e => e.props.children)
|
|
28
|
+
|
|
29
|
+
childrenElements.forEach((element, i) => {
|
|
30
|
+
const { imageProps, title, subtitle, buttons } =
|
|
31
|
+
parseCarouselElement(element)
|
|
32
|
+
|
|
33
|
+
const textMessage = getTextMessage(requestContext.session, title, subtitle)
|
|
34
|
+
|
|
35
|
+
if (imageProps?.src) {
|
|
36
|
+
const messageWithImage = <Image src={imageProps.src} />
|
|
37
|
+
messages.push(messageWithImage)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (
|
|
41
|
+
isWhatsapp(requestContext.session) &&
|
|
42
|
+
buttons.some(button => button.url)
|
|
43
|
+
) {
|
|
44
|
+
const messageWithButtonUrl = (
|
|
45
|
+
<WhatsappCTAUrlButton
|
|
46
|
+
key={`carousel-element-${i}-cta-url`}
|
|
47
|
+
body={title}
|
|
48
|
+
footer={`_${subtitle}_`}
|
|
49
|
+
displayText={buttons[0].text}
|
|
50
|
+
url={buttons[0].url}
|
|
51
|
+
/>
|
|
52
|
+
)
|
|
53
|
+
messages.push(messageWithButtonUrl)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const messageWithButtons = buttons.some(button => button.payload) ? (
|
|
57
|
+
<Text key={`carousel-element-${i}-text`}>
|
|
58
|
+
{textMessage}
|
|
59
|
+
{buttons
|
|
60
|
+
.filter(button => isWhatsapp(requestContext.session) && !button.url)
|
|
61
|
+
.map(button => (
|
|
62
|
+
<Button
|
|
63
|
+
key={`carousel-element-${i}-button`}
|
|
64
|
+
payload={button.payload}
|
|
65
|
+
url={button.url}
|
|
66
|
+
>
|
|
67
|
+
{button.text}
|
|
68
|
+
</Button>
|
|
69
|
+
))}
|
|
70
|
+
</Text>
|
|
71
|
+
) : (
|
|
72
|
+
[]
|
|
73
|
+
)
|
|
74
|
+
messages.push(messageWithButtons)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
return <>{messages}</>
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function getButtons(node) {
|
|
81
|
+
return [].concat(getFilteredElements(node, isMultichannelButton))
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function parseCarouselElement(element) {
|
|
85
|
+
let imageProps, title, subtitle
|
|
86
|
+
const buttonsChildren = []
|
|
87
|
+
|
|
88
|
+
for (const node of element) {
|
|
89
|
+
if (isNodePic(node)) imageProps = node.props
|
|
90
|
+
if (isNodeTitle(node)) title = node.props.children
|
|
91
|
+
if (isNodeSubtitle(node)) subtitle = node.props.children
|
|
92
|
+
if (isMultichannelButton(node)) buttonsChildren.push(node)
|
|
93
|
+
if (Array.isArray(node)) buttonsChildren.push(...getButtons(node))
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const buttons = buttonsChildren.map(button => {
|
|
97
|
+
return {
|
|
98
|
+
text: button.props.children,
|
|
99
|
+
payload: button.props.payload,
|
|
100
|
+
url: button.props.url,
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
return { imageProps, title, subtitle, buttons }
|
|
96
105
|
}
|
|
97
106
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
// buttons += ` - ${buttonProps.children}: ${buttonProps.url}`
|
|
105
|
-
// caption = `${header ? `${header}\n` : ''}${buttons}`
|
|
106
|
-
// }
|
|
107
|
-
// if (buttonProps.payload || buttonProps.path) {
|
|
108
|
-
// buttons += `${index}. `
|
|
109
|
-
// caption = `${buttons}${buttonProps.children}`
|
|
110
|
-
// }
|
|
111
|
-
// return caption
|
|
112
|
-
// }
|
|
107
|
+
function getTextMessage(session, title, subtitle) {
|
|
108
|
+
const formattedTextMessage = `**${title}**${subtitle ? ` _${subtitle}_` : ''}`
|
|
109
|
+
return isWhatsapp(session) || isFacebook(session)
|
|
110
|
+
? convertToMarkdownMeta(formattedTextMessage)
|
|
111
|
+
: formattedTextMessage
|
|
112
|
+
}
|
|
@@ -10,18 +10,25 @@ const PicStyled = styled.img`
|
|
|
10
10
|
border-top-right-radius: 8px;
|
|
11
11
|
width: ${WEBCHAT.DEFAULTS.ELEMENT_WIDTH}px;
|
|
12
12
|
height: 140px;
|
|
13
|
-
background: ${COLORS.SOLID_WHITE}
|
|
14
|
-
|
|
13
|
+
background: ${COLORS.SOLID_WHITE};
|
|
14
|
+
object-fit: center/cover;
|
|
15
15
|
border-bottom: 1px solid ${COLORS.SEASHELL_WHITE};
|
|
16
16
|
`
|
|
17
|
+
export interface PicProps {
|
|
18
|
+
src: string
|
|
19
|
+
}
|
|
17
20
|
|
|
18
|
-
export const Pic = props => {
|
|
21
|
+
export const Pic = (props: PicProps) => {
|
|
19
22
|
props = { ...props, src: staticAsset(props.src) }
|
|
23
|
+
|
|
20
24
|
const renderBrowser = () => <PicStyled src={props.src} />
|
|
25
|
+
|
|
26
|
+
// @ts-ignore
|
|
21
27
|
const renderNode = () => <pic>{props.src}</pic>
|
|
28
|
+
|
|
22
29
|
return renderComponent({ renderBrowser, renderNode })
|
|
23
30
|
}
|
|
24
31
|
|
|
25
|
-
Pic.serialize =
|
|
26
|
-
return { pic:
|
|
32
|
+
Pic.serialize = (props: PicProps) => {
|
|
33
|
+
return { pic: props.src }
|
|
27
34
|
}
|
|
@@ -9,21 +9,21 @@ const SubtitleContainer = styled.div`
|
|
|
9
9
|
padding: 0px 15px 10px 15px;
|
|
10
10
|
color: ${COLORS.MID_GRAY};
|
|
11
11
|
`
|
|
12
|
-
|
|
12
|
+
|
|
13
|
+
export interface SubtitleProps {
|
|
14
|
+
children: React.ReactNode
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const Subtitle = (props: SubtitleProps) => {
|
|
13
18
|
const renderBrowser = () => (
|
|
14
|
-
<SubtitleContainer
|
|
15
|
-
style={{
|
|
16
|
-
...props.style,
|
|
17
|
-
}}
|
|
18
|
-
>
|
|
19
|
-
{props.children}
|
|
20
|
-
</SubtitleContainer>
|
|
19
|
+
<SubtitleContainer>{props.children}</SubtitleContainer>
|
|
21
20
|
)
|
|
21
|
+
|
|
22
22
|
const renderNode = () => <desc>{props.children}</desc>
|
|
23
23
|
|
|
24
24
|
return renderComponent({ renderBrowser, renderNode })
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
Subtitle.serialize =
|
|
28
|
-
return { subtitle:
|
|
27
|
+
Subtitle.serialize = (props: SubtitleProps) => {
|
|
28
|
+
return { subtitle: props.children }
|
|
29
29
|
}
|
|
@@ -7,16 +7,18 @@ const TitleContainer = styled.div`
|
|
|
7
7
|
font-size: 14px;
|
|
8
8
|
padding: 10px 15px;
|
|
9
9
|
`
|
|
10
|
+
export interface TitleProps {
|
|
11
|
+
children: React.ReactNode
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const Title = (props: TitleProps) => {
|
|
15
|
+
const renderBrowser = () => <TitleContainer>{props.children}</TitleContainer>
|
|
10
16
|
|
|
11
|
-
export const Title = props => {
|
|
12
|
-
const renderBrowser = () => (
|
|
13
|
-
<TitleContainer style={{ ...props.style }}>{props.children}</TitleContainer>
|
|
14
|
-
)
|
|
15
17
|
const renderNode = () => <title>{props.children}</title>
|
|
16
18
|
|
|
17
19
|
return renderComponent({ renderBrowser, renderNode })
|
|
18
20
|
}
|
|
19
21
|
|
|
20
|
-
Title.serialize =
|
|
21
|
-
return { title:
|
|
22
|
+
Title.serialize = (props: TitleProps) => {
|
|
23
|
+
return { title: props.children }
|
|
22
24
|
}
|
|
@@ -32,15 +32,15 @@ export interface WhatsappButtonListProps {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
const serialize = _whatsappButtonListProps => {
|
|
35
|
-
// TODO: Implement to have data
|
|
35
|
+
// TODO: Implement to have data persistence in localStorage, not needed for this WhatsApp development
|
|
36
36
|
return {}
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export const WhatsappButtonList = (props: WhatsappButtonListProps) => {
|
|
40
|
-
const
|
|
40
|
+
const truncateSectionsContents = (
|
|
41
41
|
sections: WhatsappButtonListSectionProps[]
|
|
42
42
|
): WhatsappButtonListSectionProps[] => {
|
|
43
|
-
const
|
|
43
|
+
const truncateRowContents = (
|
|
44
44
|
row: WhatsappButtonListRowProps
|
|
45
45
|
): WhatsappButtonListRowProps => {
|
|
46
46
|
const title = truncateText(row.title, WHATSAPP_MAX_BUTTON_LIST_CHARS)
|
|
@@ -62,7 +62,7 @@ export const WhatsappButtonList = (props: WhatsappButtonListProps) => {
|
|
|
62
62
|
title: section.title
|
|
63
63
|
? truncateText(section.title, WHATSAPP_MAX_BUTTON_LIST_CHARS)
|
|
64
64
|
: undefined,
|
|
65
|
-
rows: section.rows.map(
|
|
65
|
+
rows: section.rows.map(truncateRowContents),
|
|
66
66
|
}))
|
|
67
67
|
}
|
|
68
68
|
|
|
@@ -87,7 +87,7 @@ export const WhatsappButtonList = (props: WhatsappButtonListProps) => {
|
|
|
87
87
|
{...props}
|
|
88
88
|
body={convertToMarkdownMeta(props.body)}
|
|
89
89
|
button={truncateText(props.button, WHATSAPP_MAX_BUTTON_CHARS)}
|
|
90
|
-
sections={JSON.stringify(
|
|
90
|
+
sections={JSON.stringify(truncateSectionsContents(props.sections))}
|
|
91
91
|
type={INPUT.WHATSAPP_BUTTON_LIST}
|
|
92
92
|
/>
|
|
93
93
|
)
|
|
@@ -36,7 +36,7 @@ export type WhatsappCTAUrlButtonProps =
|
|
|
36
36
|
| WhatsappCTAUrlButtonWebviewProps
|
|
37
37
|
|
|
38
38
|
const serialize = _whatsappCTAUrlButtonProps => {
|
|
39
|
-
// TODO: Implement to have data
|
|
39
|
+
// TODO: Implement to have data persistence in localStorage, not needed for this WhatsApp development
|
|
40
40
|
return {}
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -66,7 +66,10 @@ export const WhatsappCTAUrlButton = (props: WhatsappCTAUrlButtonProps) => {
|
|
|
66
66
|
WHATSAPP_MAX_BODY_CHARS
|
|
67
67
|
),
|
|
68
68
|
footer: props.footer
|
|
69
|
-
? truncateText(
|
|
69
|
+
? truncateText(
|
|
70
|
+
convertToMarkdownMeta(props.footer),
|
|
71
|
+
WHATSAPP_MAX_FOOTER_CHARS
|
|
72
|
+
)
|
|
70
73
|
: undefined,
|
|
71
74
|
displayText: truncateText(props.displayText, WHATSAPP_MAX_BUTTON_CHARS),
|
|
72
75
|
url:
|
package/src/index-types.ts
CHANGED
package/src/msg-to-botonic.jsx
CHANGED
|
@@ -129,7 +129,7 @@ function textToBotonic(msg) {
|
|
|
129
129
|
return (
|
|
130
130
|
<Text {...msg} key={msg.key}>
|
|
131
131
|
{txt}
|
|
132
|
-
{
|
|
132
|
+
{parseQuickReplies(msg)}
|
|
133
133
|
</Text>
|
|
134
134
|
)
|
|
135
135
|
if (msg.buttons && msg.buttons.length)
|
|
@@ -182,7 +182,7 @@ function buttonsParse(buttons) {
|
|
|
182
182
|
})
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
function
|
|
185
|
+
function parseQuickReplies(msg) {
|
|
186
186
|
let replies = null
|
|
187
187
|
if (msg.replies) {
|
|
188
188
|
replies = msg.replies.map((el, i) => {
|
package/src/webchat-app.tsx
CHANGED
|
@@ -279,7 +279,7 @@ export class WebchatApp {
|
|
|
279
279
|
delete message.sent_by
|
|
280
280
|
const response = msgToBotonic(
|
|
281
281
|
message,
|
|
282
|
-
// TODO: Review if is
|
|
282
|
+
// TODO: Review if is needed allow declar customTypes inside and outside theme
|
|
283
283
|
this.theme?.message?.customTypes || this.theme?.customMessageTypes
|
|
284
284
|
)
|
|
285
285
|
|