From 296b5dbf594aadc384fd2c3c0c95f116fc3b96da Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Mon, 2 Sep 2024 16:02:21 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F(frontend)=20add=20modal=20co?= =?UTF-8?q?nfirmation=20restore=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add modal confirmation restore version explaining that the current version will be replaced by the selected version, and that some data may be lost. --- .../__tests__/app-impress/doc-version.spec.ts | 8 ++ .../docs/doc-editor/hook/useSaveDoc.tsx | 15 -- .../src/features/docs/doc-editor/index.tsx | 1 + .../docs/doc-editor/stores/useDocStore.tsx | 8 -- .../components/ModalVersion.tsx | 122 ++++++++++++++++ .../doc-versioning/components/VersionItem.tsx | 133 ++++++++---------- 6 files changed, 193 insertions(+), 94 deletions(-) create mode 100644 src/frontend/apps/impress/src/features/docs/doc-versioning/components/ModalVersion.tsx diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-version.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-version.spec.ts index 330c989c..94a44e0c 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-version.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-version.spec.ts @@ -119,6 +119,14 @@ test.describe('Doc Version', () => { await panel.getByLabel('Open the version options').click(); await page.getByText('Restore the version').click(); + await expect(page.getByText('Restore this version?')).toBeVisible(); + + await page + .getByRole('button', { + name: 'Restore', + }) + .click(); + await expect(panel.locator('li')).toHaveCount(3); await panel.getByText('Current version').click(); diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useSaveDoc.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useSaveDoc.tsx index 8b036b32..0a21cd45 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useSaveDoc.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useSaveDoc.tsx @@ -5,12 +5,9 @@ import * as Y from 'yjs'; import { useUpdateDoc } from '@/features/docs/doc-management/'; import { KEY_LIST_DOC_VERSIONS } from '@/features/docs/doc-versioning'; -import { useDocStore } from '../stores'; import { toBase64 } from '../utils'; const useSaveDoc = (docId: string, doc: Y.Doc, canSave: boolean) => { - const { forceSave, setForceSave } = useDocStore(); - const { mutate: updateDoc } = useUpdateDoc({ listInvalideQueries: [KEY_LIST_DOC_VERSIONS], }); @@ -68,18 +65,6 @@ const useSaveDoc = (docId: string, doc: Y.Doc, canSave: boolean) => { }); }, [doc, docId, updateDoc]); - useEffect(() => { - if (forceSave === 'false') { - return; - } - - setForceSave('false'); - - if ((forceSave === 'current' && hasChanged()) || forceSave === 'version') { - saveDoc(); - } - }, [forceSave, hasChanged, saveDoc, setForceSave]); - const timeout = useRef(); const router = useRouter(); diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/index.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/index.tsx index 70605fb7..24ecfc79 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/index.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/index.tsx @@ -1,2 +1,3 @@ export * from './components'; export * from './stores'; +export * from './utils'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/stores/useDocStore.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/stores/useDocStore.tsx index 93c9e759..db877db8 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/stores/useDocStore.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/stores/useDocStore.tsx @@ -11,24 +11,16 @@ interface DocStore { editor?: BlockNoteEditor; } -type ForceSaveState = 'false' | 'version' | 'current'; - export interface UseDocStore { docsStore: { [storeId: string]: DocStore; }; createProvider: (storeId: string, initialDoc: Base64) => WebrtcProvider; setStore: (storeId: string, props: Partial) => void; - forceSave: ForceSaveState; - setForceSave: (forceSave: ForceSaveState) => void; } export const useDocStore = create((set, get) => ({ docsStore: {}, - forceSave: 'false', - setForceSave: (forceSave) => { - set(() => ({ forceSave })); - }, createProvider: (storeId: string, initialDoc: Base64) => { const doc = new Y.Doc({ guid: storeId, diff --git a/src/frontend/apps/impress/src/features/docs/doc-versioning/components/ModalVersion.tsx b/src/frontend/apps/impress/src/features/docs/doc-versioning/components/ModalVersion.tsx new file mode 100644 index 00000000..4240bfda --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-versioning/components/ModalVersion.tsx @@ -0,0 +1,122 @@ +import { + Alert, + Button, + Modal, + ModalSize, + VariantType, + useToastProvider, +} from '@openfun/cunningham-react'; +import { t } from 'i18next'; +import { useRouter } from 'next/navigation'; +import * as Y from 'yjs'; + +import { Box, Text } from '@/components'; +import { toBase64, useDocStore } from '@/features/docs/doc-editor'; +import { Doc, useUpdateDoc } from '@/features/docs/doc-management'; + +import { KEY_LIST_DOC_VERSIONS } from '../api/useDocVersions'; +import { Versions } from '../types'; +import { revertUpdate } from '../utils'; + +interface ModalVersionProps { + onClose: () => void; + docId: Doc['id']; + + versionId: Versions['version_id']; +} + +export const ModalVersion = ({ + onClose, + docId, + versionId, +}: ModalVersionProps) => { + const { toast } = useToastProvider(); + const router = useRouter(); + const { docsStore, setStore } = useDocStore(); + const { mutate: updateDoc } = useUpdateDoc({ + listInvalideQueries: [KEY_LIST_DOC_VERSIONS], + onSuccess: () => { + const onDisplaySuccess = () => { + toast(t('Version restored successfully'), VariantType.SUCCESS); + router.push(`/docs/${docId}`); + }; + + if (!docsStore?.[docId]?.provider || !docsStore?.[versionId]?.provider) { + onDisplaySuccess(); + return; + } + + setStore(docId, { + editor: undefined, + }); + + revertUpdate( + docsStore[docId].provider.doc, + docsStore[docId].provider.doc, + docsStore[versionId].provider.doc, + ); + + onDisplaySuccess(); + }, + }); + + return ( + onClose()} + > + {t('Cancel')} + + } + onClose={() => onClose()} + rightActions={ + + } + size={ModalSize.MEDIUM} + title={ + + + restore + + + {t('Restore this version?')} + + + } + > + + + + + {t('Your current document will revert to this version.')} + + {t('If a member is editing, his works can be lost.')} + + + + + ); +}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-versioning/components/VersionItem.tsx b/src/frontend/apps/impress/src/features/docs/doc-versioning/components/VersionItem.tsx index fcdb3b1d..738cc0c6 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-versioning/components/VersionItem.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-versioning/components/VersionItem.tsx @@ -4,11 +4,11 @@ import React, { PropsWithChildren, useState } from 'react'; import { Box, DropButton, IconOptions, StyledLink, Text } from '@/components'; import { useCunninghamTheme } from '@/cunningham'; -import { useDocStore } from '@/features/docs/doc-editor'; import { Doc } from '@/features/docs/doc-management'; import { Versions } from '../types'; -import { revertUpdate } from '../utils'; + +import { ModalVersion } from './ModalVersion'; interface VersionItemProps { docId: Doc['id']; @@ -25,15 +25,16 @@ export const VersionItem = ({ link, isActive, }: VersionItemProps) => { - const { setForceSave, docsStore, setStore } = useDocStore(); const { colorsTokens } = useCunninghamTheme(); const [isDropOpen, setIsDropOpen] = useState(false); + const [isModalVersionOpen, setIsModalVersionOpen] = useState(false); return ( - + - - - - - description - - - {text} - + $hasTransition + $minWidth="13rem" + > + + + + + description + + + {text} + + + {isActive && versionId && ( + + } + onOpenChange={(isOpen) => setIsDropOpen(isOpen)} + isOpen={isDropOpen} + > + + + + + )} - {isActive && versionId && ( - - } - onOpenChange={(isOpen) => setIsDropOpen(isOpen)} - isOpen={isDropOpen} - > - - - - - )} - - - + + + {isModalVersionOpen && versionId && ( + setIsModalVersionOpen(false)} + docId={docId} + versionId={versionId} + /> + )} + ); };