🌐 Add translation keys for input blocks (#1114)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Integrated localization support across various components using the `useTranslate` hook for dynamic translations. - **Enhancements** - Replaced hardcoded text with localized strings to support multiple languages in the user interface. - **User Interface** - Updated labels, placeholders, tooltips, and button texts to utilize translated content for a multilingual experience. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Baptiste Arnaud <baptiste.arnaud95@gmail.com>
This commit is contained in:
@ -1,4 +1,5 @@
|
||||
import { useColorModeValue, HStack, Tag, Text } from '@chakra-ui/react'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
import { Variable } from '@typebot.io/schemas'
|
||||
|
||||
export const SetVariableLabel = ({
|
||||
@ -8,6 +9,7 @@ export const SetVariableLabel = ({
|
||||
variableId: string
|
||||
variables?: Variable[]
|
||||
}) => {
|
||||
const { t } = useTranslate()
|
||||
const textColor = useColorModeValue('gray.600', 'gray.400')
|
||||
const variableName = variables?.find(
|
||||
(variable) => variable.id === variableId
|
||||
@ -17,7 +19,7 @@ export const SetVariableLabel = ({
|
||||
return (
|
||||
<HStack fontStyle="italic" spacing={1}>
|
||||
<Text fontSize="sm" color={textColor}>
|
||||
Set
|
||||
{t('variables.set')}
|
||||
</Text>
|
||||
<Tag bg="orange.400" color="white" size="sm">
|
||||
{variableName}
|
||||
|
@ -33,6 +33,7 @@ import { byId, isDefined, isNotDefined } from '@typebot.io/lib'
|
||||
import { useOutsideClick } from '@/hooks/useOutsideClick'
|
||||
import { useParentModal } from '@/features/graph/providers/ParentModalProvider'
|
||||
import { MoreInfoTooltip } from '../MoreInfoTooltip'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
type Props = {
|
||||
initialVariableId: string | undefined
|
||||
@ -78,6 +79,7 @@ export const VariableSearchInput = ({
|
||||
const createVariableItemRef = useRef<HTMLButtonElement | null>(null)
|
||||
const itemsRef = useRef<(HTMLButtonElement | null)[]>([])
|
||||
const { ref: parentModalRef } = useParentModal()
|
||||
const { t } = useTranslate()
|
||||
|
||||
useOutsideClick({
|
||||
ref: dropdownRef,
|
||||
@ -137,7 +139,7 @@ export const VariableSearchInput = ({
|
||||
const handleRenameVariableClick =
|
||||
(variable: Variable) => (e: React.MouseEvent) => {
|
||||
e.stopPropagation()
|
||||
const name = prompt('Rename variable', variable.name)
|
||||
const name = prompt(t('variables.rename'), variable.name)
|
||||
if (!name) return
|
||||
updateVariable(variable.id, { name })
|
||||
setFilteredItems(
|
||||
@ -221,7 +223,7 @@ export const VariableSearchInput = ({
|
||||
onChange={onInputChange}
|
||||
onFocus={openDropdown}
|
||||
onKeyDown={handleKeyUp}
|
||||
placeholder={placeholder ?? 'Select a variable'}
|
||||
placeholder={placeholder ?? t('variables.select')}
|
||||
autoComplete="off"
|
||||
{...inputProps}
|
||||
/>
|
||||
@ -255,7 +257,7 @@ export const VariableSearchInput = ({
|
||||
: 'transparent'
|
||||
}
|
||||
>
|
||||
Create
|
||||
{t('create')}
|
||||
<Tag colorScheme="orange" ml="1">
|
||||
<Text noOfLines={0} display="block">
|
||||
{inputValue}
|
||||
@ -296,13 +298,13 @@ export const VariableSearchInput = ({
|
||||
<HStack>
|
||||
<IconButton
|
||||
icon={<EditIcon />}
|
||||
aria-label="Rename variable"
|
||||
aria-label={t('variables.rename')}
|
||||
size="xs"
|
||||
onClick={handleRenameVariableClick(item)}
|
||||
/>
|
||||
<IconButton
|
||||
icon={<TrashIcon />}
|
||||
aria-label="Remove variable"
|
||||
aria-label={t('variables.remove')}
|
||||
size="xs"
|
||||
onClick={handleDeleteVariableClick(item)}
|
||||
/>
|
||||
|
@ -4,6 +4,7 @@ import { Stack, Tag, Text, Wrap } from '@chakra-ui/react'
|
||||
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
|
||||
import { SetVariableLabel } from '@/components/SetVariableLabel'
|
||||
import { ItemNodesList } from '@/features/graph/components/nodes/item/ItemNodesList'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
type Props = {
|
||||
block: ChoiceInputBlock
|
||||
@ -12,6 +13,7 @@ type Props = {
|
||||
|
||||
export const ButtonsBlockNode = ({ block, indices }: Props) => {
|
||||
const { typebot } = useTypebot()
|
||||
const { t } = useTranslate()
|
||||
const dynamicVariableName = typebot?.variables.find(
|
||||
(variable) => variable.id === block.options?.dynamicVariableId
|
||||
)?.name
|
||||
@ -20,11 +22,11 @@ export const ButtonsBlockNode = ({ block, indices }: Props) => {
|
||||
<Stack w="full">
|
||||
{block.options?.dynamicVariableId ? (
|
||||
<Wrap spacing={1}>
|
||||
<Text>Display</Text>
|
||||
<Text>{t('blocks.inputs.button.variables.display.label')}</Text>
|
||||
<Tag bg="orange.400" color="white">
|
||||
{dynamicVariableName}
|
||||
</Tag>
|
||||
<Text>buttons</Text>
|
||||
<Text>{t('blocks.inputs.button.variables.buttons.label')}</Text>
|
||||
</Wrap>
|
||||
) : (
|
||||
<ItemNodesList block={block} indices={indices} />
|
||||
|
@ -6,6 +6,7 @@ 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'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
type Props = {
|
||||
options?: ChoiceInputBlock['options']
|
||||
@ -13,6 +14,7 @@ type Props = {
|
||||
}
|
||||
|
||||
export const ButtonsBlockSettings = ({ options, onOptionsChange }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
const updateIsMultiple = (isMultipleChoice: boolean) =>
|
||||
onOptionsChange({ ...options, isMultipleChoice })
|
||||
const updateIsSearchable = (isSearchable: boolean) =>
|
||||
@ -29,7 +31,7 @@ export const ButtonsBlockSettings = ({ options, onOptionsChange }: Props) => {
|
||||
return (
|
||||
<Stack spacing={4}>
|
||||
<SwitchWithRelatedSettings
|
||||
label="Multiple choice?"
|
||||
label={t('blocks.inputs.settings.multipleChoice.label')}
|
||||
initialValue={
|
||||
options?.isMultipleChoice ??
|
||||
defaultChoiceInputOptions.isMultipleChoice
|
||||
@ -37,35 +39,34 @@ export const ButtonsBlockSettings = ({ options, onOptionsChange }: Props) => {
|
||||
onCheckChange={updateIsMultiple}
|
||||
>
|
||||
<TextInput
|
||||
label="Submit button label:"
|
||||
label={t('blocks.inputs.settings.submitButton.label')}
|
||||
defaultValue={
|
||||
options?.buttonLabel ?? defaultChoiceInputOptions.buttonLabel
|
||||
options?.buttonLabel ?? t('blocks.inputs.settings.buttonText.label')
|
||||
}
|
||||
onChange={updateButtonLabel}
|
||||
/>
|
||||
</SwitchWithRelatedSettings>
|
||||
<SwitchWithRelatedSettings
|
||||
label="Is searchable?"
|
||||
label={t('blocks.inputs.settings.isSearchable.label')}
|
||||
initialValue={
|
||||
options?.isSearchable ?? defaultChoiceInputOptions.isSearchable
|
||||
}
|
||||
onCheckChange={updateIsSearchable}
|
||||
>
|
||||
<TextInput
|
||||
label="Input placeholder:"
|
||||
label={t('blocks.inputs.settings.input.placeholder.label')}
|
||||
defaultValue={
|
||||
options?.searchInputPlaceholder ??
|
||||
defaultChoiceInputOptions.searchInputPlaceholder
|
||||
t('blocks.inputs.settings.input.filterOptions.label')
|
||||
}
|
||||
onChange={updateSearchInputPlaceholder}
|
||||
/>
|
||||
</SwitchWithRelatedSettings>
|
||||
<FormControl>
|
||||
<FormLabel>
|
||||
Dynamic data:{' '}
|
||||
{t('blocks.inputs.button.settings.dynamicData.label')}{' '}
|
||||
<MoreInfoTooltip>
|
||||
If defined, buttons will be dynamically displayed based on what the
|
||||
variable contains.
|
||||
{t('blocks.inputs.button.settings.dynamicData.infoText.label')}
|
||||
</MoreInfoTooltip>
|
||||
</FormLabel>
|
||||
<VariableSearchInput
|
||||
@ -75,7 +76,7 @@ export const ButtonsBlockSettings = ({ options, onOptionsChange }: Props) => {
|
||||
</FormControl>
|
||||
<Stack>
|
||||
<FormLabel mb="0" htmlFor="variable">
|
||||
Save answer in a variable:
|
||||
{t('blocks.inputs.settings.saveAnswer.label')}
|
||||
</FormLabel>
|
||||
<VariableSearchInput
|
||||
initialVariableId={options?.variableId}
|
||||
|
@ -21,6 +21,7 @@ import React, { useRef, useState } from 'react'
|
||||
import { isNotDefined } from '@typebot.io/lib'
|
||||
import { useGraph } from '@/features/graph/providers/GraphProvider'
|
||||
import { ButtonsItemSettings } from './ButtonsItemSettings'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
type Props = {
|
||||
item: ButtonItem
|
||||
@ -29,9 +30,12 @@ type Props = {
|
||||
}
|
||||
|
||||
export const ButtonsItemNode = ({ item, indices, isMouseOver }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
const { deleteItem, updateItem, createItem } = useTypebot()
|
||||
const { openedItemId, setOpenedItemId } = useGraph()
|
||||
const [itemValue, setItemValue] = useState(item.content ?? 'Click to edit')
|
||||
const [itemValue, setItemValue] = useState(
|
||||
item.content ?? t('blocks.inputs.button.clickToEdit.label')
|
||||
)
|
||||
const editableRef = useRef<HTMLDivElement | null>(null)
|
||||
const ref = useRef<HTMLDivElement | null>(null)
|
||||
const arrowColor = useColorModeValue('white', 'gray.800')
|
||||
@ -47,8 +51,16 @@ export const ButtonsItemNode = ({ item, indices, isMouseOver }: Props) => {
|
||||
}
|
||||
|
||||
const handleKeyPress = (e: React.KeyboardEvent<HTMLDivElement>) => {
|
||||
if (e.key === 'Escape' && itemValue === 'Click to edit') deleteItem(indices)
|
||||
if (e.key === 'Enter' && itemValue !== '' && itemValue !== 'Click to edit')
|
||||
if (
|
||||
e.key === 'Escape' &&
|
||||
itemValue === t('blocks.inputs.button.clickToEdit.label')
|
||||
)
|
||||
deleteItem(indices)
|
||||
if (
|
||||
e.key === 'Enter' &&
|
||||
itemValue !== '' &&
|
||||
itemValue !== t('blocks.inputs.button.clickToEdit.label')
|
||||
)
|
||||
handlePlusClick()
|
||||
}
|
||||
|
||||
@ -82,7 +94,11 @@ export const ButtonsItemNode = ({ item, indices, isMouseOver }: Props) => {
|
||||
>
|
||||
<EditablePreview
|
||||
w="full"
|
||||
color={item.content !== 'Click to edit' ? 'inherit' : 'gray.500'}
|
||||
color={
|
||||
item.content !== t('blocks.inputs.button.clickToEdit.label')
|
||||
? 'inherit'
|
||||
: 'gray.500'
|
||||
}
|
||||
cursor="pointer"
|
||||
/>
|
||||
<EditableInput onMouseDownCapture={(e) => e.stopPropagation()} />
|
||||
@ -101,7 +117,7 @@ export const ButtonsItemNode = ({ item, indices, isMouseOver }: Props) => {
|
||||
>
|
||||
<Flex bgColor={useColorModeValue('white', 'gray.800')} rounded="md">
|
||||
<IconButton
|
||||
aria-label="Open settings"
|
||||
aria-label={t('blocks.inputs.button.openSettings.ariaLabel')}
|
||||
icon={<SettingsIcon />}
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
@ -121,7 +137,7 @@ export const ButtonsItemNode = ({ item, indices, isMouseOver }: Props) => {
|
||||
unmountOnExit
|
||||
>
|
||||
<IconButton
|
||||
aria-label="Add item"
|
||||
aria-label={t('blocks.inputs.button.addItem.ariaLabel')}
|
||||
icon={<PlusIcon />}
|
||||
size="xs"
|
||||
shadow="md"
|
||||
|
@ -4,6 +4,7 @@ import { SwitchWithRelatedSettings } from '@/components/SwitchWithRelatedSetting
|
||||
import { ConditionForm } from '@/features/blocks/logic/condition/components/ConditionForm'
|
||||
import { ButtonItem, Condition } from '@typebot.io/schemas'
|
||||
import { LogicalOperator } from '@typebot.io/schemas/features/blocks/logic/condition/constants'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
type Props = {
|
||||
item: ButtonItem
|
||||
@ -11,6 +12,8 @@ type Props = {
|
||||
}
|
||||
|
||||
export const ButtonsItemSettings = ({ item, onSettingsChange }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
|
||||
const updateIsDisplayConditionEnabled = (isEnabled: boolean) =>
|
||||
onSettingsChange({
|
||||
...item,
|
||||
@ -32,8 +35,10 @@ export const ButtonsItemSettings = ({ item, onSettingsChange }: Props) => {
|
||||
return (
|
||||
<Stack spacing={4}>
|
||||
<SwitchWithRelatedSettings
|
||||
label="Display condition"
|
||||
moreInfoContent="Only display this item if a condition is met."
|
||||
label={t('blocks.inputs.settings.displayCondition.label')}
|
||||
moreInfoContent={t(
|
||||
'blocks.inputs.button.buttonSettings.displayCondition.infoText.label'
|
||||
)}
|
||||
initialValue={item.displayCondition?.isEnabled ?? false}
|
||||
onCheckChange={updateIsDisplayConditionEnabled}
|
||||
>
|
||||
|
@ -6,6 +6,7 @@ import { FormLabel, Stack } from '@chakra-ui/react'
|
||||
import { DateInputBlock, Variable } from '@typebot.io/schemas'
|
||||
import React from 'react'
|
||||
import { defaultDateInputOptions } from '@typebot.io/schemas/features/blocks/inputs/date/constants'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
type Props = {
|
||||
options: DateInputBlock['options']
|
||||
@ -13,6 +14,7 @@ type Props = {
|
||||
}
|
||||
|
||||
export const DateInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
const updateFromLabel = (from: string) =>
|
||||
onOptionsChange({ ...options, labels: { ...options?.labels, from } })
|
||||
const updateToLabel = (to: string) =>
|
||||
@ -41,64 +43,69 @@ export const DateInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
return (
|
||||
<Stack spacing={4}>
|
||||
<SwitchWithRelatedSettings
|
||||
label="Is range?"
|
||||
label={t('blocks.inputs.date.settings.isRange.label')}
|
||||
initialValue={options?.isRange ?? defaultDateInputOptions.isRange}
|
||||
onCheckChange={updateIsRange}
|
||||
>
|
||||
<TextInput
|
||||
label="From label:"
|
||||
label={t('blocks.inputs.date.settings.from.label')}
|
||||
defaultValue={
|
||||
options?.labels?.from ?? defaultDateInputOptions.labels.from
|
||||
}
|
||||
onChange={updateFromLabel}
|
||||
/>
|
||||
<TextInput
|
||||
label="To label:"
|
||||
label={t('blocks.inputs.date.settings.to.label')}
|
||||
defaultValue={
|
||||
options?.labels?.to ?? defaultDateInputOptions.labels.to
|
||||
options?.labels?.to ??
|
||||
t('blocks.inputs.date.settings.toInputValue.label')
|
||||
}
|
||||
onChange={updateToLabel}
|
||||
/>
|
||||
</SwitchWithRelatedSettings>
|
||||
<SwitchWithLabel
|
||||
label="With time?"
|
||||
label={t('blocks.inputs.date.settings.withTime.label')}
|
||||
initialValue={options?.hasTime ?? defaultDateInputOptions.hasTime}
|
||||
onCheckChange={updateHasTime}
|
||||
/>
|
||||
<TextInput
|
||||
label="Button label:"
|
||||
label={t('blocks.inputs.settings.button.label')}
|
||||
defaultValue={
|
||||
options?.labels?.button ?? defaultDateInputOptions.labels.button
|
||||
}
|
||||
onChange={updateButtonLabel}
|
||||
/>
|
||||
<TextInput
|
||||
label="Min:"
|
||||
label={t('blocks.inputs.settings.min.label')}
|
||||
defaultValue={options?.min}
|
||||
placeholder={options?.hasTime ? 'YYYY-MM-DDTHH:mm' : 'YYYY-MM-DD'}
|
||||
onChange={updateMin}
|
||||
/>
|
||||
<TextInput
|
||||
label="Max:"
|
||||
label={t('blocks.inputs.settings.max.label')}
|
||||
defaultValue={options?.max}
|
||||
placeholder={options?.hasTime ? 'YYYY-MM-DDTHH:mm' : 'YYYY-MM-DD'}
|
||||
onChange={updateMax}
|
||||
/>
|
||||
<TextInput
|
||||
label="Format:"
|
||||
label={t('blocks.inputs.date.settings.format.label')}
|
||||
defaultValue={
|
||||
options?.format ??
|
||||
(options?.hasTime
|
||||
? defaultDateInputOptions.formatWithTime
|
||||
: defaultDateInputOptions.format)
|
||||
}
|
||||
moreInfoTooltip="i.e dd/MM/yyyy, MM/dd/yy, yyyy-MM-dd"
|
||||
moreInfoTooltip={`
|
||||
${t(
|
||||
'blocks.inputs.date.settings.format.example.label'
|
||||
)} dd/MM/yyyy, MM/dd/yy, yyyy-MM-dd
|
||||
`}
|
||||
placeholder={options?.hasTime ? 'dd/MM/yyyy HH:mm' : 'dd/MM/yyyy'}
|
||||
onChange={updateFormat}
|
||||
/>
|
||||
<Stack>
|
||||
<FormLabel mb="0" htmlFor="variable">
|
||||
Save answer in a variable:
|
||||
{t('blocks.inputs.settings.saveAnswer.label')}
|
||||
</FormLabel>
|
||||
<VariableSearchInput
|
||||
initialVariableId={options?.variableId}
|
||||
|
@ -1,13 +1,17 @@
|
||||
import React from 'react'
|
||||
import { Text } from '@chakra-ui/react'
|
||||
import { WithVariableContent } from '@/features/graph/components/nodes/block/WithVariableContent'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
type Props = {
|
||||
variableId?: string
|
||||
}
|
||||
export const DateNodeContent = ({ variableId }: Props) =>
|
||||
variableId ? (
|
||||
export const DateNodeContent = ({ variableId }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
|
||||
return variableId ? (
|
||||
<WithVariableContent variableId={variableId} />
|
||||
) : (
|
||||
<Text color={'gray.500'}>Pick a date...</Text>
|
||||
<Text color={'gray.500'}>{t('blocks.inputs.date.placeholder.label')}</Text>
|
||||
)
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { TextInput } from '@/components/inputs'
|
||||
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
|
||||
import { FormLabel, Stack } from '@chakra-ui/react'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
import { EmailInputBlock, Variable } from '@typebot.io/schemas'
|
||||
import { defaultEmailInputOptions } from '@typebot.io/schemas/features/blocks/inputs/email/constants'
|
||||
import React from 'react'
|
||||
@ -11,6 +12,7 @@ type Props = {
|
||||
}
|
||||
|
||||
export const EmailInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
const handlePlaceholderChange = (placeholder: string) =>
|
||||
onOptionsChange({ ...options, labels: { ...options?.labels, placeholder } })
|
||||
const handleButtonLabelChange = (button: string) =>
|
||||
@ -23,7 +25,7 @@ export const EmailInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
return (
|
||||
<Stack spacing={4}>
|
||||
<TextInput
|
||||
label="Placeholder:"
|
||||
label={t('blocks.inputs.settings.placeholder.label')}
|
||||
defaultValue={
|
||||
options?.labels?.placeholder ??
|
||||
defaultEmailInputOptions.labels.placeholder
|
||||
@ -31,14 +33,14 @@ export const EmailInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
onChange={handlePlaceholderChange}
|
||||
/>
|
||||
<TextInput
|
||||
label="Button label:"
|
||||
label={t('blocks.inputs.settings.button.label')}
|
||||
defaultValue={
|
||||
options?.labels?.button ?? defaultEmailInputOptions.labels.button
|
||||
}
|
||||
onChange={handleButtonLabelChange}
|
||||
/>
|
||||
<TextInput
|
||||
label="Retry message:"
|
||||
label={t('blocks.inputs.settings.retryMessage.label')}
|
||||
defaultValue={
|
||||
options?.retryMessageContent ??
|
||||
defaultEmailInputOptions.retryMessageContent
|
||||
@ -47,7 +49,7 @@ export const EmailInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
/>
|
||||
<Stack>
|
||||
<FormLabel mb="0" htmlFor="variable">
|
||||
Save answer in a variable:
|
||||
{t('blocks.inputs.settings.saveAnswer.label')}
|
||||
</FormLabel>
|
||||
<VariableSearchInput
|
||||
initialVariableId={options?.variableId}
|
||||
|
@ -1,16 +1,22 @@
|
||||
import { WithVariableContent } from '@/features/graph/components/nodes/block/WithVariableContent'
|
||||
import { Text } from '@chakra-ui/react'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
import { FileInputBlock } from '@typebot.io/schemas'
|
||||
|
||||
type Props = {
|
||||
options: FileInputBlock['options']
|
||||
}
|
||||
|
||||
export const FileInputContent = ({ options }: Props) =>
|
||||
options?.variableId ? (
|
||||
export const FileInputContent = ({ options }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
|
||||
return options?.variableId ? (
|
||||
<WithVariableContent variableId={options.variableId} />
|
||||
) : (
|
||||
<Text noOfLines={1} pr="6">
|
||||
Collect {options?.isMultipleAllowed ? 'files' : 'file'}
|
||||
{options?.isMultipleAllowed
|
||||
? t('blocks.inputs.file.collectMultiple.label')
|
||||
: t('blocks.inputs.file.collectSingle.label')}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ 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'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
type Props = {
|
||||
options: FileInputBlock['options']
|
||||
@ -13,6 +14,8 @@ type Props = {
|
||||
}
|
||||
|
||||
export const FileInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
|
||||
const handleButtonLabelChange = (button: string) =>
|
||||
onOptionsChange({ ...options, labels: { ...options?.labels, button } })
|
||||
|
||||
@ -37,12 +40,12 @@ export const FileInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
return (
|
||||
<Stack spacing={4}>
|
||||
<SwitchWithLabel
|
||||
label="Required?"
|
||||
label={t('blocks.inputs.file.settings.required.label')}
|
||||
initialValue={options?.isRequired ?? defaultFileInputOptions.isRequired}
|
||||
onCheckChange={handleRequiredChange}
|
||||
/>
|
||||
<SwitchWithLabel
|
||||
label="Allow multiple files?"
|
||||
label={t('blocks.inputs.file.settings.allowMultiple.label')}
|
||||
initialValue={
|
||||
options?.isMultipleAllowed ??
|
||||
defaultFileInputOptions.isMultipleAllowed
|
||||
@ -50,7 +53,9 @@ export const FileInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
onCheckChange={handleMultipleFilesChange}
|
||||
/>
|
||||
<Stack>
|
||||
<FormLabel mb="0">Placeholder:</FormLabel>
|
||||
<FormLabel mb="0">
|
||||
{t('blocks.inputs.settings.placeholder.label')}
|
||||
</FormLabel>
|
||||
<CodeEditor
|
||||
lang="html"
|
||||
onChange={handlePlaceholderLabelChange}
|
||||
@ -63,7 +68,7 @@ export const FileInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
/>
|
||||
</Stack>
|
||||
<TextInput
|
||||
label="Button label:"
|
||||
label={t('blocks.inputs.settings.button.label')}
|
||||
defaultValue={
|
||||
options?.labels?.button ?? defaultFileInputOptions.labels.button
|
||||
}
|
||||
@ -71,7 +76,7 @@ export const FileInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
withVariableButton={false}
|
||||
/>
|
||||
<TextInput
|
||||
label="Clear button label:"
|
||||
label={t('blocks.inputs.file.settings.clear.label')}
|
||||
defaultValue={
|
||||
options?.labels?.clear ?? defaultFileInputOptions.labels.clear
|
||||
}
|
||||
@ -79,7 +84,7 @@ export const FileInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
withVariableButton={false}
|
||||
/>
|
||||
<TextInput
|
||||
label="Skip button label:"
|
||||
label={t('blocks.inputs.file.settings.skip.label')}
|
||||
defaultValue={
|
||||
options?.labels?.skip ?? defaultFileInputOptions.labels.skip
|
||||
}
|
||||
@ -88,7 +93,9 @@ export const FileInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
/>
|
||||
<Stack>
|
||||
<FormLabel mb="0" htmlFor="variable">
|
||||
Save upload URL{options?.isMultipleAllowed ? 's' : ''} in a variable:
|
||||
{options?.isMultipleAllowed
|
||||
? t('blocks.inputs.file.settings.saveMultipleUpload.label')
|
||||
: t('blocks.inputs.file.settings.saveSingleUpload.label')}
|
||||
</FormLabel>
|
||||
<VariableSearchInput
|
||||
initialVariableId={options?.variableId}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { TextInput, NumberInput } from '@/components/inputs'
|
||||
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
|
||||
import { FormLabel, Stack } from '@chakra-ui/react'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
import { NumberInputBlock, Variable } from '@typebot.io/schemas'
|
||||
import { defaultNumberInputOptions } from '@typebot.io/schemas/features/blocks/inputs/number/constants'
|
||||
import React from 'react'
|
||||
@ -11,6 +12,7 @@ type Props = {
|
||||
}
|
||||
|
||||
export const NumberInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
const handlePlaceholderChange = (placeholder: string) =>
|
||||
onOptionsChange({ ...options, labels: { ...options?.labels, placeholder } })
|
||||
const handleButtonLabelChange = (button: string) =>
|
||||
@ -31,7 +33,7 @@ export const NumberInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
return (
|
||||
<Stack spacing={4}>
|
||||
<TextInput
|
||||
label="Placeholder:"
|
||||
label={t('blocks.inputs.settings.placeholder.label')}
|
||||
defaultValue={
|
||||
options?.labels?.placeholder ??
|
||||
defaultNumberInputOptions.labels.placeholder
|
||||
@ -39,30 +41,30 @@ export const NumberInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
onChange={handlePlaceholderChange}
|
||||
/>
|
||||
<TextInput
|
||||
label="Button label:"
|
||||
label={t('blocks.inputs.settings.button.label')}
|
||||
defaultValue={
|
||||
options?.labels?.button ?? defaultNumberInputOptions.labels.button
|
||||
}
|
||||
onChange={handleButtonLabelChange}
|
||||
/>
|
||||
<NumberInput
|
||||
label="Min:"
|
||||
label={t('blocks.inputs.settings.min.label')}
|
||||
defaultValue={options?.min}
|
||||
onValueChange={handleMinChange}
|
||||
/>
|
||||
<NumberInput
|
||||
label="Max:"
|
||||
label={t('blocks.inputs.settings.max.label')}
|
||||
defaultValue={options?.max}
|
||||
onValueChange={handleMaxChange}
|
||||
/>
|
||||
<NumberInput
|
||||
label="Step:"
|
||||
label={t('blocks.inputs.number.settings.step.label')}
|
||||
defaultValue={options?.step}
|
||||
onValueChange={handleStepChange}
|
||||
/>
|
||||
<Stack>
|
||||
<FormLabel mb="0" htmlFor="variable">
|
||||
Save answer in a variable:
|
||||
{t('blocks.inputs.settings.saveAnswer.label')}
|
||||
</FormLabel>
|
||||
<VariableSearchInput
|
||||
initialVariableId={options?.variableId}
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
import React from 'react'
|
||||
import { TextInput } from '@/components/inputs'
|
||||
import { PaymentAddress } from '@typebot.io/schemas'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
type Props = {
|
||||
address: PaymentAddress
|
||||
@ -16,6 +17,8 @@ type Props = {
|
||||
}
|
||||
|
||||
export const PaymentAddressSettings = ({ address, onAddressChange }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
|
||||
const updateCountry = (country: string) =>
|
||||
onAddressChange({
|
||||
...address,
|
||||
@ -56,37 +59,41 @@ export const PaymentAddressSettings = ({ address, onAddressChange }: Props) => {
|
||||
<Accordion allowToggle>
|
||||
<AccordionItem>
|
||||
<AccordionButton justifyContent="space-between">
|
||||
Address
|
||||
{t('blocks.inputs.payment.settings.address.label')}
|
||||
<AccordionIcon />
|
||||
</AccordionButton>
|
||||
<AccordionPanel py={4} as={Stack} spacing="4">
|
||||
<TextInput
|
||||
label="Country:"
|
||||
label={t('blocks.inputs.payment.settings.address.country.label')}
|
||||
defaultValue={address?.country ?? ''}
|
||||
onChange={updateCountry}
|
||||
/>
|
||||
<TextInput
|
||||
label="Line 1:"
|
||||
label={t('blocks.inputs.payment.settings.address.line.label', {
|
||||
line: '1',
|
||||
})}
|
||||
defaultValue={address?.line1 ?? ''}
|
||||
onChange={updateLine1}
|
||||
/>
|
||||
<TextInput
|
||||
label="Line 2:"
|
||||
label={t('blocks.inputs.payment.settings.address.line.label', {
|
||||
line: '2',
|
||||
})}
|
||||
defaultValue={address?.line2 ?? ''}
|
||||
onChange={updateLine2}
|
||||
/>
|
||||
<TextInput
|
||||
label="City:"
|
||||
label={t('blocks.inputs.payment.settings.address.city.label')}
|
||||
defaultValue={address?.city ?? ''}
|
||||
onChange={updateCity}
|
||||
/>
|
||||
<TextInput
|
||||
label="State:"
|
||||
label={t('blocks.inputs.payment.settings.address.state.label')}
|
||||
defaultValue={address?.state ?? ''}
|
||||
onChange={updateState}
|
||||
/>
|
||||
<TextInput
|
||||
label="Postal code:"
|
||||
label={t('blocks.inputs.payment.settings.address.postalCode.label')}
|
||||
defaultValue={address?.postalCode ?? ''}
|
||||
onChange={updatePostalCode}
|
||||
/>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Text } from '@chakra-ui/react'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
import { PaymentInputBlock } from '@typebot.io/schemas'
|
||||
|
||||
type Props = {
|
||||
@ -6,15 +7,22 @@ type Props = {
|
||||
}
|
||||
|
||||
export const PaymentInputContent = ({ block }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
|
||||
if (
|
||||
!block.options?.amount ||
|
||||
!block.options.credentialsId ||
|
||||
!block.options.currency
|
||||
)
|
||||
return <Text color="gray.500">Configure...</Text>
|
||||
return (
|
||||
<Text color="gray.500">
|
||||
{t('blocks.inputs.payment.placeholder.label')}
|
||||
</Text>
|
||||
)
|
||||
return (
|
||||
<Text noOfLines={1} pr="6">
|
||||
Collect {block.options.amount} {block.options.currency}
|
||||
{t('blocks.inputs.payment.collect.label')} {block.options.amount}{' '}
|
||||
{block.options.currency}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import {
|
||||
PaymentProvider,
|
||||
defaultPaymentInputOptions,
|
||||
} from '@typebot.io/schemas/features/blocks/inputs/payment/constants'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
type Props = {
|
||||
options: PaymentInputBlock['options']
|
||||
@ -32,6 +33,7 @@ type Props = {
|
||||
export const PaymentSettings = ({ options, onOptionsChange }: Props) => {
|
||||
const { workspace } = useWorkspace()
|
||||
const { isOpen, onOpen, onClose } = useDisclosure()
|
||||
const { t } = useTranslate()
|
||||
|
||||
const updateProvider = (provider: PaymentProvider) => {
|
||||
onOptionsChange({
|
||||
@ -104,7 +106,7 @@ export const PaymentSettings = ({ options, onOptionsChange }: Props) => {
|
||||
return (
|
||||
<Stack spacing={4}>
|
||||
<Stack>
|
||||
<Text>Provider:</Text>
|
||||
<Text>{t('blocks.inputs.payment.settings.provider.label')}</Text>
|
||||
<DropdownList
|
||||
onItemSelect={updateProvider}
|
||||
items={Object.values(PaymentProvider)}
|
||||
@ -112,7 +114,7 @@ export const PaymentSettings = ({ options, onOptionsChange }: Props) => {
|
||||
/>
|
||||
</Stack>
|
||||
<Stack>
|
||||
<Text>Account:</Text>
|
||||
<Text>{t('blocks.inputs.payment.settings.account.label')}</Text>
|
||||
{workspace && (
|
||||
<CredentialsDropdown
|
||||
type="stripe"
|
||||
@ -120,19 +122,24 @@ export const PaymentSettings = ({ options, onOptionsChange }: Props) => {
|
||||
currentCredentialsId={options?.credentialsId}
|
||||
onCredentialsSelect={updateCredentials}
|
||||
onCreateNewClick={onOpen}
|
||||
credentialsName="Stripe account"
|
||||
credentialsName={t(
|
||||
'blocks.inputs.payment.settings.accountText.label',
|
||||
{
|
||||
provider: 'Stripe',
|
||||
}
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
<HStack>
|
||||
<TextInput
|
||||
label="Price amount:"
|
||||
label={t('blocks.inputs.payment.settings.priceAmount.label')}
|
||||
onChange={updateAmount}
|
||||
defaultValue={options?.amount}
|
||||
placeholder="30.00"
|
||||
/>
|
||||
<Stack>
|
||||
<Text>Currency:</Text>
|
||||
<Text>{t('blocks.inputs.payment.settings.currency.label')}</Text>
|
||||
<Select
|
||||
placeholder="Select option"
|
||||
value={options?.currency ?? defaultPaymentInputOptions.currency}
|
||||
@ -147,14 +154,14 @@ export const PaymentSettings = ({ options, onOptionsChange }: Props) => {
|
||||
</Stack>
|
||||
</HStack>
|
||||
<TextInput
|
||||
label="Button label:"
|
||||
label={t('blocks.inputs.settings.button.label')}
|
||||
onChange={updateButtonLabel}
|
||||
defaultValue={
|
||||
options?.labels?.button ?? defaultPaymentInputOptions.labels.button
|
||||
}
|
||||
/>
|
||||
<TextInput
|
||||
label="Success message:"
|
||||
label={t('blocks.inputs.payment.settings.successMessage.label')}
|
||||
onChange={updateSuccessLabel}
|
||||
defaultValue={
|
||||
options?.labels?.success ?? defaultPaymentInputOptions.labels.success
|
||||
@ -163,30 +170,38 @@ export const PaymentSettings = ({ options, onOptionsChange }: Props) => {
|
||||
<Accordion allowToggle>
|
||||
<AccordionItem>
|
||||
<AccordionButton justifyContent="space-between">
|
||||
Additional information
|
||||
{t('blocks.inputs.payment.settings.additionalInformation.label')}
|
||||
<AccordionIcon />
|
||||
</AccordionButton>
|
||||
<AccordionPanel py={4} as={Stack} spacing="6">
|
||||
<TextInput
|
||||
label="Description:"
|
||||
label={t('blocks.inputs.settings.description.label')}
|
||||
defaultValue={options?.additionalInformation?.description}
|
||||
onChange={updateDescription}
|
||||
placeholder="A digital product"
|
||||
placeholder={t(
|
||||
'blocks.inputs.payment.settings.additionalInformation.description.placeholder.label'
|
||||
)}
|
||||
/>
|
||||
<TextInput
|
||||
label="Name:"
|
||||
label={t(
|
||||
'blocks.inputs.payment.settings.additionalInformation.name.label'
|
||||
)}
|
||||
defaultValue={options?.additionalInformation?.name}
|
||||
onChange={updateName}
|
||||
placeholder="John Smith"
|
||||
/>
|
||||
<TextInput
|
||||
label="Email:"
|
||||
label={t(
|
||||
'blocks.inputs.payment.settings.additionalInformation.email.label'
|
||||
)}
|
||||
defaultValue={options?.additionalInformation?.email}
|
||||
onChange={updateEmail}
|
||||
placeholder="john@gmail.com"
|
||||
/>
|
||||
<TextInput
|
||||
label="Phone number:"
|
||||
label={t(
|
||||
'blocks.inputs.payment.settings.additionalInformation.phone.label'
|
||||
)}
|
||||
defaultValue={options?.additionalInformation?.phoneNumber}
|
||||
onChange={updatePhoneNumber}
|
||||
placeholder="+33XXXXXXXXX"
|
||||
|
@ -23,6 +23,7 @@ import { StripeCredentials } from '@typebot.io/schemas'
|
||||
import { trpc } from '@/lib/trpc'
|
||||
import { isNotEmpty } from '@typebot.io/lib'
|
||||
import { useUser } from '@/features/account/hooks/useUser'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
type Props = {
|
||||
isOpen: boolean
|
||||
@ -35,6 +36,7 @@ export const StripeConfigModal = ({
|
||||
onNewCredentials,
|
||||
onClose,
|
||||
}: Props) => {
|
||||
const { t } = useTranslate()
|
||||
const { user } = useUser()
|
||||
const { workspace } = useWorkspace()
|
||||
const [isCreating, setIsCreating] = useState(false)
|
||||
@ -122,13 +124,17 @@ export const StripeConfigModal = ({
|
||||
<Modal isOpen={isOpen} onClose={onClose}>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>Connect Stripe account</ModalHeader>
|
||||
<ModalHeader>
|
||||
{t('blocks.inputs.payment.settings.stripeConfig.title.label')}
|
||||
</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<Stack as="form" spacing={4}>
|
||||
<TextInput
|
||||
isRequired
|
||||
label="Account name:"
|
||||
label={t(
|
||||
'blocks.inputs.payment.settings.stripeConfig.accountName.label'
|
||||
)}
|
||||
onChange={handleNameChange}
|
||||
placeholder="Typebot"
|
||||
withVariableButton={false}
|
||||
@ -136,9 +142,13 @@ export const StripeConfigModal = ({
|
||||
/>
|
||||
<Stack>
|
||||
<FormLabel>
|
||||
Test keys:{' '}
|
||||
{t(
|
||||
'blocks.inputs.payment.settings.stripeConfig.testKeys.label'
|
||||
)}{' '}
|
||||
<MoreInfoTooltip>
|
||||
Will be used when previewing the bot.
|
||||
{t(
|
||||
'blocks.inputs.payment.settings.stripeConfig.testKeys.infoText.label'
|
||||
)}
|
||||
</MoreInfoTooltip>
|
||||
</FormLabel>
|
||||
<HStack>
|
||||
@ -157,7 +167,11 @@ export const StripeConfigModal = ({
|
||||
</HStack>
|
||||
</Stack>
|
||||
<Stack>
|
||||
<FormLabel>Live keys:</FormLabel>
|
||||
<FormLabel>
|
||||
{t(
|
||||
'blocks.inputs.payment.settings.stripeConfig.liveKeys.label'
|
||||
)}
|
||||
</FormLabel>
|
||||
<HStack>
|
||||
<FormControl>
|
||||
<TextInput
|
||||
@ -179,9 +193,11 @@ export const StripeConfigModal = ({
|
||||
</Stack>
|
||||
|
||||
<Text>
|
||||
(You can find your keys{' '}
|
||||
({t('blocks.inputs.payment.settings.stripeConfig.findKeys.label')}{' '}
|
||||
<TextLink href="https://dashboard.stripe.com/apikeys" isExternal>
|
||||
here
|
||||
{t(
|
||||
'blocks.inputs.payment.settings.stripeConfig.findKeys.here.label'
|
||||
)}
|
||||
</TextLink>
|
||||
)
|
||||
</Text>
|
||||
@ -199,7 +215,7 @@ export const StripeConfigModal = ({
|
||||
}
|
||||
isLoading={isCreating}
|
||||
>
|
||||
Connect
|
||||
{t('connect')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Select } from '@chakra-ui/react'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
import React, { ChangeEvent } from 'react'
|
||||
|
||||
type Props = {
|
||||
@ -7,12 +8,15 @@ type Props = {
|
||||
}
|
||||
|
||||
export const CountryCodeSelect = ({ countryCode, onSelect }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
const handleOnChange = (e: ChangeEvent<HTMLSelectElement>) => {
|
||||
onSelect(e.target.value)
|
||||
}
|
||||
return (
|
||||
<Select
|
||||
placeholder="International"
|
||||
placeholder={t(
|
||||
'blocks.inputs.phone.settings.international.placeholder.label'
|
||||
)}
|
||||
value={countryCode}
|
||||
onChange={handleOnChange}
|
||||
>
|
||||
|
@ -4,6 +4,7 @@ import { FormLabel, Stack } from '@chakra-ui/react'
|
||||
import { PhoneNumberInputBlock, Variable } from '@typebot.io/schemas'
|
||||
import React from 'react'
|
||||
import { CountryCodeSelect } from './CountryCodeSelect'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
import { defaultPhoneInputOptions } from '@typebot.io/schemas/features/blocks/inputs/phone/constants'
|
||||
|
||||
type Props = {
|
||||
@ -12,6 +13,7 @@ type Props = {
|
||||
}
|
||||
|
||||
export const PhoneInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
const handlePlaceholderChange = (placeholder: string) =>
|
||||
onOptionsChange({ ...options, labels: { ...options?.labels, placeholder } })
|
||||
const handleButtonLabelChange = (button: string) =>
|
||||
@ -26,7 +28,7 @@ export const PhoneInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
return (
|
||||
<Stack spacing={4}>
|
||||
<TextInput
|
||||
label="Placeholder:"
|
||||
label={t('blocks.inputs.settings.placeholder.label')}
|
||||
defaultValue={
|
||||
options?.labels?.placeholder ??
|
||||
defaultPhoneInputOptions.labels.placeholder
|
||||
@ -34,7 +36,7 @@ export const PhoneInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
onChange={handlePlaceholderChange}
|
||||
/>
|
||||
<TextInput
|
||||
label="Button label:"
|
||||
label={t('blocks.inputs.settings.button.label')}
|
||||
defaultValue={
|
||||
options?.labels?.button ?? defaultPhoneInputOptions.labels.button
|
||||
}
|
||||
@ -42,7 +44,7 @@ export const PhoneInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
/>
|
||||
<Stack>
|
||||
<FormLabel mb="0" htmlFor="button">
|
||||
Default country:
|
||||
{t('blocks.inputs.phone.settings.defaultCountry.label')}
|
||||
</FormLabel>
|
||||
<CountryCodeSelect
|
||||
onSelect={handleDefaultCountryChange}
|
||||
@ -50,7 +52,7 @@ export const PhoneInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
/>
|
||||
</Stack>
|
||||
<TextInput
|
||||
label="Retry message:"
|
||||
label={t('blocks.inputs.settings.retryMessage.label')}
|
||||
defaultValue={
|
||||
options?.retryMessageContent ??
|
||||
defaultPhoneInputOptions.retryMessageContent
|
||||
@ -59,7 +61,7 @@ export const PhoneInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
/>
|
||||
<Stack>
|
||||
<FormLabel mb="0" htmlFor="variable">
|
||||
Save answer in a variable:
|
||||
{t('blocks.inputs.settings.saveAnswer.label')}
|
||||
</FormLabel>
|
||||
<VariableSearchInput
|
||||
initialVariableId={options?.variableId}
|
||||
|
@ -15,6 +15,7 @@ import { SwitchWithRelatedSettings } from '@/components/SwitchWithRelatedSetting
|
||||
import { ConditionForm } from '@/features/blocks/logic/condition/components/ConditionForm'
|
||||
import { Condition } from '@typebot.io/schemas'
|
||||
import { LogicalOperator } from '@typebot.io/schemas/features/blocks/logic/condition/constants'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
type Props = {
|
||||
workspaceId: string
|
||||
@ -31,6 +32,8 @@ export const PictureChoiceItemSettings = ({
|
||||
item,
|
||||
onItemChange,
|
||||
}: Props) => {
|
||||
const { t } = useTranslate()
|
||||
|
||||
const updateTitle = (title: string) => onItemChange({ ...item, title })
|
||||
|
||||
const updateImage = (pictureSrc: string) => {
|
||||
@ -61,13 +64,17 @@ export const PictureChoiceItemSettings = ({
|
||||
return (
|
||||
<Stack spacing={4}>
|
||||
<HStack>
|
||||
<Text fontWeight="medium">Image:</Text>
|
||||
<Text fontWeight="medium">
|
||||
{t('blocks.inputs.picture.itemSettings.image.label')}
|
||||
</Text>
|
||||
<Popover isLazy>
|
||||
{({ onClose }) => (
|
||||
<>
|
||||
<PopoverTrigger>
|
||||
<Button size="sm">
|
||||
{item.pictureSrc ? 'Change image' : 'Pick an image'}
|
||||
{item.pictureSrc
|
||||
? t('blocks.inputs.picture.itemSettings.image.change.label')
|
||||
: t('blocks.inputs.picture.itemSettings.image.pick.label')}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent p="4" w="500px">
|
||||
@ -91,17 +98,17 @@ export const PictureChoiceItemSettings = ({
|
||||
</Popover>
|
||||
</HStack>
|
||||
<TextInput
|
||||
label="Title:"
|
||||
label={t('blocks.inputs.picture.itemSettings.title.label')}
|
||||
defaultValue={item.title}
|
||||
onChange={updateTitle}
|
||||
/>
|
||||
<Textarea
|
||||
label="Description:"
|
||||
label={t('blocks.inputs.settings.description.label')}
|
||||
defaultValue={item.description}
|
||||
onChange={updateDescription}
|
||||
/>
|
||||
<SwitchWithRelatedSettings
|
||||
label="Display condition"
|
||||
label={t('blocks.inputs.settings.displayCondition.label')}
|
||||
initialValue={item.displayCondition?.isEnabled ?? false}
|
||||
onCheckChange={updateIsDisplayConditionEnabled}
|
||||
>
|
||||
|
@ -5,6 +5,7 @@ import { useTypebot } from '@/features/editor/providers/TypebotProvider'
|
||||
import { SetVariableLabel } from '@/components/SetVariableLabel'
|
||||
import { ItemNodesList } from '@/features/graph/components/nodes/item/ItemNodesList'
|
||||
import { PictureChoiceBlock } from '@typebot.io/schemas/features/blocks/inputs/pictureChoice'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
type Props = {
|
||||
block: PictureChoiceBlock
|
||||
@ -12,6 +13,7 @@ type Props = {
|
||||
}
|
||||
|
||||
export const PictureChoiceNode = ({ block, indices }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
const { typebot } = useTypebot()
|
||||
const dynamicVariableName = typebot?.variables.find(
|
||||
(variable) =>
|
||||
@ -22,11 +24,17 @@ export const PictureChoiceNode = ({ block, indices }: Props) => {
|
||||
<Stack w="full">
|
||||
{block.options?.dynamicItems?.isEnabled && dynamicVariableName ? (
|
||||
<Wrap spacing={1}>
|
||||
<Text>Display</Text>
|
||||
<Text>
|
||||
{t('blocks.inputs.picture.settings.dynamicVariables.display.label')}
|
||||
</Text>
|
||||
<Tag bg="orange.400" color="white">
|
||||
{dynamicVariableName}
|
||||
</Tag>
|
||||
<Text>pictures</Text>
|
||||
<Text>
|
||||
{t(
|
||||
'blocks.inputs.picture.settings.dynamicVariables.pictures.label'
|
||||
)}
|
||||
</Text>
|
||||
</Wrap>
|
||||
) : (
|
||||
<ItemNodesList block={block} indices={indices} />
|
||||
|
@ -6,6 +6,7 @@ import React from 'react'
|
||||
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'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
type Props = {
|
||||
options?: PictureChoiceBlock['options']
|
||||
@ -13,6 +14,8 @@ type Props = {
|
||||
}
|
||||
|
||||
export const PictureChoiceSettings = ({ options, onOptionsChange }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
|
||||
const updateIsMultiple = (isMultipleChoice: boolean) =>
|
||||
onOptionsChange({ ...options, isMultipleChoice })
|
||||
const updateButtonLabel = (buttonLabel: string) =>
|
||||
@ -63,14 +66,14 @@ export const PictureChoiceSettings = ({ options, onOptionsChange }: Props) => {
|
||||
return (
|
||||
<Stack spacing={4}>
|
||||
<SwitchWithRelatedSettings
|
||||
label="Is searchable?"
|
||||
label={t('blocks.inputs.settings.isSearchable.label')}
|
||||
initialValue={
|
||||
options?.isSearchable ?? defaultPictureChoiceOptions.isSearchable
|
||||
}
|
||||
onCheckChange={updateIsSearchable}
|
||||
>
|
||||
<TextInput
|
||||
label="Input placeholder:"
|
||||
label={t('blocks.inputs.settings.input.placeholder.label')}
|
||||
defaultValue={
|
||||
options?.searchInputPlaceholder ??
|
||||
defaultPictureChoiceOptions.searchInputPlaceholder
|
||||
@ -79,7 +82,7 @@ export const PictureChoiceSettings = ({ options, onOptionsChange }: Props) => {
|
||||
/>
|
||||
</SwitchWithRelatedSettings>
|
||||
<SwitchWithRelatedSettings
|
||||
label="Multiple choice?"
|
||||
label={t('blocks.inputs.settings.multipleChoice.label')}
|
||||
initialValue={
|
||||
options?.isMultipleChoice ??
|
||||
defaultPictureChoiceOptions.isMultipleChoice
|
||||
@ -87,7 +90,7 @@ export const PictureChoiceSettings = ({ options, onOptionsChange }: Props) => {
|
||||
onCheckChange={updateIsMultiple}
|
||||
>
|
||||
<TextInput
|
||||
label="Submit button label:"
|
||||
label={t('blocks.inputs.settings.submitButton.label')}
|
||||
defaultValue={
|
||||
options?.buttonLabel ?? defaultPictureChoiceOptions.buttonLabel
|
||||
}
|
||||
@ -96,7 +99,7 @@ export const PictureChoiceSettings = ({ options, onOptionsChange }: Props) => {
|
||||
</SwitchWithRelatedSettings>
|
||||
|
||||
<SwitchWithRelatedSettings
|
||||
label="Dynamic items?"
|
||||
label={t('blocks.inputs.picture.settings.dynamicItems.label')}
|
||||
initialValue={
|
||||
options?.dynamicItems?.isEnabled ??
|
||||
defaultPictureChoiceOptions.dynamicItems.isEnabled
|
||||
@ -105,7 +108,7 @@ export const PictureChoiceSettings = ({ options, onOptionsChange }: Props) => {
|
||||
>
|
||||
<Stack>
|
||||
<FormLabel mb="0" htmlFor="variable">
|
||||
Images:
|
||||
{t('blocks.inputs.picture.settings.dynamicItems.images.label')}
|
||||
</FormLabel>
|
||||
<VariableSearchInput
|
||||
initialVariableId={options?.dynamicItems?.pictureSrcsVariableId}
|
||||
@ -114,7 +117,7 @@ export const PictureChoiceSettings = ({ options, onOptionsChange }: Props) => {
|
||||
</Stack>
|
||||
<Stack>
|
||||
<FormLabel mb="0" htmlFor="variable">
|
||||
Titles:
|
||||
{t('blocks.inputs.picture.settings.dynamicItems.titles.label')}
|
||||
</FormLabel>
|
||||
<VariableSearchInput
|
||||
initialVariableId={options?.dynamicItems?.titlesVariableId}
|
||||
@ -123,7 +126,9 @@ export const PictureChoiceSettings = ({ options, onOptionsChange }: Props) => {
|
||||
</Stack>
|
||||
<Stack>
|
||||
<FormLabel mb="0" htmlFor="variable">
|
||||
Descriptions:
|
||||
{t(
|
||||
'blocks.inputs.picture.settings.dynamicItems.descriptions.label'
|
||||
)}
|
||||
</FormLabel>
|
||||
<VariableSearchInput
|
||||
initialVariableId={options?.dynamicItems?.descriptionsVariableId}
|
||||
@ -134,7 +139,7 @@ export const PictureChoiceSettings = ({ options, onOptionsChange }: Props) => {
|
||||
|
||||
<Stack>
|
||||
<FormLabel mb="0" htmlFor="variable">
|
||||
Save answer in a variable:
|
||||
{t('blocks.inputs.settings.saveAnswer.label')}
|
||||
</FormLabel>
|
||||
<VariableSearchInput
|
||||
initialVariableId={options?.variableId}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { WithVariableContent } from '@/features/graph/components/nodes/block/WithVariableContent'
|
||||
import { Text } from '@chakra-ui/react'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
import { RatingInputBlock } from '@typebot.io/schemas'
|
||||
import { defaultRatingInputOptions } from '@typebot.io/schemas/features/blocks/inputs/rating/constants'
|
||||
|
||||
@ -8,12 +9,17 @@ type Props = {
|
||||
block: RatingInputBlock
|
||||
}
|
||||
|
||||
export const RatingInputContent = ({ variableId, block }: Props) =>
|
||||
variableId ? (
|
||||
export const RatingInputContent = ({ variableId, block }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
|
||||
return variableId ? (
|
||||
<WithVariableContent variableId={variableId} />
|
||||
) : (
|
||||
<Text noOfLines={1} pr="6">
|
||||
Rate from {block.options?.buttonType === 'Icons' ? 1 : 0} to{' '}
|
||||
{t('blocks.inputs.rating.from.label')}{' '}
|
||||
{block.options?.buttonType === 'Icons' ? 1 : 0}{' '}
|
||||
{t('blocks.inputs.rating.to.label')}{' '}
|
||||
{block.options?.length ?? defaultRatingInputOptions.length}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ 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'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
type Props = {
|
||||
options: RatingInputBlock['options']
|
||||
@ -13,6 +14,8 @@ type Props = {
|
||||
}
|
||||
|
||||
export const RatingInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
|
||||
const handleLengthChange = (length: number) =>
|
||||
onOptionsChange({ ...options, length })
|
||||
|
||||
@ -52,7 +55,7 @@ export const RatingInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
<Stack spacing={4}>
|
||||
<Stack>
|
||||
<FormLabel mb="0" htmlFor="button">
|
||||
Maximum:
|
||||
{t('blocks.inputs.rating.settings.maximum.label')}
|
||||
</FormLabel>
|
||||
<DropdownList
|
||||
onItemSelect={handleLengthChange}
|
||||
@ -63,7 +66,7 @@ export const RatingInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
|
||||
<Stack>
|
||||
<FormLabel mb="0" htmlFor="button">
|
||||
Type:
|
||||
{t('blocks.inputs.rating.settings.type.label')}
|
||||
</FormLabel>
|
||||
<DropdownList
|
||||
onItemSelect={handleTypeChange}
|
||||
@ -76,7 +79,7 @@ export const RatingInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
|
||||
{options?.buttonType === 'Icons' && (
|
||||
<SwitchWithLabel
|
||||
label="Custom icon?"
|
||||
label={t('blocks.inputs.rating.settings.customIcon.label')}
|
||||
initialValue={
|
||||
options?.customIcon?.isEnabled ??
|
||||
defaultRatingInputOptions.customIcon.isEnabled
|
||||
@ -86,33 +89,43 @@ export const RatingInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
)}
|
||||
{options?.buttonType === 'Icons' && options.customIcon?.isEnabled && (
|
||||
<TextInput
|
||||
label="Icon SVG:"
|
||||
label={t('blocks.inputs.rating.settings.iconSVG.label')}
|
||||
defaultValue={options.customIcon.svg}
|
||||
onChange={handleIconSvgChange}
|
||||
placeholder="<svg>...</svg>"
|
||||
/>
|
||||
)}
|
||||
<TextInput
|
||||
label={`${options?.buttonType === 'Icons' ? '1' : '0'} label:`}
|
||||
label={t('blocks.inputs.rating.settings.rateLabel.label', {
|
||||
rate: options?.buttonType === 'Icons' ? '1' : '0',
|
||||
})}
|
||||
defaultValue={options?.labels?.left}
|
||||
onChange={handleLeftLabelChange}
|
||||
placeholder="Not likely at all"
|
||||
placeholder={t(
|
||||
'blocks.inputs.rating.settings.notLikely.placeholder.label'
|
||||
)}
|
||||
/>
|
||||
<TextInput
|
||||
label={`${length} label:`}
|
||||
label={t('blocks.inputs.rating.settings.rateLabel.label', {
|
||||
rate: length,
|
||||
})}
|
||||
defaultValue={options?.labels?.right}
|
||||
onChange={handleRightLabelChange}
|
||||
placeholder="Extremely likely"
|
||||
placeholder={t(
|
||||
'blocks.inputs.rating.settings.extremelyLikely.placeholder.label'
|
||||
)}
|
||||
/>
|
||||
<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.'
|
||||
label={t('blocks.inputs.rating.settings.oneClickSubmit.label')}
|
||||
moreInfoContent={t(
|
||||
'blocks.inputs.rating.settings.oneClickSubmit.infoText.label'
|
||||
)}
|
||||
initialValue={isOneClickSubmitEnabled}
|
||||
onCheckChange={handleOneClickSubmitChange}
|
||||
/>
|
||||
{!isOneClickSubmitEnabled && (
|
||||
<TextInput
|
||||
label="Button label:"
|
||||
label={t('blocks.inputs.settings.button.label')}
|
||||
defaultValue={
|
||||
options?.labels?.button ?? defaultRatingInputOptions.labels.button
|
||||
}
|
||||
@ -121,7 +134,7 @@ export const RatingInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
)}
|
||||
<Stack>
|
||||
<FormLabel mb="0" htmlFor="variable">
|
||||
Save answer in a variable:
|
||||
{t('blocks.inputs.settings.saveAnswer.label')}
|
||||
</FormLabel>
|
||||
<VariableSearchInput
|
||||
initialVariableId={options?.variableId}
|
||||
|
@ -2,6 +2,7 @@ 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 { useTranslate } from '@tolgee/react'
|
||||
import { TextInputBlock, Variable } from '@typebot.io/schemas'
|
||||
import { defaultTextInputOptions } from '@typebot.io/schemas/features/blocks/inputs/text/constants'
|
||||
import React from 'react'
|
||||
@ -12,6 +13,7 @@ type Props = {
|
||||
}
|
||||
|
||||
export const TextInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
const handlePlaceholderChange = (placeholder: string) =>
|
||||
onOptionsChange({ ...options, labels: { ...options?.labels, placeholder } })
|
||||
const handleButtonLabelChange = (button: string) =>
|
||||
@ -24,12 +26,12 @@ export const TextInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
return (
|
||||
<Stack spacing={4}>
|
||||
<SwitchWithLabel
|
||||
label="Long text?"
|
||||
label={t('blocks.inputs.text.settings.longText.label')}
|
||||
initialValue={options?.isLong ?? defaultTextInputOptions.isLong}
|
||||
onCheckChange={handleLongChange}
|
||||
/>
|
||||
<TextInput
|
||||
label="Placeholder:"
|
||||
label={t('blocks.inputs.settings.placeholder.label')}
|
||||
defaultValue={
|
||||
options?.labels?.placeholder ??
|
||||
defaultTextInputOptions.labels.placeholder
|
||||
@ -37,7 +39,7 @@ export const TextInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
onChange={handlePlaceholderChange}
|
||||
/>
|
||||
<TextInput
|
||||
label="Button label:"
|
||||
label={t('blocks.inputs.settings.button.label')}
|
||||
defaultValue={
|
||||
options?.labels?.button ?? defaultTextInputOptions.labels.button
|
||||
}
|
||||
@ -45,7 +47,7 @@ export const TextInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
/>
|
||||
<Stack>
|
||||
<FormLabel mb="0" htmlFor="variable">
|
||||
Save answer in a variable:
|
||||
{t('blocks.inputs.settings.saveAnswer.label')}
|
||||
</FormLabel>
|
||||
<VariableSearchInput
|
||||
initialVariableId={options?.variableId}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { TextInput } from '@/components/inputs'
|
||||
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
|
||||
import { FormLabel, Stack } from '@chakra-ui/react'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
import { UrlInputBlock, Variable } from '@typebot.io/schemas'
|
||||
import { defaultUrlInputOptions } from '@typebot.io/schemas/features/blocks/inputs/url/constants'
|
||||
import React from 'react'
|
||||
@ -11,6 +12,7 @@ type Props = {
|
||||
}
|
||||
|
||||
export const UrlInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
const handlePlaceholderChange = (placeholder: string) =>
|
||||
onOptionsChange({ ...options, labels: { ...options?.labels, placeholder } })
|
||||
const handleButtonLabelChange = (button: string) =>
|
||||
@ -23,7 +25,7 @@ export const UrlInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
return (
|
||||
<Stack spacing={4}>
|
||||
<TextInput
|
||||
label="Placeholder:"
|
||||
label={t('blocks.inputs.settings.placeholder.label')}
|
||||
defaultValue={
|
||||
options?.labels?.placeholder ??
|
||||
defaultUrlInputOptions.labels.placeholder
|
||||
@ -31,14 +33,14 @@ export const UrlInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
onChange={handlePlaceholderChange}
|
||||
/>
|
||||
<TextInput
|
||||
label="Button label:"
|
||||
label={t('blocks.inputs.settings.button.label')}
|
||||
defaultValue={
|
||||
options?.labels?.button ?? defaultUrlInputOptions.labels.button
|
||||
}
|
||||
onChange={handleButtonLabelChange}
|
||||
/>
|
||||
<TextInput
|
||||
label="Retry message:"
|
||||
label={t('blocks.inputs.settings.retryMessage.label')}
|
||||
defaultValue={
|
||||
options?.retryMessageContent ??
|
||||
defaultUrlInputOptions.retryMessageContent
|
||||
@ -47,7 +49,7 @@ export const UrlInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
/>
|
||||
<Stack>
|
||||
<FormLabel mb="0" htmlFor="variable">
|
||||
Save answer in a variable:
|
||||
{t('blocks.inputs.settings.saveAnswer.label')}
|
||||
</FormLabel>
|
||||
<VariableSearchInput
|
||||
initialVariableId={options?.variableId}
|
||||
|
@ -8,8 +8,8 @@ type Props = {
|
||||
options: UrlInputBlock['options']
|
||||
}
|
||||
|
||||
export const UrlNodeContent = ({ options }: Props) =>
|
||||
options?.variableId ? (
|
||||
export const UrlNodeContent = ({ options }: Props) => {
|
||||
return options?.variableId ? (
|
||||
<WithVariableContent variableId={options.variableId} />
|
||||
) : (
|
||||
<Text color={'gray.500'} w="90%">
|
||||
@ -17,3 +17,4 @@ export const UrlNodeContent = ({ options }: Props) =>
|
||||
defaultUrlInputOptions.labels.placeholder}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
@ -5,11 +5,14 @@ import { TableListItemProps } from '@/components/TableList'
|
||||
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
|
||||
import { TextInput } from '@/components/inputs'
|
||||
import { ComparisonOperators } from '@typebot.io/schemas/features/blocks/logic/condition/constants'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
export const ComparisonItem = ({
|
||||
item,
|
||||
onItemChange,
|
||||
}: TableListItemProps<Comparison>) => {
|
||||
const { t } = useTranslate()
|
||||
|
||||
const handleSelectVariable = (variable?: Variable) => {
|
||||
if (variable?.id === item.variableId) return
|
||||
onItemChange({ ...item, variableId: variable?.id })
|
||||
@ -31,13 +34,15 @@ export const ComparisonItem = ({
|
||||
<VariableSearchInput
|
||||
initialVariableId={item.variableId}
|
||||
onSelectVariable={handleSelectVariable}
|
||||
placeholder="Search for a variable"
|
||||
placeholder={t('variables.search')}
|
||||
/>
|
||||
<DropdownList
|
||||
currentItem={item.comparisonOperator}
|
||||
onItemSelect={handleSelectComparisonOperator}
|
||||
items={Object.values(ComparisonOperators)}
|
||||
placeholder="Select an operator"
|
||||
placeholder={t(
|
||||
'blocks.inputs.button.buttonSettings.displayCondition.selectOperator.label'
|
||||
)}
|
||||
/>
|
||||
{item.comparisonOperator !== ComparisonOperators.IS_SET &&
|
||||
item.comparisonOperator !== ComparisonOperators.IS_EMPTY && (
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Stack, Wrap, Tag, Text, useColorModeValue } from '@chakra-ui/react'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
import { byId } from '@typebot.io/lib'
|
||||
import { Condition, Variable } from '@typebot.io/schemas'
|
||||
import { ComparisonOperators } from '@typebot.io/schemas/features/blocks/logic/condition/constants'
|
||||
@ -15,6 +16,7 @@ export const ConditionContent = ({
|
||||
size = 'sm',
|
||||
displaySemicolon,
|
||||
}: Props) => {
|
||||
const { t } = useTranslate()
|
||||
const comparisonValueBg = useColorModeValue('gray.200', 'gray.700')
|
||||
return (
|
||||
<Stack>
|
||||
@ -22,7 +24,11 @@ export const ConditionContent = ({
|
||||
const variable = variables.find(byId(comparison.variableId))
|
||||
return (
|
||||
<Wrap key={comparison.id} spacing={1} noOfLines={1}>
|
||||
{idx === 0 && <Text fontSize={size}>IF</Text>}
|
||||
{idx === 0 && (
|
||||
<Text fontSize={size}>
|
||||
{t('blocks.inputs.button.conditionContent.if.label')}
|
||||
</Text>
|
||||
)}
|
||||
{idx > 0 && (
|
||||
<Text fontSize={size}>{condition.logicalOperator ?? ''}</Text>
|
||||
)}
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
LogicalOperator,
|
||||
defaultConditionItemContent,
|
||||
} from '@typebot.io/schemas/features/blocks/logic/condition/constants'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
type Props = {
|
||||
condition: Condition | undefined
|
||||
@ -15,6 +16,7 @@ type Props = {
|
||||
}
|
||||
|
||||
export const ConditionForm = ({ condition, onConditionChange }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
const handleComparisonsChange = (comparisons: Comparison[]) =>
|
||||
onConditionChange({ ...condition, comparisons })
|
||||
const handleLogicalOperatorChange = (logicalOperator: LogicalOperator) =>
|
||||
@ -36,7 +38,9 @@ export const ConditionForm = ({ condition, onConditionChange }: Props) => {
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
addLabel="Add a comparison"
|
||||
addLabel={t(
|
||||
'blocks.inputs.button.buttonSettings.addComparisonButton.label'
|
||||
)}
|
||||
>
|
||||
{(props) => <ComparisonItem {...props} />}
|
||||
</TableList>
|
||||
|
@ -15,6 +15,7 @@ import { useToast } from '../../../hooks/useToast'
|
||||
import { Credentials } from '@typebot.io/schemas'
|
||||
import { trpc } from '@/lib/trpc'
|
||||
import { useWorkspace } from '@/features/workspace/WorkspaceProvider'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
type Props = Omit<ButtonProps, 'type'> & {
|
||||
type: Credentials['type']
|
||||
@ -36,6 +37,7 @@ export const CredentialsDropdown = ({
|
||||
credentialsName,
|
||||
...props
|
||||
}: Props) => {
|
||||
const { t } = useTranslate()
|
||||
const { showToast } = useToast()
|
||||
const { currentRole } = useWorkspace()
|
||||
const { data, refetch } = trpc.credentials.listCredentials.useQuery({
|
||||
@ -62,7 +64,7 @@ export const CredentialsDropdown = ({
|
||||
})
|
||||
|
||||
const defaultCredentialsLabel =
|
||||
defaultCredentialLabel ?? `Select ${credentialsName}`
|
||||
defaultCredentialLabel ?? `${t('select')} ${credentialsName}`
|
||||
|
||||
const currentCredential = data?.credentials.find(
|
||||
(c) => c.id === currentCredentialsId
|
||||
@ -91,7 +93,7 @@ export const CredentialsDropdown = ({
|
||||
isDisabled={currentRole === 'GUEST'}
|
||||
{...props}
|
||||
>
|
||||
Add {credentialsName}
|
||||
{t('add')} {credentialsName}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
@ -140,7 +142,9 @@ export const CredentialsDropdown = ({
|
||||
{credentials.name}
|
||||
<IconButton
|
||||
icon={<TrashIcon />}
|
||||
aria-label="Remove credentials"
|
||||
aria-label={t(
|
||||
'blocks.inputs.payment.settings.credentials.removeCredentials.label'
|
||||
)}
|
||||
size="xs"
|
||||
onClick={deleteCredentials(credentials.id)}
|
||||
isLoading={isDeleting === credentials.id}
|
||||
@ -156,7 +160,7 @@ export const CredentialsDropdown = ({
|
||||
icon={<PlusIcon />}
|
||||
onClick={onCreateNewClick}
|
||||
>
|
||||
Connect new
|
||||
{t('blocks.inputs.payment.settings.credentials.connectNew.label')}
|
||||
</MenuItem>
|
||||
)}
|
||||
</Stack>
|
||||
|
@ -31,9 +31,11 @@ const groupsActions = (setTypebot: SetTypebot): GroupsActions => ({
|
||||
id,
|
||||
block,
|
||||
indices,
|
||||
groupLabel,
|
||||
...graphCoordinates
|
||||
}: Coordinates & {
|
||||
id: string
|
||||
groupLabel?: string
|
||||
block: BlockV6 | BlockV6['type']
|
||||
indices: BlockIndices
|
||||
}) =>
|
||||
@ -42,7 +44,7 @@ const groupsActions = (setTypebot: SetTypebot): GroupsActions => ({
|
||||
const newGroup: GroupV6 = {
|
||||
id,
|
||||
graphCoordinates,
|
||||
title: `Group #${typebot.groups.length + 1}`,
|
||||
title: `${groupLabel ?? 'Group'} #${typebot.groups.length + 1}`,
|
||||
blocks: [],
|
||||
}
|
||||
typebot.groups.push(newGroup)
|
||||
|
@ -2,9 +2,11 @@ import { MenuList, MenuItem } from '@chakra-ui/react'
|
||||
import { CopyIcon, TrashIcon } from '@/components/icons'
|
||||
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
|
||||
import { BlockIndices } from '@typebot.io/schemas'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
type Props = { indices: BlockIndices }
|
||||
export const BlockNodeContextMenu = ({ indices }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
const { deleteBlock, duplicateBlock } = useTypebot()
|
||||
|
||||
const handleDuplicateClick = () => duplicateBlock(indices)
|
||||
@ -14,10 +16,10 @@ export const BlockNodeContextMenu = ({ indices }: Props) => {
|
||||
return (
|
||||
<MenuList>
|
||||
<MenuItem icon={<CopyIcon />} onClick={handleDuplicateClick}>
|
||||
Duplicate
|
||||
{t('duplicate')}
|
||||
</MenuItem>
|
||||
<MenuItem icon={<TrashIcon />} onClick={handleDeleteClick}>
|
||||
Delete
|
||||
{t('delete')}
|
||||
</MenuItem>
|
||||
</MenuList>
|
||||
)
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
import { BlockWithOptions } from '@typebot.io/schemas'
|
||||
import { getHelpDocUrl } from '@/features/graph/helpers/getHelpDocUrl'
|
||||
import { useForgedBlock } from '@/features/forge/hooks/useForgedBlock'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
type Props = {
|
||||
blockType: BlockWithOptions['type']
|
||||
@ -16,6 +17,7 @@ type Props = {
|
||||
}
|
||||
|
||||
export const SettingsHoverBar = ({ blockType, onExpandClick }: Props) => {
|
||||
const { t } = useTranslate()
|
||||
const { blockDef } = useForgedBlock(blockType)
|
||||
const helpDocUrl = getHelpDocUrl(blockType, blockDef)
|
||||
return (
|
||||
@ -46,7 +48,7 @@ export const SettingsHoverBar = ({ blockType, onExpandClick }: Props) => {
|
||||
href={helpDocUrl}
|
||||
isExternal
|
||||
>
|
||||
Help
|
||||
{t('help')}
|
||||
</Button>
|
||||
)}
|
||||
</HStack>
|
||||
|
@ -1,12 +1,14 @@
|
||||
import { MenuList, MenuItem } from '@chakra-ui/react'
|
||||
import { CopyIcon, TrashIcon } from '@/components/icons'
|
||||
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
export const GroupNodeContextMenu = ({
|
||||
groupIndex,
|
||||
}: {
|
||||
groupIndex: number
|
||||
}) => {
|
||||
const { t } = useTranslate()
|
||||
const { deleteGroup, duplicateGroup } = useTypebot()
|
||||
|
||||
const handleDeleteClick = () => deleteGroup(groupIndex)
|
||||
@ -16,10 +18,10 @@ export const GroupNodeContextMenu = ({
|
||||
return (
|
||||
<MenuList>
|
||||
<MenuItem icon={<CopyIcon />} onClick={handleDuplicateClick}>
|
||||
Duplicate
|
||||
{t('duplicate')}
|
||||
</MenuItem>
|
||||
<MenuItem icon={<TrashIcon />} onClick={handleDeleteClick}>
|
||||
Delete
|
||||
{t('delete')}
|
||||
</MenuItem>
|
||||
</MenuList>
|
||||
)
|
||||
|
@ -22,6 +22,7 @@ import { Coordinates } from '@dnd-kit/utilities'
|
||||
import { BlockSourceEndpoint } from '../../endpoints/BlockSourceEndpoint'
|
||||
import { LogicBlockType } from '@typebot.io/schemas/features/blocks/logic/constants'
|
||||
import { InputBlockType } from '@typebot.io/schemas/features/blocks/inputs/constants'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
|
||||
type Props = {
|
||||
block: BlockWithItems
|
||||
@ -192,6 +193,8 @@ const DefaultItemNode = ({
|
||||
block: BlockWithItems
|
||||
groupId: string
|
||||
}) => {
|
||||
const { t } = useTranslate()
|
||||
|
||||
return (
|
||||
<Flex
|
||||
px="4"
|
||||
@ -205,7 +208,9 @@ const DefaultItemNode = ({
|
||||
cursor="not-allowed"
|
||||
>
|
||||
<Text color="gray.500">
|
||||
{block.type === LogicBlockType.CONDITION ? 'Else' : 'Default'}
|
||||
{block.type === LogicBlockType.CONDITION
|
||||
? t('blocks.inputs.button.else.label')
|
||||
: t('blocks.inputs.button.default.label')}
|
||||
</Text>
|
||||
<BlockSourceEndpoint
|
||||
source={{
|
||||
|
@ -30,6 +30,7 @@
|
||||
"account.preferences.graphNavigation.trackpad.label": "Trackpad",
|
||||
"account.preferences.language.heading": "Language",
|
||||
"account.preferences.language.tooltip": "The translations are not complete yet. It is a work in progress. \uD83E\uDD13",
|
||||
"add": "Add",
|
||||
"analytics.completionRateLabel": "Completion rate",
|
||||
"analytics.notAvailableLabel": "Not available",
|
||||
"analytics.startsLabel": "Starts",
|
||||
@ -112,7 +113,103 @@
|
||||
"billing.usage.heading": "Usage",
|
||||
"billing.usage.unlimited": "Unlimited",
|
||||
"blocks.bubbles.embed.blockCard.tooltip": "Embed a pdf, an iframe, a website...",
|
||||
"blocks.inputs.button.addItem.ariaLabel": "Add item",
|
||||
"blocks.inputs.button.buttonSettings.addComparisonButton.label": "Add comparison",
|
||||
"blocks.inputs.button.buttonSettings.displayCondition.infoText.label": "Only display this item if a condition is met.",
|
||||
"blocks.inputs.button.buttonSettings.displayCondition.selectOperator.label": "Select an operator",
|
||||
"blocks.inputs.button.clickToEdit.label": "Click to edit",
|
||||
"blocks.inputs.button.conditionContent.if.label": "IF",
|
||||
"blocks.inputs.button.default.label": "Default",
|
||||
"blocks.inputs.button.else.label": "Else",
|
||||
"blocks.inputs.button.openSettings.ariaLabel": "Open settings",
|
||||
"blocks.inputs.button.settings.dynamicData.infoText.label": "If defined, buttons will be dynamically displayed based on what the variable contains.",
|
||||
"blocks.inputs.button.settings.dynamicData.label": "Dynamic data:",
|
||||
"blocks.inputs.button.variables.buttons.label": "buttons",
|
||||
"blocks.inputs.button.variables.display.label": "Display",
|
||||
"blocks.inputs.date.placeholder.label": "Pick a date...",
|
||||
"blocks.inputs.date.settings.format.example.label": "i.e",
|
||||
"blocks.inputs.date.settings.format.label": "Format:",
|
||||
"blocks.inputs.date.settings.from.label": "From label:",
|
||||
"blocks.inputs.date.settings.isRange.label": "Is range?",
|
||||
"blocks.inputs.date.settings.to.label": "To label:",
|
||||
"blocks.inputs.date.settings.toInputValue.label": "To:",
|
||||
"blocks.inputs.date.settings.withTime.label": "With time?",
|
||||
"blocks.inputs.file.collectMultiple.label": "Collect files",
|
||||
"blocks.inputs.file.collectSingle.label": "Collect file",
|
||||
"blocks.inputs.file.settings.allowMultiple.label": "Allow multiple files?",
|
||||
"blocks.inputs.file.settings.clear.label": "Clear button label:",
|
||||
"blocks.inputs.file.settings.required.label": "Required?",
|
||||
"blocks.inputs.file.settings.saveMultipleUpload.label": "Save upload URLs in a variable:",
|
||||
"blocks.inputs.file.settings.saveSingleUpload.label": "Save upload URL in a variable:",
|
||||
"blocks.inputs.file.settings.skip.label": "Skip button label:",
|
||||
"blocks.inputs.fileUpload.blockCard.tooltip": "Upload Files",
|
||||
"blocks.inputs.number.settings.step.label": "Step:",
|
||||
"blocks.inputs.payment.collect.label": "Coletar",
|
||||
"blocks.inputs.payment.placeholder.label": "Configure...",
|
||||
"blocks.inputs.payment.settings.account.label": "Account:",
|
||||
"blocks.inputs.payment.settings.accountText.label": "{provider} account",
|
||||
"blocks.inputs.payment.settings.additionalInformation.description.placeholder.label": "A digital product",
|
||||
"blocks.inputs.payment.settings.additionalInformation.email.label": "Email:",
|
||||
"blocks.inputs.payment.settings.additionalInformation.label": "Additional information",
|
||||
"blocks.inputs.payment.settings.additionalInformation.name.label": "Name:",
|
||||
"blocks.inputs.payment.settings.additionalInformation.phone.label": "Phone number:",
|
||||
"blocks.inputs.payment.settings.address.city.label": "City:",
|
||||
"blocks.inputs.payment.settings.address.country.label": "Country:",
|
||||
"blocks.inputs.payment.settings.address.label": "Address",
|
||||
"blocks.inputs.payment.settings.address.line.label": "Line {line}:",
|
||||
"blocks.inputs.payment.settings.address.postalCode.label": "Postal code:",
|
||||
"blocks.inputs.payment.settings.address.state.label": "State:",
|
||||
"blocks.inputs.payment.settings.credentials.connectNew.label": "Connect new",
|
||||
"blocks.inputs.payment.settings.credentials.removeCredentials.label": "Remove credentials",
|
||||
"blocks.inputs.payment.settings.currency.label": "Currency:",
|
||||
"blocks.inputs.payment.settings.priceAmount.label": "Price amount:",
|
||||
"blocks.inputs.payment.settings.provider.label": "Provider:",
|
||||
"blocks.inputs.payment.settings.stripeConfig.accountName.label": "Account name:",
|
||||
"blocks.inputs.payment.settings.stripeConfig.findKeys.here.label": "here",
|
||||
"blocks.inputs.payment.settings.stripeConfig.findKeys.label": "You can find your keys",
|
||||
"blocks.inputs.payment.settings.stripeConfig.liveKeys.label": "Live keys:",
|
||||
"blocks.inputs.payment.settings.stripeConfig.testKeys.infoText.label": "Will be used when previewing the bot.",
|
||||
"blocks.inputs.payment.settings.stripeConfig.testKeys.label": "Test keys:",
|
||||
"blocks.inputs.payment.settings.stripeConfig.title.label": "Connect Stripe account",
|
||||
"blocks.inputs.payment.settings.successMessage.label": "Success message:",
|
||||
"blocks.inputs.phone.settings.defaultCountry.label": "Default country:",
|
||||
"blocks.inputs.phone.settings.international.placeholder.label": "International",
|
||||
"blocks.inputs.picture.itemSettings.image.change.label": "Change image",
|
||||
"blocks.inputs.picture.itemSettings.image.label": "Image:",
|
||||
"blocks.inputs.picture.itemSettings.image.pick.label": "Pick an image",
|
||||
"blocks.inputs.picture.itemSettings.title.label": "Title:",
|
||||
"blocks.inputs.picture.settings.dynamicItems.descriptions.label": "Descriptions:",
|
||||
"blocks.inputs.picture.settings.dynamicItems.images.label": "Images:",
|
||||
"blocks.inputs.picture.settings.dynamicItems.label": "Dynamic items?",
|
||||
"blocks.inputs.picture.settings.dynamicItems.titles.label": "Titles:",
|
||||
"blocks.inputs.picture.settings.dynamicVariables.display.label": "Display",
|
||||
"blocks.inputs.picture.settings.dynamicVariables.pictures.label": "pictures",
|
||||
"blocks.inputs.rating.from.label": "Rate from",
|
||||
"blocks.inputs.rating.settings.customIcon.label": "Custom icon?",
|
||||
"blocks.inputs.rating.settings.extremelyLikely.placeholder.label": "Extremely likely",
|
||||
"blocks.inputs.rating.settings.iconSVG.label": "Icon SVG:",
|
||||
"blocks.inputs.rating.settings.maximum.label": "Maximum:",
|
||||
"blocks.inputs.rating.settings.notLikely.placeholder.label": "Not likely at all",
|
||||
"blocks.inputs.rating.settings.oneClickSubmit.infoText.label": "If enabled, the answer will be submitted as soon as the user clicks on a rating instead of showing the \"Send\" button.",
|
||||
"blocks.inputs.rating.settings.oneClickSubmit.label": "One click submit",
|
||||
"blocks.inputs.rating.settings.rateLabel.label": "{rate} label",
|
||||
"blocks.inputs.rating.settings.type.label": "Type:",
|
||||
"blocks.inputs.rating.to.label": "to",
|
||||
"blocks.inputs.settings.button.label": "Button label:",
|
||||
"blocks.inputs.settings.buttonText.label": "Send",
|
||||
"blocks.inputs.settings.description.label": "Description:",
|
||||
"blocks.inputs.settings.displayCondition.label": "Display condition",
|
||||
"blocks.inputs.settings.input.filterOptions.label": "Filter the options...",
|
||||
"blocks.inputs.settings.input.placeholder.label": "Input placeholder:",
|
||||
"blocks.inputs.settings.isSearchable.label": "Is searchable?",
|
||||
"blocks.inputs.settings.max.label": "Max:",
|
||||
"blocks.inputs.settings.min.label": "Min:",
|
||||
"blocks.inputs.settings.multipleChoice.label": "Multiple choice?",
|
||||
"blocks.inputs.settings.placeholder.label": "Placeholder:",
|
||||
"blocks.inputs.settings.retryMessage.label": "Retry message:",
|
||||
"blocks.inputs.settings.saveAnswer.label": "Save the answer in a variable:",
|
||||
"blocks.inputs.settings.submitButton.label": "Submit button label:",
|
||||
"blocks.inputs.text.settings.longText.label": "Long text?",
|
||||
"blocks.integrations.googleAnalytics.blockCard.tooltip": "Google Analytics",
|
||||
"blocks.integrations.googleSheets.blockCard.tooltip": "Google Sheets",
|
||||
"cancel": "Cancel",
|
||||
@ -124,13 +221,16 @@
|
||||
"colorPicker.colorValue.ariaLabel": "Color value",
|
||||
"colorPicker.pickColor.ariaLabel": "Pick a color",
|
||||
"confirmModal.defaultTitle": "Are you sure?",
|
||||
"connect": "Connect",
|
||||
"copied": "Copied",
|
||||
"copy": "Copy",
|
||||
"create": "Create",
|
||||
"dashboard.header.settingsButton.label": "Settings & Members",
|
||||
"dashboard.redirectionMessage": "You are being redirected...",
|
||||
"dashboard.title": "My typebots",
|
||||
"delete": "Delete",
|
||||
"downgrade": "Downgrade",
|
||||
"duplicate": "Duplicate",
|
||||
"editor.blockCard.logicBlock.tooltip.code.label": "Execute Javascript code",
|
||||
"editor.blockCard.logicBlock.tooltip.jump.label": "Fast forward the flow to another group",
|
||||
"editor.blockCard.logicBlock.tooltip.typebotLink.label": "Link and jump to another typebot",
|
||||
@ -238,6 +338,7 @@
|
||||
"folders.typebotButton.live": "Live",
|
||||
"folders.typebotButton.showMoreOptions": "Show more options",
|
||||
"folders.typebotButton.unpublish": "Unpublish",
|
||||
"help": "Help",
|
||||
"pending": "Pending",
|
||||
"preview.restartButton.label": "Restart",
|
||||
"publish.error.label": "Error while publishing typebot",
|
||||
@ -258,6 +359,7 @@
|
||||
"remove": "Remove",
|
||||
"rename": "Rename",
|
||||
"save": "Save",
|
||||
"select": "Select",
|
||||
"share.button.label": "Share",
|
||||
"share.button.popover.ariaLabel": "Open share popover",
|
||||
"share.button.popover.collaboratorsFetch.error.label": "Couldn't fetch collaborators",
|
||||
@ -355,6 +457,11 @@
|
||||
"upgrade": "Upgrade",
|
||||
"variables.button.searchInput.placeholder": "Search for a variable",
|
||||
"variables.button.tooltip": "Insert a variable",
|
||||
"variables.remove": "Remove variable",
|
||||
"variables.rename": "Rename variable",
|
||||
"variables.search": "Search for a variable",
|
||||
"variables.select": "Select a variable",
|
||||
"variables.set": "Set",
|
||||
"video.aspectRatioInput.label": "Aspect ratio",
|
||||
"video.aspectRatioInput.moreInfoTooltip": "Example: \"16/9\" or \"9/16\"",
|
||||
"video.maxWidthInput.label": "Max width",
|
||||
|
@ -30,6 +30,7 @@
|
||||
"account.preferences.graphNavigation.trackpad.label": "Trackpad",
|
||||
"account.preferences.language.heading": "Idioma",
|
||||
"account.preferences.language.tooltip": "As traduções ainda não estão completas. É um trabalho em andamento. \uD83E\uDD13",
|
||||
"add": "Adicionar",
|
||||
"analytics.completionRateLabel": "Taxa de conclusão",
|
||||
"analytics.notAvailableLabel": "Não disponível",
|
||||
"analytics.startsLabel": "Inícios",
|
||||
@ -112,7 +113,103 @@
|
||||
"billing.usage.heading": "Uso",
|
||||
"billing.usage.unlimited": "Ilimitado",
|
||||
"blocks.bubbles.embed.blockCard.tooltip": "Incorporar pdf, iframe, website...",
|
||||
"blocks.inputs.button.addItem.ariaLabel": "Adicionar item",
|
||||
"blocks.inputs.button.buttonSettings.addComparisonButton.label": "Adicionar comparação",
|
||||
"blocks.inputs.button.buttonSettings.displayCondition.infoText.label": "Apenas exiba esse item se a condição for cumprida.",
|
||||
"blocks.inputs.button.buttonSettings.displayCondition.selectOperator.label": "Selecione um operador",
|
||||
"blocks.inputs.button.clickToEdit.label": "Clique para editar",
|
||||
"blocks.inputs.button.conditionContent.if.label": "SE",
|
||||
"blocks.inputs.button.default.label": "Padrão",
|
||||
"blocks.inputs.button.else.label": "Senão",
|
||||
"blocks.inputs.button.openSettings.ariaLabel": "Abrir configurações",
|
||||
"blocks.inputs.button.settings.dynamicData.infoText.label": "Se definido, os botões serão exibidos dinamicamente com base no que a variável contém.",
|
||||
"blocks.inputs.button.settings.dynamicData.label": "Dados dinâmicos:",
|
||||
"blocks.inputs.button.variables.buttons.label": "botões",
|
||||
"blocks.inputs.button.variables.display.label": "Exibir",
|
||||
"blocks.inputs.date.placeholder.label": "Escolha uma data...",
|
||||
"blocks.inputs.date.settings.format.example.label": "Ex:",
|
||||
"blocks.inputs.date.settings.format.label": "Formatar:",
|
||||
"blocks.inputs.date.settings.from.label": "Legenda de:",
|
||||
"blocks.inputs.date.settings.isRange.label": "Intervalo?",
|
||||
"blocks.inputs.date.settings.to.label": "Legenda até:",
|
||||
"blocks.inputs.date.settings.toInputValue.label": "Até:",
|
||||
"blocks.inputs.date.settings.withTime.label": "Com tempo?",
|
||||
"blocks.inputs.file.collectMultiple.label": "Coletar arquivos",
|
||||
"blocks.inputs.file.collectSingle.label": "Coletar arquivo",
|
||||
"blocks.inputs.file.settings.allowMultiple.label": "Permitir múltiplos arquivos?",
|
||||
"blocks.inputs.file.settings.clear.label": "Legenda do botão de limpar:",
|
||||
"blocks.inputs.file.settings.required.label": "Obrigatório?",
|
||||
"blocks.inputs.file.settings.saveMultipleUpload.label": "Salve as URLs carregadas numa variável:",
|
||||
"blocks.inputs.file.settings.saveSingleUpload.label": "Salve a URL carregada numa variável:",
|
||||
"blocks.inputs.file.settings.skip.label": "Legenda do botão de pular:",
|
||||
"blocks.inputs.fileUpload.blockCard.tooltip": "Anexar arquivos",
|
||||
"blocks.inputs.number.settings.step.label": "Intervalo",
|
||||
"blocks.inputs.payment.collect.label": "Coletar",
|
||||
"blocks.inputs.payment.placeholder.label": "Configure...",
|
||||
"blocks.inputs.payment.settings.account.label": "Conta:",
|
||||
"blocks.inputs.payment.settings.accountText.label": "conta {provider}",
|
||||
"blocks.inputs.payment.settings.additionalInformation.description.placeholder.label": "Um produto digital",
|
||||
"blocks.inputs.payment.settings.additionalInformation.email.label": "Email:",
|
||||
"blocks.inputs.payment.settings.additionalInformation.label": "Informação adicional",
|
||||
"blocks.inputs.payment.settings.additionalInformation.name.label": "Nome:",
|
||||
"blocks.inputs.payment.settings.additionalInformation.phone.label": "Número de telefone:",
|
||||
"blocks.inputs.payment.settings.address.city.label": "Cidade:",
|
||||
"blocks.inputs.payment.settings.address.country.label": "País:",
|
||||
"blocks.inputs.payment.settings.address.label": "Endereço",
|
||||
"blocks.inputs.payment.settings.address.line.label": "Linha {line}:",
|
||||
"blocks.inputs.payment.settings.address.postalCode.label": "Código postal:",
|
||||
"blocks.inputs.payment.settings.address.state.label": "Estado:",
|
||||
"blocks.inputs.payment.settings.credentials.connectNew.label": "Nova conexão",
|
||||
"blocks.inputs.payment.settings.credentials.removeCredentials.label": "Remover credenciais",
|
||||
"blocks.inputs.payment.settings.currency.label": "Moeda:",
|
||||
"blocks.inputs.payment.settings.priceAmount.label": "Valor do preço:",
|
||||
"blocks.inputs.payment.settings.provider.label": "Provedor:",
|
||||
"blocks.inputs.payment.settings.stripeConfig.accountName.label": "Nome da conta:",
|
||||
"blocks.inputs.payment.settings.stripeConfig.findKeys.here.label": "aqui",
|
||||
"blocks.inputs.payment.settings.stripeConfig.findKeys.label": "Você pode encontrar suas chaves",
|
||||
"blocks.inputs.payment.settings.stripeConfig.liveKeys.label": "Chaves de produção:",
|
||||
"blocks.inputs.payment.settings.stripeConfig.testKeys.infoText.label": "Será usada durante a visualização do bot.",
|
||||
"blocks.inputs.payment.settings.stripeConfig.testKeys.label": "Chaves teste:",
|
||||
"blocks.inputs.payment.settings.stripeConfig.title.label": "Conectar conta Stripe",
|
||||
"blocks.inputs.payment.settings.successMessage.label": "Mensagem de sucesso:",
|
||||
"blocks.inputs.phone.settings.defaultCountry.label": "País padrão:",
|
||||
"blocks.inputs.phone.settings.international.placeholder.label": "Internacional",
|
||||
"blocks.inputs.picture.itemSettings.image.change.label": "Alterar imagem",
|
||||
"blocks.inputs.picture.itemSettings.image.label": "Imagem",
|
||||
"blocks.inputs.picture.itemSettings.image.pick.label": "Escolha uma imagem",
|
||||
"blocks.inputs.picture.itemSettings.title.label": "Título:",
|
||||
"blocks.inputs.picture.settings.dynamicItems.descriptions.label": "Descrições:",
|
||||
"blocks.inputs.picture.settings.dynamicItems.images.label": "Imagens:",
|
||||
"blocks.inputs.picture.settings.dynamicItems.label": "Itens dinâmicos?",
|
||||
"blocks.inputs.picture.settings.dynamicItems.titles.label": "Títulos:",
|
||||
"blocks.inputs.picture.settings.dynamicVariables.display.label": "Exibir",
|
||||
"blocks.inputs.picture.settings.dynamicVariables.pictures.label": "imagens",
|
||||
"blocks.inputs.rating.from.label": "Avalie de",
|
||||
"blocks.inputs.rating.settings.customIcon.label": "Customizar ícone?",
|
||||
"blocks.inputs.rating.settings.extremelyLikely.placeholder.label": "Extremamente provável",
|
||||
"blocks.inputs.rating.settings.iconSVG.label": "Ícone SVG:",
|
||||
"blocks.inputs.rating.settings.maximum.label": "Máximo:",
|
||||
"blocks.inputs.rating.settings.notLikely.placeholder.label": "Nada provável",
|
||||
"blocks.inputs.rating.settings.oneClickSubmit.infoText.label": "Se habilitado, a resposta será enviada no momento em que o usuário clicar em uma avaliação ao invés de mostrar o botão de envio",
|
||||
"blocks.inputs.rating.settings.oneClickSubmit.label": "Enviar em um clique",
|
||||
"blocks.inputs.rating.settings.rateLabel.label": "Legenda {rate}",
|
||||
"blocks.inputs.rating.settings.type.label": "Tipo:",
|
||||
"blocks.inputs.rating.to.label": "a",
|
||||
"blocks.inputs.settings.button.label": "Legenda do botão:",
|
||||
"blocks.inputs.settings.buttonText.label": "Enviar",
|
||||
"blocks.inputs.settings.description.label": "Descrição:",
|
||||
"blocks.inputs.settings.displayCondition.label": "Condição de exibição",
|
||||
"blocks.inputs.settings.input.filterOptions.label": "Filtre as opções...",
|
||||
"blocks.inputs.settings.input.placeholder.label": "Placeholder do input:",
|
||||
"blocks.inputs.settings.isSearchable.label": "É pesquisável?",
|
||||
"blocks.inputs.settings.max.label": "Máx:",
|
||||
"blocks.inputs.settings.min.label": "Mín:",
|
||||
"blocks.inputs.settings.multipleChoice.label": "Múltipla escolha?",
|
||||
"blocks.inputs.settings.placeholder.label": "Placeholder:",
|
||||
"blocks.inputs.settings.retryMessage.label": "Mensagem de nova tentativa:",
|
||||
"blocks.inputs.settings.saveAnswer.label": "Salve a resposta em uma variável:",
|
||||
"blocks.inputs.settings.submitButton.label": "Legenda do botão de envio:",
|
||||
"blocks.inputs.text.settings.longText.label": "Texto longo?",
|
||||
"blocks.integrations.googleAnalytics.blockCard.tooltip": "Google Analytics",
|
||||
"blocks.integrations.googleSheets.blockCard.tooltip": "Google Sheets",
|
||||
"cancel": "Cancelar",
|
||||
@ -124,13 +221,16 @@
|
||||
"colorPicker.colorValue.ariaLabel": "Valor da cor",
|
||||
"colorPicker.pickColor.ariaLabel": "Escolha uma cor",
|
||||
"confirmModal.defaultTitle": "Tem certeza?",
|
||||
"connect": "Conectar",
|
||||
"copied": "Copiado",
|
||||
"copy": "Copiar",
|
||||
"create": "Criar",
|
||||
"dashboard.header.settingsButton.label": "Configurações & Membros",
|
||||
"dashboard.redirectionMessage": "Você está sendo redirecionado...",
|
||||
"dashboard.title": "Meus typebots",
|
||||
"delete": "Apagar",
|
||||
"downgrade": "Downgrade",
|
||||
"duplicate": "Duplicar",
|
||||
"editor.blockCard.logicBlock.tooltip.code.label": "Executar código Javascript",
|
||||
"editor.blockCard.logicBlock.tooltip.jump.label": "Encaminhar fluxo para outro grupo",
|
||||
"editor.blockCard.logicBlock.tooltip.typebotLink.label": "Link e salte para outro typebot",
|
||||
@ -238,6 +338,7 @@
|
||||
"folders.typebotButton.live": "Live",
|
||||
"folders.typebotButton.showMoreOptions": "Mostrar mais opções",
|
||||
"folders.typebotButton.unpublish": "Despublicar",
|
||||
"help": "Ajuda",
|
||||
"pending": "Pendente",
|
||||
"preview.restartButton.label": "Reiniciar",
|
||||
"publish.error.label": "Erro durante a publicação do typebot",
|
||||
@ -257,6 +358,7 @@
|
||||
"remove": "Remover",
|
||||
"rename": "Renomear",
|
||||
"save": "Salvar",
|
||||
"select": "Selecionar",
|
||||
"share.button.label": "Compartilhar",
|
||||
"share.button.popover.ariaLabel": "Abrir popover de compartilhamento",
|
||||
"share.button.popover.collaboratorsFetch.error.label": "Falha ao buscar os colaboradores",
|
||||
@ -348,6 +450,11 @@
|
||||
"upgrade": "Upgrade",
|
||||
"variables.button.searchInput.placeholder": "Procure por uma variável",
|
||||
"variables.button.tooltip": "Insira uma variável",
|
||||
"variables.remove": "Remova a variável",
|
||||
"variables.rename": "Renomeie a variável",
|
||||
"variables.search": "Pesquise uma variável",
|
||||
"variables.select": "Selecione uma variável",
|
||||
"variables.set": "Definir",
|
||||
"video.aspectRatioInput.label": "Proporção",
|
||||
"video.aspectRatioInput.moreInfoTooltip": "Exemplo: \"16/9\" ou \"9/16\"",
|
||||
"video.maxWidthInput.label": "Largura máxima",
|
||||
|
Reference in New Issue
Block a user