Add Wait block

Closes #142
This commit is contained in:
Baptiste Arnaud
2023-01-26 18:23:09 +01:00
parent ee864d9729
commit fa9e4b7b67
29 changed files with 621 additions and 313 deletions

View File

@@ -0,0 +1,14 @@
import { featherIconsBaseProps } from '@/components/icons'
import { Icon, IconProps, useColorModeValue } from '@chakra-ui/react'
export const WaitIcon = (props: IconProps) => (
<Icon
viewBox="0 0 24 24"
color={useColorModeValue('purple.500', 'purple.300')}
{...featherIconsBaseProps}
{...props}
>
<circle cx="12" cy="12" r="10"></circle>
<polyline points="12 6 12 12 16 14"></polyline>
</Icon>
)

View File

@@ -0,0 +1,13 @@
import { Text } from '@chakra-ui/react'
import { WaitOptions } from 'models'
import React from 'react'
type Props = {
options: WaitOptions
}
export const WaitNodeContent = ({ options: { secondsToWaitFor } }: Props) => (
<Text color={secondsToWaitFor ? 'currentcolor' : 'gray.500'} noOfLines={1}>
{secondsToWaitFor ? `Wait for ${secondsToWaitFor}s` : 'Configure...'}
</Text>
)

View File

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

View File

@@ -0,0 +1,26 @@
import test, { expect } from '@playwright/test'
import { typebotViewer } from 'utils/playwright/testHelpers'
import { importTypebotInDatabase } from 'utils/playwright/databaseActions'
import cuid from 'cuid'
import { getTestAsset } from '@/test/utils/playwright'
const typebotId = cuid()
test.describe('Wait block', () => {
test('wait should trigger', async ({ page }) => {
await importTypebotInDatabase(getTestAsset('typebots/logic/wait.json'), {
id: typebotId,
})
await page.goto(`/typebots/${typebotId}/edit`)
await page.click('text=Configure...')
await page.getByRole('textbox', { name: 'Seconds to wait for:' }).fill('3')
await page.click('text=Preview')
await typebotViewer(page).locator('text=Wait now').click()
await page.waitForTimeout(1000)
await expect(typebotViewer(page).locator('text="Hi there!"')).toBeHidden()
await page.waitForTimeout(3000)
await expect(typebotViewer(page).locator('text="Hi there!"')).toBeVisible()
})
})

View File

@@ -36,6 +36,7 @@ import { TextInputIcon } from '@/features/blocks/inputs/textInput'
import { EmbedBubbleIcon } from '@/features/blocks/bubbles/embed'
import { GoogleAnalyticsLogo } from '@/features/blocks/integrations/googleAnalytics'
import { AudioBubbleIcon } from '@/features/blocks/bubbles/audio'
import { WaitIcon } from '@/features/blocks/logic/wait/components/WaitIcon'
type BlockIconProps = { type: BlockType } & IconProps
@@ -82,6 +83,8 @@ export const BlockIcon = ({ type, ...props }: BlockIconProps) => {
return <RedirectIcon color={purple} {...props} />
case LogicBlockType.CODE:
return <CodeIcon color={purple} {...props} />
case LogicBlockType.WAIT:
return <WaitIcon color={purple} {...props} />
case LogicBlockType.TYPEBOT_LINK:
return <TypebotLinkIcon color={purple} {...props} />
case IntegrationBlockType.GOOGLE_SHEETS:

View File

@@ -77,6 +77,8 @@ export const BlockTypeLabel = ({ type }: Props): JSX.Element => {
<Text>Typebot</Text>
</Tooltip>
)
case LogicBlockType.WAIT:
return <Text>Wait</Text>
case IntegrationBlockType.GOOGLE_SHEETS:
return (
<Tooltip label="Google Sheets">

View File

@@ -37,6 +37,7 @@ import { SendEmailContent } from '@/features/blocks/integrations/sendEmail'
import { isInputBlock, isChoiceInput, blockHasItems } from 'utils'
import { MakeComContent } from '@/features/blocks/integrations/makeCom'
import { AudioBubbleNode } from '@/features/blocks/bubbles/audio'
import { WaitNodeContent } from '@/features/blocks/logic/wait/components/WaitNodeContent'
type Props = {
block: Block | StartBlock
@@ -120,6 +121,9 @@ export const BlockNodeContent = ({ block, indices }: Props): JSX.Element => {
/>
)
}
case LogicBlockType.WAIT: {
return <WaitNodeContent options={block.options} />
}
case LogicBlockType.TYPEBOT_LINK:
return <TypebotLinkNode block={block} />

View File

@@ -40,6 +40,8 @@ const getHelpDocUrl = (blockType: BlockWithOptions['type']): string | null => {
return 'https://docs.typebot.io/editor/blocks/logic/redirect'
case LogicBlockType.CODE:
return 'https://docs.typebot.io/editor/blocks/logic/code'
case LogicBlockType.WAIT:
return 'https://docs.typebot.io/editor/blocks/logic/wait'
case InputBlockType.TEXT:
return 'https://docs.typebot.io/editor/blocks/inputs/text'
case InputBlockType.NUMBER:

View File

@@ -41,6 +41,7 @@ import { ButtonsOptionsForm } from '@/features/blocks/inputs/buttons'
import { ChatwootSettingsForm } from '@/features/blocks/integrations/chatwoot'
import { MakeComSettings } from '@/features/blocks/integrations/makeCom'
import { HelpDocButton } from './HelpDocButton'
import { WaitSettings } from '@/features/blocks/logic/wait/components/WaitSettings'
type Props = {
block: BlockWithOptions
@@ -212,6 +213,14 @@ export const BlockSettings = ({
/>
)
}
case LogicBlockType.WAIT: {
return (
<WaitSettings
options={block.options}
onOptionsChange={handleOptionsChange}
/>
)
}
case IntegrationBlockType.GOOGLE_SHEETS: {
return (
<GoogleSheetsSettingsBody

View File

@@ -37,6 +37,7 @@ import {
Item,
ItemType,
LogicBlockType,
defaultWaitOptions,
} from 'models'
import {
stubLength,
@@ -434,6 +435,8 @@ const parseDefaultBlockOptions = (type: BlockWithOptionsType): BlockOptions => {
return defaultRedirectOptions
case LogicBlockType.CODE:
return defaultCodeOptions
case LogicBlockType.WAIT:
return defaultWaitOptions
case LogicBlockType.TYPEBOT_LINK:
return {}
case IntegrationBlockType.GOOGLE_SHEETS:

View File

@@ -13,9 +13,7 @@ import React from 'react'
import { VariableSearchInput } from '@/components/VariableSearchInput'
type Props = {
onSelectVariable: (
variable: Pick<Variable, 'name' | 'id'> | undefined
) => void
onSelectVariable: (variable: Pick<Variable, 'name' | 'id'>) => void
} & Omit<IconButtonProps, 'aria-label'>
export const VariablesButton = ({ onSelectVariable, ...props }: Props) => {