♻️ Introduce typebot v6 with events (#1013)

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

View File

@@ -6,17 +6,21 @@ import {
Tag,
Text,
} from '@chakra-ui/react'
import { GeneralSettings, rememberUserStorages } from '@typebot.io/schemas'
import { Settings } from '@typebot.io/schemas'
import React from 'react'
import { isDefined } from '@typebot.io/lib'
import { SwitchWithLabel } from '@/components/inputs/SwitchWithLabel'
import { SwitchWithRelatedSettings } from '@/components/SwitchWithRelatedSettings'
import { DropdownList } from '@/components/DropdownList'
import { MoreInfoTooltip } from '@/components/MoreInfoTooltip'
import {
defaultSettings,
rememberUserStorages,
} from '@typebot.io/schemas/features/typebot/settings/constants'
type Props = {
generalSettings: GeneralSettings
onGeneralSettingsChange: (generalSettings: GeneralSettings) => void
generalSettings: Settings['general'] | undefined
onGeneralSettingsChange: (generalSettings: Settings['general']) => void
}
export const GeneralSettingsForm = ({
@@ -27,7 +31,7 @@ export const GeneralSettingsForm = ({
onGeneralSettingsChange({
...generalSettings,
rememberUser: {
...generalSettings.rememberUser,
...generalSettings?.rememberUser,
isEnabled,
},
})
@@ -45,12 +49,14 @@ export const GeneralSettingsForm = ({
})
const updateRememberUserStorage = (
storage: NonNullable<GeneralSettings['rememberUser']>['storage']
storage: NonNullable<
NonNullable<Settings['general']>['rememberUser']
>['storage']
) =>
onGeneralSettingsChange({
...generalSettings,
rememberUser: {
...generalSettings.rememberUser,
...generalSettings?.rememberUser,
storage,
},
})
@@ -59,13 +65,19 @@ export const GeneralSettingsForm = ({
<Stack spacing={6}>
<SwitchWithLabel
label="Prefill input"
initialValue={generalSettings.isInputPrefillEnabled ?? true}
initialValue={
generalSettings?.isInputPrefillEnabled ??
defaultSettings.general.isInputPrefillEnabled
}
onCheckChange={handleInputPrefillChange}
moreInfoContent="Inputs are automatically pre-filled whenever their associated variable has a value"
/>
<SwitchWithLabel
label="Hide query params on bot start"
initialValue={generalSettings.isHideQueryParamsEnabled ?? true}
initialValue={
generalSettings?.isHideQueryParamsEnabled ??
defaultSettings.general.isHideQueryParamsEnabled
}
onCheckChange={handleHideQueryParamsChange}
moreInfoContent="If your URL contains query params, they will be automatically hidden when the bot starts."
/>
@@ -73,9 +85,9 @@ export const GeneralSettingsForm = ({
label={'Remember user'}
moreInfoContent="If enabled, user previous variables will be prefilled and his new answers will override the previous ones."
initialValue={
generalSettings.rememberUser?.isEnabled ??
(isDefined(generalSettings.isNewResultOnRefreshEnabled)
? !generalSettings.isNewResultOnRefreshEnabled
generalSettings?.rememberUser?.isEnabled ??
(isDefined(generalSettings?.isNewResultOnRefreshEnabled)
? !generalSettings?.isNewResultOnRefreshEnabled
: false)
}
onCheckChange={toggleRememberUser}
@@ -97,7 +109,7 @@ export const GeneralSettingsForm = ({
</MoreInfoTooltip>
</FormLabel>
<DropdownList
currentItem={generalSettings.rememberUser?.storage ?? 'session'}
currentItem={generalSettings?.rememberUser?.storage ?? 'session'}
onItemSelect={updateRememberUserStorage}
items={rememberUserStorages}
></DropdownList>

View File

@@ -1,5 +1,5 @@
import React from 'react'
import { Metadata } from '@typebot.io/schemas'
import { Settings } from '@typebot.io/schemas'
import {
FormLabel,
Popover,
@@ -14,13 +14,15 @@ import { CodeEditor } from '@/components/inputs/CodeEditor'
import { ImageUploadContent } from '@/components/ImageUploadContent'
import { MoreInfoTooltip } from '@/components/MoreInfoTooltip'
import { TextInput, Textarea } from '@/components/inputs'
import { env } from '@typebot.io/env'
import { defaultSettings } from '@typebot.io/schemas/features/typebot/settings/constants'
type Props = {
workspaceId: string
typebotId: string
typebotName: string
metadata: Metadata
onMetadataChange: (metadata: Metadata) => void
metadata: Settings['metadata']
onMetadataChange: (metadata: Settings['metadata']) => void
}
export const MetadataForm = ({
@@ -43,6 +45,14 @@ export const MetadataForm = ({
const handleHeadCodeChange = (customHeadCode: string) =>
onMetadataChange({ ...metadata, customHeadCode })
const favIconUrl =
metadata?.favIconUrl ??
defaultSettings.metadata.favIconUrl(env.NEXT_PUBLIC_VIEWER_URL[0])
const imageUrl =
metadata?.imageUrl ??
defaultSettings.metadata.imageUrl(env.NEXT_PUBLIC_VIEWER_URL[0])
return (
<Stack spacing="6">
<Stack>
@@ -52,7 +62,7 @@ export const MetadataForm = ({
<Popover isLazy placement="top">
<PopoverTrigger>
<Image
src={metadata.favIconUrl ?? '/favicon.png'}
src={favIconUrl}
w="20px"
alt="Fav icon"
cursor="pointer"
@@ -68,7 +78,7 @@ export const MetadataForm = ({
typebotId,
fileName: 'favIcon',
}}
defaultUrl={metadata.favIconUrl ?? ''}
defaultUrl={favIconUrl}
onSubmit={handleFavIconSubmit}
excludedTabs={['giphy', 'unsplash', 'emoji']}
imageSize="thumb"
@@ -83,7 +93,7 @@ export const MetadataForm = ({
<Popover isLazy placement="top">
<PopoverTrigger>
<Image
src={metadata.imageUrl ?? '/viewer-preview.png'}
src={imageUrl}
alt="Website image"
cursor="pointer"
_hover={{ filter: 'brightness(.9)' }}
@@ -98,7 +108,7 @@ export const MetadataForm = ({
typebotId,
fileName: 'ogImage',
}}
defaultUrl={metadata.imageUrl}
defaultUrl={imageUrl}
onSubmit={handleImageSubmit}
excludedTabs={['giphy', 'icon', 'emoji']}
/>
@@ -107,16 +117,18 @@ export const MetadataForm = ({
</Stack>
<TextInput
label="Title:"
defaultValue={metadata.title ?? typebotName}
defaultValue={metadata?.title ?? typebotName}
onChange={handleTitleChange}
/>
<Textarea
defaultValue={metadata.description}
defaultValue={
metadata?.description ?? defaultSettings.metadata.description
}
onChange={handleDescriptionChange}
label="Description:"
/>
<TextInput
defaultValue={metadata.googleTagManagerId}
defaultValue={metadata?.googleTagManagerId}
placeholder="GTM-XXXXXX"
onChange={handleGoogleTagManagerIdChange}
label="Google Tag Manager ID:"
@@ -132,7 +144,7 @@ export const MetadataForm = ({
</HStack>
<CodeEditor
id="head"
defaultValue={metadata.customHeadCode ?? ''}
defaultValue={metadata?.customHeadCode}
onChange={handleHeadCodeChange}
lang="html"
withVariableButton={false}

View File

@@ -9,7 +9,7 @@ import {
Stack,
} from '@chakra-ui/react'
import { ChatIcon, CodeIcon, MoreVerticalIcon } from '@/components/icons'
import { GeneralSettings, Metadata, TypingEmulation } from '@typebot.io/schemas'
import { Settings } from '@typebot.io/schemas'
import React from 'react'
import { GeneralSettingsForm } from './GeneralSettingsForm'
import { MetadataForm } from './MetadataForm'
@@ -20,17 +20,19 @@ import { headerHeight } from '@/features/editor/constants'
export const SettingsSideMenu = () => {
const { typebot, updateTypebot } = useTypebot()
const handleTypingEmulationChange = (typingEmulation: TypingEmulation) =>
const updateTypingEmulation = (
typingEmulation: Settings['typingEmulation']
) =>
typebot &&
updateTypebot({
updates: { settings: { ...typebot.settings, typingEmulation } },
})
const handleGeneralSettingsChange = (general: GeneralSettings) =>
const handleGeneralSettingsChange = (general: Settings['general']) =>
typebot &&
updateTypebot({ updates: { settings: { ...typebot.settings, general } } })
const handleMetadataChange = (metadata: Metadata) =>
const handleMetadataChange = (metadata: Settings['metadata']) =>
typebot &&
updateTypebot({ updates: { settings: { ...typebot.settings, metadata } } })
@@ -78,7 +80,7 @@ export const SettingsSideMenu = () => {
{typebot && (
<TypingEmulationForm
typingEmulation={typebot.settings.typingEmulation}
onUpdate={handleTypingEmulationChange}
onUpdate={updateTypingEmulation}
/>
)}
</AccordionPanel>

View File

@@ -1,19 +1,21 @@
import { Flex, FormLabel, Stack, Switch } from '@chakra-ui/react'
import { TypingEmulation } from '@typebot.io/schemas'
import { Stack } from '@chakra-ui/react'
import { Settings } from '@typebot.io/schemas'
import React from 'react'
import { isDefined } from '@typebot.io/lib'
import { NumberInput } from '@/components/inputs'
import { SwitchWithLabel } from '@/components/inputs/SwitchWithLabel'
import { defaultSettings } from '@typebot.io/schemas/features/typebot/settings/constants'
type Props = {
typingEmulation: TypingEmulation
onUpdate: (typingEmulation: TypingEmulation) => void
typingEmulation: Settings['typingEmulation']
onUpdate: (typingEmulation: Settings['typingEmulation']) => void
}
export const TypingEmulationForm = ({ typingEmulation, onUpdate }: Props) => {
const handleSwitchChange = () =>
const updateIsEnabled = (enabled: boolean) =>
onUpdate({
...typingEmulation,
enabled: !typingEmulation.enabled,
enabled,
})
const handleSpeedChange = (speed?: number) =>
@@ -22,24 +24,24 @@ export const TypingEmulationForm = ({ typingEmulation, onUpdate }: Props) => {
const handleMaxDelayChange = (maxDelay?: number) =>
isDefined(maxDelay) && onUpdate({ ...typingEmulation, maxDelay })
const isEnabled =
typingEmulation?.enabled ?? defaultSettings.typingEmulation.enabled
return (
<Stack spacing={6}>
<Flex justifyContent="space-between" align="center">
<FormLabel htmlFor="typing-emulation" mb="0">
Typing emulation
</FormLabel>
<Switch
id="typing-emulation"
isChecked={typingEmulation.enabled}
onChange={handleSwitchChange}
/>
</Flex>
{typingEmulation.enabled && (
<SwitchWithLabel
label={'Typing emulation'}
initialValue={isEnabled}
onCheckChange={updateIsEnabled}
/>
{isEnabled && (
<Stack pl={10}>
<NumberInput
label="Words per minutes:"
data-testid="speed"
defaultValue={typingEmulation.speed}
defaultValue={
typingEmulation?.speed ?? defaultSettings.typingEmulation.speed
}
onValueChange={handleSpeedChange}
withVariableButton={false}
maxW="100px"
@@ -48,7 +50,10 @@ export const TypingEmulationForm = ({ typingEmulation, onUpdate }: Props) => {
<NumberInput
label="Max delay (in seconds):"
data-testid="max-delay"
defaultValue={typingEmulation.maxDelay}
defaultValue={
typingEmulation?.maxDelay ??
defaultSettings.typingEmulation.maxDelay
}
onValueChange={handleMaxDelayChange}
withVariableButton={false}
maxW="100px"

View File

@@ -1,8 +1,8 @@
import { getTestAsset } from '@/test/utils/playwright'
import test, { expect } from '@playwright/test'
import { createId } from '@paralleldrive/cuid2'
import { defaultTextInputOptions } from '@typebot.io/schemas'
import { importTypebotInDatabase } from '@typebot.io/lib/playwright/databaseActions'
import { defaultTextInputOptions } from '@typebot.io/schemas/features/blocks/inputs/text/constants'
test.describe.parallel('Settings page', () => {
test.describe('General', () => {
@@ -65,7 +65,10 @@ test.describe.parallel('Settings page', () => {
// Fav icon
const favIconImg = page.locator('img >> nth=0')
await expect(favIconImg).toHaveAttribute('src', '/favicon.png')
await expect(favIconImg).toHaveAttribute(
'src',
'http://localhost:3001/favicon.png'
)
await favIconImg.click()
await expect(page.locator('text=Giphy')).toBeHidden()
await page.click('button:has-text("Link")')
@@ -80,7 +83,10 @@ test.describe.parallel('Settings page', () => {
// Website image
const websiteImg = page.locator('img >> nth=1')
await expect(websiteImg).toHaveAttribute('src', '/viewer-preview.png')
await expect(websiteImg).toHaveAttribute(
'src',
'http://localhost:3001/site-preview.png'
)
await websiteImg.click()
await expect(page.locator('text=Giphy')).toBeHidden()
await page.click('button >> text="Link"')