🚸 Add a better select input

Also improves other inputs behavior
This commit is contained in:
Baptiste Arnaud
2023-03-03 09:01:11 +01:00
parent a66bfca1ec
commit cc7d7285e5
94 changed files with 1251 additions and 1109 deletions

View File

@@ -1,6 +1,6 @@
import { Button, Flex, HStack, Stack, Text } from '@chakra-ui/react'
import { AudioBubbleContent } from 'models'
import { Input } from '@/components/inputs'
import { TextInput } from '@/components/inputs'
import { useState } from 'react'
import { UploadButton } from '@/components/ImageUploadContent/UploadButton'
@@ -52,7 +52,7 @@ export const AudioBubbleForm = ({
)}
{currentTab === 'link' && (
<>
<Input
<TextInput
placeholder="Paste the audio file link..."
defaultValue={content.url ?? ''}
onChange={submit}

View File

@@ -1,4 +1,4 @@
import { Input, SmartNumberInput } from '@/components/inputs'
import { TextInput, NumberInput } from '@/components/inputs'
import { HStack, Stack, Text } from '@chakra-ui/react'
import { EmbedBubbleContent } from 'models'
import { sanitizeUrl } from 'utils'
@@ -22,7 +22,7 @@ export const EmbedUploadContent = ({ content, onSubmit }: Props) => {
return (
<Stack p="2" spacing={6}>
<Stack>
<Input
<TextInput
placeholder="Paste the link or code..."
defaultValue={content?.url ?? ''}
onChange={handleUrlChange}
@@ -33,7 +33,7 @@ export const EmbedUploadContent = ({ content, onSubmit }: Props) => {
</Stack>
<HStack>
<SmartNumberInput
<NumberInput
label="Height:"
defaultValue={content?.height}
onValueChange={handleHeightChange}

View File

@@ -19,7 +19,7 @@ import { defaultTextBubbleContent, TextBubbleContent, Variable } from 'models'
import { ReactEditor } from 'slate-react'
import { serializeHtml } from '@udecode/plate-serializer-html'
import { parseHtmlStringToPlainText } from '../../utils'
import { VariableSearchInput } from '@/components/VariableSearchInput'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { colors } from '@/lib/theme'
import { useOutsideClick } from '@/hooks/useOutsideClick'

View File

@@ -4,7 +4,7 @@ import urlParser from 'js-video-url-parser/lib/base'
import 'js-video-url-parser/lib/provider/vimeo'
import 'js-video-url-parser/lib/provider/youtube'
import { isDefined } from 'utils'
import { Input } from '@/components/inputs'
import { TextInput } from '@/components/inputs'
type Props = {
content?: VideoBubbleContent
@@ -24,7 +24,7 @@ export const VideoUploadContent = ({ content, onSubmit }: Props) => {
}
return (
<Stack p="2">
<Input
<TextInput
placeholder="Paste the video link..."
defaultValue={content?.url ?? ''}
onChange={handleUrlChange}

View File

@@ -49,7 +49,7 @@ test.describe.parallel('Buttons input block', () => {
await page.click('[data-testid="block2-icon"]')
await page.click('text=Multiple choice?')
await page.fill('#button', 'Go')
await page.getByLabel('Button label:').fill('Go')
await page.getByPlaceholder('Select a variable').nth(1).click()
await page.getByText('var1').click()
await expect(page.getByText('Collectsvar1')).toBeVisible()

View File

@@ -1,7 +1,7 @@
import { Input } from '@/components/inputs'
import { TextInput } from '@/components/inputs'
import { MoreInfoTooltip } from '@/components/MoreInfoTooltip'
import { SwitchWithLabel } from '@/components/SwitchWithLabel'
import { VariableSearchInput } from '@/components/VariableSearchInput'
import { SwitchWithLabel } from '@/components/inputs/SwitchWithLabel'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { FormControl, FormLabel, Stack } from '@chakra-ui/react'
import { ChoiceInputOptions, Variable } from 'models'
import React from 'react'
@@ -29,16 +29,11 @@ export const ButtonsBlockSettings = ({ options, onOptionsChange }: Props) => {
onCheckChange={handleIsMultipleChange}
/>
{options?.isMultipleChoice && (
<Stack>
<FormLabel mb="0" htmlFor="button">
Button label:
</FormLabel>
<Input
id="button"
defaultValue={options?.buttonLabel ?? 'Send'}
onChange={handleButtonLabelChange}
/>
</Stack>
<TextInput
label="Button label:"
defaultValue={options?.buttonLabel ?? 'Send'}
onChange={handleButtonLabelChange}
/>
)}
<FormControl>
<FormLabel>

View File

@@ -1,6 +1,6 @@
import { Input } from '@/components/inputs'
import { SwitchWithLabel } from '@/components/SwitchWithLabel'
import { VariableSearchInput } from '@/components/VariableSearchInput'
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 'models'
import React from 'react'
@@ -40,39 +40,24 @@ export const DateInputSettingsBody = ({
onCheckChange={handleHasTimeChange}
/>
{options.isRange && (
<Stack>
<FormLabel mb="0" htmlFor="from">
From label:
</FormLabel>
<Input
id="from"
<>
<TextInput
label="From label:"
defaultValue={options.labels.from}
onChange={handleFromChange}
/>
</Stack>
)}
{options?.isRange && (
<Stack>
<FormLabel mb="0" htmlFor="to">
To label:
</FormLabel>
<Input
id="to"
<TextInput
label="To label:"
defaultValue={options.labels.to}
onChange={handleToChange}
/>
</Stack>
</>
)}
<Stack>
<FormLabel mb="0" htmlFor="button">
Button label:
</FormLabel>
<Input
id="button"
defaultValue={options.labels.button}
onChange={handleButtonLabelChange}
/>
</Stack>
<TextInput
label="Button label:"
defaultValue={options.labels.button}
onChange={handleButtonLabelChange}
/>
<Stack>
<FormLabel mb="0" htmlFor="variable">
Save answer in a variable:

View File

@@ -32,9 +32,9 @@ test.describe('Date input block', () => {
await page.click(`text=Pick a date...`)
await page.click('text=Is range?')
await page.click('text=With time?')
await page.fill('#from', 'Previous:')
await page.fill('#to', 'After:')
await page.fill('#button', 'Go')
await page.getByLabel('From label:').fill('Previous:')
await page.getByLabel('To label:').fill('After:')
await page.getByLabel('Button label:').fill('Go')
await page.click('text=Restart')
await expect(page.locator(`[data-testid="from-date"]`)).toHaveAttribute(

View File

@@ -1,5 +1,5 @@
import { Input } from '@/components/inputs'
import { VariableSearchInput } from '@/components/VariableSearchInput'
import { TextInput } from '@/components/inputs'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { FormLabel, Stack } from '@chakra-ui/react'
import { EmailInputOptions, Variable } from 'models'
import React from 'react'
@@ -24,36 +24,21 @@ export const EmailInputSettingsBody = ({
return (
<Stack spacing={4}>
<Stack>
<FormLabel mb="0" htmlFor="placeholder">
Placeholder:
</FormLabel>
<Input
id="placeholder"
defaultValue={options.labels.placeholder}
onChange={handlePlaceholderChange}
/>
</Stack>
<Stack>
<FormLabel mb="0" htmlFor="button">
Button label:
</FormLabel>
<Input
id="button"
defaultValue={options.labels.button}
onChange={handleButtonLabelChange}
/>
</Stack>
<Stack>
<FormLabel mb="0" htmlFor="retry">
Retry message:
</FormLabel>
<Input
id="retry"
defaultValue={options.retryMessageContent}
onChange={handleRetryMessageChange}
/>
</Stack>
<TextInput
label="Placeholder:"
defaultValue={options.labels.placeholder}
onChange={handlePlaceholderChange}
/>
<TextInput
label="Button label:"
defaultValue={options.labels.button}
onChange={handleButtonLabelChange}
/>
<TextInput
label="Retry message:"
defaultValue={options.retryMessageContent}
onChange={handleRetryMessageChange}
/>
<Stack>
<FormLabel mb="0" htmlFor="variable">
Save answer in a variable:

View File

@@ -33,7 +33,7 @@ test.describe('Email input block', () => {
'Your email...'
)
await expect(page.locator('text=Your email...')).toBeVisible()
await page.fill('#button', 'Go')
await page.getByLabel('Button label:').fill('Go')
await page.fill(
`input[value="${defaultEmailInputOptions.retryMessageContent}"]`,
'Try again bro'

View File

@@ -1,10 +1,10 @@
import { FormLabel, HStack, Stack, Text } from '@chakra-ui/react'
import { CodeEditor } from '@/components/CodeEditor'
import { CodeEditor } from '@/components/inputs/CodeEditor'
import { FileInputOptions, Variable } from 'models'
import React from 'react'
import { Input, SmartNumberInput } from '@/components/inputs'
import { SwitchWithLabel } from '@/components/SwitchWithLabel'
import { VariableSearchInput } from '@/components/VariableSearchInput'
import { TextInput, NumberInput } from '@/components/inputs'
import { SwitchWithLabel } from '@/components/inputs/SwitchWithLabel'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
type Props = {
options: FileInputOptions
@@ -49,7 +49,7 @@ export const FileInputSettings = ({ options, onOptionsChange }: Props) => {
onCheckChange={handleMultipleFilesChange}
/>
<HStack>
<SmartNumberInput
<NumberInput
label={'Size limit:'}
defaultValue={options.sizeLimit ?? 10}
onValueChange={handleSizeLimitChange}
@@ -68,21 +68,21 @@ export const FileInputSettings = ({ options, onOptionsChange }: Props) => {
withVariableButton={false}
/>
</Stack>
<Input
<TextInput
label="Button label:"
defaultValue={options.labels.button}
onChange={handleButtonLabelChange}
withVariableButton={false}
/>
<Input
<TextInput
label="Clear button label:"
defaultValue={options.labels.clear}
defaultValue={options.labels.clear ?? ''}
onChange={updateClearButtonLabel}
withVariableButton={false}
/>
<Input
<TextInput
label="Skip button label:"
defaultValue={options.labels.skip}
defaultValue={options.labels.skip ?? ''}
onChange={updateSkipButtonLabel}
withVariableButton={false}
/>

View File

@@ -1,5 +1,5 @@
import { Input, SmartNumberInput } from '@/components/inputs'
import { VariableSearchInput } from '@/components/VariableSearchInput'
import { TextInput, NumberInput } from '@/components/inputs'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { removeUndefinedFields } from '@/utils/helpers'
import { FormLabel, Stack } from '@chakra-ui/react'
import { NumberInputOptions, Variable } from 'models'
@@ -30,39 +30,29 @@ export const NumberInputSettingsBody = ({
return (
<Stack spacing={4}>
<Stack>
<FormLabel mb="0" htmlFor="placeholder">
Placeholder:
</FormLabel>
<Input
id="placeholder"
defaultValue={options.labels.placeholder}
onChange={handlePlaceholderChange}
/>
</Stack>
<Stack>
<FormLabel mb="0" htmlFor="button">
Button label:
</FormLabel>
<Input
id="button"
defaultValue={options?.labels?.button ?? 'Send'}
onChange={handleButtonLabelChange}
/>
</Stack>
<SmartNumberInput
<TextInput
label="Placeholder:"
defaultValue={options.labels.placeholder}
onChange={handlePlaceholderChange}
/>
<TextInput
label="Button label:"
defaultValue={options?.labels?.button ?? 'Send'}
onChange={handleButtonLabelChange}
/>
<NumberInput
label="Min:"
defaultValue={options.min}
onValueChange={handleMinChange}
withVariableButton={false}
/>
<SmartNumberInput
<NumberInput
label="Max:"
defaultValue={options.max}
onValueChange={handleMaxChange}
withVariableButton={false}
/>
<SmartNumberInput
<NumberInput
label="Step:"
defaultValue={options.step}
onValueChange={handleBlockChange}

View File

@@ -28,9 +28,9 @@ test.describe('Number input block', () => {
await expect(page.getByRole('button', { name: 'Send' })).toBeDisabled()
await page.click(`text=${defaultNumberInputOptions.labels.placeholder}`)
await page.fill('#placeholder', 'Your number...')
await page.getByLabel('Placeholder:').fill('Your number...')
await expect(page.locator('text=Your number...')).toBeVisible()
await page.fill('#button', 'Go')
await page.getByLabel('Button label:').fill('Go')
await page.fill('[role="spinbutton"] >> nth=0', '0')
await page.fill('[role="spinbutton"] >> nth=1', '100')
await page.fill('[role="spinbutton"] >> nth=2', '10')

View File

@@ -16,7 +16,7 @@ import React, { ChangeEvent, useState } from 'react'
import { currencies } from './currencies'
import { StripeConfigModal } from './StripeConfigModal'
import { CredentialsDropdown } from '@/features/credentials'
import { Input } from '@/components/inputs'
import { TextInput } from '@/components/inputs'
type Props = {
options: PaymentInputOptions
@@ -105,14 +105,12 @@ export const PaymentSettings = ({ options, onOptionsChange }: Props) => {
/>
</Stack>
<HStack>
<Stack>
<Text>Price amount:</Text>
<Input
onChange={handleAmountChange}
defaultValue={options.amount}
placeholder="30.00"
/>
</Stack>
<TextInput
label="Price amount:"
onChange={handleAmountChange}
defaultValue={options.amount ?? ''}
placeholder="30.00"
/>
<Stack>
<Text>Currency:</Text>
<Select
@@ -128,22 +126,18 @@ export const PaymentSettings = ({ options, onOptionsChange }: Props) => {
</Select>
</Stack>
</HStack>
<Stack>
<Text>Button label:</Text>
<Input
onChange={handleButtonLabelChange}
defaultValue={options.labels.button}
placeholder="Pay"
/>
</Stack>
<Stack>
<Text>Success message:</Text>
<Input
onChange={handleSuccessLabelChange}
defaultValue={options.labels.success ?? 'Success'}
placeholder="Success"
/>
</Stack>
<TextInput
label="Button label:"
onChange={handleButtonLabelChange}
defaultValue={options.labels.button}
placeholder="Pay"
/>
<TextInput
label="Success message:"
onChange={handleSuccessLabelChange}
defaultValue={options.labels.success ?? 'Success'}
placeholder="Success"
/>
<Accordion allowToggle>
<AccordionItem>
<AccordionButton justifyContent="space-between">
@@ -151,30 +145,24 @@ export const PaymentSettings = ({ options, onOptionsChange }: Props) => {
<AccordionIcon />
</AccordionButton>
<AccordionPanel pb={4} as={Stack} spacing="6">
<Stack>
<Text>Name:</Text>
<Input
defaultValue={options.additionalInformation?.name ?? ''}
onChange={handleNameChange}
placeholder="John Smith"
/>
</Stack>
<Stack>
<Text>Email:</Text>
<Input
defaultValue={options.additionalInformation?.email ?? ''}
onChange={handleEmailChange}
placeholder="john@gmail.com"
/>
</Stack>
<Stack>
<Text>Phone number:</Text>
<Input
defaultValue={options.additionalInformation?.phoneNumber ?? ''}
onChange={handlePhoneNumberChange}
placeholder="+33XXXXXXXXX"
/>
</Stack>
<TextInput
label="Name:"
defaultValue={options.additionalInformation?.name ?? ''}
onChange={handleNameChange}
placeholder="John Smith"
/>
<TextInput
label="Email:"
defaultValue={options.additionalInformation?.email ?? ''}
onChange={handleEmailChange}
placeholder="john@gmail.com"
/>
<TextInput
label="Phone number:"
defaultValue={options.additionalInformation?.phoneNumber ?? ''}
onChange={handlePhoneNumberChange}
placeholder="+33XXXXXXXXX"
/>
</AccordionPanel>
</AccordionItem>
</Accordion>

View File

@@ -19,7 +19,7 @@ import React, { useState } from 'react'
import { useWorkspace } from '@/features/workspace'
import { omit } from 'utils'
import { useToast } from '@/hooks/useToast'
import { Input } from '@/components/inputs'
import { TextInput } from '@/components/inputs'
import { MoreInfoTooltip } from '@/components/MoreInfoTooltip'
import { TextLink } from '@/components/TextLink'
import { createCredentialsQuery } from '@/features/credentials'
@@ -102,14 +102,13 @@ export const StripeConfigModal = ({
<ModalCloseButton />
<ModalBody>
<Stack as="form" spacing={4}>
<FormControl isRequired>
<FormLabel>Account name:</FormLabel>
<Input
onChange={handleNameChange}
placeholder="Typebot"
withVariableButton={false}
/>
</FormControl>
<TextInput
isRequired
label="Account name:"
onChange={handleNameChange}
placeholder="Typebot"
withVariableButton={false}
/>
<Stack>
<FormLabel>
Test keys:{' '}
@@ -118,34 +117,30 @@ export const StripeConfigModal = ({
</MoreInfoTooltip>
</FormLabel>
<HStack>
<FormControl>
<Input
onChange={handleTestPublicKeyChange}
placeholder="pk_test_..."
withVariableButton={false}
/>
</FormControl>
<FormControl>
<Input
onChange={handleTestSecretKeyChange}
placeholder="sk_test_..."
withVariableButton={false}
/>
</FormControl>
<TextInput
onChange={handleTestPublicKeyChange}
placeholder="pk_test_..."
withVariableButton={false}
/>
<TextInput
onChange={handleTestSecretKeyChange}
placeholder="sk_test_..."
withVariableButton={false}
/>
</HStack>
</Stack>
<Stack>
<FormLabel>Live keys:</FormLabel>
<HStack>
<FormControl>
<Input
<TextInput
onChange={handlePublicKeyChange}
placeholder="pk_live_..."
withVariableButton={false}
/>
</FormControl>
<FormControl>
<Input
<TextInput
onChange={handleSecretKeyChange}
placeholder="sk_live_..."
withVariableButton={false}

View File

@@ -1,5 +1,5 @@
import { Input } from '@/components/inputs'
import { VariableSearchInput } from '@/components/VariableSearchInput'
import { TextInput } from '@/components/inputs'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { FormLabel, Stack } from '@chakra-ui/react'
import { PhoneNumberInputOptions, Variable } from 'models'
import React from 'react'
@@ -27,26 +27,16 @@ export const PhoneNumberSettingsBody = ({
return (
<Stack spacing={4}>
<Stack>
<FormLabel mb="0" htmlFor="placeholder">
Placeholder:
</FormLabel>
<Input
id="placeholder"
defaultValue={options.labels.placeholder}
onChange={handlePlaceholderChange}
/>
</Stack>
<Stack>
<FormLabel mb="0" htmlFor="button">
Button label:
</FormLabel>
<Input
id="button"
defaultValue={options.labels.button}
onChange={handleButtonLabelChange}
/>
</Stack>
<TextInput
label="Placeholder:"
defaultValue={options.labels.placeholder}
onChange={handlePlaceholderChange}
/>
<TextInput
label="Button label:"
defaultValue={options.labels.button}
onChange={handleButtonLabelChange}
/>
<Stack>
<FormLabel mb="0" htmlFor="button">
Default country:
@@ -56,16 +46,11 @@ export const PhoneNumberSettingsBody = ({
countryCode={options.defaultCountryCode}
/>
</Stack>
<Stack>
<FormLabel mb="0" htmlFor="retry">
Retry message:
</FormLabel>
<Input
id="retry"
defaultValue={options.retryMessageContent}
onChange={handleRetryMessageChange}
/>
</Stack>
<TextInput
label="Retry message:"
defaultValue={options.retryMessageContent}
onChange={handleRetryMessageChange}
/>
<Stack>
<FormLabel mb="0" htmlFor="variable">
Save answer in a variable:

View File

@@ -28,8 +28,8 @@ test.describe('Phone input block', () => {
await expect(page.getByRole('button', { name: 'Send' })).toBeDisabled()
await page.click(`text=${defaultPhoneInputOptions.labels.placeholder}`)
await page.fill('#placeholder', '+33 XX XX XX XX')
await page.fill('#button', 'Go')
await page.getByLabel('Placeholder:').fill('+33 XX XX XX XX')
await page.getByLabel('Button label:').fill('Go')
await page.fill(
`input[value="${defaultPhoneInputOptions.retryMessageContent}"]`,
'Try again bro'

View File

@@ -2,9 +2,9 @@ import { FormLabel, Stack } from '@chakra-ui/react'
import { DropdownList } from '@/components/DropdownList'
import { RatingInputOptions, Variable } from 'models'
import React from 'react'
import { SwitchWithLabel } from '@/components/SwitchWithLabel'
import { Input } from '@/components/inputs'
import { VariableSearchInput } from '@/components/VariableSearchInput'
import { SwitchWithLabel } from '@/components/inputs/SwitchWithLabel'
import { TextInput } from '@/components/inputs'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
type RatingInputSettingsProps = {
options: RatingInputOptions
@@ -77,56 +77,36 @@ export const RatingInputSettings = ({
/>
)}
{options.buttonType === 'Icons' && options.customIcon.isEnabled && (
<Stack>
<FormLabel mb="0" htmlFor="svg">
Icon SVG:
</FormLabel>
<Input
id="svg"
defaultValue={options.customIcon.svg}
onChange={handleIconSvgChange}
placeholder="<svg>...</svg>"
/>
</Stack>
<TextInput
label="Icon SVG:"
defaultValue={options.customIcon.svg}
onChange={handleIconSvgChange}
placeholder="<svg>...</svg>"
/>
)}
<Stack>
<FormLabel mb="0" htmlFor="button">
{options.buttonType === 'Icons' ? '1' : '0'} label:
</FormLabel>
<Input
id="button"
defaultValue={options.labels.left}
onChange={handleLeftLabelChange}
placeholder="Not likely at all"
/>
</Stack>
<Stack>
<FormLabel mb="0" htmlFor="button">
{options.length} label:
</FormLabel>
<Input
id="button"
defaultValue={options.labels.right}
onChange={handleRightLabelChange}
placeholder="Extremely likely"
/>
</Stack>
<TextInput
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}
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}
onCheckChange={handleOneClickSubmitChange}
/>
<Stack>
<FormLabel mb="0" htmlFor="button">
Button label:
</FormLabel>
<Input
id="button"
defaultValue={options.labels.button}
onChange={handleButtonLabelChange}
/>
</Stack>
<TextInput
label="Button label:"
defaultValue={options.labels.button}
onChange={handleButtonLabelChange}
/>
<Stack>
<FormLabel mb="0" htmlFor="variable">
Save answer in a variable:

View File

@@ -1,6 +1,6 @@
import { Input } from '@/components/inputs'
import { SwitchWithLabel } from '@/components/SwitchWithLabel'
import { VariableSearchInput } from '@/components/VariableSearchInput'
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 'models'
import React from 'react'
@@ -30,26 +30,16 @@ export const TextInputSettingsBody = ({
initialValue={options?.isLong ?? false}
onCheckChange={handleLongChange}
/>
<Stack>
<FormLabel mb="0" htmlFor="placeholder">
Placeholder:
</FormLabel>
<Input
id="placeholder"
defaultValue={options.labels.placeholder}
onChange={handlePlaceholderChange}
/>
</Stack>
<Stack>
<FormLabel mb="0" htmlFor="button">
Button label:
</FormLabel>
<Input
id="button"
defaultValue={options.labels.button}
onChange={handleButtonLabelChange}
/>
</Stack>
<TextInput
label="Placeholder:"
defaultValue={options.labels.placeholder}
onChange={handlePlaceholderChange}
/>
<TextInput
label="Button label:"
defaultValue={options.labels.button}
onChange={handleButtonLabelChange}
/>
<Stack>
<FormLabel mb="0" htmlFor="variable">
Save answer in a variable:

View File

@@ -28,8 +28,8 @@ test.describe.parallel('Text input block', () => {
await expect(page.getByRole('button', { name: 'Send' })).toBeDisabled()
await page.click(`text=${defaultTextInputOptions.labels.placeholder}`)
await page.fill('#placeholder', 'Your name...')
await page.fill('#button', 'Go')
await page.getByLabel('Placeholder:').fill('Your name...')
await page.getByLabel('Button label:').fill('Go')
await page.click('text=Long text?')
await page.click('text=Restart')

View File

@@ -1,5 +1,5 @@
import { Input } from '@/components/inputs'
import { VariableSearchInput } from '@/components/VariableSearchInput'
import { TextInput } from '@/components/inputs'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { FormLabel, Stack } from '@chakra-ui/react'
import { UrlInputOptions, Variable } from 'models'
import React from 'react'
@@ -24,36 +24,21 @@ export const UrlInputSettingsBody = ({
return (
<Stack spacing={4}>
<Stack>
<FormLabel mb="0" htmlFor="placeholder">
Placeholder:
</FormLabel>
<Input
id="placeholder"
defaultValue={options.labels.placeholder}
onChange={handlePlaceholderChange}
/>
</Stack>
<Stack>
<FormLabel mb="0" htmlFor="button">
Button label:
</FormLabel>
<Input
id="button"
defaultValue={options.labels.button}
onChange={handleButtonLabelChange}
/>
</Stack>
<Stack>
<FormLabel mb="0" htmlFor="retry">
Retry message:
</FormLabel>
<Input
id="retry"
defaultValue={options.retryMessageContent}
onChange={handleRetryMessageChange}
/>
</Stack>
<TextInput
label="Placeholder:"
defaultValue={options.labels.placeholder}
onChange={handlePlaceholderChange}
/>
<TextInput
label="Button label:"
defaultValue={options.labels.button}
onChange={handleButtonLabelChange}
/>
<TextInput
label="Retry message:"
defaultValue={options.retryMessageContent}
onChange={handleRetryMessageChange}
/>
<Stack>
<FormLabel mb="0" htmlFor="variable">
Save answer in a variable:

View File

@@ -30,9 +30,9 @@ test.describe('Url input block', () => {
).toBeDisabled()
await page.click(`text=${defaultUrlInputOptions.labels.placeholder}`)
await page.fill('#placeholder', 'Your URL...')
await page.getByLabel('Placeholder:').fill('Your URL...')
await expect(page.locator('text=Your URL...')).toBeVisible()
await page.fill('#button', 'Go')
await page.getByLabel('Button label:').fill('Go')
await page.fill(
`input[value="${defaultUrlInputOptions.retryMessageContent}"]`,
'Try again bro'

View File

@@ -1,4 +1,4 @@
import { Input } from '@/components/inputs'
import { TextInput } from '@/components/inputs'
import {
Accordion,
AccordionButton,
@@ -18,7 +18,7 @@ type Props = {
export const ChatwootSettingsForm = ({ options, onOptionsChange }: Props) => {
return (
<Stack spacing={4}>
<Input
<TextInput
isRequired
label="Base URL"
defaultValue={options.baseUrl}
@@ -27,7 +27,7 @@ export const ChatwootSettingsForm = ({ options, onOptionsChange }: Props) => {
}}
withVariableButton={false}
/>
<Input
<TextInput
isRequired
label="Website token"
defaultValue={options.websiteToken}
@@ -43,14 +43,14 @@ export const ChatwootSettingsForm = ({ options, onOptionsChange }: Props) => {
<AccordionIcon />
</AccordionButton>
<AccordionPanel pb={4} as={Stack} spacing="4">
<Input
<TextInput
label="ID"
defaultValue={options.user?.id}
onChange={(id: string) => {
onOptionsChange({ ...options, user: { ...options.user, id } })
}}
/>
<Input
<TextInput
label="Name"
defaultValue={options.user?.name}
onChange={(name: string) => {
@@ -60,7 +60,7 @@ export const ChatwootSettingsForm = ({ options, onOptionsChange }: Props) => {
})
}}
/>
<Input
<TextInput
label="Email"
defaultValue={options.user?.email}
onChange={(email: string) => {
@@ -70,7 +70,7 @@ export const ChatwootSettingsForm = ({ options, onOptionsChange }: Props) => {
})
}}
/>
<Input
<TextInput
label="Avatar URL"
defaultValue={options.user?.avatarUrl}
onChange={(avatarUrl: string) => {
@@ -80,7 +80,7 @@ export const ChatwootSettingsForm = ({ options, onOptionsChange }: Props) => {
})
}}
/>
<Input
<TextInput
label="Phone number"
defaultValue={options.user?.phoneNumber}
onChange={(phoneNumber: string) => {

View File

@@ -1,4 +1,4 @@
import { Input } from '@/components/inputs'
import { TextInput } from '@/components/inputs'
import {
Accordion,
AccordionButton,
@@ -42,39 +42,24 @@ export const GoogleAnalyticsSettings = ({
return (
<Stack spacing={4}>
<Stack>
<FormLabel mb="0" htmlFor="tracking-id">
Tracking ID:
</FormLabel>
<Input
id="tracking-id"
defaultValue={options?.trackingId ?? ''}
placeholder="G-123456..."
onChange={handleTrackingIdChange}
/>
</Stack>
<Stack>
<FormLabel mb="0" htmlFor="category">
Event category:
</FormLabel>
<Input
id="category"
defaultValue={options?.category ?? ''}
placeholder="Example: Typebot"
onChange={handleCategoryChange}
/>
</Stack>
<Stack>
<FormLabel mb="0" htmlFor="action">
Event action:
</FormLabel>
<Input
id="action"
defaultValue={options?.action ?? ''}
placeholder="Example: Submit email"
onChange={handleActionChange}
/>
</Stack>
<TextInput
label="Tracking ID:"
defaultValue={options?.trackingId ?? ''}
placeholder="G-123456..."
onChange={handleTrackingIdChange}
/>
<TextInput
label="Event category:"
defaultValue={options?.category ?? ''}
placeholder="Example: Typebot"
onChange={handleCategoryChange}
/>
<TextInput
label="Event action:"
defaultValue={options?.action ?? ''}
placeholder="Example: Submit email"
onChange={handleActionChange}
/>
<Accordion allowToggle>
<AccordionItem>
<h2>
@@ -86,28 +71,28 @@ export const GoogleAnalyticsSettings = ({
</AccordionButton>
</h2>
<AccordionPanel pb={4} as={Stack} spacing="6">
<Stack>
<FormLabel mb="0" htmlFor="label">
Event label <Tag>Optional</Tag>:
</FormLabel>
<Input
id="label"
defaultValue={options?.label ?? ''}
placeholder="Example: Campaign Z"
onChange={handleLabelChange}
/>
</Stack>
<Stack>
<FormLabel mb="0" htmlFor="value">
Event value <Tag>Optional</Tag>:
</FormLabel>
<Input
id="value"
defaultValue={options?.value?.toString() ?? ''}
placeholder="Example: 0"
onChange={handleValueChange}
/>
</Stack>
<TextInput
label={
<>
Event label <Tag>Optional</Tag>:
</>
}
defaultValue={options?.label ?? ''}
placeholder="Example: Campaign Z"
onChange={handleLabelChange}
/>
<TextInput
label={
<>
<FormLabel mb="0" htmlFor="value">
Event value <Tag>Optional</Tag>:
</FormLabel>
</>
}
defaultValue={options?.value?.toString() ?? ''}
placeholder="Example: 0"
onChange={handleValueChange}
/>
</AccordionPanel>
</AccordionItem>
</Accordion>

View File

@@ -2,7 +2,7 @@ import { Stack } from '@chakra-ui/react'
import { DropdownList } from '@/components/DropdownList'
import { Cell } from 'models'
import { TableListItemProps } from '@/components/TableList'
import { Input } from '@/components/inputs'
import { TextInput } from '@/components/inputs'
export const CellWithValueStack = ({
item,
@@ -25,7 +25,7 @@ export const CellWithValueStack = ({
items={columns}
placeholder="Select a column"
/>
<Input
<TextInput
defaultValue={item.value ?? ''}
onChange={handleValueChange}
placeholder="Type a value..."

View File

@@ -2,7 +2,7 @@ import { Stack } from '@chakra-ui/react'
import { DropdownList } from '@/components/DropdownList'
import { ExtractingCell, Variable } from 'models'
import { TableListItemProps } from '@/components/TableList'
import { VariableSearchInput } from '@/components/VariableSearchInput'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
export const CellWithVariableIdStack = ({
item,

View File

@@ -1,5 +1,5 @@
import { DropdownList } from '@/components/DropdownList'
import { Input } from '@/components/inputs'
import { TextInput } from '@/components/inputs'
import { TableListItemProps } from '@/components/TableList'
import { Stack } from '@chakra-ui/react'
import { ComparisonOperators, RowsFilterComparison } from 'models'
@@ -42,7 +42,7 @@ export const RowsFilterComparisonItem = ({
placeholder="Select an operator"
/>
{item.comparisonOperator !== ComparisonOperators.IS_SET && (
<Input
<TextInput
defaultValue={item.value ?? ''}
onChange={handleChangeValue}
placeholder="Type a value..."

View File

@@ -1,8 +1,6 @@
import { MoreInfoTooltip } from '@/components/MoreInfoTooltip'
import { SearchableDropdown } from '@/components/SearchableDropdown'
import { Select } from '@/components/inputs/Select'
import { HStack, Input } from '@chakra-ui/react'
import { useMemo } from 'react'
import { isDefined } from 'utils'
import { Sheet } from '../../types'
type Props = {
@@ -18,16 +16,6 @@ export const SheetsDropdown = ({
sheetId,
onSelectSheetId,
}: Props) => {
const currentSheet = useMemo(
() => sheets?.find((s) => s.id === sheetId),
[sheetId, sheets]
)
const handleSpreadsheetSelect = (name: string) => {
const id = sheets?.find((s) => s.name === name)?.id
if (isDefined(id)) onSelectSheetId(id)
}
if (isLoading) return <Input value="Loading..." isDisabled />
if (!sheets || sheets.length === 0)
return (
@@ -40,10 +28,10 @@ export const SheetsDropdown = ({
</HStack>
)
return (
<SearchableDropdown
selectedItem={currentSheet?.name}
items={(sheets ?? []).map((s) => s.name)}
onValueChange={handleSpreadsheetSelect}
<Select
selectedItem={sheetId}
items={(sheets ?? []).map((s) => ({ label: s.name, value: s.id }))}
onSelect={onSelectSheetId}
placeholder={'Select the sheet'}
/>
)

View File

@@ -1,6 +1,5 @@
import { SearchableDropdown } from '@/components/SearchableDropdown'
import { Select } from '@/components/inputs/Select'
import { Input, Tooltip } from '@chakra-ui/react'
import { useMemo } from 'react'
import { useSpreadsheets } from '../../hooks/useSpreadsheets'
type Props = {
@@ -17,15 +16,7 @@ export const SpreadsheetsDropdown = ({
const { spreadsheets, isLoading } = useSpreadsheets({
credentialsId,
})
const currentSpreadsheet = useMemo(
() => spreadsheets?.find((s) => s.id === spreadsheetId),
[spreadsheetId, spreadsheets]
)
const handleSpreadsheetSelect = (name: string) => {
const id = spreadsheets?.find((s) => s.name === name)?.id
if (id) onSelectSpreadsheetId(id)
}
if (isLoading) return <Input value="Loading..." isDisabled />
if (!spreadsheets || spreadsheets.length === 0)
return (
@@ -36,10 +27,13 @@ export const SpreadsheetsDropdown = ({
</Tooltip>
)
return (
<SearchableDropdown
selectedItem={currentSpreadsheet?.name}
items={(spreadsheets ?? []).map((s) => s.name)}
onValueChange={handleSpreadsheetSelect}
<Select
selectedItem={spreadsheetId}
items={(spreadsheets ?? []).map((spreadsheet) => ({
label: spreadsheet.name,
value: spreadsheet.id,
}))}
onSelect={onSelectSpreadsheetId}
placeholder={'Search for spreadsheet'}
/>
)

View File

@@ -7,15 +7,15 @@ import {
Switch,
FormLabel,
} from '@chakra-ui/react'
import { CodeEditor } from '@/components/CodeEditor'
import { CodeEditor } from '@/components/inputs/CodeEditor'
import { CredentialsType, SendEmailOptions, Variable } from 'models'
import React, { useState } from 'react'
import { env, isNotEmpty } from 'utils'
import { SmtpConfigModal } from './SmtpConfigModal'
import { SwitchWithLabel } from '@/components/SwitchWithLabel'
import { VariableSearchInput } from '@/components/VariableSearchInput'
import { SwitchWithLabel } from '@/components/inputs/SwitchWithLabel'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { CredentialsDropdown } from '@/features/credentials'
import { Input, Textarea } from '@/components/inputs'
import { TextInput, Textarea } from '@/components/inputs'
type Props = {
options: SendEmailOptions
@@ -120,46 +120,35 @@ export const SendEmailSettings = ({ options, onOptionsChange }: Props) => {
refreshDropdownKey={refreshCredentialsKey}
/>
</Stack>
<Stack>
<Text>Reply to: </Text>
<Input
onChange={handleReplyToChange}
defaultValue={options.replyTo}
placeholder={'email@gmail.com'}
/>
</Stack>
<Stack>
<Text>To: </Text>
<Input
onChange={handleToChange}
defaultValue={options.recipients.join(', ')}
placeholder="email1@gmail.com, email2@gmail.com"
/>
</Stack>
<Stack>
<Text>Cc: </Text>
<Input
onChange={handleCcChange}
defaultValue={options.cc?.join(', ') ?? ''}
placeholder="email1@gmail.com, email2@gmail.com"
/>
</Stack>
<Stack>
<Text>Bcc: </Text>
<Input
onChange={handleBccChange}
defaultValue={options.bcc?.join(', ') ?? ''}
placeholder="email1@gmail.com, email2@gmail.com"
/>
</Stack>
<Stack>
<Text>Subject: </Text>
<Input
data-testid="subject-input"
onChange={handleSubjectChange}
defaultValue={options.subject ?? ''}
/>
</Stack>
<TextInput
label="Reply to:"
onChange={handleReplyToChange}
defaultValue={options.replyTo}
placeholder={'email@gmail.com'}
/>
<TextInput
label="To:"
onChange={handleToChange}
defaultValue={options.recipients.join(', ')}
placeholder="email1@gmail.com, email2@gmail.com"
/>
<TextInput
label="Cc:"
onChange={handleCcChange}
defaultValue={options.cc?.join(', ') ?? ''}
placeholder="email1@gmail.com, email2@gmail.com"
/>
<TextInput
label="Bcc:"
onChange={handleBccChange}
defaultValue={options.bcc?.join(', ') ?? ''}
placeholder="email1@gmail.com, email2@gmail.com"
/>
<TextInput
label="Subject:"
onChange={handleSubjectChange}
defaultValue={options.subject ?? ''}
/>
<SwitchWithLabel
label={'Custom content?'}
moreInfoContent="By default, the email body will be a recap of what has been collected so far. You can override it with this option."

View File

@@ -1,5 +1,5 @@
import { Input, SmartNumberInput } from '@/components/inputs'
import { SwitchWithLabel } from '@/components/SwitchWithLabel'
import { TextInput, NumberInput } from '@/components/inputs'
import { SwitchWithLabel } from '@/components/inputs/SwitchWithLabel'
import { Stack } from '@chakra-ui/react'
import { isDefined } from '@udecode/plate-common'
import { SmtpCredentialsData } from 'models'
@@ -27,7 +27,7 @@ export const SmtpConfigForm = ({ config, onConfigChange }: Props) => {
return (
<Stack as="form" spacing={4}>
<Input
<TextInput
isRequired
label="From email"
defaultValue={config.from.email ?? ''}
@@ -35,14 +35,14 @@ export const SmtpConfigForm = ({ config, onConfigChange }: Props) => {
placeholder="notifications@provider.com"
withVariableButton={false}
/>
<Input
<TextInput
label="From name"
defaultValue={config.from.name ?? ''}
onChange={handleFromNameChange}
placeholder="John Smith"
withVariableButton={false}
/>
<Input
<TextInput
isRequired
label="Host"
defaultValue={config.host ?? ''}
@@ -50,7 +50,7 @@ export const SmtpConfigForm = ({ config, onConfigChange }: Props) => {
placeholder="mail.provider.com"
withVariableButton={false}
/>
<Input
<TextInput
isRequired
label="Username / Email"
type="email"
@@ -59,7 +59,7 @@ export const SmtpConfigForm = ({ config, onConfigChange }: Props) => {
placeholder="user@provider.com"
withVariableButton={false}
/>
<Input
<TextInput
isRequired
label="Password"
type="password"
@@ -73,7 +73,7 @@ export const SmtpConfigForm = ({ config, onConfigChange }: Props) => {
onCheckChange={handleTlsCheck}
moreInfoContent="If enabled, the connection will use TLS when connecting to server. If disabled then TLS is used if server supports the STARTTLS extension. In most cases enable it if you are connecting to port 465. For port 587 or 25 keep it disabled."
/>
<SmartNumberInput
<NumberInput
isRequired
label="Port number:"
placeholder="25"

View File

@@ -58,9 +58,9 @@ test.describe('Send email block', () => {
'[placeholder="email1@gmail.com, email2@gmail.com"]',
'email1@gmail.com, email2@gmail.com'
)
await page.fill('[data-testid="subject-input"]', 'Email subject')
await page.getByLabel('Subject:').fill('Email subject')
await page.click('text="Custom content?"')
await page.fill('[data-testid="body-input"]', 'Here is my email')
await page.locator('textarea').fill('Here is my email')
await page.click('text=Preview')
await page.locator('typebot-standard').locator('text=Go').click()

View File

@@ -1,6 +1,6 @@
import { Input } from '@/components/inputs'
import { TextInput } from '@/components/inputs'
import { TableListItemProps } from '@/components/TableList'
import { Stack, FormControl, FormLabel } from '@chakra-ui/react'
import { Stack } from '@chakra-ui/react'
import { KeyValue } from 'models'
export const QueryParamsInputs = (props: TableListItemProps<KeyValue>) => (
@@ -39,26 +39,20 @@ export const KeyValueInputs = ({
}
return (
<Stack p="4" rounded="md" flex="1" borderWidth="1px">
<FormControl>
<FormLabel htmlFor={'key' + item.id}>Key:</FormLabel>
<Input
id={'key' + item.id}
defaultValue={item.key ?? ''}
onChange={handleKeyChange}
placeholder={keyPlaceholder}
debounceTimeout={debounceTimeout}
/>
</FormControl>
<FormControl>
<FormLabel htmlFor={'value' + item.id}>Value:</FormLabel>
<Input
id={'value' + item.id}
defaultValue={item.value ?? ''}
onChange={handleValueChange}
placeholder={valuePlaceholder}
debounceTimeout={debounceTimeout}
/>
</FormControl>
<TextInput
label="Key:"
defaultValue={item.key ?? ''}
onChange={handleKeyChange}
placeholder={keyPlaceholder}
debounceTimeout={debounceTimeout}
/>
<TextInput
label="Value:"
defaultValue={item.value ?? ''}
onChange={handleValueChange}
placeholder={valuePlaceholder}
debounceTimeout={debounceTimeout}
/>
</Stack>
)
}

View File

@@ -1,6 +1,6 @@
import { SearchableDropdown } from '@/components/SearchableDropdown'
import { AutocompleteInput } from '@/components/inputs/AutocompleteInput'
import { TableListItemProps } from '@/components/TableList'
import { VariableSearchInput } from '@/components/VariableSearchInput'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { Stack, FormControl, FormLabel } from '@chakra-ui/react'
import { Variable, ResponseVariableMapping } from 'models'
@@ -18,10 +18,10 @@ export const DataVariableInputs = ({
<Stack p="4" rounded="md" flex="1" borderWidth="1px">
<FormControl>
<FormLabel htmlFor="name">Data:</FormLabel>
<SearchableDropdown
<AutocompleteInput
items={dataItems}
value={item.bodyPath}
onValueChange={handleBodyPathChange}
defaultValue={item.bodyPath}
onChange={handleBodyPathChange}
placeholder="Select the data"
withVariableButton
/>

View File

@@ -1,6 +1,6 @@
import { Input } from '@/components/inputs'
import { TextInput } from '@/components/inputs'
import { TableListItemProps } from '@/components/TableList'
import { VariableSearchInput } from '@/components/VariableSearchInput'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { Stack, FormControl, FormLabel } from '@chakra-ui/react'
import { VariableForTest, Variable } from 'models'
@@ -25,15 +25,12 @@ export const VariableForTestInputs = ({
onSelectVariable={handleVariableSelect}
/>
</FormControl>
<FormControl>
<FormLabel htmlFor={'value' + item.id}>Test value:</FormLabel>
<Input
id={'value' + item.id}
defaultValue={item.value ?? ''}
onChange={handleValueChange}
debounceTimeout={debounceTimeout}
/>
</FormControl>
<TextInput
label="Test value:"
defaultValue={item.value ?? ''}
onChange={handleValueChange}
debounceTimeout={debounceTimeout}
/>
</Stack>
)
}

View File

@@ -27,18 +27,18 @@ import {
Webhook,
} from 'models'
import { DropdownList } from '@/components/DropdownList'
import { CodeEditor } from '@/components/CodeEditor'
import { CodeEditor } from '@/components/inputs/CodeEditor'
import { HeadersInputs, QueryParamsInputs } from './KeyValueInputs'
import { VariableForTestInputs } from './VariableForTestInputs'
import { DataVariableInputs } from './ResponseMappingInputs'
import { byId, env } from 'utils'
import { ExternalLinkIcon } from '@/components/icons'
import { useToast } from '@/hooks/useToast'
import { SwitchWithLabel } from '@/components/SwitchWithLabel'
import { SwitchWithLabel } from '@/components/inputs/SwitchWithLabel'
import { TableListItemProps, TableList } from '@/components/TableList'
import { executeWebhook } from '../../queries/executeWebhookQuery'
import { getDeepKeys } from '../../utils/getDeepKeys'
import { Input } from '@/components/inputs'
import { TextInput } from '@/components/inputs'
import { convertVariablesForTestToVariables } from '../../utils/convertVariablesForTestToVariables'
import { useDebouncedCallback } from 'use-debounce'
@@ -157,7 +157,7 @@ export const WebhookSettings = ({
</Stack>
</Alert>
)}
<Input
<TextInput
placeholder="Paste webhook URL..."
defaultValue={localWebhook.url ?? ''}
onChange={handleUrlChange}

View File

@@ -2,8 +2,8 @@ import { Stack } from '@chakra-ui/react'
import { DropdownList } from '@/components/DropdownList'
import { Comparison, Variable, ComparisonOperators } from 'models'
import { TableListItemProps } from '@/components/TableList'
import { VariableSearchInput } from '@/components/VariableSearchInput'
import { Input } from '@/components/inputs'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { TextInput } from '@/components/inputs'
export const ComparisonItem = ({
item,
@@ -39,7 +39,7 @@ export const ComparisonItem = ({
placeholder="Select an operator"
/>
{item.comparisonOperator !== ComparisonOperators.IS_SET && (
<Input
<TextInput
defaultValue={item.value ?? ''}
onChange={handleChangeValue}
placeholder="Type a value..."

View File

@@ -1,6 +1,6 @@
import { Input } from '@/components/inputs'
import { SwitchWithLabel } from '@/components/SwitchWithLabel'
import { FormLabel, Stack } from '@chakra-ui/react'
import { TextInput } from '@/components/inputs'
import { SwitchWithLabel } from '@/components/inputs/SwitchWithLabel'
import { Stack } from '@chakra-ui/react'
import { RedirectOptions } from 'models'
import React from 'react'
@@ -17,17 +17,12 @@ export const RedirectSettings = ({ options, onOptionsChange }: Props) => {
return (
<Stack spacing={4}>
<Stack>
<FormLabel mb="0" htmlFor="tracking-id">
Url:
</FormLabel>
<Input
id="tracking-id"
defaultValue={options.url ?? ''}
placeholder="Type a URL..."
onChange={handleUrlChange}
/>
</Stack>
<TextInput
label="Url:"
defaultValue={options.url ?? ''}
placeholder="Type a URL..."
onChange={handleUrlChange}
/>
<SwitchWithLabel
label="Open in new tab?"
initialValue={options.isNewTab}

View File

@@ -1,7 +1,7 @@
import { FormLabel, Stack, Text } from '@chakra-ui/react'
import { CodeEditor } from '@/components/CodeEditor'
import { Stack, Text } from '@chakra-ui/react'
import { CodeEditor } from '@/components/inputs/CodeEditor'
import React from 'react'
import { Input } from '@/components/inputs'
import { TextInput } from '@/components/inputs'
import { ScriptOptions } from 'models'
type Props = {
@@ -17,17 +17,12 @@ export const ScriptSettings = ({ options, onOptionsChange }: Props) => {
return (
<Stack spacing={4}>
<Stack>
<FormLabel mb="0" htmlFor="name">
Name:
</FormLabel>
<Input
id="name"
defaultValue={options.name}
onChange={handleNameChange}
withVariableButton={false}
/>
</Stack>
<TextInput
label="Name:"
defaultValue={options.name}
onChange={handleNameChange}
withVariableButton={false}
/>
<Stack>
<Text>Code:</Text>
<CodeEditor

View File

@@ -1,8 +1,8 @@
import { FormLabel, HStack, Stack, Switch, Text } from '@chakra-ui/react'
import { CodeEditor } from '@/components/CodeEditor'
import { CodeEditor } from '@/components/inputs/CodeEditor'
import { SetVariableOptions, Variable } from 'models'
import React from 'react'
import { VariableSearchInput } from '@/components/VariableSearchInput'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { Textarea } from '@/components/inputs'
type Props = {

View File

@@ -1,8 +1,6 @@
import { SearchableDropdown } from '@/components/SearchableDropdown'
import { Select } from '@/components/inputs/Select'
import { Input } from '@chakra-ui/react'
import { Group } from 'models'
import { useMemo } from 'react'
import { byId } from 'utils'
type Props = {
groups: Group[]
@@ -17,24 +15,17 @@ export const GroupsDropdown = ({
onGroupIdSelected,
isLoading,
}: Props) => {
const currentGroup = useMemo(
() => groups?.find(byId(groupId)),
[groupId, groups]
)
const handleGroupSelect = (title: string) => {
const id = groups?.find((b) => b.title === title)?.id
if (id) onGroupIdSelected(id)
}
if (isLoading) return <Input value="Loading..." isDisabled />
if (!groups || groups.length === 0)
return <Input value="No groups found" isDisabled />
return (
<SearchableDropdown
selectedItem={currentGroup?.title}
items={(groups ?? []).map((b) => b.title)}
onValueChange={handleGroupSelect}
<Select
selectedItem={groupId}
items={(groups ?? []).map((group) => ({
label: group.title,
value: group.id,
}))}
onSelect={onGroupIdSelected}
placeholder={'Select a block'}
/>
)

View File

@@ -24,7 +24,7 @@ export const TypebotLinkForm = ({ options, onOptionsChange }: Props) => {
<TypebotsDropdown
idsToExclude={[typebot.id]}
typebotId={options.typebotId}
onSelectTypebotId={handleTypebotIdChange}
onSelect={handleTypebotIdChange}
currentWorkspaceId={typebot.workspaceId as string}
/>
)}

View File

@@ -1,25 +1,23 @@
import { HStack, IconButton, Input, Text } from '@chakra-ui/react'
import { HStack, IconButton, Input } from '@chakra-ui/react'
import { ExternalLinkIcon } from '@/components/icons'
import { useToast } from '@/hooks/useToast'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useMemo } from 'react'
import { byId } from 'utils'
import { useTypebots } from '@/features/dashboard'
import { SearchableDropdown } from '@/components/SearchableDropdown'
import { Select } from '@/components/inputs/Select'
import { EmojiOrImageIcon } from '@/components/EmojiOrImageIcon'
type Props = {
idsToExclude: string[]
typebotId?: string | 'current'
currentWorkspaceId: string
onSelectTypebotId: (typebotId: string | 'current') => void
onSelect: (typebotId: string | 'current') => void
}
export const TypebotsDropdown = ({
idsToExclude,
typebotId,
onSelectTypebotId,
onSelect,
currentWorkspaceId,
}: Props) => {
const { query } = useRouter()
@@ -28,56 +26,42 @@ export const TypebotsDropdown = ({
workspaceId: currentWorkspaceId,
onError: (e) => showToast({ title: e.name, description: e.message }),
})
const currentTypebot = useMemo(
() => typebots?.find(byId(typebotId)),
[typebotId, typebots]
)
const handleTypebotSelect = (name: string) => {
if (name === 'Current typebot') return onSelectTypebotId('current')
const id = typebots?.find((s) => s.name === name)?.id
if (id) onSelectTypebotId(id)
}
if (isLoading) return <Input value="Loading..." isDisabled />
if (!typebots || typebots.length === 0)
return <Input value="No typebots found" isDisabled />
return (
<HStack>
<SearchableDropdown
selectedItem={
typebotId === 'current' ? 'Current typebot' : currentTypebot?.name
}
<Select
selectedItem={typebotId}
items={[
{
label: 'Current typebot',
value: 'Current typebot',
value: 'current',
},
...(typebots ?? [])
.filter((typebot) => !idsToExclude.includes(typebot.id))
.map((typebot) => ({
value: typebot.name,
label: (
<HStack as="span" spacing="2">
<EmojiOrImageIcon
icon={typebot.icon}
boxSize="18px"
emojiFontSize="18px"
/>
<Text>{typebot.name}</Text>
</HStack>
icon: (
<EmojiOrImageIcon
icon={typebot.icon}
boxSize="18px"
emojiFontSize="18px"
/>
),
label: typebot.name,
value: typebot.id,
})),
]}
onValueChange={handleTypebotSelect}
onSelect={onSelect}
placeholder={'Select a typebot'}
/>
{currentTypebot?.id && (
{typebotId && typebotId !== 'current' && (
<IconButton
aria-label="Navigate to typebot"
icon={<ExternalLinkIcon />}
as={Link}
href={`/typebots/${currentTypebot?.id}/edit?parentId=${query.typebotId}`}
href={`/typebots/${typebotId}/edit?parentId=${query.typebotId}`}
/>
)}
</HStack>

View File

@@ -29,7 +29,9 @@ test('should be configurable', async ({ page }) => {
await page.click('[aria-label="Navigate back"]')
await expect(page).toHaveURL(`/typebots/${typebotId}/edit`)
await page.click('text=Jump in My link typebot 2')
await expect(page.locator('input[value="My link typebot 2"]')).toBeVisible()
await expect(page.getByTestId('selected-item-label').first()).toHaveText(
'My link typebot 2'
)
await page.click('input[placeholder="Select a block"]')
await page.click('text=Group #2')
@@ -40,8 +42,7 @@ test('should be configurable', async ({ page }) => {
await page.click('[aria-label="Close"]')
await page.click('text=Jump to Group #2 in My link typebot 2')
await page.click('input[value="Group #2"]', { clickCount: 3 })
await page.press('input[value="Group #2"]', 'Backspace')
await page.getByTestId('selected-item-label').nth(1).click({ force: true })
await page.click('button >> text=Start')
await page.click('text=Preview')
@@ -54,13 +55,9 @@ test('should be configurable', async ({ page }) => {
await page.click('[aria-label="Close"]')
await page.click('text=Jump to Start in My link typebot 2')
await page.waitForTimeout(1000)
await page.click('input[value="My link typebot 2"]', { clickCount: 3 })
await page.press('input[value="My link typebot 2"]', 'Backspace')
await page.getByTestId('selected-item-label').first().click({ force: true })
await page.click('button >> text=Current typebot')
await page.click('input[placeholder="Select a block"]', {
clickCount: 3,
})
await page.press('input[placeholder="Select a block"]', 'Backspace')
await page.getByPlaceholder('Select a block').click()
await page.click('button >> text=Hello')
await page.click('text=Preview')

View File

@@ -1,7 +1,7 @@
import { Stack } from '@chakra-ui/react'
import { WaitOptions } from 'models'
import React from 'react'
import { Input } from '@/components/inputs'
import { TextInput } from '@/components/inputs'
type Props = {
options: WaitOptions
@@ -15,7 +15,7 @@ export const WaitSettings = ({ options, onOptionsChange }: Props) => {
return (
<Stack spacing={4}>
<Input
<TextInput
label="Seconds to wait for:"
defaultValue={options.secondsToWaitFor}
onChange={handleSecondsChange}