2
0

feat(editor): Add auto save

This commit is contained in:
Baptiste Arnaud
2022-01-23 08:23:05 +01:00
parent a58600a38a
commit 079cf5ec57
20 changed files with 145 additions and 198 deletions

View File

@ -26,7 +26,7 @@ export const TypebotHeader = () => {
const handleNameSubmit = (name: string) => updateTypebot({ name }) const handleNameSubmit = (name: string) => updateTypebot({ name })
const handlePreviewClick = async () => { const handlePreviewClick = async () => {
await save() save().then()
setRightPanel(RightPanel.PREVIEW) setRightPanel(RightPanel.PREVIEW)
} }

View File

@ -30,6 +30,9 @@ import { choiceItemsAction, ChoiceItemsActions } from './actions/choiceItems'
import { variablesAction, VariablesActions } from './actions/variables' import { variablesAction, VariablesActions } from './actions/variables'
import { edgesAction, EdgesActions } from './actions/edges' import { edgesAction, EdgesActions } from './actions/edges'
import { webhooksAction, WebhooksAction } from './actions/webhooks' import { webhooksAction, WebhooksAction } from './actions/webhooks'
import { useDebounce } from 'use-debounce'
const autoSaveTimeout = 10000
type UpdateTypebotPayload = Partial<{ type UpdateTypebotPayload = Partial<{
theme: Theme theme: Theme
@ -85,6 +88,12 @@ export const TypebotContext = ({
undefined undefined
) )
const [debouncedLocalTypebot] = useDebounce(localTypebot, autoSaveTimeout)
useEffect(() => {
if (hasUnsavedChanges) saveTypebot()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [debouncedLocalTypebot])
const [localPublishedTypebot, setLocalPublishedTypebot] = const [localPublishedTypebot, setLocalPublishedTypebot] =
useState<PublicTypebot>() useState<PublicTypebot>()
const [isSavingLoading, setIsSavingLoading] = useState(false) const [isSavingLoading, setIsSavingLoading] = useState(false)

View File

@ -9,14 +9,22 @@ import 'assets/styles/plate.css'
import 'focus-visible/dist/focus-visible' import 'focus-visible/dist/focus-visible'
import 'assets/styles/submissionsTable.css' import 'assets/styles/submissionsTable.css'
import 'assets/styles/codeMirror.css' import 'assets/styles/codeMirror.css'
import { UserContext } from 'contexts/UserContext'
import { TypebotContext } from 'contexts/TypebotContext'
import { useRouter } from 'next/router'
const App = ({ Component, pageProps }: AppProps) => { const App = ({ Component, pageProps }: AppProps) => {
useRouterProgressBar() useRouterProgressBar()
const { query } = useRouter()
return ( return (
<ChakraProvider theme={customTheme}> <ChakraProvider theme={customTheme}>
<SessionProvider> <SessionProvider>
<UserContext>
<TypebotContext typebotId={query.typebotId?.toString()}>
<Component {...pageProps} /> <Component {...pageProps} />
</TypebotContext>
</UserContext>
</SessionProvider> </SessionProvider>
</ChakraProvider> </ChakraProvider>
) )

View File

@ -1,18 +1,13 @@
import { Stack } from '@chakra-ui/react' import { Stack } from '@chakra-ui/react'
import { AccountHeader } from 'components/account/AccountHeader' import { AccountHeader } from 'components/account/AccountHeader'
import { Seo } from 'components/Seo' import { Seo } from 'components/Seo'
import { UserContext } from 'contexts/UserContext'
import { AccountContent } from 'layouts/account/AccountContent' import { AccountContent } from 'layouts/account/AccountContent'
const AccountSubscriptionPage = () => { const AccountSubscriptionPage = () => (
return (
<UserContext>
<Seo title="My account" />{' '}
<Stack> <Stack>
<Seo title="My account" />
<AccountHeader /> <AccountHeader />
<AccountContent /> <AccountContent />
</Stack> </Stack>
</UserContext> )
)
}
export default AccountSubscriptionPage export default AccountSubscriptionPage

View File

@ -3,12 +3,14 @@ import { SignInForm } from 'components/auth/SignInForm'
import { Heading, VStack } from '@chakra-ui/react' import { Heading, VStack } from '@chakra-ui/react'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import React from 'react' import React from 'react'
import { Seo } from 'components/Seo'
const RegisterPage = () => { const RegisterPage = () => {
const { query } = useRouter() const { query } = useRouter()
return ( return (
<VStack spacing={4} h="100vh" justifyContent="center"> <VStack spacing={4} h="100vh" justifyContent="center">
<Seo title="Register" />
<Heading>Create an account</Heading> <Heading>Create an account</Heading>
<AuthSwitcher type="register" /> <AuthSwitcher type="register" />
<SignInForm defaultEmail={query.g?.toString()} /> <SignInForm defaultEmail={query.g?.toString()} />

View File

@ -2,10 +2,12 @@ import { AuthSwitcher } from 'components/auth/AuthSwitcher'
import { SignInForm } from 'components/auth/SignInForm' import { SignInForm } from 'components/auth/SignInForm'
import { Heading, VStack } from '@chakra-ui/react' import { Heading, VStack } from '@chakra-ui/react'
import React from 'react' import React from 'react'
import { Seo } from 'components/Seo'
const SignInPage = () => { const SignInPage = () => {
return ( return (
<VStack spacing={4} h="100vh" justifyContent="center"> <VStack spacing={4} h="100vh" justifyContent="center">
<Seo title="Sign in" />
<Heading>Sign in</Heading> <Heading>Sign in</Heading>
<AuthSwitcher type="signin" /> <AuthSwitcher type="signin" />
<SignInForm /> <SignInForm />

View File

@ -1,34 +0,0 @@
import { Flex } from '@chakra-ui/layout'
import { Board } from 'components/board/Board'
import { Seo } from 'components/Seo'
import { TypebotHeader } from 'components/shared/TypebotHeader'
import { EditorContext } from 'contexts/EditorContext'
import { TypebotContext } from 'contexts/TypebotContext/TypebotContext'
import { useRouter } from 'next/router'
import { KBarProvider } from 'kbar'
import React from 'react'
import { actions } from 'libs/kbar'
import { KBar } from 'components/shared/KBar'
import { UserContext } from 'contexts/UserContext'
const TypebotEditPage = () => {
const { query } = useRouter()
return (
<UserContext>
<TypebotContext typebotId={query.id?.toString()}>
<Seo title="Editor" />
<EditorContext>
<KBarProvider actions={actions}>
<KBar />
<Flex overflow="hidden" h="100vh" flexDir="column">
<TypebotHeader />
<Board />
</Flex>
</KBarProvider>
</EditorContext>
</TypebotContext>
</UserContext>
)
}
export default TypebotEditPage

View File

@ -1,25 +0,0 @@
import { Flex } from '@chakra-ui/layout'
import { ResultsContent } from 'layouts/results/ResultsContent'
import { Seo } from 'components/Seo'
import { TypebotHeader } from 'components/shared/TypebotHeader'
import { TypebotContext } from 'contexts/TypebotContext/TypebotContext'
import { useRouter } from 'next/router'
import React from 'react'
import { UserContext } from 'contexts/UserContext'
const ResultsPage = () => {
const { query } = useRouter()
return (
<UserContext>
<TypebotContext typebotId={query.id?.toString()}>
<Seo title="Share" />
<Flex overflow="hidden" h="100vh" flexDir="column">
<TypebotHeader />
<ResultsContent />
</Flex>
</TypebotContext>
</UserContext>
)
}
export default ResultsPage

View File

@ -1,25 +0,0 @@
import { Flex } from '@chakra-ui/layout'
import { ResultsContent } from 'layouts/results/ResultsContent'
import { Seo } from 'components/Seo'
import { TypebotHeader } from 'components/shared/TypebotHeader'
import { TypebotContext } from 'contexts/TypebotContext/TypebotContext'
import { useRouter } from 'next/router'
import React from 'react'
import { UserContext } from 'contexts/UserContext'
const AnalyticsPage = () => {
const { query } = useRouter()
return (
<UserContext>
<TypebotContext typebotId={query.id?.toString()}>
<Seo title="Analytics" />
<Flex overflow="hidden" h="100vh" flexDir="column">
<TypebotHeader />
<ResultsContent />
</Flex>
</TypebotContext>
</UserContext>
)
}
export default AnalyticsPage

View File

@ -1,25 +0,0 @@
import { Flex } from '@chakra-ui/layout'
import { Seo } from 'components/Seo'
import { SettingsContent } from 'components/settings/SettingsContent'
import { TypebotHeader } from 'components/shared/TypebotHeader'
import { TypebotContext } from 'contexts/TypebotContext/TypebotContext'
import { UserContext } from 'contexts/UserContext'
import { useRouter } from 'next/router'
import React from 'react'
const SettingsPage = () => {
const { query } = useRouter()
return (
<UserContext>
<TypebotContext typebotId={query.id?.toString()}>
<Seo title="Settings" />
<Flex overflow="hidden" h="100vh" flexDir="column">
<TypebotHeader />
<SettingsContent />
</Flex>
</TypebotContext>
</UserContext>
)
}
export default SettingsPage

View File

@ -1,25 +0,0 @@
import { Flex } from '@chakra-ui/layout'
import { Seo } from 'components/Seo'
import { ShareContent } from 'components/share/ShareContent'
import { TypebotHeader } from 'components/shared/TypebotHeader'
import { TypebotContext } from 'contexts/TypebotContext/TypebotContext'
import { UserContext } from 'contexts/UserContext'
import { useRouter } from 'next/router'
import React from 'react'
const SharePage = () => {
const { query } = useRouter()
return (
<UserContext>
<TypebotContext typebotId={query.id?.toString()}>
<Seo title="Share" />
<Flex overflow="hidden" h="100vh" flexDir="column">
<TypebotHeader />
<ShareContent />
</Flex>
</TypebotContext>
</UserContext>
)
}
export default SharePage

View File

@ -1,25 +0,0 @@
import { Flex } from '@chakra-ui/layout'
import { Seo } from 'components/Seo'
import { TypebotHeader } from 'components/shared/TypebotHeader'
import { ThemeContent } from 'components/theme/ThemeContent'
import { TypebotContext } from 'contexts/TypebotContext/TypebotContext'
import { UserContext } from 'contexts/UserContext'
import { useRouter } from 'next/router'
import React from 'react'
const ThemePage = () => {
const { query } = useRouter()
return (
<UserContext>
<TypebotContext typebotId={query.id?.toString()}>
<Seo title="Theme" />
<Flex overflow="hidden" h="100vh" flexDir="column">
<TypebotHeader />
<ThemeContent />
</Flex>
</TypebotContext>
</UserContext>
)
}
export default ThemePage

View File

@ -0,0 +1,23 @@
import { Flex } from '@chakra-ui/layout'
import { Board } from 'components/board/Board'
import { Seo } from 'components/Seo'
import { TypebotHeader } from 'components/shared/TypebotHeader'
import { EditorContext } from 'contexts/EditorContext'
import { KBarProvider } from 'kbar'
import React from 'react'
import { actions } from 'libs/kbar'
import { KBar } from 'components/shared/KBar'
const TypebotEditPage = () => (
<EditorContext>
<Seo title="Editor" />
<KBarProvider actions={actions}>
<KBar />
<Flex overflow="hidden" h="100vh" flexDir="column">
<TypebotHeader />
<Board />
</Flex>
</KBarProvider>
</EditorContext>
)
export default TypebotEditPage

View File

@ -0,0 +1,15 @@
import { Flex } from '@chakra-ui/layout'
import { ResultsContent } from 'layouts/results/ResultsContent'
import { Seo } from 'components/Seo'
import { TypebotHeader } from 'components/shared/TypebotHeader'
import React from 'react'
const ResultsPage = () => (
<Flex overflow="hidden" h="100vh" flexDir="column">
<Seo title="Share" />
<TypebotHeader />
<ResultsContent />
</Flex>
)
export default ResultsPage

View File

@ -0,0 +1,15 @@
import { Flex } from '@chakra-ui/layout'
import { ResultsContent } from 'layouts/results/ResultsContent'
import { Seo } from 'components/Seo'
import { TypebotHeader } from 'components/shared/TypebotHeader'
import React from 'react'
const AnalyticsPage = () => (
<Flex overflow="hidden" h="100vh" flexDir="column">
<Seo title="Analytics" />
<TypebotHeader />
<ResultsContent />
</Flex>
)
export default AnalyticsPage

View File

@ -0,0 +1,15 @@
import { Flex } from '@chakra-ui/layout'
import { Seo } from 'components/Seo'
import { SettingsContent } from 'components/settings/SettingsContent'
import { TypebotHeader } from 'components/shared/TypebotHeader'
import React from 'react'
const SettingsPage = () => (
<Flex overflow="hidden" h="100vh" flexDir="column">
<Seo title="Settings" />
<TypebotHeader />
<SettingsContent />
</Flex>
)
export default SettingsPage

View File

@ -0,0 +1,15 @@
import { Flex } from '@chakra-ui/layout'
import { Seo } from 'components/Seo'
import { ShareContent } from 'components/share/ShareContent'
import { TypebotHeader } from 'components/shared/TypebotHeader'
import React from 'react'
const SharePage = () => (
<Flex overflow="hidden" h="100vh" flexDir="column">
<Seo title="Share" />
<TypebotHeader />
<ShareContent />
</Flex>
)
export default SharePage

View File

@ -0,0 +1,15 @@
import { Flex } from '@chakra-ui/layout'
import { Seo } from 'components/Seo'
import { TypebotHeader } from 'components/shared/TypebotHeader'
import { ThemeContent } from 'components/theme/ThemeContent'
import React from 'react'
const ThemePage = () => (
<Flex overflow="hidden" h="100vh" flexDir="column">
<Seo title="Theme" />
<TypebotHeader />
<ThemeContent />
</Flex>
)
export default ThemePage

View File

@ -2,19 +2,14 @@ import React from 'react'
import { Stack } from '@chakra-ui/react' import { Stack } from '@chakra-ui/react'
import { Seo } from 'components/Seo' import { Seo } from 'components/Seo'
import { DashboardHeader } from 'components/dashboard/DashboardHeader' import { DashboardHeader } from 'components/dashboard/DashboardHeader'
import { UserContext } from 'contexts/UserContext'
import { TemplatesContent } from 'layouts/dashboard/TemplatesContent' import { TemplatesContent } from 'layouts/dashboard/TemplatesContent'
const TemplatesPage = () => { const TemplatesPage = () => (
return (
<UserContext>
<Seo title="Templates" />
<Stack> <Stack>
<Seo title="Templates" />
<DashboardHeader /> <DashboardHeader />
<TemplatesContent /> <TemplatesContent />
</Stack> </Stack>
</UserContext> )
)
}
export default TemplatesPage export default TemplatesPage

View File

@ -6,7 +6,6 @@ import { FolderContent } from 'components/dashboard/FolderContent'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import { useFolderContent } from 'services/folders' import { useFolderContent } from 'services/folders'
import { Spinner, useToast } from '@chakra-ui/react' import { Spinner, useToast } from '@chakra-ui/react'
import { UserContext } from 'contexts/UserContext'
const FolderPage = () => { const FolderPage = () => {
const router = useRouter() const router = useRouter()
@ -27,9 +26,8 @@ const FolderPage = () => {
}) })
return ( return (
<UserContext>
<Seo title="My typebots" />
<Stack> <Stack>
<Seo title="My typebots" />
<DashboardHeader /> <DashboardHeader />
{!folder ? ( {!folder ? (
<Flex flex="1"> <Flex flex="1">
@ -39,7 +37,6 @@ const FolderPage = () => {
<FolderContent folder={folder} /> <FolderContent folder={folder} />
)} )}
</Stack> </Stack>
</UserContext>
) )
} }