diff --git a/CHANGELOG.md b/CHANGELOG.md index e02b0034..8dbffb0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,9 @@ and this project adheres to - ♻️(frontend) better separation collaboration process #528 - 💄(frontend) updating the header and leftpanel for responsive #421 - 💄(frontend) update DocsGrid component #431 +- 💄(frontend) update DocsGridOptions component #432 +- 💄(frontend) update DocHeader ui #446 +- 💄(frontend) update doc versioning ui #463 ## [1.10.0] - 2024-12-17 @@ -40,6 +43,7 @@ and this project adheres to - ⚡️(e2e) reduce flakiness on e2e tests #511 + ## [1.9.0] - 2024-12-11 ## Added @@ -62,8 +66,10 @@ and this project adheres to - 🐛(backend) fix sanitize problem IA #490 + ## [1.8.2] - 2024-11-28 + ## Changed - ♻️(SW) change strategy html caching #460 @@ -88,9 +94,6 @@ and this project adheres to - ✨(frontend) config endpoint #424 - ✨(frontend) add sentry #424 - ✨(frontend) add crisp chatbot #450 -- 💄(frontend) update DocsGridOptions component #432 -- 💄(frontend) update DocHeader ui #446 - ## Changed diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-member-list.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-member-list.spec.ts index 3d9553a1..fba63bb0 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-member-list.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-member-list.spec.ts @@ -54,8 +54,10 @@ test.describe('Document list members', () => { const list = page.getByLabel('List members card').locator('ul'); await expect(list.locator('li')).toHaveCount(20); await list.getByText(`impress@impress.world-page-${1}-18`).hover(); - await page.mouse.wheel(0, 10); - + const loadMoreButton = page + .getByLabel('List members card') + .getByRole('button', { name: 'arrow_downward Load more' }); + await loadMoreButton.scrollIntoViewIfNeeded(); await waitForElementCount(list.locator('li'), 21, 10000); expect(await list.locator('li').count()).toBeGreaterThan(20); @@ -109,9 +111,13 @@ test.describe('Document list members', () => { await page.getByRole('button', { name: 'Share' }).click(); const list = page.getByLabel('List invitation card').locator('ul'); + await expect(list.locator('li')).toHaveCount(20); await list.getByText(`impress@impress.world-page-${1}-18`).hover(); - await page.mouse.wheel(0, 10); + const loadMoreButton = page + .getByLabel('List invitation card') + .getByRole('button', { name: 'arrow_downward Load more' }); + await loadMoreButton.scrollIntoViewIfNeeded(); await waitForElementCount(list.locator('li'), 21, 10000); 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 3166bd27..f3236195 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 @@ -23,24 +23,27 @@ test.describe('Doc Version', () => { name: 'Version history', }) .click(); + await expect(page.getByText('History', { exact: true })).toBeVisible(); - const panel = page.getByLabel('Document panel'); - - await expect(panel.getByText('Current version')).toBeVisible(); - expect(await panel.locator('li').count()).toBe(1); + const modal = page.getByLabel('version history modal'); + const panel = modal.getByLabel('version list'); + await expect(panel).toBeVisible(); + await expect(modal.getByText('No versions')).toBeVisible(); + await modal.getByRole('button', { name: 'close' }).click(); await page.locator('.ProseMirror.bn-editor').click(); await page.locator('.ProseMirror.bn-editor').last().fill('Hello World'); - await goToGridDoc(page, { title: randomDoc, }); - await expect(page.getByText('Hello World')).toBeVisible(); + await expect( + page.getByRole('heading', { name: 'Hello World' }), + ).toBeVisible(); await page .locator('.ProseMirror .bn-block') - .getByText('Hello World') + .getByRole('heading', { name: 'Hello World' }) .fill('It will create a version'); await goToGridDoc(page, { @@ -48,7 +51,9 @@ test.describe('Doc Version', () => { }); await expect(page.getByText('Hello World')).toBeHidden(); - await expect(page.getByText('It will create a version')).toBeVisible(); + await expect( + page.getByRole('heading', { name: 'It will create a version' }), + ).toBeVisible(); await page.getByLabel('Open the document options').click(); await page @@ -57,19 +62,16 @@ test.describe('Doc Version', () => { }) .click(); - await expect(panel.getByText('Current version')).toBeVisible(); - expect(await panel.locator('li').count()).toBe(2); + await expect(panel).toBeVisible(); + await expect(page.getByText('History', { exact: true })).toBeVisible(); + await expect(page.getByRole('status')).toBeVisible(); + await expect(page.getByRole('status')).toBeHidden(); + const items = await panel.locator('.version-item').all(); + expect(items.length).toBe(1); + await items[0].click(); - await panel.locator('li').nth(1).click(); - await expect( - page.getByText('Read only, you cannot edit document versions.'), - ).toBeVisible(); - await expect(page.getByText('Hello World')).toBeVisible(); - await expect(page.getByText('It will create a version')).toBeHidden(); - - await panel.getByText('Current version').click(); - await expect(page.getByText('Hello World')).toBeHidden(); - await expect(page.getByText('It will create a version')).toBeVisible(); + await expect(modal.getByText('Hello World')).toBeVisible(); + await expect(modal.getByText('It will create a version')).toBeHidden(); }); test('it does not display the doc versions if not allowed', async ({ @@ -90,12 +92,6 @@ test.describe('Doc Version', () => { await expect( page.getByRole('button', { name: 'Version history' }), ).toBeDisabled(); - - await page.getByRole('button', { name: 'Table of content' }).click(); - - await expect( - page.getByLabel('Document panel').getByText('Versions'), - ).toBeHidden(); }); test('it restores the doc version', async ({ page, browserName }) => { @@ -105,7 +101,6 @@ test.describe('Doc Version', () => { await page.locator('.bn-block-outer').last().click(); await page.locator('.bn-block-outer').last().fill('Hello'); - expect(true).toBe(true); await goToGridDoc(page, { title: randomDoc, }); @@ -129,84 +124,26 @@ test.describe('Doc Version', () => { }) .click(); - const panel = page.getByLabel('Document panel'); - await panel.locator('li').nth(1).click(); - await expect(page.getByText('World')).toBeHidden(); + const modal = page.getByLabel('version history modal'); + const panel = modal.getByLabel('version list'); + await expect(panel).toBeVisible(); - await panel.getByLabel('Open the version options').click(); - await page.getByText('Restore the version').click(); + await expect(page.getByText('History', { exact: true })).toBeVisible(); + await expect(page.getByRole('status')).toBeVisible(); + await expect(page.getByRole('status')).toBeHidden(); + const items = await panel.locator('.version-item').all(); + expect(items.length).toBe(1); + await items[0].click(); - await expect(page.getByText('Restore this version?')).toBeVisible(); + await expect(modal.getByText('World')).toBeHidden(); - await page - .getByRole('button', { - name: 'Restore', - }) - .click(); + await page.getByRole('button', { name: 'Restore' }).click(); + await expect(page.getByText('Your current document will')).toBeVisible(); + await page.getByText('If a member is editing, his').click(); - await expect(panel.locator('li')).toHaveCount(3); + await page.getByLabel('Restore', { exact: true }).click(); - await panel.getByText('Current version').click(); await expect(page.getByText('Hello')).toBeVisible(); await expect(page.getByText('World')).toBeHidden(); }); - - test('it restores the doc version from button title', async ({ - page, - browserName, - }) => { - const [randomDoc] = await createDoc(page, 'doc-version', browserName, 1); - - await verifyDocName(page, randomDoc); - - const editor = page.locator('.ProseMirror'); - await editor.locator('.bn-block-outer').last().click(); - await editor.locator('.bn-block-outer').last().fill('Hello'); - - await goToGridDoc(page, { - title: randomDoc, - }); - - await expect(editor.getByText('Hello')).toBeVisible(); - await editor.locator('.bn-block-outer').last().click(); - await page.keyboard.press('Enter'); - await editor.locator('.bn-block-outer').last().fill('World'); - - await goToGridDoc(page, { - title: randomDoc, - }); - - await expect(editor.getByText('World')).toBeVisible(); - - await page.getByLabel('Open the document options').click(); - await page - .getByRole('button', { - name: 'Version history', - }) - .click(); - - const panel = page.getByLabel('Document panel'); - await panel.locator('li').nth(1).click(); - await expect(editor.getByText('World')).toBeHidden(); - - await page - .getByRole('button', { - name: 'Restore this 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(); - await expect(editor.getByText('Hello')).toBeVisible(); - await expect(editor.getByText('World')).toBeHidden(); - }); }); diff --git a/src/frontend/apps/impress/src/components/DropdownMenu.tsx b/src/frontend/apps/impress/src/components/DropdownMenu.tsx index f30f8334..cd2dc771 100644 --- a/src/frontend/apps/impress/src/components/DropdownMenu.tsx +++ b/src/frontend/apps/impress/src/components/DropdownMenu.tsx @@ -11,6 +11,7 @@ export type DropdownMenuOption = { callback?: () => void | Promise; danger?: boolean; disabled?: boolean; + show?: boolean; }; export type DropdownMenuProps = { @@ -59,6 +60,10 @@ export const DropdownMenu = ({ > {options.map((option, index) => { + if (option.show !== undefined && !option.show) { + return; + } + const isDisabled = option.disabled !== undefined && option.disabled; return ( void; - scrollContainer: HTMLElement | null; + scrollContainer?: HTMLElement | null; + buttonLabel?: string; } export const InfiniteScroll = ({ @@ -14,42 +18,31 @@ export const InfiniteScroll = ({ hasMore, isLoading, next, - scrollContainer, + buttonLabel, ...boxProps }: PropsWithChildren) => { - const timeout = useRef>(); - - useEffect(() => { - if (!scrollContainer) { + const { t } = useTranslation(); + const loadMore = (inView: boolean) => { + if (!inView || isLoading) { return; } + void next(); + }; - const nextHandle = () => { - if (!hasMore || isLoading) { - return; - } - - // To not wait until the end of the scroll to load more data - const heightFromBottom = 150; - - const { scrollTop, clientHeight, scrollHeight } = scrollContainer; - if (scrollTop + clientHeight >= scrollHeight - heightFromBottom) { - next(); - } - }; - - const handleScroll = () => { - if (timeout.current) { - clearTimeout(timeout.current); - } - timeout.current = setTimeout(nextHandle, 50); - }; - - scrollContainer.addEventListener('scroll', handleScroll); - return () => { - scrollContainer.removeEventListener('scroll', handleScroll); - }; - }, [hasMore, isLoading, next, scrollContainer]); - - return {children}; + return ( + + {children} + + {!isLoading && hasMore && ( + + )} + + + ); }; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx index 5cb15fc0..fa39f405 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx @@ -6,7 +6,7 @@ import * as Y from 'yjs'; import { Box, Card, Text, TextErrors } from '@/components'; import { useCunninghamTheme } from '@/cunningham'; -import { DocHeader } from '@/features/docs/doc-header'; +import { DocHeader, DocVersionHeader } from '@/features/docs/doc-header/'; import { Doc, base64ToBlocknoteXmlFragment, @@ -20,12 +20,10 @@ import { IconOpenPanelEditor, PanelEditor } from './PanelEditor'; interface DocEditorProps { doc: Doc; + versionId?: Versions['version_id']; } -export const DocEditor = ({ doc }: DocEditorProps) => { - const { - query: { versionId }, - } = useRouter(); +export const DocEditor = ({ doc, versionId }: DocEditorProps) => { const { t } = useTranslation(); const { isMobile } = useResponsiveStore(); @@ -41,7 +39,12 @@ export const DocEditor = ({ doc }: DocEditorProps) => { return ( <> - + {isVersion ? ( + + ) : ( + + )} + {!doc.abilities.partial_update && ( @@ -49,18 +52,11 @@ export const DocEditor = ({ doc }: DocEditorProps) => { )} - {isVersion && ( - - - {t(`Read only, you cannot edit document versions.`)} - - - )} + @@ -75,9 +71,9 @@ export const DocEditor = ({ doc }: DocEditorProps) => { ) : ( )} - {!isMobile && } + {!isMobile && !isVersion && } - + {!isVersion && } ); diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/PanelEditor.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/PanelEditor.tsx index 0f325f95..729fe6c2 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/PanelEditor.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/PanelEditor.tsx @@ -1,20 +1,14 @@ -import React, { PropsWithChildren, useEffect, useState } from 'react'; +import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Box, BoxButton, Card, IconBG, Text } from '@/components'; import { useCunninghamTheme } from '@/cunningham'; -import { Doc } from '@/features/docs/doc-management'; import { TableContent } from '@/features/docs/doc-table-content'; -import { VersionList } from '@/features/docs/doc-versioning'; import { useResponsiveStore } from '@/stores'; import { useHeadingStore, usePanelEditorStore } from '../stores'; -interface PanelProps { - doc: Doc; -} - -export const PanelEditor = ({ doc }: PropsWithChildren) => { +export const PanelEditor = () => { const { t } = useTranslation(); const { colorsTokens } = useCunninghamTheme(); const { isMobile } = useResponsiveStore(); @@ -72,7 +66,7 @@ export const PanelEditor = ({ doc }: PropsWithChildren) => { $background="white" $position="absolute" $height="100%" - $width={doc.abilities.versions_list ? '50%' : '100%'} + $width="100%" $hasTransition="slow" $css={` border-top: 2px solid ${colorsTokens()['primary-600']}; @@ -88,7 +82,7 @@ export const PanelEditor = ({ doc }: PropsWithChildren) => { `} /> setIsPanelTableContentOpen(true)} $zIndex={1} > @@ -103,29 +97,8 @@ export const PanelEditor = ({ doc }: PropsWithChildren) => { {t('Table of content')} - {doc.abilities.versions_list && ( - setIsPanelTableContentOpen(false)} - $zIndex={1} - > - - {t('Versions')} - - - )} - {isPanelTableContentOpen && } - {!isPanelTableContentOpen && doc.abilities.versions_list && ( - - )} + ); diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocHeader.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocHeader.tsx index 1d29bd73..05012188 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocHeader.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocHeader.tsx @@ -68,6 +68,7 @@ export const DocHeader = ({ doc }: DocHeaderProps) => { > + {isDesktop && ( <> diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx index e10f8bd1..18dc51be 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx @@ -25,23 +25,30 @@ interface DocTitleProps { } export const DocTitle = ({ doc }: DocTitleProps) => { - const { isMobile } = useResponsiveStore(); - if (!doc.abilities.partial_update) { - return ( - - {doc.title} - - ); + return ; } return ; }; +interface DocTitleTextProps { + title: string; +} + +export const DocTitleText = ({ title }: DocTitleTextProps) => { + const { isMobile } = useResponsiveStore(); + return ( + + {title} + + ); +}; + const DocTitleInput = ({ doc }: DocTitleProps) => { const { isDesktop } = useResponsiveStore(); const { t } = useTranslation(); diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx index e5358ab9..c88a7406 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx @@ -1,9 +1,9 @@ import { Button, VariantType, + useModal, useToastProvider, } from '@openfun/cunningham-react'; -import { useRouter } from 'next/router'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { css } from 'styled-components'; @@ -26,7 +26,7 @@ import { ModalRemoveDoc, ModalShare, } from '@/features/docs/doc-management'; -import { ModalVersion } from '@/features/docs/doc-versioning'; +import { ModalSelectVersion } from '@/features/docs/doc-versioning'; import { useResponsiveStore } from '@/stores'; import { ModalPDF } from './ModalExport'; @@ -36,9 +36,6 @@ interface DocToolBoxProps { } export const DocToolBox = ({ doc }: DocToolBoxProps) => { - const { - query: { versionId }, - } = useRouter(); const { t } = useTranslation(); const { spacingsTokens, colorsTokens } = useCunninghamTheme(); @@ -48,10 +45,10 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => { const [isModalShareOpen, setIsModalShareOpen] = useState(false); const [isModalRemoveOpen, setIsModalRemoveOpen] = useState(false); const [isModalPDFOpen, setIsModalPDFOpen] = useState(false); - + const selectHistoryModal = useModal(); const { setIsPanelOpen, setIsPanelTableContentOpen } = usePanelEditorStore(); - const [isModalVersionOpen, setIsModalVersionOpen] = useState(false); - const { isSmallMobile } = useResponsiveStore(); + + const { isSmallMobile, isDesktop } = useResponsiveStore(); const { authenticated } = useAuthStore(); const { editor } = useEditorStore(); const { toast } = useToastProvider(); @@ -80,9 +77,9 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => { icon: 'history', disabled: !doc.abilities.versions_list, callback: () => { - setIsPanelOpen(true); - setIsPanelTableContentOpen(false); + selectHistoryModal.open(); }, + show: isDesktop, }, { label: t('Table of contents'), @@ -147,19 +144,6 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => { $gap="0.5rem 1.5rem" $wrap={isSmallMobile ? 'wrap' : 'nowrap'} > - {versionId && ( - - - - )} {authenticated && !isSmallMobile && ( - } onClose={() => onClose()} rightActions={ - + + onClose(); + }} + > + {t('Restore')} + + } size={ModalSize.MEDIUM} title={ - - - restore - - - {t('Restore this version?')} - - + + {t('Warning')} + } > - - - - {t('Your current document will revert to this version.')} - - {t('If a member is editing, his works can be lost.')} - - + + {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/ModalSelectVersion.tsx b/src/frontend/apps/impress/src/features/docs/doc-versioning/components/ModalSelectVersion.tsx new file mode 100644 index 00000000..cc0adb09 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-versioning/components/ModalSelectVersion.tsx @@ -0,0 +1,156 @@ +import { Button, Modal, ModalSize, useModal } from '@openfun/cunningham-react'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { createGlobalStyle, css } from 'styled-components'; + +import { Box, Icon, Text } from '@/components'; + +import { DocEditor } from '../../doc-editor/components/DocEditor'; +import { Doc } from '../../doc-management'; +import { Versions } from '../types'; + +import { ModalConfirmationVersion } from './ModalConfirmationVersion'; +import { VersionList } from './VersionList'; + +const NoPaddingStyle = createGlobalStyle` + .c__modal__scroller:has(.noPadding) { + padding: 0 !important; + + .c__modal__close .c__button { + right: 0; + top: 7px; + padding: 1rem 0.5rem; + } + } +`; + +type ModalSelectVersionProps = { + doc: Doc; + onClose: () => void; +}; + +export const ModalSelectVersion = ({ + onClose, + doc, +}: ModalSelectVersionProps) => { + const { t } = useTranslation(); + const [selectedVersionId, setSelectedVersionId] = + useState(); + + const restoreModal = useModal(); + return ( + <> + + + + + + {selectedVersionId && ( + + )} + {!selectedVersionId && ( + + + {t('Select a version on the right to restore')} + + + )} + + + + + + + {t('History')} + + + + + + + {restoreModal.isOpen && selectedVersionId && ( + { + restoreModal.close(); + onClose(); + setSelectedVersionId(undefined); + }} + docId={doc.id} + versionId={selectedVersionId} + /> + )} + + ); +}; 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 21a4aa91..45c81d36 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 @@ -1,19 +1,17 @@ -import { Button } from '@openfun/cunningham-react'; -import { PropsWithChildren, useState } from 'react'; -import { useTranslation } from 'react-i18next'; +import { useState } from 'react'; -import { Box, DropButton, IconOptions, StyledLink, Text } from '@/components'; +import { Box, Text } from '@/components'; import { useCunninghamTheme } from '@/cunningham'; import { Doc } from '@/features/docs/doc-management'; import { Versions } from '../types'; -import { ModalVersion } from './ModalVersion'; +import { ModalConfirmationVersion } from './ModalConfirmationVersion'; interface VersionItemProps { docId: Doc['id']; text: string; - link: string; + versionId?: Versions['version_id']; isActive: boolean; } @@ -22,78 +20,47 @@ export const VersionItem = ({ docId, versionId, text, - link, + isActive, }: VersionItemProps) => { - const { t } = useTranslation(); - const { colorsTokens } = useCunninghamTheme(); - const [isDropOpen, setIsDropOpen] = useState(false); + const { colorsTokens, spacingsTokens } = useCunninghamTheme(); + const spacing = spacingsTokens(); + const [isModalVersionOpen, setIsModalVersionOpen] = useState(false); return ( <> - - - - - description - - - {text} - - - {isActive && versionId && ( - - } - onOpenChange={(isOpen) => setIsDropOpen(isOpen)} - isOpen={isDropOpen} - > - - - - - )} + + + + {text} + - + {isModalVersionOpen && versionId && ( - setIsModalVersionOpen(false)} docId={docId} versionId={versionId} @@ -102,16 +69,3 @@ export const VersionItem = ({ ); }; - -interface LinkProps { - href: string; - isActive: boolean; -} - -const Link = ({ href, children, isActive }: PropsWithChildren) => { - return isActive ? ( - <>{children} - ) : ( - {children} - ); -}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-versioning/components/VersionList.tsx b/src/frontend/apps/impress/src/features/docs/doc-versioning/components/VersionList.tsx index d68e3910..86d7dca7 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-versioning/components/VersionList.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-versioning/components/VersionList.tsx @@ -1,10 +1,10 @@ import { Loader } from '@openfun/cunningham-react'; -import { useRouter } from 'next/router'; -import React, { useMemo, useRef } from 'react'; +import { DateTime } from 'luxon'; +import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { APIError } from '@/api'; -import { Box, InfiniteScroll, Text, TextErrors } from '@/components'; +import { Box, BoxButton, InfiniteScroll, Text, TextErrors } from '@/components'; import { Doc } from '@/features/docs/doc-management'; import { useDate } from '@/hook'; @@ -18,19 +18,20 @@ interface VersionListStateProps { error: APIError | null; versions?: Versions[]; doc: Doc; + selectedVersionId?: Versions['version_id']; + onSelectVersion?: (versionId: Versions['version_id']) => void; } const VersionListState = ({ + onSelectVersion, + selectedVersionId, + isLoading, error, versions, doc, }: VersionListStateProps) => { - const { t } = useTranslation(); const { formatDate } = useDate(); - const { - query: { versionId }, - } = useRouter(); if (isLoading) { return ( @@ -41,26 +42,23 @@ const VersionListState = ({ } return ( - <> - + {versions?.map((version) => ( - + onClick={() => { + onSelectVersion?.(version.version_id); + }} + > + + ))} {error && ( )} - + ); }; interface VersionListProps { doc: Doc; + onSelectVersion?: (versionId: Versions['version_id']) => void; + selectedVersionId?: Versions['version_id']; } -export const VersionList = ({ doc }: VersionListProps) => { +export const VersionList = ({ + doc, + onSelectVersion, + selectedVersionId, +}: VersionListProps) => { + const { t } = useTranslation(); + const { data, error, @@ -98,7 +104,7 @@ export const VersionList = ({ doc }: VersionListProps) => { } = useDocVersionsInfiniteQuery({ docId: doc.id, }); - const containerRef = useRef(null); + const versions = useMemo(() => { return data?.pages.reduce((acc, page) => { return acc.concat(page.versions); @@ -106,24 +112,32 @@ export const VersionList = ({ doc }: VersionListProps) => { }, [data?.pages]); return ( - + { void fetchNextPage(); }} - scrollContainer={containerRef.current} as="ul" $padding="none" $margin={{ top: 'none' }} role="listbox" > + {versions?.length === 0 && ( + + + {t('No versions')} + + + )} diff --git a/src/frontend/apps/impress/src/features/docs/doc-versioning/components/index.ts b/src/frontend/apps/impress/src/features/docs/doc-versioning/components/index.ts index ca8e49eb..61a1f6f9 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-versioning/components/index.ts +++ b/src/frontend/apps/impress/src/features/docs/doc-versioning/components/index.ts @@ -1,2 +1,3 @@ -export * from './ModalVersion'; +export * from './ModalConfirmationVersion'; +export * from './ModalSelectVersion'; export * from './VersionList'; diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridItem.tsx b/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridItem.tsx index 7018b064..4cfeea24 100644 --- a/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridItem.tsx +++ b/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridItem.tsx @@ -19,7 +19,7 @@ export const DocsGridItem = ({ doc }: DocsGridItemProps) => { const isPublic = doc.link_reach === LinkReach.PUBLIC; const isAuthenticated = doc.link_reach === LinkReach.AUTHENTICATED; const isRestricted = doc.link_reach === LinkReach.RESTRICTED; - const sharedCount = doc.accesses.length - 1; + const sharedCount = doc.nb_accesses - 1; const isShared = sharedCount > 0; return ( diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/components/SimpleDocItem.tsx b/src/frontend/apps/impress/src/features/docs/docs-grid/components/SimpleDocItem.tsx index c9c74de2..1e442905 100644 --- a/src/frontend/apps/impress/src/features/docs/docs-grid/components/SimpleDocItem.tsx +++ b/src/frontend/apps/impress/src/features/docs/docs-grid/components/SimpleDocItem.tsx @@ -33,8 +33,8 @@ export const SimpleDocItem = ({ const spacings = spacingsTokens(); const isPublic = doc?.link_reach === LinkReach.PUBLIC; - const isShared = !isPublic && doc.accesses.length > 1; - const accessCount = doc.accesses.length - 1; + const isShared = !isPublic && doc.nb_accesses > 1; + const accessCount = doc.nb_accesses - 1; const isSharedOrPublic = isShared || isPublic; return (