From 1b900b3f5d8f4f31bec99ea69080645955f09a75 Mon Sep 17 00:00:00 2001 From: Baptiste Arnaud Date: Mon, 21 Feb 2022 19:02:44 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=94=A5=20Remove=20save=20button?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GoogleSheetsSettingsBody.tsx | 7 +-- .../shared/TypebotHeader/SaveButton.tsx | 33 -------------- .../shared/TypebotHeader/TypebotHeader.tsx | 32 +++++++++++--- .../TypebotContext/TypebotContext.tsx | 43 +++++++++++-------- 4 files changed, 53 insertions(+), 62 deletions(-) delete mode 100644 apps/builder/components/shared/TypebotHeader/SaveButton.tsx diff --git a/apps/builder/components/shared/Graph/Nodes/StepNode/SettingsPopoverContent/bodies/GoogleSheetsSettingsBody/GoogleSheetsSettingsBody.tsx b/apps/builder/components/shared/Graph/Nodes/StepNode/SettingsPopoverContent/bodies/GoogleSheetsSettingsBody/GoogleSheetsSettingsBody.tsx index a4a31a228..1df22e7d1 100644 --- a/apps/builder/components/shared/Graph/Nodes/StepNode/SettingsPopoverContent/bodies/GoogleSheetsSettingsBody/GoogleSheetsSettingsBody.tsx +++ b/apps/builder/components/shared/Graph/Nodes/StepNode/SettingsPopoverContent/bodies/GoogleSheetsSettingsBody/GoogleSheetsSettingsBody.tsx @@ -37,7 +37,7 @@ export const GoogleSheetsSettingsBody = ({ onOptionsChange, stepId, }: Props) => { - const { save, hasUnsavedChanges } = useTypebot() + const { save } = useTypebot() const { sheets, isLoading } = useSheets({ credentialsId: options?.credentialsId, spreadsheetId: options?.spreadsheetId, @@ -83,10 +83,7 @@ export const GoogleSheetsSettingsBody = ({ } const handleCreateNewClick = async () => { - if (hasUnsavedChanges) { - const errorToastId = await save() - if (errorToastId) return - } + await save() const linkElement = document.createElement('a') linkElement.href = getGoogleSheetsConsentScreenUrl( window.location.href, diff --git a/apps/builder/components/shared/TypebotHeader/SaveButton.tsx b/apps/builder/components/shared/TypebotHeader/SaveButton.tsx deleted file mode 100644 index 3c5005bef..000000000 --- a/apps/builder/components/shared/TypebotHeader/SaveButton.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { IconButton, Text, Tooltip } from '@chakra-ui/react' -import { CheckIcon, SaveIcon } from 'assets/icons' -import { useTypebot } from 'contexts/TypebotContext/TypebotContext' -import React from 'react' - -export const SaveButton = () => { - const { save, isSavingLoading, hasUnsavedChanges } = useTypebot() - - const handleSaveClick = async () => { - await save() - } - - return ( - <> - {hasUnsavedChanges && ( - - Unsaved changes - - )} - - : - } - aria-label={hasUnsavedChanges ? 'Save' : 'Saved'} - /> - - - ) -} diff --git a/apps/builder/components/shared/TypebotHeader/TypebotHeader.tsx b/apps/builder/components/shared/TypebotHeader/TypebotHeader.tsx index 5370c6077..d7469e46c 100644 --- a/apps/builder/components/shared/TypebotHeader/TypebotHeader.tsx +++ b/apps/builder/components/shared/TypebotHeader/TypebotHeader.tsx @@ -1,4 +1,12 @@ -import { Flex, HStack, Button, IconButton, Tooltip } from '@chakra-ui/react' +import { + Flex, + HStack, + Button, + IconButton, + Tooltip, + Spinner, + Text, +} from '@chakra-ui/react' import { ChevronLeftIcon, RedoIcon, UndoIcon } from 'assets/icons' import { NextChakraLink } from 'components/nextChakra/NextChakraLink' import { RightPanel, useEditor } from 'contexts/EditorContext' @@ -7,7 +15,6 @@ import { useRouter } from 'next/router' import React from 'react' import { PublishButton } from '../buttons/PublishButton' import { EditableTypebotName } from './EditableTypebotName' -import { SaveButton } from './SaveButton' export const headerHeight = 56 @@ -21,7 +28,7 @@ export const TypebotHeader = () => { redo, canUndo, canRedo, - publishedTypebot, + isSavingLoading, } = useTypebot() const { setRightPanel } = useEditor() @@ -96,7 +103,13 @@ export const TypebotHeader = () => { )} - + { /> - + {isSavingLoading && ( + + + + Saving... + + + )} + - diff --git a/apps/builder/contexts/TypebotContext/TypebotContext.tsx b/apps/builder/contexts/TypebotContext/TypebotContext.tsx index 42de77542..0da73f3aa 100644 --- a/apps/builder/contexts/TypebotContext/TypebotContext.tsx +++ b/apps/builder/contexts/TypebotContext/TypebotContext.tsx @@ -1,4 +1,4 @@ -import { ToastId, useToast } from '@chakra-ui/react' +import { useToast } from '@chakra-ui/react' import { PublicTypebot, Settings, Theme, Typebot } from 'models' import { useRouter } from 'next/router' import { @@ -32,7 +32,8 @@ import useUndo from 'services/utils/useUndo' import { useDebounce } from 'use-debounce' import { itemsAction, ItemsActions } from './actions/items' import { generate } from 'short-uuid' -const autoSaveTimeout = 40000 +import { deepEqual } from 'fast-equals' +const autoSaveTimeout = 10000 type UpdateTypebotPayload = Partial<{ theme: Theme @@ -49,9 +50,8 @@ const typebotContext = createContext< publishedTypebot?: PublicTypebot isPublished: boolean isPublishing: boolean - hasUnsavedChanges: boolean isSavingLoading: boolean - save: () => Promise + save: () => Promise undo: () => void redo: () => void canRedo: boolean @@ -93,6 +93,13 @@ export const TypebotContext = ({ }), }) + useEffect(() => { + if (!typebot || !localTypebot || deepEqual(typebot, localTypebot)) return + if (typebot?.blocks.length === localTypebot?.blocks.length) + setLocalTypebot({ ...typebot }) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [typebot]) + const [ { present: localTypebot }, { @@ -106,12 +113,16 @@ export const TypebotContext = ({ ] = useUndo(undefined) const saveTypebot = async () => { + if (deepEqual(typebot, localTypebot)) return const typebotToSave = currentTypebotRef.current if (!typebotToSave) return setIsSavingLoading(true) const { error } = await updateTypebot(typebotToSave.id, typebotToSave) setIsSavingLoading(false) - if (error) return toast({ title: error.name, description: error.message }) + if (error) { + toast({ title: error.name, description: error.message }) + return + } mutate({ typebot: typebotToSave }) window.removeEventListener('beforeunload', preventUserFromRefreshing) } @@ -130,18 +141,9 @@ export const TypebotContext = ({ }) } - const hasUnsavedChanges = useMemo( - () => - isDefined(typebot) && - isDefined(localTypebot) && - !checkIfTypebotsAreEqual(localTypebot, typebot), - [typebot, localTypebot] - ) - useAutoSave({ handler: saveTypebot, item: localTypebot, - canSave: hasUnsavedChanges, debounceTimeout: autoSaveTimeout, }) @@ -257,7 +259,6 @@ export const TypebotContext = ({ value={{ typebot: localTypebot, publishedTypebot, - hasUnsavedChanges, isSavingLoading, save: saveTypebot, undo, @@ -306,18 +307,24 @@ export const useFetchedTypebot = ({ const useAutoSave = ({ handler, item, - canSave, debounceTimeout, }: { // eslint-disable-next-line @typescript-eslint/no-explicit-any handler: (item?: T) => Promise item?: T - canSave: boolean debounceTimeout: number }) => { const [debouncedItem] = useDebounce(item, debounceTimeout) + useEffect(() => { + const save = () => handler(item) + document.addEventListener('visibilitychange', save) + return () => { + document.removeEventListener('visibilitychange', save) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) return useEffect(() => { - if (canSave) handler(item) + handler(item) // eslint-disable-next-line react-hooks/exhaustive-deps }, [debouncedItem]) }