From 2a7c0ef800f7cdb09783ef973d6cc1a4ea75f7d1 Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Fri, 25 Apr 2025 12:28:40 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(frontend)=20create=20page=20from=20dr?= =?UTF-8?q?opdown=20search?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are now able to create a new page from the dropdown search. --- .../__tests__/app-impress/doc-create.spec.ts | 22 +++++++ .../apps/impress/src/components/BoxButton.tsx | 2 +- .../docs/doc-editor/assets/doc-found.svg | 3 + .../InterlinkingSearchInlineContent.tsx | 45 +++----------- .../Interlinking/SearchPage.tsx | 58 ++++++++++++++++++- .../docs/doc-management/hooks/index.ts | 1 + .../hooks/useCreateChildDocTree.tsx | 35 +++++++++++ 7 files changed, 127 insertions(+), 39 deletions(-) create mode 100644 src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-found.svg create mode 100644 src/frontend/apps/impress/src/features/docs/doc-management/hooks/useCreateChildDocTree.tsx diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-create.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-create.spec.ts index 28ff84b7..f05e1f24 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-create.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-create.spec.ts @@ -51,6 +51,28 @@ test.describe('Doc Create', () => { page.locator('.c__tree-view--row-content').getByText('Untitled document'), ).toBeVisible(); }); + + test('it creates a sub doc from interlinking dropdown', async ({ + page, + browserName, + }) => { + const [title] = await createDoc(page, 'my-new-slash-doc', browserName, 1); + + await verifyDocName(page, title); + + await page.locator('.bn-block-outer').last().fill('/'); + await page.getByText('Link a doc').first().click(); + await page + .locator('.quick-search-container') + .getByText('New sub-doc') + .click(); + + const input = page.getByRole('textbox', { name: 'doc title input' }); + await expect(input).toHaveText(''); + await expect( + page.locator('.c__tree-view--row-content').getByText('Untitled document'), + ).toBeVisible(); + }); }); test.describe('Doc Create: Not logged', () => { diff --git a/src/frontend/apps/impress/src/components/BoxButton.tsx b/src/frontend/apps/impress/src/components/BoxButton.tsx index 3b8d7751..15d1b340 100644 --- a/src/frontend/apps/impress/src/components/BoxButton.tsx +++ b/src/frontend/apps/impress/src/components/BoxButton.tsx @@ -31,11 +31,11 @@ const BoxButton = forwardRef( $background="none" $margin="none" $padding="none" + $hasTransition $css={css` cursor: ${props.disabled ? 'not-allowed' : 'pointer'}; border: none; outline: none; - transition: all 0.2s ease-in-out; font-family: inherit; color: ${props.disabled diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-found.svg b/src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-found.svg new file mode 100644 index 00000000..87d445d6 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-found.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx index 2ac6fa90..d4a5acf1 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx @@ -1,14 +1,11 @@ /* eslint-disable react-hooks/rules-of-hooks */ import { createReactInlineContentSpec } from '@blocknote/react'; -import { useTreeContext } from '@gouvfr-lasuite/ui-kit'; import { TFunction } from 'i18next'; -import { useRouter } from 'next/navigation'; -import { useCallback } from 'react'; import { DocsBlockNoteEditor } from '@/docs/doc-editor'; import LinkPageIcon from '@/docs/doc-editor/assets/doc-link.svg'; import AddPageIcon from '@/docs/doc-editor/assets/doc-plus.svg'; -import { Doc, useCreateChildDoc, useDocStore } from '@/docs/doc-management'; +import { useCreateChildDocTree, useDocStore } from '@/docs/doc-management'; import { SearchPage } from './SearchPage'; @@ -29,12 +26,12 @@ export const InterlinkingSearchInlineContent = createReactInlineContentSpec( return null; } - return ; + return ; }, }, ); -export const getInterlinkingMenuItems = ( +export const getInterlinkinghMenuItems = ( editor: DocsBlockNoteEditor, t: TFunction<'translation', undefined>, group: string, @@ -68,37 +65,11 @@ export const getInterlinkingMenuItems = ( ]; export const useGetInterlinkingMenuItems = () => { - const treeContext = useTreeContext(); - const router = useRouter(); const { currentDoc } = useDocStore(); + const createChildDoc = useCreateChildDocTree(currentDoc?.id); - const { mutate: createChildDoc } = useCreateChildDoc({ - onSuccess: (createdDoc) => { - const newDoc = { - ...createdDoc, - children: [], - childrenCount: 0, - parentId: currentDoc?.id ?? undefined, - }; - treeContext?.treeData.addChild(currentDoc?.id || null, newDoc); - - router.push(`/docs/${newDoc.id}`); - treeContext?.treeData.setSelectedNode(createdDoc); - }, - }); - - return useCallback( - (editor: DocsBlockNoteEditor, t: TFunction<'translation', undefined>) => - getInterlinkingMenuItems( - editor, - t, - t('Links'), - () => - currentDoc?.id && - createChildDoc({ - parentId: currentDoc.id, - }), - ), - [createChildDoc, currentDoc?.id], - ); + return ( + editor: DocsBlockNoteEditor, + t: TFunction<'translation', undefined>, + ) => getInterlinkinghMenuItems(editor, t, t('Links'), createChildDoc); }; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx index b61c3e33..ce3953e8 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx @@ -5,6 +5,7 @@ import { } from '@blocknote/core'; import { useBlockNoteEditor } from '@blocknote/react'; import { useEffect, useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { css } from 'styled-components'; import { @@ -12,6 +13,7 @@ import { Card, Icon, QuickSearch, + QuickSearchGroup, QuickSearchItemContent, Text, } from '@/components'; @@ -22,7 +24,12 @@ import { DocsStyleSchema, } from '@/docs/doc-editor'; import FoundPageIcon from '@/docs/doc-editor/assets/doc-found.svg'; -import { useTrans } from '@/docs/doc-management'; +import AddPageIcon from '@/docs/doc-editor/assets/doc-plus.svg'; +import { + useCreateChildDocTree, + useDocStore, + useTrans, +} from '@/docs/doc-management'; import { DocSearchSubPageContent, DocSearchTarget } from '@/docs/doc-search'; import { useResponsiveStore } from '@/stores'; @@ -64,6 +71,9 @@ export const SearchPage = ({ DocsInlineContentSchema, DocsStyleSchema >(); + const { t } = useTranslation(); + const { currentDoc } = useDocStore(); + const createChildDoc = useCreateChildDocTree(currentDoc?.id); const inputRef = useRef(null); const [search, setSearch] = useState(''); const { isDesktop } = useResponsiveStore(); @@ -248,6 +258,52 @@ export const SearchPage = ({ /> )} /> + + + + + {t('New sub-doc')} + + + + ), + }, + ], + }} + /> diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/hooks/index.ts b/src/frontend/apps/impress/src/features/docs/doc-management/hooks/index.ts index adf2d777..930e2d49 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/hooks/index.ts +++ b/src/frontend/apps/impress/src/features/docs/doc-management/hooks/index.ts @@ -1,5 +1,6 @@ export * from './useCollaboration'; export * from './useCopyDocLink'; +export * from './useCreateChildDocTree'; export * from './useDocUtils'; export * from './useIsCollaborativeEditable'; export * from './useTrans'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/hooks/useCreateChildDocTree.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/hooks/useCreateChildDocTree.tsx new file mode 100644 index 00000000..b11a3d34 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-management/hooks/useCreateChildDocTree.tsx @@ -0,0 +1,35 @@ +import { useTreeContext } from '@gouvfr-lasuite/ui-kit'; +import { useRouter } from 'next/navigation'; + +import { useCreateChildDoc } from '../api'; +import { Doc } from '../types'; + +export const useCreateChildDocTree = (parentId?: string) => { + const treeContext = useTreeContext(); + const router = useRouter(); + + const { mutate: createChildDoc } = useCreateChildDoc({ + onSuccess: (createdDoc) => { + const newDoc = { + ...createdDoc, + children: [], + childrenCount: 0, + parentId: parentId ?? undefined, + }; + treeContext?.treeData.addChild(parentId || null, newDoc); + + router.push(`/docs/${newDoc.id}`); + treeContext?.treeData.setSelectedNode(createdDoc); + }, + }); + + return () => { + if (!parentId) { + return null; + } + + createChildDoc({ + parentId, + }); + }; +};