feat(editor): ✨ Add auto save
This commit is contained in:
@ -26,7 +26,7 @@ export const TypebotHeader = () => {
|
||||
const handleNameSubmit = (name: string) => updateTypebot({ name })
|
||||
|
||||
const handlePreviewClick = async () => {
|
||||
await save()
|
||||
save().then()
|
||||
setRightPanel(RightPanel.PREVIEW)
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,9 @@ import { choiceItemsAction, ChoiceItemsActions } from './actions/choiceItems'
|
||||
import { variablesAction, VariablesActions } from './actions/variables'
|
||||
import { edgesAction, EdgesActions } from './actions/edges'
|
||||
import { webhooksAction, WebhooksAction } from './actions/webhooks'
|
||||
import { useDebounce } from 'use-debounce'
|
||||
|
||||
const autoSaveTimeout = 10000
|
||||
|
||||
type UpdateTypebotPayload = Partial<{
|
||||
theme: Theme
|
||||
@ -85,6 +88,12 @@ export const TypebotContext = ({
|
||||
undefined
|
||||
)
|
||||
|
||||
const [debouncedLocalTypebot] = useDebounce(localTypebot, autoSaveTimeout)
|
||||
useEffect(() => {
|
||||
if (hasUnsavedChanges) saveTypebot()
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [debouncedLocalTypebot])
|
||||
|
||||
const [localPublishedTypebot, setLocalPublishedTypebot] =
|
||||
useState<PublicTypebot>()
|
||||
const [isSavingLoading, setIsSavingLoading] = useState(false)
|
||||
|
@ -9,14 +9,22 @@ import 'assets/styles/plate.css'
|
||||
import 'focus-visible/dist/focus-visible'
|
||||
import 'assets/styles/submissionsTable.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) => {
|
||||
useRouterProgressBar()
|
||||
const { query } = useRouter()
|
||||
|
||||
return (
|
||||
<ChakraProvider theme={customTheme}>
|
||||
<SessionProvider>
|
||||
<UserContext>
|
||||
<TypebotContext typebotId={query.typebotId?.toString()}>
|
||||
<Component {...pageProps} />
|
||||
</TypebotContext>
|
||||
</UserContext>
|
||||
</SessionProvider>
|
||||
</ChakraProvider>
|
||||
)
|
||||
|
@ -1,18 +1,13 @@
|
||||
import { Stack } from '@chakra-ui/react'
|
||||
import { AccountHeader } from 'components/account/AccountHeader'
|
||||
import { Seo } from 'components/Seo'
|
||||
import { UserContext } from 'contexts/UserContext'
|
||||
import { AccountContent } from 'layouts/account/AccountContent'
|
||||
|
||||
const AccountSubscriptionPage = () => {
|
||||
return (
|
||||
<UserContext>
|
||||
<Seo title="My account" />{' '}
|
||||
const AccountSubscriptionPage = () => (
|
||||
<Stack>
|
||||
<Seo title="My account" />
|
||||
<AccountHeader />
|
||||
<AccountContent />
|
||||
</Stack>
|
||||
</UserContext>
|
||||
)
|
||||
}
|
||||
)
|
||||
export default AccountSubscriptionPage
|
||||
|
@ -3,12 +3,14 @@ import { SignInForm } from 'components/auth/SignInForm'
|
||||
import { Heading, VStack } from '@chakra-ui/react'
|
||||
import { useRouter } from 'next/router'
|
||||
import React from 'react'
|
||||
import { Seo } from 'components/Seo'
|
||||
|
||||
const RegisterPage = () => {
|
||||
const { query } = useRouter()
|
||||
|
||||
return (
|
||||
<VStack spacing={4} h="100vh" justifyContent="center">
|
||||
<Seo title="Register" />
|
||||
<Heading>Create an account</Heading>
|
||||
<AuthSwitcher type="register" />
|
||||
<SignInForm defaultEmail={query.g?.toString()} />
|
||||
|
@ -2,10 +2,12 @@ import { AuthSwitcher } from 'components/auth/AuthSwitcher'
|
||||
import { SignInForm } from 'components/auth/SignInForm'
|
||||
import { Heading, VStack } from '@chakra-ui/react'
|
||||
import React from 'react'
|
||||
import { Seo } from 'components/Seo'
|
||||
|
||||
const SignInPage = () => {
|
||||
return (
|
||||
<VStack spacing={4} h="100vh" justifyContent="center">
|
||||
<Seo title="Sign in" />
|
||||
<Heading>Sign in</Heading>
|
||||
<AuthSwitcher type="signin" />
|
||||
<SignInForm />
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
23
apps/builder/pages/typebots/[typebotId]/edit.tsx
Normal file
23
apps/builder/pages/typebots/[typebotId]/edit.tsx
Normal 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
|
15
apps/builder/pages/typebots/[typebotId]/results.tsx
Normal file
15
apps/builder/pages/typebots/[typebotId]/results.tsx
Normal 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
|
@ -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
|
15
apps/builder/pages/typebots/[typebotId]/settings.tsx
Normal file
15
apps/builder/pages/typebots/[typebotId]/settings.tsx
Normal 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
|
15
apps/builder/pages/typebots/[typebotId]/share.tsx
Normal file
15
apps/builder/pages/typebots/[typebotId]/share.tsx
Normal 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
|
15
apps/builder/pages/typebots/[typebotId]/theme.tsx
Normal file
15
apps/builder/pages/typebots/[typebotId]/theme.tsx
Normal 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
|
@ -2,19 +2,14 @@ import React from 'react'
|
||||
import { Stack } from '@chakra-ui/react'
|
||||
import { Seo } from 'components/Seo'
|
||||
import { DashboardHeader } from 'components/dashboard/DashboardHeader'
|
||||
import { UserContext } from 'contexts/UserContext'
|
||||
import { TemplatesContent } from 'layouts/dashboard/TemplatesContent'
|
||||
|
||||
const TemplatesPage = () => {
|
||||
return (
|
||||
<UserContext>
|
||||
<Seo title="Templates" />
|
||||
const TemplatesPage = () => (
|
||||
<Stack>
|
||||
<Seo title="Templates" />
|
||||
<DashboardHeader />
|
||||
<TemplatesContent />
|
||||
</Stack>
|
||||
</UserContext>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
export default TemplatesPage
|
||||
|
@ -6,7 +6,6 @@ import { FolderContent } from 'components/dashboard/FolderContent'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useFolderContent } from 'services/folders'
|
||||
import { Spinner, useToast } from '@chakra-ui/react'
|
||||
import { UserContext } from 'contexts/UserContext'
|
||||
|
||||
const FolderPage = () => {
|
||||
const router = useRouter()
|
||||
@ -27,9 +26,8 @@ const FolderPage = () => {
|
||||
})
|
||||
|
||||
return (
|
||||
<UserContext>
|
||||
<Seo title="My typebots" />
|
||||
<Stack>
|
||||
<Seo title="My typebots" />
|
||||
<DashboardHeader />
|
||||
{!folder ? (
|
||||
<Flex flex="1">
|
||||
@ -39,7 +37,6 @@ const FolderPage = () => {
|
||||
<FolderContent folder={folder} />
|
||||
)}
|
||||
</Stack>
|
||||
</UserContext>
|
||||
)
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user