♻️ Introduce typebot v6 with events (#1013)

Closes #885
This commit is contained in:
Baptiste Arnaud
2023-11-08 15:34:16 +01:00
committed by GitHub
parent 68e4fc71fb
commit 35300eaf34
634 changed files with 58971 additions and 31449 deletions

View File

@@ -4,13 +4,9 @@ import {
importTypebotInDatabase,
} from '@typebot.io/lib/playwright/databaseActions'
import { parseDefaultGroupWithBlock } from '@typebot.io/lib/playwright/databaseHelpers'
import {
defaultChoiceInputOptions,
InputBlockType,
ItemType,
} from '@typebot.io/schemas'
import { createId } from '@paralleldrive/cuid2'
import { getTestAsset } from '@/test/utils/playwright'
import { InputBlockType } from '@typebot.io/schemas/features/blocks/inputs/constants'
test.describe.parallel('Buttons input block', () => {
test('can edit button items', async ({ page }) => {
@@ -23,11 +19,8 @@ test.describe.parallel('Buttons input block', () => {
items: [
{
id: 'choice1',
blockId: 'block1',
type: ItemType.BUTTON,
},
],
options: { ...defaultChoiceInputOptions },
}),
},
])

View File

@@ -13,12 +13,12 @@ type Props = {
export const ButtonsBlockNode = ({ block, indices }: Props) => {
const { typebot } = useTypebot()
const dynamicVariableName = typebot?.variables.find(
(variable) => variable.id === block.options.dynamicVariableId
(variable) => variable.id === block.options?.dynamicVariableId
)?.name
return (
<Stack w="full">
{block.options.dynamicVariableId ? (
{block.options?.dynamicVariableId ? (
<Wrap spacing={1}>
<Text>Display</Text>
<Tag bg="orange.400" color="white">
@@ -29,7 +29,7 @@ export const ButtonsBlockNode = ({ block, indices }: Props) => {
) : (
<ItemNodesList block={block} indices={indices} />
)}
{block.options.variableId ? (
{block.options?.variableId ? (
<SetVariableLabel
variableId={block.options.variableId}
variables={typebot?.variables}

View File

@@ -2,49 +2,53 @@ import { TextInput } from '@/components/inputs'
import { MoreInfoTooltip } from '@/components/MoreInfoTooltip'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { FormControl, FormLabel, Stack } from '@chakra-ui/react'
import {
ChoiceInputOptions,
Variable,
defaultChoiceInputOptions,
} from '@typebot.io/schemas'
import { ChoiceInputBlock, Variable } from '@typebot.io/schemas'
import React from 'react'
import { SwitchWithRelatedSettings } from '@/components/SwitchWithRelatedSettings'
import { defaultChoiceInputOptions } from '@typebot.io/schemas/features/blocks/inputs/choice/constants'
type Props = {
options?: ChoiceInputOptions
onOptionsChange: (options: ChoiceInputOptions) => void
options?: ChoiceInputBlock['options']
onOptionsChange: (options: ChoiceInputBlock['options']) => void
}
export const ButtonsBlockSettings = ({ options, onOptionsChange }: Props) => {
const updateIsMultiple = (isMultipleChoice: boolean) =>
options && onOptionsChange({ ...options, isMultipleChoice })
onOptionsChange({ ...options, isMultipleChoice })
const updateIsSearchable = (isSearchable: boolean) =>
options && onOptionsChange({ ...options, isSearchable })
onOptionsChange({ ...options, isSearchable })
const updateButtonLabel = (buttonLabel: string) =>
options && onOptionsChange({ ...options, buttonLabel })
onOptionsChange({ ...options, buttonLabel })
const updateSearchInputPlaceholder = (searchInputPlaceholder: string) =>
options && onOptionsChange({ ...options, searchInputPlaceholder })
onOptionsChange({ ...options, searchInputPlaceholder })
const updateSaveVariable = (variable?: Variable) =>
options && onOptionsChange({ ...options, variableId: variable?.id })
onOptionsChange({ ...options, variableId: variable?.id })
const updateDynamicDataVariable = (variable?: Variable) =>
options && onOptionsChange({ ...options, dynamicVariableId: variable?.id })
onOptionsChange({ ...options, dynamicVariableId: variable?.id })
return (
<Stack spacing={4}>
<SwitchWithRelatedSettings
label="Multiple choice?"
initialValue={options?.isMultipleChoice ?? false}
initialValue={
options?.isMultipleChoice ??
defaultChoiceInputOptions.isMultipleChoice
}
onCheckChange={updateIsMultiple}
>
<TextInput
label="Submit button label:"
defaultValue={options?.buttonLabel ?? 'Send'}
defaultValue={
options?.buttonLabel ?? defaultChoiceInputOptions.buttonLabel
}
onChange={updateButtonLabel}
/>
</SwitchWithRelatedSettings>
<SwitchWithRelatedSettings
label="Is searchable?"
initialValue={options?.isSearchable ?? false}
initialValue={
options?.isSearchable ?? defaultChoiceInputOptions.isSearchable
}
onCheckChange={updateIsSearchable}
>
<TextInput

View File

@@ -16,7 +16,7 @@ import {
} from '@chakra-ui/react'
import { PlusIcon, SettingsIcon } from '@/components/icons'
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
import { ButtonItem, Item, ItemIndices, ItemType } from '@typebot.io/schemas'
import { ButtonItem, Item, ItemIndices } from '@typebot.io/schemas'
import React, { useRef, useState } from 'react'
import { isNotDefined } from '@typebot.io/lib'
import { useGraph } from '@/features/graph/providers/GraphProvider'
@@ -54,7 +54,7 @@ export const ButtonsItemNode = ({ item, indices, isMouseOver }: Props) => {
const handlePlusClick = () => {
const itemIndex = indices.itemIndex + 1
createItem({ type: ItemType.BUTTON }, { ...indices, itemIndex })
createItem({}, { ...indices, itemIndex })
}
const updateItemSettings = (settings: Omit<ButtonItem, 'content'>) => {

View File

@@ -2,7 +2,8 @@ import React from 'react'
import { Stack } from '@chakra-ui/react'
import { SwitchWithRelatedSettings } from '@/components/SwitchWithRelatedSettings'
import { ConditionForm } from '@/features/blocks/logic/condition/components/ConditionForm'
import { ButtonItem, Condition, LogicalOperator } from '@typebot.io/schemas'
import { ButtonItem, Condition } from '@typebot.io/schemas'
import { LogicalOperator } from '@typebot.io/schemas/features/blocks/logic/condition/constants'
type Props = {
item: ButtonItem

View File

@@ -3,12 +3,13 @@ import { TextInput } from '@/components/inputs'
import { SwitchWithLabel } from '@/components/inputs/SwitchWithLabel'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { FormLabel, Stack } from '@chakra-ui/react'
import { DateInputOptions, Variable } from '@typebot.io/schemas'
import { DateInputBlock, Variable } from '@typebot.io/schemas'
import React from 'react'
import { defaultDateInputOptions } from '@typebot.io/schemas/features/blocks/inputs/date/constants'
type Props = {
options: DateInputOptions
onOptionsChange: (options: DateInputOptions) => void
options: DateInputBlock['options']
onOptionsChange: (options: DateInputBlock['options']) => void
}
export const DateInputSettings = ({ options, onOptionsChange }: Props) => {
@@ -41,47 +42,56 @@ export const DateInputSettings = ({ options, onOptionsChange }: Props) => {
<Stack spacing={4}>
<SwitchWithRelatedSettings
label="Is range?"
initialValue={options.isRange}
initialValue={options?.isRange ?? defaultDateInputOptions.isRange}
onCheckChange={updateIsRange}
>
<TextInput
label="From label:"
defaultValue={options.labels.from}
defaultValue={options?.labels?.from}
onChange={updateFromLabel}
/>
<TextInput
label="To label:"
defaultValue={options.labels.to}
defaultValue={
options?.labels?.to ?? defaultDateInputOptions.labels.to
}
onChange={updateToLabel}
/>
</SwitchWithRelatedSettings>
<SwitchWithLabel
label="With time?"
initialValue={options.hasTime}
initialValue={options?.hasTime ?? defaultDateInputOptions.hasTime}
onCheckChange={updateHasTime}
/>
<TextInput
label="Button label:"
defaultValue={options.labels.button}
defaultValue={
options?.labels?.button ?? defaultDateInputOptions.labels.button
}
onChange={updateButtonLabel}
/>
<TextInput
label="Min:"
defaultValue={options.min}
placeholder={options.hasTime ? 'YYYY-MM-DDTHH:mm' : 'YYYY-MM-DD'}
defaultValue={options?.min}
placeholder={options?.hasTime ? 'YYYY-MM-DDTHH:mm' : 'YYYY-MM-DD'}
onChange={updateMin}
/>
<TextInput
label="Max:"
defaultValue={options.max}
placeholder={options.hasTime ? 'YYYY-MM-DDTHH:mm' : 'YYYY-MM-DD'}
defaultValue={options?.max}
placeholder={options?.hasTime ? 'YYYY-MM-DDTHH:mm' : 'YYYY-MM-DD'}
onChange={updateMax}
/>
<TextInput
label="Format:"
defaultValue={options.format}
moreInfoTooltip="Popular formats: dd/MM/yyyy, MM/dd/yy, yyyy-MM-dd"
placeholder={options.hasTime ? 'dd/MM/yyyy HH:mm' : 'dd/MM/yyyy'}
defaultValue={
options?.format ??
(options?.hasTime
? defaultDateInputOptions.formatWithTime
: defaultDateInputOptions.format)
}
moreInfoTooltip="i.e dd/MM/yyyy, MM/dd/yy, yyyy-MM-dd"
placeholder={options?.hasTime ? 'dd/MM/yyyy HH:mm' : 'dd/MM/yyyy'}
onChange={updateFormat}
/>
<Stack>
@@ -89,7 +99,7 @@ export const DateInputSettings = ({ options, onOptionsChange }: Props) => {
Save answer in a variable:
</FormLabel>
<VariableSearchInput
initialVariableId={options.variableId}
initialVariableId={options?.variableId}
onSelectVariable={updateVariable}
/>
</Stack>

View File

@@ -1,8 +1,8 @@
import test, { expect } from '@playwright/test'
import { createTypebots } from '@typebot.io/lib/playwright/databaseActions'
import { parseDefaultGroupWithBlock } from '@typebot.io/lib/playwright/databaseHelpers'
import { defaultDateInputOptions, InputBlockType } from '@typebot.io/schemas'
import { createId } from '@paralleldrive/cuid2'
import { InputBlockType } from '@typebot.io/schemas/features/blocks/inputs/constants'
test.describe('Date input block', () => {
test('options should work', async ({ page }) => {
@@ -12,7 +12,6 @@ test.describe('Date input block', () => {
id: typebotId,
...parseDefaultGroupWithBlock({
type: InputBlockType.DATE,
options: defaultDateInputOptions,
}),
},
])

View File

@@ -2,15 +2,19 @@ import React from 'react'
import { Text } from '@chakra-ui/react'
import { EmailInputBlock } from '@typebot.io/schemas'
import { WithVariableContent } from '@/features/graph/components/nodes/block/WithVariableContent'
import { defaultEmailInputOptions } from '@typebot.io/schemas/features/blocks/inputs/email/constants'
type Props = {
variableId?: string
placeholder: EmailInputBlock['options']['labels']['placeholder']
options: EmailInputBlock['options']
}
export const EmailInputNodeContent = ({ variableId, placeholder }: Props) =>
export const EmailInputNodeContent = ({
options: { variableId, labels } = {},
}: Props) =>
variableId ? (
<WithVariableContent variableId={variableId} />
) : (
<Text color={'gray.500'}>{placeholder}</Text>
<Text color={'gray.500'}>
{labels?.placeholder ?? defaultEmailInputOptions.labels.placeholder}
</Text>
)

View File

@@ -1,23 +1,20 @@
import { TextInput } from '@/components/inputs'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { FormLabel, Stack } from '@chakra-ui/react'
import {
EmailInputOptions,
Variable,
invalidEmailDefaultRetryMessage,
} from '@typebot.io/schemas'
import { EmailInputBlock, Variable } from '@typebot.io/schemas'
import { defaultEmailInputOptions } from '@typebot.io/schemas/features/blocks/inputs/email/constants'
import React from 'react'
type Props = {
options: EmailInputOptions
onOptionsChange: (options: EmailInputOptions) => void
options: EmailInputBlock['options']
onOptionsChange: (options: EmailInputBlock['options']) => void
}
export const EmailInputSettings = ({ options, onOptionsChange }: Props) => {
const handlePlaceholderChange = (placeholder: string) =>
onOptionsChange({ ...options, labels: { ...options.labels, placeholder } })
onOptionsChange({ ...options, labels: { ...options?.labels, placeholder } })
const handleButtonLabelChange = (button: string) =>
onOptionsChange({ ...options, labels: { ...options.labels, button } })
onOptionsChange({ ...options, labels: { ...options?.labels, button } })
const handleVariableChange = (variable?: Variable) =>
onOptionsChange({ ...options, variableId: variable?.id })
const handleRetryMessageChange = (retryMessageContent: string) =>
@@ -27,18 +24,24 @@ export const EmailInputSettings = ({ options, onOptionsChange }: Props) => {
<Stack spacing={4}>
<TextInput
label="Placeholder:"
defaultValue={options.labels.placeholder}
defaultValue={
options?.labels?.placeholder ??
defaultEmailInputOptions.labels.placeholder
}
onChange={handlePlaceholderChange}
/>
<TextInput
label="Button label:"
defaultValue={options.labels.button}
defaultValue={
options?.labels?.button ?? defaultEmailInputOptions.labels.button
}
onChange={handleButtonLabelChange}
/>
<TextInput
label="Retry message:"
defaultValue={
options.retryMessageContent ?? invalidEmailDefaultRetryMessage
options?.retryMessageContent ??
defaultEmailInputOptions.retryMessageContent
}
onChange={handleRetryMessageChange}
/>
@@ -47,7 +50,7 @@ export const EmailInputSettings = ({ options, onOptionsChange }: Props) => {
Save answer in a variable:
</FormLabel>
<VariableSearchInput
initialVariableId={options.variableId}
initialVariableId={options?.variableId}
onSelectVariable={handleVariableChange}
/>
</Stack>

View File

@@ -1,12 +1,9 @@
import test, { expect } from '@playwright/test'
import { createTypebots } from '@typebot.io/lib/playwright/databaseActions'
import { parseDefaultGroupWithBlock } from '@typebot.io/lib/playwright/databaseHelpers'
import {
defaultEmailInputOptions,
InputBlockType,
invalidEmailDefaultRetryMessage,
} from '@typebot.io/schemas'
import { createId } from '@paralleldrive/cuid2'
import { InputBlockType } from '@typebot.io/schemas/features/blocks/inputs/constants'
import { defaultEmailInputOptions } from '@typebot.io/schemas/features/blocks/inputs/email/constants'
test.describe('Email input block', () => {
test('options should work', async ({ page }) => {
@@ -16,7 +13,6 @@ test.describe('Email input block', () => {
id: typebotId,
...parseDefaultGroupWithBlock({
type: InputBlockType.EMAIL,
options: defaultEmailInputOptions,
}),
},
])
@@ -39,7 +35,7 @@ test.describe('Email input block', () => {
await expect(page.locator('text=Your email...')).toBeVisible()
await page.getByLabel('Button label:').fill('Go')
await page.fill(
`input[value="${invalidEmailDefaultRetryMessage}"]`,
`input[value="${defaultEmailInputOptions.retryMessageContent}"]`,
'Try again bro'
)

View File

@@ -1,18 +1,16 @@
import { WithVariableContent } from '@/features/graph/components/nodes/block/WithVariableContent'
import { Text } from '@chakra-ui/react'
import { FileInputOptions } from '@typebot.io/schemas'
import { FileInputBlock } from '@typebot.io/schemas'
type Props = {
options: FileInputOptions
options: FileInputBlock['options']
}
export const FileInputContent = ({
options: { isMultipleAllowed, variableId },
}: Props) =>
variableId ? (
<WithVariableContent variableId={variableId} />
export const FileInputContent = ({ options }: Props) =>
options?.variableId ? (
<WithVariableContent variableId={options.variableId} />
) : (
<Text noOfLines={1} pr="6">
Collect {isMultipleAllowed ? 'files' : 'file'}
Collect {options?.isMultipleAllowed ? 'files' : 'file'}
</Text>
)

View File

@@ -1,22 +1,23 @@
import { FormLabel, Stack } from '@chakra-ui/react'
import { CodeEditor } from '@/components/inputs/CodeEditor'
import { FileInputOptions, Variable } from '@typebot.io/schemas'
import { FileInputBlock, Variable } from '@typebot.io/schemas'
import React from 'react'
import { TextInput } from '@/components/inputs'
import { SwitchWithLabel } from '@/components/inputs/SwitchWithLabel'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { defaultFileInputOptions } from '@typebot.io/schemas/features/blocks/inputs/file/constants'
type Props = {
options: FileInputOptions
onOptionsChange: (options: FileInputOptions) => void
options: FileInputBlock['options']
onOptionsChange: (options: FileInputBlock['options']) => void
}
export const FileInputSettings = ({ options, onOptionsChange }: Props) => {
const handleButtonLabelChange = (button: string) =>
onOptionsChange({ ...options, labels: { ...options.labels, button } })
onOptionsChange({ ...options, labels: { ...options?.labels, button } })
const handlePlaceholderLabelChange = (placeholder: string) =>
onOptionsChange({ ...options, labels: { ...options.labels, placeholder } })
onOptionsChange({ ...options, labels: { ...options?.labels, placeholder } })
const handleMultipleFilesChange = (isMultipleAllowed: boolean) =>
onOptionsChange({ ...options, isMultipleAllowed })
@@ -28,21 +29,24 @@ export const FileInputSettings = ({ options, onOptionsChange }: Props) => {
onOptionsChange({ ...options, isRequired })
const updateClearButtonLabel = (clear: string) =>
onOptionsChange({ ...options, labels: { ...options.labels, clear } })
onOptionsChange({ ...options, labels: { ...options?.labels, clear } })
const updateSkipButtonLabel = (skip: string) =>
onOptionsChange({ ...options, labels: { ...options.labels, skip } })
onOptionsChange({ ...options, labels: { ...options?.labels, skip } })
return (
<Stack spacing={4}>
<SwitchWithLabel
label="Required?"
initialValue={options.isRequired ?? true}
initialValue={options?.isRequired ?? defaultFileInputOptions.isRequired}
onCheckChange={handleRequiredChange}
/>
<SwitchWithLabel
label="Allow multiple files?"
initialValue={options.isMultipleAllowed}
initialValue={
options?.isMultipleAllowed ??
defaultFileInputOptions.isMultipleAllowed
}
onCheckChange={handleMultipleFilesChange}
/>
<Stack>
@@ -50,35 +54,44 @@ export const FileInputSettings = ({ options, onOptionsChange }: Props) => {
<CodeEditor
lang="html"
onChange={handlePlaceholderLabelChange}
defaultValue={options.labels.placeholder}
defaultValue={
options?.labels?.placeholder ??
defaultFileInputOptions.labels.placeholder
}
height={'100px'}
withVariableButton={false}
/>
</Stack>
<TextInput
label="Button label:"
defaultValue={options.labels.button}
defaultValue={
options?.labels?.button ?? defaultFileInputOptions.labels.button
}
onChange={handleButtonLabelChange}
withVariableButton={false}
/>
<TextInput
label="Clear button label:"
defaultValue={options.labels.clear ?? ''}
defaultValue={
options?.labels?.clear ?? defaultFileInputOptions.labels.clear
}
onChange={updateClearButtonLabel}
withVariableButton={false}
/>
<TextInput
label="Skip button label:"
defaultValue={options.labels.skip ?? ''}
defaultValue={
options?.labels?.skip ?? defaultFileInputOptions.labels.skip
}
onChange={updateSkipButtonLabel}
withVariableButton={false}
/>
<Stack>
<FormLabel mb="0" htmlFor="variable">
Save upload URL{options.isMultipleAllowed ? 's' : ''} in a variable:
Save upload URL{options?.isMultipleAllowed ? 's' : ''} in a variable:
</FormLabel>
<VariableSearchInput
initialVariableId={options.variableId}
initialVariableId={options?.variableId}
onSelectVariable={handleVariableChange}
/>
</Stack>

View File

@@ -1,10 +1,10 @@
import test, { expect } from '@playwright/test'
import { createTypebots } from '@typebot.io/lib/playwright/databaseActions'
import { parseDefaultGroupWithBlock } from '@typebot.io/lib/playwright/databaseHelpers'
import { defaultFileInputOptions, InputBlockType } from '@typebot.io/schemas'
import { createId } from '@paralleldrive/cuid2'
import { freeWorkspaceId } from '@typebot.io/lib/playwright/databaseSetup'
import { getTestAsset } from '@/test/utils/playwright'
import { InputBlockType } from '@typebot.io/schemas/features/blocks/inputs/constants'
test.describe.configure({ mode: 'parallel' })
@@ -15,7 +15,6 @@ test('options should work', async ({ page }) => {
id: typebotId,
...parseDefaultGroupWithBlock({
type: InputBlockType.FILE,
options: defaultFileInputOptions,
}),
},
])
@@ -59,8 +58,8 @@ test.describe('Free workspace', () => {
id: typebotId,
...parseDefaultGroupWithBlock({
type: InputBlockType.FILE,
options: defaultFileInputOptions,
}),
version: '6',
workspaceId: freeWorkspaceId,
},
])

View File

@@ -1,25 +1,29 @@
import { TextInput, NumberInput } from '@/components/inputs'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { FormLabel, Stack } from '@chakra-ui/react'
import { NumberInputOptions, Variable } from '@typebot.io/schemas'
import { NumberInputBlock, Variable } from '@typebot.io/schemas'
import { defaultNumberInputOptions } from '@typebot.io/schemas/features/blocks/inputs/number/constants'
import React from 'react'
type Props = {
options: NumberInputOptions
onOptionsChange: (options: NumberInputOptions) => void
options: NumberInputBlock['options']
onOptionsChange: (options: NumberInputBlock['options']) => void
}
export const NumberInputSettings = ({ options, onOptionsChange }: Props) => {
const handlePlaceholderChange = (placeholder: string) =>
onOptionsChange({ ...options, labels: { ...options.labels, placeholder } })
onOptionsChange({ ...options, labels: { ...options?.labels, placeholder } })
const handleButtonLabelChange = (button: string) =>
onOptionsChange({ ...options, labels: { ...options.labels, button } })
const handleMinChange = (min?: NumberInputOptions['min']) =>
onOptionsChange({ ...options, min })
const handleMaxChange = (max?: NumberInputOptions['max']) =>
onOptionsChange({ ...options, max })
const handleStepChange = (step?: NumberInputOptions['step']) =>
onOptionsChange({ ...options, step })
onOptionsChange({ ...options, labels: { ...options?.labels, button } })
const handleMinChange = (
min?: NonNullable<NumberInputBlock['options']>['min']
) => onOptionsChange({ ...options, min })
const handleMaxChange = (
max?: NonNullable<NumberInputBlock['options']>['max']
) => onOptionsChange({ ...options, max })
const handleStepChange = (
step?: NonNullable<NumberInputBlock['options']>['step']
) => onOptionsChange({ ...options, step })
const handleVariableChange = (variable?: Variable) => {
onOptionsChange({ ...options, variableId: variable?.id })
}
@@ -28,27 +32,32 @@ export const NumberInputSettings = ({ options, onOptionsChange }: Props) => {
<Stack spacing={4}>
<TextInput
label="Placeholder:"
defaultValue={options.labels.placeholder}
defaultValue={
options?.labels?.placeholder ??
defaultNumberInputOptions.labels.placeholder
}
onChange={handlePlaceholderChange}
/>
<TextInput
label="Button label:"
defaultValue={options?.labels?.button ?? 'Send'}
defaultValue={
options?.labels?.button ?? defaultNumberInputOptions.labels.button
}
onChange={handleButtonLabelChange}
/>
<NumberInput
label="Min:"
defaultValue={options.min}
defaultValue={options?.min}
onValueChange={handleMinChange}
/>
<NumberInput
label="Max:"
defaultValue={options.max}
defaultValue={options?.max}
onValueChange={handleMaxChange}
/>
<NumberInput
label="Step:"
defaultValue={options.step}
defaultValue={options?.step}
onValueChange={handleStepChange}
/>
<Stack>
@@ -56,7 +65,7 @@ export const NumberInputSettings = ({ options, onOptionsChange }: Props) => {
Save answer in a variable:
</FormLabel>
<VariableSearchInput
initialVariableId={options.variableId}
initialVariableId={options?.variableId}
onSelectVariable={handleVariableChange}
/>
</Stack>

View File

@@ -2,15 +2,19 @@ import React from 'react'
import { Text } from '@chakra-ui/react'
import { NumberInputBlock } from '@typebot.io/schemas'
import { WithVariableContent } from '@/features/graph/components/nodes/block/WithVariableContent'
import { defaultNumberInputOptions } from '@typebot.io/schemas/features/blocks/inputs/number/constants'
type Props = {
variableId?: string
placeholder: NumberInputBlock['options']['labels']['placeholder']
options: NumberInputBlock['options']
}
export const NumberNodeContent = ({ variableId, placeholder }: Props) =>
export const NumberNodeContent = ({
options: { variableId, labels } = {},
}: Props) =>
variableId ? (
<WithVariableContent variableId={variableId} />
) : (
<Text color={'gray.500'}>{placeholder}</Text>
<Text color={'gray.500'}>
{labels?.placeholder ?? defaultNumberInputOptions.labels.placeholder}
</Text>
)

View File

@@ -1,8 +1,9 @@
import test, { expect } from '@playwright/test'
import { createTypebots } from '@typebot.io/lib/playwright/databaseActions'
import { parseDefaultGroupWithBlock } from '@typebot.io/lib/playwright/databaseHelpers'
import { defaultNumberInputOptions, InputBlockType } from '@typebot.io/schemas'
import { createId } from '@paralleldrive/cuid2'
import { InputBlockType } from '@typebot.io/schemas/features/blocks/inputs/constants'
import { defaultNumberInputOptions } from '@typebot.io/schemas/features/blocks/inputs/number/constants'
test.describe('Number input block', () => {
test('options should work', async ({ page }) => {
@@ -12,7 +13,6 @@ test.describe('Number input block', () => {
id: typebotId,
...parseDefaultGroupWithBlock({
type: InputBlockType.NUMBER,
options: defaultNumberInputOptions,
}),
},
])

View File

@@ -7,7 +7,7 @@ type Props = {
export const PaymentInputContent = ({ block }: Props) => {
if (
!block.options.amount ||
!block.options?.amount ||
!block.options.credentialsId ||
!block.options.currency
)

View File

@@ -11,11 +11,7 @@ import {
AccordionPanel,
} from '@chakra-ui/react'
import { DropdownList } from '@/components/DropdownList'
import {
PaymentAddress,
PaymentInputOptions,
PaymentProvider,
} from '@typebot.io/schemas'
import { PaymentAddress, PaymentInputBlock } from '@typebot.io/schemas'
import React, { ChangeEvent } from 'react'
import { currencies } from '../currencies'
import { StripeConfigModal } from './StripeConfigModal'
@@ -23,10 +19,14 @@ import { CredentialsDropdown } from '@/features/credentials/components/Credentia
import { TextInput } from '@/components/inputs'
import { useWorkspace } from '@/features/workspace/WorkspaceProvider'
import { PaymentAddressSettings } from './PaymentAddressSettings'
import {
PaymentProvider,
defaultPaymentInputOptions,
} from '@typebot.io/schemas/features/blocks/inputs/payment/constants'
type Props = {
options: PaymentInputOptions
onOptionsChange: (options: PaymentInputOptions) => void
options: PaymentInputBlock['options']
onOptionsChange: (options: PaymentInputBlock['options']) => void
}
export const PaymentSettings = ({ options, onOptionsChange }: Props) => {
@@ -62,43 +62,43 @@ export const PaymentSettings = ({ options, onOptionsChange }: Props) => {
const updateName = (name: string) =>
onOptionsChange({
...options,
additionalInformation: { ...options.additionalInformation, name },
additionalInformation: { ...options?.additionalInformation, name },
})
const updateEmail = (email: string) =>
onOptionsChange({
...options,
additionalInformation: { ...options.additionalInformation, email },
additionalInformation: { ...options?.additionalInformation, email },
})
const updatePhoneNumber = (phoneNumber: string) =>
onOptionsChange({
...options,
additionalInformation: { ...options.additionalInformation, phoneNumber },
additionalInformation: { ...options?.additionalInformation, phoneNumber },
})
const updateButtonLabel = (button: string) =>
onOptionsChange({
...options,
labels: { ...options.labels, button },
labels: { ...options?.labels, button },
})
const updateSuccessLabel = (success: string) =>
onOptionsChange({
...options,
labels: { ...options.labels, success },
labels: { ...options?.labels, success },
})
const updateDescription = (description: string) =>
onOptionsChange({
...options,
additionalInformation: { ...options.additionalInformation, description },
additionalInformation: { ...options?.additionalInformation, description },
})
const updateAddress = (address: PaymentAddress) =>
onOptionsChange({
...options,
additionalInformation: { ...options.additionalInformation, address },
additionalInformation: { ...options?.additionalInformation, address },
})
return (
@@ -108,7 +108,7 @@ export const PaymentSettings = ({ options, onOptionsChange }: Props) => {
<DropdownList
onItemSelect={updateProvider}
items={Object.values(PaymentProvider)}
currentItem={options.provider}
currentItem={options?.provider ?? defaultPaymentInputOptions.provider}
/>
</Stack>
<Stack>
@@ -117,7 +117,7 @@ export const PaymentSettings = ({ options, onOptionsChange }: Props) => {
<CredentialsDropdown
type="stripe"
workspaceId={workspace.id}
currentCredentialsId={options.credentialsId}
currentCredentialsId={options?.credentialsId}
onCredentialsSelect={updateCredentials}
onCreateNewClick={onOpen}
credentialsName="Stripe account"
@@ -128,14 +128,14 @@ export const PaymentSettings = ({ options, onOptionsChange }: Props) => {
<TextInput
label="Price amount:"
onChange={updateAmount}
defaultValue={options.amount ?? ''}
defaultValue={options?.amount}
placeholder="30.00"
/>
<Stack>
<Text>Currency:</Text>
<Select
placeholder="Select option"
value={options.currency}
value={options?.currency ?? defaultPaymentInputOptions.currency}
onChange={updateCurrency}
>
{currencies.map((currency) => (
@@ -149,14 +149,16 @@ export const PaymentSettings = ({ options, onOptionsChange }: Props) => {
<TextInput
label="Button label:"
onChange={updateButtonLabel}
defaultValue={options.labels.button}
placeholder="Pay"
defaultValue={
options?.labels?.button ?? defaultPaymentInputOptions.labels.button
}
/>
<TextInput
label="Success message:"
onChange={updateSuccessLabel}
defaultValue={options.labels.success ?? 'Success'}
placeholder="Success"
defaultValue={
options?.labels?.success ?? defaultPaymentInputOptions.labels.success
}
/>
<Accordion allowToggle>
<AccordionItem>
@@ -167,30 +169,30 @@ export const PaymentSettings = ({ options, onOptionsChange }: Props) => {
<AccordionPanel py={4} as={Stack} spacing="6">
<TextInput
label="Description:"
defaultValue={options.additionalInformation?.description ?? ''}
defaultValue={options?.additionalInformation?.description}
onChange={updateDescription}
placeholder="A digital product"
/>
<TextInput
label="Name:"
defaultValue={options.additionalInformation?.name ?? ''}
defaultValue={options?.additionalInformation?.name}
onChange={updateName}
placeholder="John Smith"
/>
<TextInput
label="Email:"
defaultValue={options.additionalInformation?.email ?? ''}
defaultValue={options?.additionalInformation?.email}
onChange={updateEmail}
placeholder="john@gmail.com"
/>
<TextInput
label="Phone number:"
defaultValue={options.additionalInformation?.phoneNumber ?? ''}
defaultValue={options?.additionalInformation?.phoneNumber}
onChange={updatePhoneNumber}
placeholder="+33XXXXXXXXX"
/>
<PaymentAddressSettings
address={options.additionalInformation?.address}
address={options?.additionalInformation?.address}
onAddressChange={updateAddress}
/>
</AccordionPanel>

View File

@@ -1,10 +1,10 @@
import test, { expect } from '@playwright/test'
import { createTypebots } from '@typebot.io/lib/playwright/databaseActions'
import { parseDefaultGroupWithBlock } from '@typebot.io/lib/playwright/databaseHelpers'
import { defaultPaymentInputOptions, InputBlockType } from '@typebot.io/schemas'
import { createId } from '@paralleldrive/cuid2'
import { stripePaymentForm } from '@/test/utils/selectorUtils'
import { env } from '@typebot.io/env'
import { InputBlockType } from '@typebot.io/schemas/features/blocks/inputs/constants'
test.describe('Payment input block', () => {
test('Can configure Stripe account', async ({ page }) => {
@@ -14,7 +14,6 @@ test.describe('Payment input block', () => {
id: typebotId,
...parseDefaultGroupWithBlock({
type: InputBlockType.PAYMENT,
options: defaultPaymentInputOptions,
}),
},
])

View File

@@ -1,20 +1,21 @@
import { TextInput } from '@/components/inputs'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { FormLabel, Stack } from '@chakra-ui/react'
import { PhoneNumberInputOptions, Variable } from '@typebot.io/schemas'
import { PhoneNumberInputBlock, Variable } from '@typebot.io/schemas'
import React from 'react'
import { CountryCodeSelect } from './CountryCodeSelect'
import { defaultPhoneInputOptions } from '@typebot.io/schemas/features/blocks/inputs/phone/constants'
type Props = {
options: PhoneNumberInputOptions
onOptionsChange: (options: PhoneNumberInputOptions) => void
options: PhoneNumberInputBlock['options']
onOptionsChange: (options: PhoneNumberInputBlock['options']) => void
}
export const PhoneInputSettings = ({ options, onOptionsChange }: Props) => {
const handlePlaceholderChange = (placeholder: string) =>
onOptionsChange({ ...options, labels: { ...options.labels, placeholder } })
onOptionsChange({ ...options, labels: { ...options?.labels, placeholder } })
const handleButtonLabelChange = (button: string) =>
onOptionsChange({ ...options, labels: { ...options.labels, button } })
onOptionsChange({ ...options, labels: { ...options?.labels, button } })
const handleVariableChange = (variable?: Variable) =>
onOptionsChange({ ...options, variableId: variable?.id })
const handleRetryMessageChange = (retryMessageContent: string) =>
@@ -26,12 +27,17 @@ export const PhoneInputSettings = ({ options, onOptionsChange }: Props) => {
<Stack spacing={4}>
<TextInput
label="Placeholder:"
defaultValue={options.labels.placeholder}
defaultValue={
options?.labels?.placeholder ??
defaultPhoneInputOptions.labels.placeholder
}
onChange={handlePlaceholderChange}
/>
<TextInput
label="Button label:"
defaultValue={options.labels.button}
defaultValue={
options?.labels?.button ?? defaultPhoneInputOptions.labels.button
}
onChange={handleButtonLabelChange}
/>
<Stack>
@@ -40,12 +46,15 @@ export const PhoneInputSettings = ({ options, onOptionsChange }: Props) => {
</FormLabel>
<CountryCodeSelect
onSelect={handleDefaultCountryChange}
countryCode={options.defaultCountryCode}
countryCode={options?.defaultCountryCode}
/>
</Stack>
<TextInput
label="Retry message:"
defaultValue={options.retryMessageContent}
defaultValue={
options?.retryMessageContent ??
defaultPhoneInputOptions.retryMessageContent
}
onChange={handleRetryMessageChange}
/>
<Stack>
@@ -53,7 +62,7 @@ export const PhoneInputSettings = ({ options, onOptionsChange }: Props) => {
Save answer in a variable:
</FormLabel>
<VariableSearchInput
initialVariableId={options.variableId}
initialVariableId={options?.variableId}
onSelectVariable={handleVariableChange}
/>
</Stack>

View File

@@ -1,16 +1,20 @@
import React from 'react'
import { Text } from '@chakra-ui/react'
import { PhoneNumberInputOptions } from '@typebot.io/schemas'
import { WithVariableContent } from '@/features/graph/components/nodes/block/WithVariableContent'
import { PhoneNumberInputBlock } from '@typebot.io/schemas'
import { defaultPhoneInputOptions } from '@typebot.io/schemas/features/blocks/inputs/phone/constants'
type Props = {
variableId?: string
placeholder: PhoneNumberInputOptions['labels']['placeholder']
options: PhoneNumberInputBlock['options']
}
export const PhoneNodeContent = ({ variableId, placeholder }: Props) =>
export const PhoneNodeContent = ({
options: { variableId, labels } = {},
}: Props) =>
variableId ? (
<WithVariableContent variableId={variableId} />
) : (
<Text color={'gray.500'}>{placeholder}</Text>
<Text color={'gray.500'}>
{labels?.placeholder ?? defaultPhoneInputOptions.labels.placeholder}
</Text>
)

View File

@@ -1,8 +1,9 @@
import test, { expect } from '@playwright/test'
import { createTypebots } from '@typebot.io/lib/playwright/databaseActions'
import { parseDefaultGroupWithBlock } from '@typebot.io/lib/playwright/databaseHelpers'
import { defaultPhoneInputOptions, InputBlockType } from '@typebot.io/schemas'
import { createId } from '@paralleldrive/cuid2'
import { InputBlockType } from '@typebot.io/schemas/features/blocks/inputs/constants'
import { defaultPhoneInputOptions } from '@typebot.io/schemas/features/blocks/inputs/phone/constants'
test.describe('Phone input block', () => {
test('options should work', async ({ page }) => {
@@ -12,7 +13,6 @@ test.describe('Phone input block', () => {
id: typebotId,
...parseDefaultGroupWithBlock({
type: InputBlockType.PHONE,
options: defaultPhoneInputOptions,
}),
},
])

View File

@@ -14,7 +14,7 @@ import {
} from '@chakra-ui/react'
import { ImageIcon, PlusIcon } from '@/components/icons'
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
import { ItemIndices, ItemType } from '@typebot.io/schemas'
import { ItemIndices } from '@typebot.io/schemas'
import React, { useRef } from 'react'
import { PictureChoiceItem } from '@typebot.io/schemas/features/blocks/inputs/pictureChoice'
import { useGraph } from '@/features/graph/providers/GraphProvider'
@@ -40,7 +40,7 @@ export const PictureChoiceItemNode = ({
const handlePlusClick = (e: React.MouseEvent) => {
e.stopPropagation()
const itemIndex = indices.itemIndex + 1
createItem({ type: ItemType.PICTURE_CHOICE }, { ...indices, itemIndex })
createItem({}, { ...indices, itemIndex })
}
const handleMouseDown = (e: React.MouseEvent) => e.stopPropagation()

View File

@@ -13,7 +13,8 @@ import {
import { ImageUploadContent } from '@/components/ImageUploadContent'
import { SwitchWithRelatedSettings } from '@/components/SwitchWithRelatedSettings'
import { ConditionForm } from '@/features/blocks/logic/condition/components/ConditionForm'
import { Condition, LogicalOperator } from '@typebot.io/schemas'
import { Condition } from '@typebot.io/schemas'
import { LogicalOperator } from '@typebot.io/schemas/features/blocks/logic/condition/constants'
type Props = {
workspaceId: string

View File

@@ -15,12 +15,12 @@ export const PictureChoiceNode = ({ block, indices }: Props) => {
const { typebot } = useTypebot()
const dynamicVariableName = typebot?.variables.find(
(variable) =>
variable.id === block.options.dynamicItems?.pictureSrcsVariableId
variable.id === block.options?.dynamicItems?.pictureSrcsVariableId
)?.name
return (
<Stack w="full">
{block.options.dynamicItems?.isEnabled && dynamicVariableName ? (
{block.options?.dynamicItems?.isEnabled && dynamicVariableName ? (
<Wrap spacing={1}>
<Text>Display</Text>
<Tag bg="orange.400" color="white">
@@ -31,7 +31,7 @@ export const PictureChoiceNode = ({ block, indices }: Props) => {
) : (
<ItemNodesList block={block} indices={indices} />
)}
{block.options.variableId ? (
{block.options?.variableId ? (
<SetVariableLabel
variableId={block.options.variableId}
variables={typebot?.variables}

View File

@@ -3,11 +3,9 @@ import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { FormLabel, Stack } from '@chakra-ui/react'
import { Variable } from '@typebot.io/schemas'
import React from 'react'
import {
PictureChoiceBlock,
defaultPictureChoiceOptions,
} from '@typebot.io/schemas/features/blocks/inputs/pictureChoice'
import { PictureChoiceBlock } from '@typebot.io/schemas/features/blocks/inputs/pictureChoice'
import { SwitchWithRelatedSettings } from '@/components/SwitchWithRelatedSettings'
import { defaultPictureChoiceOptions } from '@typebot.io/schemas/features/blocks/inputs/pictureChoice/constants'
type Props = {
options?: PictureChoiceBlock['options']
@@ -16,52 +14,48 @@ type Props = {
export const PictureChoiceSettings = ({ options, onOptionsChange }: Props) => {
const updateIsMultiple = (isMultipleChoice: boolean) =>
options && onOptionsChange({ ...options, isMultipleChoice })
onOptionsChange({ ...options, isMultipleChoice })
const updateButtonLabel = (buttonLabel: string) =>
options && onOptionsChange({ ...options, buttonLabel })
onOptionsChange({ ...options, buttonLabel })
const updateSaveVariable = (variable?: Variable) =>
options && onOptionsChange({ ...options, variableId: variable?.id })
onOptionsChange({ ...options, variableId: variable?.id })
const updateSearchInputPlaceholder = (searchInputPlaceholder: string) =>
options && onOptionsChange({ ...options, searchInputPlaceholder })
onOptionsChange({ ...options, searchInputPlaceholder })
const updateIsSearchable = (isSearchable: boolean) =>
options && onOptionsChange({ ...options, isSearchable })
onOptionsChange({ ...options, isSearchable })
const updateIsDynamicItemsEnabled = (isEnabled: boolean) =>
options &&
onOptionsChange({
...options,
dynamicItems: {
...options.dynamicItems,
...options?.dynamicItems,
isEnabled,
},
})
const updateDynamicItemsPictureSrcsVariable = (variable?: Variable) =>
options &&
onOptionsChange({
...options,
dynamicItems: {
...options.dynamicItems,
...options?.dynamicItems,
pictureSrcsVariableId: variable?.id,
},
})
const updateDynamicItemsTitlesVariable = (variable?: Variable) =>
options &&
onOptionsChange({
...options,
dynamicItems: {
...options.dynamicItems,
...options?.dynamicItems,
titlesVariableId: variable?.id,
},
})
const updateDynamicItemsDescriptionsVariable = (variable?: Variable) =>
options &&
onOptionsChange({
...options,
dynamicItems: {
...options.dynamicItems,
...options?.dynamicItems,
descriptionsVariableId: variable?.id,
},
})
@@ -70,7 +64,9 @@ export const PictureChoiceSettings = ({ options, onOptionsChange }: Props) => {
<Stack spacing={4}>
<SwitchWithRelatedSettings
label="Is searchable?"
initialValue={options?.isSearchable ?? false}
initialValue={
options?.isSearchable ?? defaultPictureChoiceOptions.isSearchable
}
onCheckChange={updateIsSearchable}
>
<TextInput
@@ -84,19 +80,27 @@ export const PictureChoiceSettings = ({ options, onOptionsChange }: Props) => {
</SwitchWithRelatedSettings>
<SwitchWithRelatedSettings
label="Multiple choice?"
initialValue={options?.isMultipleChoice ?? false}
initialValue={
options?.isMultipleChoice ??
defaultPictureChoiceOptions.isMultipleChoice
}
onCheckChange={updateIsMultiple}
>
<TextInput
label="Submit button label:"
defaultValue={options?.buttonLabel ?? 'Send'}
defaultValue={
options?.buttonLabel ?? defaultPictureChoiceOptions.buttonLabel
}
onChange={updateButtonLabel}
/>
</SwitchWithRelatedSettings>
<SwitchWithRelatedSettings
label="Dynamic items?"
initialValue={options?.dynamicItems?.isEnabled ?? false}
initialValue={
options?.dynamicItems?.isEnabled ??
defaultPictureChoiceOptions.dynamicItems.isEnabled
}
onCheckChange={updateIsDynamicItemsEnabled}
>
<Stack>

View File

@@ -1,9 +1,8 @@
import test, { expect } from '@playwright/test'
import { createTypebots } from '@typebot.io/lib/playwright/databaseActions'
import { parseDefaultGroupWithBlock } from '@typebot.io/lib/playwright/databaseHelpers'
import { InputBlockType, ItemType } from '@typebot.io/schemas'
import { createId } from '@paralleldrive/cuid2'
import { defaultPictureChoiceOptions } from '@typebot.io/schemas/features/blocks/inputs/pictureChoice'
import { InputBlockType } from '@typebot.io/schemas/features/blocks/inputs/constants'
const firstImageSrc =
'https://images.unsplash.com/flagged/photo-1575517111839-3a3843ee7f5d?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2940&q=80'
@@ -25,10 +24,8 @@ test.describe.parallel('Picture choice input block', () => {
items: [
{
id: 'choice1',
type: ItemType.PICTURE_CHOICE,
},
],
options: { ...defaultPictureChoiceOptions },
}),
},
])

View File

@@ -1,6 +1,7 @@
import { WithVariableContent } from '@/features/graph/components/nodes/block/WithVariableContent'
import { Text } from '@chakra-ui/react'
import { RatingInputBlock } from '@typebot.io/schemas'
import { defaultRatingInputOptions } from '@typebot.io/schemas/features/blocks/inputs/rating/constants'
type Props = {
variableId?: string
@@ -12,7 +13,7 @@ export const RatingInputContent = ({ variableId, block }: Props) =>
<WithVariableContent variableId={variableId} />
) : (
<Text noOfLines={1} pr="6">
Rate from {block.options.buttonType === 'Icons' ? 1 : 0} to{' '}
{block.options.length}
Rate from {block.options?.buttonType === 'Icons' ? 1 : 0} to{' '}
{block.options?.length ?? defaultRatingInputOptions.length}
</Text>
)

View File

@@ -1,14 +1,15 @@
import { FormLabel, Stack } from '@chakra-ui/react'
import { DropdownList } from '@/components/DropdownList'
import { RatingInputOptions, Variable } from '@typebot.io/schemas'
import { RatingInputBlock, Variable } from '@typebot.io/schemas'
import React from 'react'
import { SwitchWithLabel } from '@/components/inputs/SwitchWithLabel'
import { TextInput } from '@/components/inputs'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { defaultRatingInputOptions } from '@typebot.io/schemas/features/blocks/inputs/rating/constants'
type Props = {
options: RatingInputOptions
onOptionsChange: (options: RatingInputOptions) => void
options: RatingInputBlock['options']
onOptionsChange: (options: RatingInputBlock['options']) => void
}
export const RatingInputSettings = ({ options, onOptionsChange }: Props) => {
@@ -21,20 +22,20 @@ export const RatingInputSettings = ({ options, onOptionsChange }: Props) => {
const handleCustomIconCheck = (isEnabled: boolean) =>
onOptionsChange({
...options,
customIcon: { ...options.customIcon, isEnabled },
customIcon: { ...options?.customIcon, isEnabled },
})
const handleIconSvgChange = (svg: string) =>
onOptionsChange({ ...options, customIcon: { ...options.customIcon, svg } })
onOptionsChange({ ...options, customIcon: { ...options?.customIcon, svg } })
const handleLeftLabelChange = (left: string) =>
onOptionsChange({ ...options, labels: { ...options.labels, left } })
onOptionsChange({ ...options, labels: { ...options?.labels, left } })
const handleRightLabelChange = (right: string) =>
onOptionsChange({ ...options, labels: { ...options.labels, right } })
onOptionsChange({ ...options, labels: { ...options?.labels, right } })
const handleButtonLabelChange = (button: string) =>
onOptionsChange({ ...options, labels: { ...options.labels, button } })
onOptionsChange({ ...options, labels: { ...options?.labels, button } })
const handleVariableChange = (variable?: Variable) =>
onOptionsChange({ ...options, variableId: variable?.id })
@@ -42,6 +43,11 @@ export const RatingInputSettings = ({ options, onOptionsChange }: Props) => {
const handleOneClickSubmitChange = (isOneClickSubmitEnabled: boolean) =>
onOptionsChange({ ...options, isOneClickSubmitEnabled })
const length = options?.length ?? defaultRatingInputOptions.length
const isOneClickSubmitEnabled =
options?.isOneClickSubmitEnabled ??
defaultRatingInputOptions.isOneClickSubmitEnabled
return (
<Stack spacing={4}>
<Stack>
@@ -51,7 +57,7 @@ export const RatingInputSettings = ({ options, onOptionsChange }: Props) => {
<DropdownList
onItemSelect={handleLengthChange}
items={[3, 4, 5, 6, 7, 8, 9, 10]}
currentItem={options.length}
currentItem={length}
/>
</Stack>
@@ -62,18 +68,23 @@ export const RatingInputSettings = ({ options, onOptionsChange }: Props) => {
<DropdownList
onItemSelect={handleTypeChange}
items={['Icons', 'Numbers'] as const}
currentItem={options.buttonType}
currentItem={
options?.buttonType ?? defaultRatingInputOptions.buttonType
}
/>
</Stack>
{options.buttonType === 'Icons' && (
{options?.buttonType === 'Icons' && (
<SwitchWithLabel
label="Custom icon?"
initialValue={options.customIcon.isEnabled}
initialValue={
options?.customIcon?.isEnabled ??
defaultRatingInputOptions.customIcon.isEnabled
}
onCheckChange={handleCustomIconCheck}
/>
)}
{options.buttonType === 'Icons' && options.customIcon.isEnabled && (
{options?.buttonType === 'Icons' && options.customIcon?.isEnabled && (
<TextInput
label="Icon SVG:"
defaultValue={options.customIcon.svg}
@@ -82,27 +93,29 @@ export const RatingInputSettings = ({ options, onOptionsChange }: Props) => {
/>
)}
<TextInput
label={`${options.buttonType === 'Icons' ? '1' : '0'} label:`}
defaultValue={options.labels.left}
label={`${options?.buttonType === 'Icons' ? '1' : '0'} label:`}
defaultValue={options?.labels?.left}
onChange={handleLeftLabelChange}
placeholder="Not likely at all"
/>
<TextInput
label={`${options.length} label:`}
defaultValue={options.labels.right}
label={`${length} label:`}
defaultValue={options?.labels?.right}
onChange={handleRightLabelChange}
placeholder="Extremely likely"
/>
<SwitchWithLabel
label="One click submit"
moreInfoContent='If enabled, the answer will be submitted as soon as the user clicks on a rating instead of showing the "Send" button.'
initialValue={options.isOneClickSubmitEnabled ?? false}
initialValue={isOneClickSubmitEnabled}
onCheckChange={handleOneClickSubmitChange}
/>
{!options.isOneClickSubmitEnabled && (
{!isOneClickSubmitEnabled && (
<TextInput
label="Button label:"
defaultValue={options.labels.button}
defaultValue={
options?.labels?.button ?? defaultRatingInputOptions.labels.button
}
onChange={handleButtonLabelChange}
/>
)}
@@ -111,7 +124,7 @@ export const RatingInputSettings = ({ options, onOptionsChange }: Props) => {
Save answer in a variable:
</FormLabel>
<VariableSearchInput
initialVariableId={options.variableId}
initialVariableId={options?.variableId}
onSelectVariable={handleVariableChange}
/>
</Stack>

View File

@@ -1,8 +1,8 @@
import test, { expect } from '@playwright/test'
import { createTypebots } from '@typebot.io/lib/playwright/databaseActions'
import { parseDefaultGroupWithBlock } from '@typebot.io/lib/playwright/databaseHelpers'
import { defaultRatingInputOptions, InputBlockType } from '@typebot.io/schemas'
import { createId } from '@paralleldrive/cuid2'
import { InputBlockType } from '@typebot.io/schemas/features/blocks/inputs/constants'
const boxSvg = `<svg
xmlns="http://www.w3.org/2000/svg"
@@ -24,7 +24,6 @@ test('options should work', async ({ page }) => {
id: typebotId,
...parseDefaultGroupWithBlock({
type: InputBlockType.RATING,
options: defaultRatingInputOptions,
}),
},
])

View File

@@ -1,29 +1,25 @@
import React from 'react'
import { Text } from '@chakra-ui/react'
import { TextInputOptions } from '@typebot.io/schemas'
import { WithVariableContent } from '@/features/graph/components/nodes/block/WithVariableContent'
import { TextInputBlock } from '@typebot.io/schemas'
import { defaultTextInputOptions } from '@typebot.io/schemas/features/blocks/inputs/text/constants'
type Props = {
placeholder: TextInputOptions['labels']['placeholder']
isLong: TextInputOptions['isLong']
variableId?: string
options: TextInputBlock['options']
}
export const TextInputNodeContent = ({
placeholder,
isLong,
variableId,
}: Props) => {
if (variableId)
export const TextInputNodeContent = ({ options }: Props) => {
if (options?.variableId)
return (
<WithVariableContent
variableId={variableId}
h={isLong ? '100px' : 'auto'}
variableId={options?.variableId}
h={options.isLong ? '100px' : 'auto'}
/>
)
return (
<Text color={'gray.500'} h={isLong ? '100px' : 'auto'}>
{placeholder}
<Text color={'gray.500'} h={options?.isLong ? '100px' : 'auto'}>
{options?.labels?.placeholder ??
defaultTextInputOptions.labels.placeholder}
</Text>
)
}

View File

@@ -2,19 +2,20 @@ import { TextInput } from '@/components/inputs'
import { SwitchWithLabel } from '@/components/inputs/SwitchWithLabel'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { FormLabel, Stack } from '@chakra-ui/react'
import { TextInputOptions, Variable } from '@typebot.io/schemas'
import { TextInputBlock, Variable } from '@typebot.io/schemas'
import { defaultTextInputOptions } from '@typebot.io/schemas/features/blocks/inputs/text/constants'
import React from 'react'
type Props = {
options: TextInputOptions
onOptionsChange: (options: TextInputOptions) => void
options: TextInputBlock['options']
onOptionsChange: (options: TextInputBlock['options']) => void
}
export const TextInputSettings = ({ options, onOptionsChange }: Props) => {
const handlePlaceholderChange = (placeholder: string) =>
onOptionsChange({ ...options, labels: { ...options.labels, placeholder } })
onOptionsChange({ ...options, labels: { ...options?.labels, placeholder } })
const handleButtonLabelChange = (button: string) =>
onOptionsChange({ ...options, labels: { ...options.labels, button } })
onOptionsChange({ ...options, labels: { ...options?.labels, button } })
const handleLongChange = (isLong: boolean) =>
onOptionsChange({ ...options, isLong })
const handleVariableChange = (variable?: Variable) =>
@@ -24,17 +25,22 @@ export const TextInputSettings = ({ options, onOptionsChange }: Props) => {
<Stack spacing={4}>
<SwitchWithLabel
label="Long text?"
initialValue={options?.isLong ?? false}
initialValue={options?.isLong ?? defaultTextInputOptions.isLong}
onCheckChange={handleLongChange}
/>
<TextInput
label="Placeholder:"
defaultValue={options.labels.placeholder}
defaultValue={
options?.labels?.placeholder ??
defaultTextInputOptions.labels.placeholder
}
onChange={handlePlaceholderChange}
/>
<TextInput
label="Button label:"
defaultValue={options.labels.button}
defaultValue={
options?.labels?.button ?? defaultTextInputOptions.labels.button
}
onChange={handleButtonLabelChange}
/>
<Stack>
@@ -42,7 +48,7 @@ export const TextInputSettings = ({ options, onOptionsChange }: Props) => {
Save answer in a variable:
</FormLabel>
<VariableSearchInput
initialVariableId={options.variableId}
initialVariableId={options?.variableId}
onSelectVariable={handleVariableChange}
/>
</Stack>

View File

@@ -1,8 +1,9 @@
import test, { expect } from '@playwright/test'
import { createTypebots } from '@typebot.io/lib/playwright/databaseActions'
import { parseDefaultGroupWithBlock } from '@typebot.io/lib/playwright/databaseHelpers'
import { defaultTextInputOptions, InputBlockType } from '@typebot.io/schemas'
import { createId } from '@paralleldrive/cuid2'
import { InputBlockType } from '@typebot.io/schemas/features/blocks/inputs/constants'
import { defaultTextInputOptions } from '@typebot.io/schemas/features/blocks/inputs/text/constants'
test.describe.parallel('Text input block', () => {
test('options should work', async ({ page }) => {
@@ -12,7 +13,6 @@ test.describe.parallel('Text input block', () => {
id: typebotId,
...parseDefaultGroupWithBlock({
type: InputBlockType.TEXT,
options: defaultTextInputOptions,
}),
},
])

View File

@@ -1,19 +1,20 @@
import { TextInput } from '@/components/inputs'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { FormLabel, Stack } from '@chakra-ui/react'
import { UrlInputOptions, Variable } from '@typebot.io/schemas'
import { UrlInputBlock, Variable } from '@typebot.io/schemas'
import { defaultUrlInputOptions } from '@typebot.io/schemas/features/blocks/inputs/url/constants'
import React from 'react'
type Props = {
options: UrlInputOptions
onOptionsChange: (options: UrlInputOptions) => void
options: UrlInputBlock['options']
onOptionsChange: (options: UrlInputBlock['options']) => void
}
export const UrlInputSettings = ({ options, onOptionsChange }: Props) => {
const handlePlaceholderChange = (placeholder: string) =>
onOptionsChange({ ...options, labels: { ...options.labels, placeholder } })
onOptionsChange({ ...options, labels: { ...options?.labels, placeholder } })
const handleButtonLabelChange = (button: string) =>
onOptionsChange({ ...options, labels: { ...options.labels, button } })
onOptionsChange({ ...options, labels: { ...options?.labels, button } })
const handleVariableChange = (variable?: Variable) =>
onOptionsChange({ ...options, variableId: variable?.id })
const handleRetryMessageChange = (retryMessageContent: string) =>
@@ -23,17 +24,25 @@ export const UrlInputSettings = ({ options, onOptionsChange }: Props) => {
<Stack spacing={4}>
<TextInput
label="Placeholder:"
defaultValue={options.labels.placeholder}
defaultValue={
options?.labels?.placeholder ??
defaultUrlInputOptions.labels.placeholder
}
onChange={handlePlaceholderChange}
/>
<TextInput
label="Button label:"
defaultValue={options.labels.button}
defaultValue={
options?.labels?.button ?? defaultUrlInputOptions.labels.button
}
onChange={handleButtonLabelChange}
/>
<TextInput
label="Retry message:"
defaultValue={options.retryMessageContent}
defaultValue={
options?.retryMessageContent ??
defaultUrlInputOptions.retryMessageContent
}
onChange={handleRetryMessageChange}
/>
<Stack>
@@ -41,7 +50,7 @@ export const UrlInputSettings = ({ options, onOptionsChange }: Props) => {
Save answer in a variable:
</FormLabel>
<VariableSearchInput
initialVariableId={options.variableId}
initialVariableId={options?.variableId}
onSelectVariable={handleVariableChange}
/>
</Stack>

View File

@@ -1,18 +1,19 @@
import React from 'react'
import { Text } from '@chakra-ui/react'
import { UrlInputOptions } from '@typebot.io/schemas'
import { WithVariableContent } from '@/features/graph/components/nodes/block/WithVariableContent'
import { UrlInputBlock } from '@typebot.io/schemas'
import { defaultUrlInputOptions } from '@typebot.io/schemas/features/blocks/inputs/url/constants'
type Props = {
variableId?: string
placeholder: UrlInputOptions['labels']['placeholder']
options: UrlInputBlock['options']
}
export const UrlNodeContent = ({ placeholder, variableId }: Props) =>
variableId ? (
<WithVariableContent variableId={variableId} />
export const UrlNodeContent = ({ options }: Props) =>
options?.variableId ? (
<WithVariableContent variableId={options.variableId} />
) : (
<Text color={'gray.500'} w="90%">
{placeholder}
{options?.labels?.placeholder ??
defaultUrlInputOptions.labels.placeholder}
</Text>
)

View File

@@ -1,8 +1,9 @@
import test, { expect } from '@playwright/test'
import { createTypebots } from '@typebot.io/lib/playwright/databaseActions'
import { parseDefaultGroupWithBlock } from '@typebot.io/lib/playwright/databaseHelpers'
import { defaultUrlInputOptions, InputBlockType } from '@typebot.io/schemas'
import { createId } from '@paralleldrive/cuid2'
import { InputBlockType } from '@typebot.io/schemas/features/blocks/inputs/constants'
import { defaultUrlInputOptions } from '@typebot.io/schemas/features/blocks/inputs/url/constants'
test.describe('Url input block', () => {
test('options should work', async ({ page }) => {
@@ -12,7 +13,6 @@ test.describe('Url input block', () => {
id: typebotId,
...parseDefaultGroupWithBlock({
type: InputBlockType.URL,
options: defaultUrlInputOptions,
}),
},
])