🦴 Add settings page backbone
This commit is contained in:
26
apps/builder/components/settings/SettingsContent.tsx
Normal file
26
apps/builder/components/settings/SettingsContent.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import { Flex, Stack } from '@chakra-ui/react'
|
||||
import { TypingEmulationSettings } from 'bot-engine'
|
||||
import { useTypebot } from 'contexts/TypebotContext'
|
||||
import React from 'react'
|
||||
import { TypingEmulation } from './TypingEmulation'
|
||||
|
||||
export const SettingsContent = () => {
|
||||
const { typebot, updateSettings } = useTypebot()
|
||||
|
||||
const handleTypingEmulationUpdate = (
|
||||
typingEmulation: TypingEmulationSettings
|
||||
) => {
|
||||
if (!typebot) return
|
||||
updateSettings({ ...typebot.settings, typingEmulation })
|
||||
}
|
||||
return (
|
||||
<Flex h="full" w="full" justifyContent="center" align="flex-start">
|
||||
<Stack p="6" rounded="md" borderWidth={1} w="600px" minH="500px" mt={10}>
|
||||
<TypingEmulation
|
||||
typingEmulation={typebot?.settings.typingEmulation}
|
||||
onUpdate={handleTypingEmulationUpdate}
|
||||
/>
|
||||
</Stack>
|
||||
</Flex>
|
||||
)
|
||||
}
|
39
apps/builder/components/settings/SmartNumberInput.tsx
Normal file
39
apps/builder/components/settings/SmartNumberInput.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import {
|
||||
NumberInputProps,
|
||||
NumberInput,
|
||||
NumberInputField,
|
||||
NumberInputStepper,
|
||||
NumberIncrementStepper,
|
||||
NumberDecrementStepper,
|
||||
} from '@chakra-ui/react'
|
||||
import { useState, useEffect } from 'react'
|
||||
|
||||
export const SmartNumberInput = ({
|
||||
initialValue,
|
||||
onValueChange,
|
||||
...props
|
||||
}: {
|
||||
initialValue: number
|
||||
onValueChange: (value: number) => void
|
||||
} & NumberInputProps) => {
|
||||
const [value, setValue] = useState(initialValue.toString())
|
||||
|
||||
useEffect(() => {
|
||||
if (value.endsWith('.') || value.endsWith(',')) return
|
||||
if (value === '') onValueChange(0)
|
||||
const newValue = parseFloat(value)
|
||||
if (isNaN(newValue)) return
|
||||
onValueChange(newValue)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [value])
|
||||
|
||||
return (
|
||||
<NumberInput onChange={setValue} value={value} {...props}>
|
||||
<NumberInputField />
|
||||
<NumberInputStepper>
|
||||
<NumberIncrementStepper />
|
||||
<NumberDecrementStepper />
|
||||
</NumberInputStepper>
|
||||
</NumberInput>
|
||||
)
|
||||
}
|
63
apps/builder/components/settings/TypingEmulation.tsx
Normal file
63
apps/builder/components/settings/TypingEmulation.tsx
Normal file
@ -0,0 +1,63 @@
|
||||
import { Flex, Stack, Switch, Text } from '@chakra-ui/react'
|
||||
import { TypingEmulationSettings } from 'bot-engine'
|
||||
import React from 'react'
|
||||
import { SmartNumberInput } from './SmartNumberInput'
|
||||
|
||||
type TypingEmulationProps = {
|
||||
typingEmulation?: TypingEmulationSettings
|
||||
onUpdate: (typingEmulation: TypingEmulationSettings) => void
|
||||
}
|
||||
|
||||
export const TypingEmulation = ({
|
||||
typingEmulation,
|
||||
onUpdate,
|
||||
}: TypingEmulationProps) => {
|
||||
const handleSwitchChange = () => {
|
||||
if (!typingEmulation) return
|
||||
onUpdate({ ...typingEmulation, enabled: !typingEmulation.enabled })
|
||||
}
|
||||
|
||||
const handleSpeedChange = (speed: number) => {
|
||||
if (!typingEmulation) return
|
||||
onUpdate({ ...typingEmulation, speed })
|
||||
}
|
||||
|
||||
const handleMaxDelayChange = (maxDelay: number) => {
|
||||
if (!typingEmulation) return
|
||||
onUpdate({ ...typingEmulation, maxDelay: maxDelay })
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack spacing={4}>
|
||||
<Flex justifyContent="space-between" align="center">
|
||||
<Text>Typing emulation</Text>
|
||||
<Switch
|
||||
isChecked={typingEmulation?.enabled}
|
||||
onChange={handleSwitchChange}
|
||||
/>
|
||||
</Flex>
|
||||
{typingEmulation?.enabled && (
|
||||
<Stack pl={10}>
|
||||
<Flex justify="space-between" align="center">
|
||||
<Text>Words per minutes:</Text>
|
||||
<SmartNumberInput
|
||||
initialValue={typingEmulation.speed}
|
||||
onValueChange={handleSpeedChange}
|
||||
maxW="100px"
|
||||
step={30}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex justify="space-between" align="center">
|
||||
<Text>Max delay (in seconds):</Text>
|
||||
<SmartNumberInput
|
||||
initialValue={typingEmulation.maxDelay}
|
||||
onValueChange={handleMaxDelayChange}
|
||||
maxW="100px"
|
||||
step={0.1}
|
||||
/>
|
||||
</Flex>
|
||||
</Stack>
|
||||
)}
|
||||
</Stack>
|
||||
)
|
||||
}
|
@ -53,9 +53,9 @@ export const TypebotHeader = () => {
|
||||
</Button>
|
||||
<Button
|
||||
as={NextChakraLink}
|
||||
href={`/typebots/${typebot?.id}/design`}
|
||||
colorScheme={router.pathname.endsWith('share') ? 'blue' : 'gray'}
|
||||
variant={router.pathname.endsWith('share') ? 'outline' : 'ghost'}
|
||||
href={`/typebots/${typebot?.id}/settings`}
|
||||
colorScheme={router.pathname.endsWith('settings') ? 'blue' : 'gray'}
|
||||
variant={router.pathname.endsWith('settings') ? 'outline' : 'ghost'}
|
||||
>
|
||||
Settings
|
||||
</Button>
|
||||
|
@ -1,5 +1,13 @@
|
||||
import { useToast } from '@chakra-ui/react'
|
||||
import { Block, Step, StepType, Target, Theme, Typebot } from 'bot-engine'
|
||||
import {
|
||||
Block,
|
||||
Settings,
|
||||
Step,
|
||||
StepType,
|
||||
Target,
|
||||
Theme,
|
||||
Typebot,
|
||||
} from 'bot-engine'
|
||||
import { useRouter } from 'next/router'
|
||||
import {
|
||||
createContext,
|
||||
@ -47,6 +55,7 @@ const typebotContext = createContext<{
|
||||
}) => void
|
||||
undo: () => void
|
||||
updateTheme: (theme: Theme) => void
|
||||
updateSettings: (settings: Settings) => void
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
//@ts-ignore
|
||||
}>({})
|
||||
@ -270,6 +279,11 @@ export const TypebotContext = ({
|
||||
setLocalTypebot({ ...localTypebot, theme })
|
||||
}
|
||||
|
||||
const updateSettings = (settings: Settings) => {
|
||||
if (!localTypebot) return
|
||||
setLocalTypebot({ ...localTypebot, settings })
|
||||
}
|
||||
|
||||
return (
|
||||
<typebotContext.Provider
|
||||
value={{
|
||||
@ -286,6 +300,7 @@ export const TypebotContext = ({
|
||||
removeBlock,
|
||||
undo,
|
||||
updateTheme,
|
||||
updateSettings,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
@ -1,4 +1,10 @@
|
||||
import { BackgroundType, StartBlock, StepType, Theme } from 'bot-engine'
|
||||
import {
|
||||
BackgroundType,
|
||||
Settings,
|
||||
StartBlock,
|
||||
StepType,
|
||||
Theme,
|
||||
} from 'bot-engine'
|
||||
import { Typebot, User } from 'db'
|
||||
import prisma from 'libs/prisma'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
@ -44,8 +50,15 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
background: { type: BackgroundType.NONE, content: '#ffffff' },
|
||||
},
|
||||
}
|
||||
const settings: Settings = {
|
||||
typingEmulation: {
|
||||
enabled: true,
|
||||
speed: 300,
|
||||
maxDelay: 1.5,
|
||||
},
|
||||
}
|
||||
const typebot = await prisma.typebot.create({
|
||||
data: { ...data, ownerId: user.id, startBlock, theme },
|
||||
data: { ...data, ownerId: user.id, startBlock, theme, settings },
|
||||
})
|
||||
return res.send(typebot)
|
||||
}
|
||||
|
23
apps/builder/pages/typebots/[id]/settings.tsx
Normal file
23
apps/builder/pages/typebots/[id]/settings.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import { Flex } from '@chakra-ui/layout'
|
||||
import withAuth from 'components/HOC/withUser'
|
||||
import { Seo } from 'components/Seo'
|
||||
import { SettingsContent } from 'components/settings/SettingsContent'
|
||||
import { TypebotHeader } from 'components/shared/TypebotHeader'
|
||||
import { TypebotContext } from 'contexts/TypebotContext'
|
||||
import { useRouter } from 'next/router'
|
||||
import React from 'react'
|
||||
|
||||
const SettingsPage = () => {
|
||||
const { query } = useRouter()
|
||||
return (
|
||||
<TypebotContext typebotId={query.id?.toString()}>
|
||||
<Seo title="Settings" />
|
||||
<Flex overflow="hidden" h="100vh" flexDir="column">
|
||||
<TypebotHeader />
|
||||
<SettingsContent />
|
||||
</Flex>
|
||||
</TypebotContext>
|
||||
)
|
||||
}
|
||||
|
||||
export default withAuth(SettingsPage)
|
@ -156,4 +156,5 @@ export const parseTypebotToPublicTypebot = (
|
||||
startBlock: typebot.startBlock,
|
||||
typebotId: typebot.id,
|
||||
theme: typebot.theme,
|
||||
settings: typebot.settings,
|
||||
})
|
||||
|
Reference in New Issue
Block a user