diff --git a/apps/builder/playwright/fixtures/typebots/inputs/variableButton.json b/apps/builder/playwright/fixtures/typebots/inputs/variableButton.json
new file mode 100644
index 000000000..aebb8dcd2
--- /dev/null
+++ b/apps/builder/playwright/fixtures/typebots/inputs/variableButton.json
@@ -0,0 +1,132 @@
+{
+ "id": "cl4fr6kca0000p11abjka8lvd",
+ "createdAt": "2022-06-15T15:33:43.930Z",
+ "updatedAt": "2022-06-15T15:36:44.821Z",
+ "icon": null,
+ "name": "My typebot",
+ "publishedTypebotId": null,
+ "folderId": null,
+ "groups": [
+ {
+ "id": "block0",
+ "title": "Group #0",
+ "blocks": [
+ {
+ "id": "block0",
+ "type": "start",
+ "label": "Start",
+ "groupId": "block0",
+ "outgoingEdgeId": "edge1"
+ }
+ ],
+ "graphCoordinates": { "x": 0, "y": 0 }
+ },
+ {
+ "id": "block1",
+ "title": "Group #1",
+ "blocks": [
+ {
+ "id": "cl4fr6rgf0000396ml1ai0t8v",
+ "type": "Set variable",
+ "groupId": "block1",
+ "options": {
+ "variableId": "vcl4fr8f8l000b396m6gsbnrmd",
+ "expressionToEvaluate": "Variable item"
+ }
+ },
+ {
+ "id": "block1",
+ "type": "choice input",
+ "items": [
+ {
+ "id": "choice1",
+ "type": 0,
+ "blockId": "block1",
+ "content": "Item 1"
+ },
+ {
+ "id": "cl4fr7e6i0003396mkh7mol65",
+ "type": 0,
+ "blockId": "block1",
+ "content": "{{Item 2}}",
+ "outgoingEdgeId": "cl4fr80900009396my6euvunj"
+ },
+ {
+ "id": "cl4fr7lr90004396mh9vw8wnq",
+ "type": 0,
+ "blockId": "block1",
+ "content": "Item 3"
+ }
+ ],
+ "groupId": "block1",
+ "options": { "buttonLabel": "Send", "isMultipleChoice": false }
+ }
+ ],
+ "graphCoordinates": { "x": 199, "y": 210 }
+ },
+ {
+ "id": "cl4fr7wsv0007396m7xgbeymx",
+ "title": "Group #2",
+ "blocks": [
+ {
+ "id": "cl4fr7wsv0008396mf9oi9lvi",
+ "type": "text",
+ "content": {
+ "html": "
Ok great!
",
+ "richText": [
+ { "type": "p", "children": [{ "text": "Ok great!" }] }
+ ],
+ "plainText": "Ok great!"
+ },
+ "groupId": "cl4fr7wsv0007396m7xgbeymx"
+ }
+ ],
+ "graphCoordinates": { "x": 603, "y": 195 }
+ }
+ ],
+ "variables": [{ "id": "vcl4fr8f8l000b396m6gsbnrmd", "name": "Item 2" }],
+ "edges": [
+ {
+ "id": "edge1",
+ "to": { "groupId": "block1" },
+ "from": { "blockId": "block0", "groupId": "block0" }
+ },
+ {
+ "id": "cl4fr80900009396my6euvunj",
+ "to": { "groupId": "cl4fr7wsv0007396m7xgbeymx" },
+ "from": {
+ "itemId": "cl4fr7e6i0003396mkh7mol65",
+ "blockId": "block1",
+ "groupId": "block1"
+ }
+ }
+ ],
+ "theme": {
+ "chat": {
+ "inputs": {
+ "color": "#303235",
+ "backgroundColor": "#FFFFFF",
+ "placeholderColor": "#9095A0"
+ },
+ "buttons": { "color": "#FFFFFF", "backgroundColor": "#0042DA" },
+ "hostBubbles": { "color": "#303235", "backgroundColor": "#F7F8FF" },
+ "guestBubbles": { "color": "#FFFFFF", "backgroundColor": "#FF8E21" }
+ },
+ "general": { "font": "Open Sans", "background": { "type": "None" } }
+ },
+ "settings": {
+ "general": {
+ "isBrandingEnabled": true,
+ "isInputPrefillEnabled": true,
+ "isHideQueryParamsEnabled": true,
+ "isNewResultOnRefreshEnabled": false
+ },
+ "metadata": {
+ "description": "Build beautiful conversational forms and embed them directly in your applications without a line of code. Triple your response rate and collect answers that has more value compared to a traditional form."
+ },
+ "typingEmulation": { "speed": 300, "enabled": true, "maxDelay": 1.5 }
+ },
+ "publicId": null,
+ "customDomain": null,
+ "workspaceId": "proWorkspace"
+}
diff --git a/apps/builder/playwright/tests/inputs/buttons.spec.ts b/apps/builder/playwright/tests/inputs/buttons.spec.ts
index 7cf252cae..94e287740 100644
--- a/apps/builder/playwright/tests/inputs/buttons.spec.ts
+++ b/apps/builder/playwright/tests/inputs/buttons.spec.ts
@@ -1,11 +1,13 @@
import test, { expect } from '@playwright/test'
import {
createTypebots,
+ importTypebotInDatabase,
parseDefaultGroupWithBlock,
} from '../../services/database'
import { defaultChoiceInputOptions, InputBlockType, ItemType } from 'models'
import { typebotViewer } from '../../services/selectorUtils'
import cuid from 'cuid'
+import path from 'path'
test.describe.parallel('Buttons input block', () => {
test('can edit button items', async ({ page }) => {
@@ -67,3 +69,30 @@ test.describe.parallel('Buttons input block', () => {
).toBeVisible()
})
})
+
+test('Variable buttons should work', async ({ page }) => {
+ const typebotId = cuid()
+ await importTypebotInDatabase(
+ path.join(__dirname, '../../fixtures/typebots/inputs/variableButton.json'),
+ {
+ id: typebotId,
+ }
+ )
+
+ await page.goto(`/typebots/${typebotId}/edit`)
+ await page.click('text=Preview')
+ await typebotViewer(page).locator('text=Variable item').click()
+ await expect(typebotViewer(page).locator('text=Variable item')).toBeVisible()
+ await expect(typebotViewer(page).locator('text=Ok great!')).toBeVisible()
+ await page.click('text="Item 1"')
+ await page.fill('input[value="Item 1"]', '{{Item 2}}')
+ await page.click('[data-testid="block1-icon"]')
+ await page.click('text=Multiple choice?')
+ await page.click('text="Restart"')
+ await typebotViewer(page).locator('text="Variable item" >> nth=0').click()
+ await typebotViewer(page).locator('text="Variable item" >> nth=1').click()
+ await typebotViewer(page).locator('text="Send"').click()
+ await expect(
+ typebotViewer(page).locator('text="Variable item, Variable item"')
+ ).toBeVisible()
+})
diff --git a/packages/bot-engine/src/components/ChatGroup/ChatBlock/InputChatBlock.tsx b/packages/bot-engine/src/components/ChatGroup/ChatBlock/InputChatBlock.tsx
index 450035504..8f0835092 100644
--- a/packages/bot-engine/src/components/ChatGroup/ChatBlock/InputChatBlock.tsx
+++ b/packages/bot-engine/src/components/ChatGroup/ChatBlock/InputChatBlock.tsx
@@ -13,7 +13,11 @@ import { PaymentForm } from './inputs/PaymentForm'
import { RatingForm } from './inputs/RatingForm'
import { FileUploadForm } from './inputs/FileUploadForm'
-export type InputSubmitContent = { label?: string; value: string }
+export type InputSubmitContent = {
+ label?: string
+ value: string
+ itemId?: string
+}
export const InputChatBlock = ({
block,
@@ -40,7 +44,7 @@ export const InputChatBlock = ({
? variableId && typebot.variables.find(byId(variableId))?.value
: undefined
- const handleSubmit = async ({ label, value }: InputSubmitContent) => {
+ const handleSubmit = async ({ label, value, itemId }: InputSubmitContent) => {
setAnswer(label ?? value)
const isRetry = !isInputValid(value, block.type)
if (!isRetry && addAnswer)
@@ -50,7 +54,7 @@ export const InputChatBlock = ({
content: value,
variableId: variableId ?? null,
})
- if (!isEditting) onTransitionEnd({ label, value }, isRetry)
+ if (!isEditting) onTransitionEnd({ label, value, itemId }, isRetry)
setIsEditting(false)
}
diff --git a/packages/bot-engine/src/components/ChatGroup/ChatBlock/inputs/ChoiceForm.tsx b/packages/bot-engine/src/components/ChatGroup/ChatBlock/inputs/ChoiceForm.tsx
index 13722cb62..1ca5475e1 100644
--- a/packages/bot-engine/src/components/ChatGroup/ChatBlock/inputs/ChoiceForm.tsx
+++ b/packages/bot-engine/src/components/ChatGroup/ChatBlock/inputs/ChoiceForm.tsx
@@ -1,6 +1,8 @@
import { useAnswers } from 'contexts/AnswersContext'
+import { useTypebot } from 'contexts/TypebotContext'
import { ChoiceInputBlock } from 'models'
import React, { useState } from 'react'
+import { parseVariables } from 'services/variable'
import { InputSubmitContent } from '../InputChatBlock'
import { SendButton } from './SendButton'
@@ -10,13 +12,20 @@ type ChoiceFormProps = {
}
export const ChoiceForm = ({ block, onSubmit }: ChoiceFormProps) => {
+ const {
+ typebot: { variables },
+ } = useTypebot()
const { resultValues } = useAnswers()
const [selectedIndices, setSelectedIndices] = useState([])
const handleClick = (itemIndex: number) => (e: React.MouseEvent) => {
e.preventDefault()
if (block.options?.isMultipleChoice) toggleSelectedItemIndex(itemIndex)
- else onSubmit({ value: block.items[itemIndex].content ?? '' })
+ else
+ onSubmit({
+ value: parseVariables(variables)(block.items[itemIndex].content),
+ itemId: block.items[itemIndex].id,
+ })
}
const toggleSelectedItemIndex = (itemIndex: number) => {
@@ -32,7 +41,9 @@ export const ChoiceForm = ({ block, onSubmit }: ChoiceFormProps) => {
const handleSubmit = () =>
onSubmit({
value: selectedIndices
- .map((itemIndex) => block.items[itemIndex].content)
+ .map((itemIndex) =>
+ parseVariables(variables)(block.items[itemIndex].content)
+ )
.join(', '),
})
@@ -59,7 +70,7 @@ export const ChoiceForm = ({ block, onSubmit }: ChoiceFormProps) => {
data-testid="button"
data-itemid={item.id}
>
- {item.content}
+ {parseVariables(variables)(item.content)}
{isUniqueFirstButton && (
diff --git a/packages/bot-engine/src/components/ChatGroup/ChatGroup.tsx b/packages/bot-engine/src/components/ChatGroup/ChatGroup.tsx
index 9fad6a9f7..61be91f9b 100644
--- a/packages/bot-engine/src/components/ChatGroup/ChatGroup.tsx
+++ b/packages/bot-engine/src/components/ChatGroup/ChatGroup.tsx
@@ -10,6 +10,7 @@ import {
isInputBlock,
isIntegrationBlock,
isLogicBlock,
+ byId,
} from 'utils'
import { executeLogic } from 'services/logic'
import { executeIntegration } from 'services/integration'
@@ -187,7 +188,7 @@ export const ChatGroup = ({
isChoiceInput(currentBlock) && !currentBlock.options.isMultipleChoice
if (isSingleChoiceBlock) {
const nextEdgeId = currentBlock.items.find(
- (i) => i.content === answerContent?.value
+ byId(answerContent?.itemId)
)?.outgoingEdgeId
if (nextEdgeId) return onGroupEnd({ edgeId: nextEdgeId })
}