🚚(frontend) better separation concern doc-versioning features
We move some components related to doc versioning into the doc-versioning feature folder to have a better separation of concerns. We don't need a provider for the doc versioning components since they will receive the doc data directly via a request.
This commit is contained in:
@@ -1,31 +1,63 @@
|
|||||||
import { Loader } from '@openfun/cunningham-react';
|
import { useEffect } from 'react';
|
||||||
import { useRouter } from 'next/router';
|
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
import { css } from 'styled-components';
|
import { css } from 'styled-components';
|
||||||
import * as Y from 'yjs';
|
|
||||||
|
|
||||||
import { Box, Loading, Text, TextErrors } from '@/components';
|
import { Box, Loading } from '@/components';
|
||||||
import { DocHeader, DocVersionHeader } from '@/docs/doc-header/';
|
import { DocHeader } from '@/docs/doc-header/';
|
||||||
import {
|
import { Doc, useProviderStore } from '@/docs/doc-management';
|
||||||
Doc,
|
|
||||||
base64ToBlocknoteXmlFragment,
|
|
||||||
useProviderStore,
|
|
||||||
} from '@/docs/doc-management';
|
|
||||||
import { TableContent } from '@/docs/doc-table-content/';
|
import { TableContent } from '@/docs/doc-table-content/';
|
||||||
import { Versions, useDocVersion } from '@/docs/doc-versioning/';
|
|
||||||
import { useSkeletonStore } from '@/features/skeletons';
|
import { useSkeletonStore } from '@/features/skeletons';
|
||||||
import { useResponsiveStore } from '@/stores';
|
import { useResponsiveStore } from '@/stores';
|
||||||
|
|
||||||
import { BlockNoteEditor, BlockNoteEditorVersion } from './BlockNoteEditor';
|
import { BlockNoteEditor } from './BlockNoteEditor';
|
||||||
|
|
||||||
|
interface DocEditorContainerProps {
|
||||||
|
docHeader: React.ReactNode;
|
||||||
|
docEditor: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DocEditorContainer = ({
|
||||||
|
docHeader,
|
||||||
|
docEditor,
|
||||||
|
}: DocEditorContainerProps) => {
|
||||||
|
const { isDesktop } = useResponsiveStore();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box
|
||||||
|
$maxWidth="868px"
|
||||||
|
$width="100%"
|
||||||
|
$height="100%"
|
||||||
|
className="--docs--doc-editor"
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
$padding={{ horizontal: isDesktop ? '54px' : 'base' }}
|
||||||
|
className="--docs--doc-editor-header"
|
||||||
|
>
|
||||||
|
{docHeader}
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
$direction="row"
|
||||||
|
$width="100%"
|
||||||
|
$css="overflow-x: clip; flex: 1;"
|
||||||
|
$position="relative"
|
||||||
|
className="--docs--doc-editor-content"
|
||||||
|
>
|
||||||
|
<Box $css="flex:1;" $position="relative" $width="100%">
|
||||||
|
{docEditor}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
interface DocEditorProps {
|
interface DocEditorProps {
|
||||||
doc: Doc;
|
doc: Doc;
|
||||||
versionId?: Versions['version_id'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DocEditor = ({ doc, versionId }: DocEditorProps) => {
|
export const DocEditor = ({ doc }: DocEditorProps) => {
|
||||||
const { isDesktop } = useResponsiveStore();
|
const { isDesktop } = useResponsiveStore();
|
||||||
const isVersion = !!versionId && typeof versionId === 'string';
|
|
||||||
const { provider, isReady } = useProviderStore();
|
const { provider, isReady } = useProviderStore();
|
||||||
const { setIsSkeletonVisible } = useSkeletonStore();
|
const { setIsSkeletonVisible } = useSkeletonStore();
|
||||||
const isProviderReady = isReady && provider;
|
const isProviderReady = isReady && provider;
|
||||||
@@ -42,7 +74,7 @@ export const DocEditor = ({ doc, versionId }: DocEditorProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isDesktop && !isVersion && (
|
{isDesktop && (
|
||||||
<Box
|
<Box
|
||||||
$position="absolute"
|
$position="absolute"
|
||||||
$css={css`
|
$css={css`
|
||||||
@@ -53,102 +85,10 @@ export const DocEditor = ({ doc, versionId }: DocEditorProps) => {
|
|||||||
<TableContent />
|
<TableContent />
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
<Box
|
<DocEditorContainer
|
||||||
$maxWidth="868px"
|
docHeader={<DocHeader doc={doc} />}
|
||||||
$width="100%"
|
docEditor={<BlockNoteEditor doc={doc} provider={provider} />}
|
||||||
$height="100%"
|
/>
|
||||||
className="--docs--doc-editor"
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
$padding={{ horizontal: isDesktop ? '54px' : 'base' }}
|
|
||||||
className="--docs--doc-editor-header"
|
|
||||||
>
|
|
||||||
{isVersion ? <DocVersionHeader /> : <DocHeader doc={doc} />}
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Box
|
|
||||||
$direction="row"
|
|
||||||
$width="100%"
|
|
||||||
$css="overflow-x: clip; flex: 1;"
|
|
||||||
$position="relative"
|
|
||||||
className="--docs--doc-editor-content"
|
|
||||||
>
|
|
||||||
<Box $css="flex:1;" $position="relative" $width="100%">
|
|
||||||
{isVersion ? (
|
|
||||||
<DocVersionEditor docId={doc.id} versionId={versionId} />
|
|
||||||
) : (
|
|
||||||
<BlockNoteEditor doc={doc} provider={provider} />
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
interface DocVersionEditorProps {
|
|
||||||
docId: Doc['id'];
|
|
||||||
versionId: Versions['version_id'];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const DocVersionEditor = ({
|
|
||||||
docId,
|
|
||||||
versionId,
|
|
||||||
}: DocVersionEditorProps) => {
|
|
||||||
const {
|
|
||||||
data: version,
|
|
||||||
isLoading,
|
|
||||||
isError,
|
|
||||||
error,
|
|
||||||
} = useDocVersion({
|
|
||||||
docId,
|
|
||||||
versionId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { replace } = useRouter();
|
|
||||||
const [initialContent, setInitialContent] = useState<Y.XmlFragment>();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!version?.content) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setInitialContent(base64ToBlocknoteXmlFragment(version.content));
|
|
||||||
}, [version?.content]);
|
|
||||||
|
|
||||||
if (isError && error) {
|
|
||||||
if (error.status === 404) {
|
|
||||||
void replace(`/404`);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box $margin="large" className="--docs--doc-version-editor-error">
|
|
||||||
<TextErrors
|
|
||||||
causes={error.cause}
|
|
||||||
icon={
|
|
||||||
error.status === 502 ? (
|
|
||||||
<Text
|
|
||||||
className="material-icons"
|
|
||||||
$theme="danger"
|
|
||||||
aria-hidden={true}
|
|
||||||
>
|
|
||||||
wifi_off
|
|
||||||
</Text>
|
|
||||||
) : undefined
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isLoading || !version || !initialContent) {
|
|
||||||
return (
|
|
||||||
<Box $align="center" $justify="center" $height="100%">
|
|
||||||
<Loader />
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <BlockNoteEditorVersion initialContent={initialContent} />;
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
export * from './BlockNoteEditor';
|
||||||
export * from './DocEditor';
|
export * from './DocEditor';
|
||||||
export * from './EmojiPicker';
|
export * from './EmojiPicker';
|
||||||
export * from './custom-blocks/';
|
export * from './custom-blocks/';
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
export * from './DocHeader';
|
export * from './DocHeader';
|
||||||
export * from './DocVersionHeader';
|
export * from './DocTitle';
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
import { Loader } from '@openfun/cunningham-react';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import * as Y from 'yjs';
|
||||||
|
|
||||||
|
import { Box, Text, TextErrors } from '@/components';
|
||||||
|
import { BlockNoteEditorVersion, DocEditorContainer } from '@/docs/doc-editor/';
|
||||||
|
import { Doc, base64ToBlocknoteXmlFragment } from '@/docs/doc-management';
|
||||||
|
import { Versions, useDocVersion } from '@/docs/doc-versioning/';
|
||||||
|
|
||||||
|
import { DocVersionHeader } from './DocVersionHeader';
|
||||||
|
|
||||||
|
interface DocVersionEditorProps {
|
||||||
|
docId: Doc['id'];
|
||||||
|
versionId: Versions['version_id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DocVersionEditor = ({
|
||||||
|
docId,
|
||||||
|
versionId,
|
||||||
|
}: DocVersionEditorProps) => {
|
||||||
|
const {
|
||||||
|
data: version,
|
||||||
|
isLoading,
|
||||||
|
isError,
|
||||||
|
error,
|
||||||
|
} = useDocVersion({
|
||||||
|
docId,
|
||||||
|
versionId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { replace } = useRouter();
|
||||||
|
const [initialContent, setInitialContent] = useState<Y.XmlFragment>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!version?.content) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setInitialContent(base64ToBlocknoteXmlFragment(version.content));
|
||||||
|
}, [version?.content]);
|
||||||
|
|
||||||
|
if (isError && error) {
|
||||||
|
if (error.status === 404) {
|
||||||
|
void replace(`/404`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box $margin="large" className="--docs--doc-version-editor-error">
|
||||||
|
<TextErrors
|
||||||
|
causes={error.cause}
|
||||||
|
icon={
|
||||||
|
error.status === 502 ? (
|
||||||
|
<Text
|
||||||
|
className="material-icons"
|
||||||
|
$theme="danger"
|
||||||
|
aria-hidden={true}
|
||||||
|
>
|
||||||
|
wifi_off
|
||||||
|
</Text>
|
||||||
|
) : undefined
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLoading || !version || !initialContent) {
|
||||||
|
return (
|
||||||
|
<Box $align="center" $justify="center" $height="100%">
|
||||||
|
<Loader />
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DocEditorContainer
|
||||||
|
docHeader={<DocVersionHeader />}
|
||||||
|
docEditor={<BlockNoteEditorVersion initialContent={initialContent} />}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -2,8 +2,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
|
|
||||||
import { Box, HorizontalSeparator } from '@/components';
|
import { Box, HorizontalSeparator } from '@/components';
|
||||||
import { useCunninghamTheme } from '@/cunningham';
|
import { useCunninghamTheme } from '@/cunningham';
|
||||||
|
import { DocTitleText } from '@/docs/doc-header';
|
||||||
import { DocTitleText } from './DocTitle';
|
|
||||||
|
|
||||||
export const DocVersionHeader = () => {
|
export const DocVersionHeader = () => {
|
||||||
const { spacingsTokens } = useCunninghamTheme();
|
const { spacingsTokens } = useCunninghamTheme();
|
||||||
@@ -4,11 +4,11 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { createGlobalStyle, css } from 'styled-components';
|
import { createGlobalStyle, css } from 'styled-components';
|
||||||
|
|
||||||
import { Box, ButtonCloseModal, Text } from '@/components';
|
import { Box, ButtonCloseModal, Text } from '@/components';
|
||||||
import { DocEditor } from '@/docs/doc-editor';
|
|
||||||
import { Doc } from '@/docs/doc-management';
|
import { Doc } from '@/docs/doc-management';
|
||||||
|
|
||||||
import { Versions } from '../types';
|
import { Versions } from '../types';
|
||||||
|
|
||||||
|
import { DocVersionEditor } from './DocVersionEditor';
|
||||||
import { ModalConfirmationVersion } from './ModalConfirmationVersion';
|
import { ModalConfirmationVersion } from './ModalConfirmationVersion';
|
||||||
import { VersionList } from './VersionList';
|
import { VersionList } from './VersionList';
|
||||||
|
|
||||||
@@ -81,7 +81,10 @@ export const ModalSelectVersion = ({
|
|||||||
$align="center"
|
$align="center"
|
||||||
>
|
>
|
||||||
{selectedVersionId && (
|
{selectedVersionId && (
|
||||||
<DocEditor doc={doc} versionId={selectedVersionId} />
|
<DocVersionEditor
|
||||||
|
docId={doc.id}
|
||||||
|
versionId={selectedVersionId}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
{!selectedVersionId && (
|
{!selectedVersionId && (
|
||||||
<Box $align="center" $justify="center" $height="100%">
|
<Box $align="center" $justify="center" $height="100%">
|
||||||
|
|||||||
Reference in New Issue
Block a user