Skip to content

Commit 3afcf5e

Browse files
authored
Whatsapp markdown #SER-2297 (#2516)
<!-- _Set as [Draft PR](https://github.blog/2019-02-14-introducing-draft-pull-requests/) if it's not ready to be merged_. [PR best practices Reference](https://blog.codeminer42.com/on-writing-a-great-pull-request-37c60ce6f31d/) --> ## Description - add a function to apply whatsapp markdown - use this function within the multichannel to apply the default markdown in case the provider is WhatsApp <!-- - Must be clear and concise (2-3 lines). - Don't make reviewers think. The description should explain what has been implemented or what it's used for. If a pull request is not descriptive, people will be lazy or not willing to spend much time on it. - Be explicit with the names (don't abbreviate and don't use acronyms that can lead to misleading understanding). - If you consider it appropriate, include the steps to try the new features. --> ## Context <!-- - What problem is trying to solve this pull request? - What are the reasons or business goals of this implementation? - Can I provide visual resources or links to understand better the situation? --> ## Approach taken / Explain the design This function will apply bold when text is placed between `**text**` or `__text__` This function will apply italics when text is enclosed in `*text*` or `_text_` This function will apply bold and italics when text is placed between `**_text_**` For the option `__*text*__` I first normalise to `**_text_**` <!-- - Explain what the code does. - If it's a complex solution, try to provide a sketch. --> ## To document / Usage example <!-- - How this is used? - If possible, provide a snippet of code with a usage example. --> ## Testing The pull request... - has unit tests - has integration tests - doesn't need tests because... **[provide a description]**
1 parent d431d52 commit 3afcf5e

File tree

7 files changed

+946
-623
lines changed

7 files changed

+946
-623
lines changed

packages/botonic-react/package-lock.json

Lines changed: 851 additions & 618 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/botonic-react/src/components/multichannel/multichannel-carousel.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export const MultichannelCarousel = props => {
4747

4848
let header = ''
4949
if (props.showTitle && title) {
50-
header += `${title ? `*${title}*` : ''}`
50+
header += `${title ? `**${title}**` : ''}`
5151
if (title && subtitle) {
5252
header += ' '
5353
}

packages/botonic-react/src/components/multichannel/multichannel-text.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
MULTICHANNEL_WHATSAPP_PROPS,
2020
WHATSAPP_MAX_BUTTONS,
2121
} from './multichannel-utils'
22+
import { whatsappMarkdown } from './whatsapp/markdown'
2223

2324
export const MultichannelText = props => {
2425
const requestContext = useContext(RequestContext)
@@ -108,7 +109,8 @@ export const MultichannelText = props => {
108109
const { postbackButtons, urlButtons, webviewButtons } = getWhatsappButtons()
109110

110111
const textElements = texts.map(text => {
111-
return (props.newline || '') + text
112+
const textWithMarkdown = whatsappMarkdown(text)
113+
return (props.newline || '') + textWithMarkdown
112114
})
113115

114116
const webviewButtonElements = webviewButtons.map(

packages/botonic-react/src/components/multichannel/multichannel.jsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import {
1717

1818
export const Multichannel = props => {
1919
const requestContext = useContext(RequestContext)
20-
2120
if (!isWhatsapp(requestContext) && !isFacebook(requestContext)) {
2221
return props.children
2322
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
const MARKDOWN_BOLD_OPTION_1 = '**'
2+
const MARKDOWN_BOLD_OPTION_2 = '__'
3+
const MARKDOWN_WHATSAPP_BOLD = '*'
4+
5+
const MARKDOWN_ITALIC_OPTION_1 = '*'
6+
const MARKDOWN_WHATSAPP_ITALIC = '_'
7+
8+
const MARKDOWN_BOLD_OR_ITALIC_REGEX = /(\*\*|__)(.*?)\1|(\*|_)(.*?)\3/g
9+
10+
const MARKDOWN_NORMALIZED_BOLD_ITALIC_OPEN = '**_'
11+
const MARKDOWN_NORMALIZED_BOLD_ITALIC_CLOSE = '_**'
12+
13+
const MARKDOWN_BOLD_AND_ITALIC_OPTION1 = /(_\*\*)(.*?)(\*\*_)/g
14+
const MARKDOWN_BOLD_AND_ITALIC_OPTION2 = /(\*__)(.*?)(__\*)/g
15+
const MARKDOWN_BOLD_AND_ITALIC_OPTION3 = /(__\*)(.*?)(\*__)/g
16+
17+
export function whatsappMarkdown(text: string) {
18+
const textNormalized = normalizeMarkdown(text)
19+
const matches = textNormalized.match(MARKDOWN_BOLD_OR_ITALIC_REGEX)
20+
if (matches) {
21+
const matchesResult = matches.map(match => {
22+
if (match.startsWith(MARKDOWN_BOLD_OPTION_1)) {
23+
return replaceAllOccurrences(
24+
match,
25+
MARKDOWN_BOLD_OPTION_1,
26+
MARKDOWN_WHATSAPP_BOLD
27+
)
28+
}
29+
if (match.startsWith(MARKDOWN_BOLD_OPTION_2)) {
30+
return replaceAllOccurrences(
31+
match,
32+
MARKDOWN_BOLD_OPTION_2,
33+
MARKDOWN_WHATSAPP_BOLD
34+
)
35+
}
36+
if (match.startsWith(MARKDOWN_ITALIC_OPTION_1)) {
37+
return replaceAllOccurrences(
38+
match,
39+
MARKDOWN_ITALIC_OPTION_1,
40+
MARKDOWN_WHATSAPP_ITALIC
41+
)
42+
}
43+
return match
44+
})
45+
let textWhatsapp = textNormalized
46+
for (let i = 0; i < matches.length; i++) {
47+
textWhatsapp = replaceAllOccurrences(
48+
textWhatsapp,
49+
matches[i],
50+
matchesResult[i]
51+
)
52+
}
53+
return textWhatsapp
54+
}
55+
return text
56+
}
57+
58+
function normalizeMarkdown(text: string) {
59+
text = replaceBoldItalic(text, MARKDOWN_BOLD_AND_ITALIC_OPTION1)
60+
text = replaceBoldItalic(text, MARKDOWN_BOLD_AND_ITALIC_OPTION2)
61+
text = replaceBoldItalic(text, MARKDOWN_BOLD_AND_ITALIC_OPTION3)
62+
return text
63+
}
64+
65+
function replaceBoldItalic(text: string, regex: RegExp) {
66+
return text.replace(
67+
regex,
68+
(
69+
match: string,
70+
markdownOpen: string,
71+
textInsideMarkdown: string,
72+
markdownClose: string
73+
) => {
74+
if (match.startsWith(markdownOpen) && match.endsWith(markdownClose)) {
75+
return `${MARKDOWN_NORMALIZED_BOLD_ITALIC_OPEN}${textInsideMarkdown}${MARKDOWN_NORMALIZED_BOLD_ITALIC_CLOSE}`
76+
}
77+
return match
78+
}
79+
)
80+
}
81+
82+
function replaceAllOccurrences(
83+
text: string,
84+
searchValue: string,
85+
replaceValue: string
86+
) {
87+
return text.split(searchValue).join(replaceValue)
88+
}

packages/botonic-react/tsconfig.esm.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"baseUrl": ".",
66
"outDir": "./lib/esm",
77
"target": "ES2017",
8-
"module": "ES2020",
8+
"module": "ES2022",
99
"skipLibCheck": true
1010
}
1111
}

packages/botonic-react/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"esModuleInterop": true,
1010
"skipLibCheck": true,
1111
"moduleResolution": "nodenext",
12-
"jsx": "react-jsx"
12+
"jsx": "react-jsx",
13+
"lib": ["ES2021.String"]
1314
}
1415
}

0 commit comments

Comments
 (0)