From ce1b23a0e7874548f75ee729fb12aed99cf132a3 Mon Sep 17 00:00:00 2001 From: Baptiste Arnaud Date: Sun, 9 Jan 2022 07:36:29 +0100 Subject: [PATCH] =?UTF-8?q?feat(inputs):=20=E2=9C=A8=20Add=20URL=20input?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../board/StepTypesList/StepIcon.tsx | 4 ++ .../board/StepTypesList/StepTypeLabel.tsx | 3 ++ .../SettingsPopoverContent.tsx | 9 ++++ .../UrlInputSettingsBody.tsx | 46 +++++++++++++++++ .../BlockNode/StepNode/StepNodeLabel.tsx | 7 +++ apps/builder/cypress/tests/inputs.ts | 49 +++++++++++++++++-- .../ChatBlock/ChatStep/ChatStep.tsx | 1 + .../ChatStep/inputs/TextForm/TextForm.tsx | 9 +++- .../inputs/TextForm/TextInputContent.tsx | 13 ++++- packages/models/src/typebot/steps.ts | 14 +++++- 10 files changed, 146 insertions(+), 9 deletions(-) create mode 100644 apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/UrlInputSettingsBody.tsx diff --git a/apps/builder/components/board/StepTypesList/StepIcon.tsx b/apps/builder/components/board/StepTypesList/StepIcon.tsx index 9d10d3a2d35..9c4eb6b8102 100644 --- a/apps/builder/components/board/StepTypesList/StepIcon.tsx +++ b/apps/builder/components/board/StepTypesList/StepIcon.tsx @@ -2,6 +2,7 @@ import { ChatIcon, EmailIcon, FlagIcon, + GlobeIcon, NumberIcon, TextIcon, } from 'assets/icons' @@ -24,6 +25,9 @@ export const StepIcon = ({ type }: StepIconProps) => { case InputStepType.EMAIL: { return } + case InputStepType.URL: { + return + } case 'start': { return } diff --git a/apps/builder/components/board/StepTypesList/StepTypeLabel.tsx b/apps/builder/components/board/StepTypesList/StepTypeLabel.tsx index c7109690e10..ccb617819d5 100644 --- a/apps/builder/components/board/StepTypesList/StepTypeLabel.tsx +++ b/apps/builder/components/board/StepTypesList/StepTypeLabel.tsx @@ -16,6 +16,9 @@ export const StepTypeLabel = ({ type }: Props) => { case InputStepType.EMAIL: { return Email } + case InputStepType.URL: { + return Website + } default: { return <> } diff --git a/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/SettingsPopoverContent.tsx b/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/SettingsPopoverContent.tsx index 242339d86e4..cc2befbde00 100644 --- a/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/SettingsPopoverContent.tsx +++ b/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/SettingsPopoverContent.tsx @@ -4,6 +4,7 @@ import { InputStepType, Step, TextInputOptions } from 'models' import { EmailInputSettingsBody } from './EmailInputSettingsBody' import { NumberInputSettingsBody } from './NumberInputSettingsBody' import { TextInputSettingsBody } from './TextInputSettingsBody' +import { UrlInputSettingsBody } from './UrlInputSettingsBody' type Props = { step: Step @@ -51,6 +52,14 @@ const SettingsPopoverBodyContent = ({ step }: Props) => { /> ) } + case InputStepType.URL: { + return ( + + ) + } default: { return <> } diff --git a/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/UrlInputSettingsBody.tsx b/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/UrlInputSettingsBody.tsx new file mode 100644 index 00000000000..33465d06f99 --- /dev/null +++ b/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/UrlInputSettingsBody.tsx @@ -0,0 +1,46 @@ +import { FormLabel, Stack } from '@chakra-ui/react' +import { DebouncedInput } from 'components/shared/DebouncedInput' +import { UrlInputOptions } from 'models' +import React from 'react' + +type UrlInputSettingsBodyProps = { + options?: UrlInputOptions + onOptionsChange: (options: UrlInputOptions) => void +} + +export const UrlInputSettingsBody = ({ + options, + onOptionsChange, +}: UrlInputSettingsBodyProps) => { + const handlePlaceholderChange = (placeholder: string) => + onOptionsChange({ ...options, labels: { ...options?.labels, placeholder } }) + const handleButtonLabelChange = (button: string) => + onOptionsChange({ ...options, labels: { ...options?.labels, button } }) + + return ( + + + + Placeholder: + + + + + + Button label: + + + + + ) +} diff --git a/apps/builder/components/board/graph/BlockNode/StepNode/StepNodeLabel.tsx b/apps/builder/components/board/graph/BlockNode/StepNode/StepNodeLabel.tsx index 3c2d137e5aa..5d19fff8364 100644 --- a/apps/builder/components/board/graph/BlockNode/StepNode/StepNodeLabel.tsx +++ b/apps/builder/components/board/graph/BlockNode/StepNode/StepNodeLabel.tsx @@ -39,6 +39,13 @@ export const StepNodeLabel = (props: Step | StartStep) => { ) } + case InputStepType.URL: { + return ( + + {props.options?.labels?.placeholder ?? 'Type your URL...'} + + ) + } case 'start': { return {props.label} } diff --git a/apps/builder/cypress/tests/inputs.ts b/apps/builder/cypress/tests/inputs.ts index 6477dff6024..70812f6b5ce 100644 --- a/apps/builder/cypress/tests/inputs.ts +++ b/apps/builder/cypress/tests/inputs.ts @@ -21,8 +21,11 @@ describe('Text input', () => { cy.signIn('test2@gmail.com') cy.visit('/typebots/typebot3/edit') cy.findByRole('button', { name: 'Preview' }).click() - getIframeBody().findByPlaceholderText('Type your answer...').should('exist') - getIframeBody().findByRole('button', { name: 'Send' }).should('exist') + getIframeBody() + .findByPlaceholderText('Type your answer...') + .should('have.attr', 'type') + .should('equal', 'text') + getIframeBody().findByRole('button', { name: 'Send' }).should('be.disabled') cy.findByTestId('step-step1').click({ force: true }) cy.findByRole('textbox', { name: 'Placeholder:' }) .clear() @@ -50,8 +53,11 @@ describe('Number input', () => { cy.signIn('test2@gmail.com') cy.visit('/typebots/typebot3/edit') cy.findByRole('button', { name: 'Preview' }).click() - getIframeBody().findByPlaceholderText('Type your answer...').should('exist') - getIframeBody().findByRole('button', { name: 'Send' }).should('exist') + getIframeBody() + .findByPlaceholderText('Type your answer...') + .should('have.attr', 'type') + .should('equal', 'number') + getIframeBody().findByRole('button', { name: 'Send' }).should('be.disabled') cy.findByTestId('step-step1').click({ force: true }) cy.findByRole('textbox', { name: 'Placeholder:' }) .clear() @@ -84,8 +90,13 @@ describe('Email input', () => { cy.signIn('test2@gmail.com') cy.visit('/typebots/typebot3/edit') cy.findByRole('button', { name: 'Preview' }).click() - getIframeBody().findByPlaceholderText('Type your email...').should('exist') + getIframeBody() + .findByPlaceholderText('Type your email...') + .should('have.attr', 'type') + .should('equal', 'email') getIframeBody().findByRole('button', { name: 'Send' }) + getIframeBody().findByPlaceholderText('Type your email...').should('exist') + getIframeBody().findByRole('button', { name: 'Send' }).should('be.disabled') cy.findByTestId('step-step1').click({ force: true }) cy.findByRole('textbox', { name: 'Placeholder:' }) .clear() @@ -98,6 +109,34 @@ describe('Email input', () => { }) }) +describe('URL input', () => { + beforeEach(() => { + cy.task('seed') + createTypebotWithStep({ type: InputStepType.URL }) + cy.signOut() + }) + + it('options should work', () => { + cy.signIn('test2@gmail.com') + cy.visit('/typebots/typebot3/edit') + cy.findByRole('button', { name: 'Preview' }).click() + getIframeBody() + .findByPlaceholderText('Type your URL...') + .should('have.attr', 'type') + .should('eq', 'url') + getIframeBody().findByRole('button', { name: 'Send' }).should('be.disabled') + cy.findByTestId('step-step1').click({ force: true }) + cy.findByRole('textbox', { name: 'Placeholder:' }) + .clear() + .type('Your URL...') + cy.findByRole('textbox', { name: 'Button label:' }).clear().type('Go') + cy.findByTestId('step-step1').should('contain.text', 'Your URL...') + cy.findByRole('button', { name: 'Restart' }).click() + getIframeBody().findByPlaceholderText('Your URL...').should('exist') + getIframeBody().findByRole('button', { name: 'Go' }) + }) +}) + const createTypebotWithStep = (step: Omit) => { cy.task( 'createTypebot', diff --git a/packages/bot-engine/src/components/ChatBlock/ChatStep/ChatStep.tsx b/packages/bot-engine/src/components/ChatBlock/ChatStep/ChatStep.tsx index 75bcaeaf222..a54ba3667b8 100644 --- a/packages/bot-engine/src/components/ChatBlock/ChatStep/ChatStep.tsx +++ b/packages/bot-engine/src/components/ChatBlock/ChatStep/ChatStep.tsx @@ -54,6 +54,7 @@ const InputChatStep = ({ case InputStepType.TEXT: case InputStepType.NUMBER: case InputStepType.EMAIL: + case InputStepType.URL: return } } diff --git a/packages/bot-engine/src/components/ChatBlock/ChatStep/inputs/TextForm/TextForm.tsx b/packages/bot-engine/src/components/ChatBlock/ChatStep/inputs/TextForm/TextForm.tsx index b52bd0ba9c6..714d25253f6 100644 --- a/packages/bot-engine/src/components/ChatBlock/ChatStep/inputs/TextForm/TextForm.tsx +++ b/packages/bot-engine/src/components/ChatBlock/ChatStep/inputs/TextForm/TextForm.tsx @@ -1,10 +1,15 @@ -import { EmailInputStep, NumberInputStep, TextInputStep } from 'models' +import { + EmailInputStep, + NumberInputStep, + TextInputStep, + UrlInputStep, +} from 'models' import React, { FormEvent, useState } from 'react' import { SendIcon } from '../../../../../assets/icons' import { TextInput } from './TextInputContent' type TextFormProps = { - step: TextInputStep | EmailInputStep | NumberInputStep + step: TextInputStep | EmailInputStep | NumberInputStep | UrlInputStep onSubmit: (value: string) => void } diff --git a/packages/bot-engine/src/components/ChatBlock/ChatStep/inputs/TextForm/TextInputContent.tsx b/packages/bot-engine/src/components/ChatBlock/ChatStep/inputs/TextForm/TextInputContent.tsx index 1dfb7c49c87..544e4f3aae7 100644 --- a/packages/bot-engine/src/components/ChatBlock/ChatStep/inputs/TextForm/TextInputContent.tsx +++ b/packages/bot-engine/src/components/ChatBlock/ChatStep/inputs/TextForm/TextInputContent.tsx @@ -3,6 +3,7 @@ import { EmailInputStep, NumberInputStep, InputStepType, + UrlInputStep, } from 'models' import React, { ChangeEvent, @@ -13,7 +14,7 @@ import React, { } from 'react' type TextInputProps = { - step: TextInputStep | EmailInputStep | NumberInputStep + step: TextInputStep | EmailInputStep | NumberInputStep | UrlInputStep onChange: (value: string) => void } @@ -77,6 +78,16 @@ export const TextInput = ({ step, onChange }: TextInputProps) => { /> ) } + case InputStepType.URL: { + return ( + + ) + } } } diff --git a/packages/models/src/typebot/steps.ts b/packages/models/src/typebot/steps.ts index 72847b07dde..cc46d0dce47 100644 --- a/packages/models/src/typebot/steps.ts +++ b/packages/models/src/typebot/steps.ts @@ -2,7 +2,11 @@ export type Step = StartStep | BubbleStep | InputStep export type BubbleStep = TextStep -export type InputStep = TextInputStep | NumberInputStep | EmailInputStep +export type InputStep = + | TextInputStep + | NumberInputStep + | EmailInputStep + | UrlInputStep export type StepType = 'start' | BubbleStepType | InputStepType @@ -14,6 +18,7 @@ export enum InputStepType { TEXT = 'text input', NUMBER = 'number input', EMAIL = 'email input', + URL = 'url input', } export type StepBase = { id: string; blockId: string; target?: Target } @@ -43,8 +48,15 @@ export type EmailInputStep = StepBase & { options?: EmailInputOptions } +export type UrlInputStep = StepBase & { + type: InputStepType.URL + options?: UrlInputOptions +} + export type EmailInputOptions = InputOptionsBase +export type UrlInputOptions = InputOptionsBase + type InputOptionsBase = { labels?: { placeholder?: string; button?: string } }