diff --git a/CHANGELOG.md b/CHANGELOG.md index da25ad2a..0481b633 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to ## Changed - ♻️(frontend) replace docs panel with docs grid #120 +- ♻️(frontend) create a doc from a modal #132 ## [1.0.0] - 2024-07-02 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 93970de5..215897fc 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 @@ -14,18 +14,12 @@ test.describe('Doc Create', () => { await buttonCreateHomepage.click(); await expect(buttonCreateHomepage).toBeHidden(); - const card = page.getByLabel('Create new document card').first(); - - await expect(card.getByLabel('Document name')).toBeVisible(); - - await expect(card.getByLabel('icon group')).toBeVisible(); + const card = page.getByRole('dialog').first(); await expect( - card.getByRole('heading', { - name: 'Name the document', - level: 3, - }), + card.locator('h2').getByText('Create a new document'), ).toBeVisible(); + await expect(card.getByLabel('Document name')).toBeVisible(); await expect(card.getByText('Is it public ?')).toBeVisible(); @@ -35,13 +29,7 @@ test.describe('Doc Create', () => { }), ).toBeVisible(); - await expect( - card.getByRole('button', { - name: 'Cancel', - }), - ).toBeVisible(); - - await expect(page).toHaveURL('/docs/create/'); + await expect(card.getByLabel('Close the modal')).toBeVisible(); }); test('checks the cancel button interaction', async ({ page }) => { @@ -51,13 +39,9 @@ test.describe('Doc Create', () => { await buttonCreateHomepage.click(); await expect(buttonCreateHomepage).toBeHidden(); - const card = page.getByLabel('Create new document card').first(); + const card = page.getByRole('dialog').first(); - await card - .getByRole('button', { - name: 'Cancel', - }) - .click(); + await card.getByLabel('Close the modal').click(); await expect(buttonCreateHomepage).toBeVisible(); }); diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/api/useCreateDoc.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/api/useCreateDoc.tsx index f0a5b3f9..0e52174d 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/api/useCreateDoc.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-management/api/useCreateDoc.tsx @@ -6,7 +6,7 @@ import { Doc } from '../types'; import { KEY_LIST_DOC } from './useDocs'; -type CreateDocParam = Pick; +export type CreateDocParam = Pick; export const createDoc = async ({ title, diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/components/CardCreateDoc.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/components/CardCreateDoc.tsx deleted file mode 100644 index df007119..00000000 --- a/src/frontend/apps/impress/src/features/docs/doc-management/components/CardCreateDoc.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { Button, Switch } from '@openfun/cunningham-react'; -import { useRouter } from 'next/navigation'; -import { useState } from 'react'; -import { useTranslation } from 'react-i18next'; - -import IconGroup from '@/assets/icons/icon-group2.svg'; -import { Box, Card, StyledLink, Text } from '@/components'; -import { useCunninghamTheme } from '@/cunningham'; - -import { useCreateDoc } from '../api/useCreateDoc'; - -import { InputDocName } from './InputDocName'; - -export const CardCreateDoc = () => { - const { t } = useTranslation(); - const router = useRouter(); - const { - mutate: createDoc, - isError, - isPending, - error, - } = useCreateDoc({ - onSuccess: (doc) => { - router.push(`/docs/${doc.id}`); - }, - }); - const [docName, setDocName] = useState(''); - const [docPublic, setDocPublic] = useState(false); - const { colorsTokens } = useCunninghamTheme(); - - return ( - - - - - - {t('Name the document')} - - - - setDocPublic(!docPublic)} - /> - - - - - - - - - ); -}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalCreateUpdateDoc.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalCreateUpdateDoc.tsx new file mode 100644 index 00000000..e08d8b46 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalCreateUpdateDoc.tsx @@ -0,0 +1,190 @@ +import { + Alert, + Button, + Modal, + ModalSize, + Switch, + VariantType, + useToastProvider, +} from '@openfun/cunningham-react'; +import { UseMutationResult } from '@tanstack/react-query'; +import { useRouter } from 'next/navigation'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { APIError } from '@/api'; +import { Box, Text } from '@/components'; +import useCunninghamTheme from '@/cunningham/useCunninghamTheme'; + +import { KEY_DOC, KEY_LIST_DOC } from '../api'; +import { useCreateDoc } from '../api/useCreateDoc'; +import { useUpdateDoc } from '../api/useUpdateDoc'; +import IconEdit from '../assets/icon-edit.svg'; +import { Doc } from '../types'; + +import { InputDocName } from './InputDocName'; + +interface ModalCreateDocProps { + onClose: () => void; +} + +export const ModalCreateDoc = ({ onClose }: ModalCreateDocProps) => { + const router = useRouter(); + const api = useCreateDoc({ + onSuccess: (doc) => { + router.push(`/docs/${doc.id}`); + }, + }); + const { t } = useTranslation(); + + return ( + + api.mutate({ + is_public, + title, + }), + ...api, + }} + /> + ); +}; + +interface ModalUpdateDocProps { + onClose: () => void; + doc: Doc; +} + +export const ModalUpdateDoc = ({ onClose, doc }: ModalUpdateDocProps) => { + const { toast } = useToastProvider(); + const { t } = useTranslation(); + + const api = useUpdateDoc({ + onSuccess: () => { + toast(t('The document has been updated.'), VariantType.SUCCESS, { + duration: 4000, + }); + onClose(); + }, + listInvalideQueries: [KEY_DOC, KEY_LIST_DOC], + }); + + return ( + + api.mutate({ + is_public, + title, + id: doc.id, + }), + ...api, + }} + /> + ); +}; + +type ModalDoc = { + buttonText: string; + isPublic: boolean; + onClose: () => void; + titleModal: string; + validate: (title: string, is_public: boolean) => void; + initialTitle?: string; + infoText?: string; +} & UseMutationResult, T, unknown>; + +const ModalDoc = ({ + buttonText, + infoText, + initialTitle, + isPublic, + onClose, + titleModal, + validate, + ...api +}: ModalDoc) => { + const { colorsTokens } = useCunninghamTheme(); + const { t } = useTranslation(); + const [title, setTitle] = useState(initialTitle || ''); + + const [docPublic, setDocPublic] = useState(isPublic); + + return ( + onClose()} + > + {t('Cancel')} + + } + onClose={() => onClose()} + rightActions={ + + } + size={ModalSize.MEDIUM} + title={ + + + + {titleModal} + + + } + > + + {infoText && ( + + {infoText} + + )} + + + + setDocPublic(!docPublic)} + /> + + + + ); +}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalUpdateDoc.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalUpdateDoc.tsx deleted file mode 100644 index 5b790dd4..00000000 --- a/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalUpdateDoc.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import { - Alert, - Button, - Modal, - ModalSize, - Switch, - VariantType, - useToastProvider, -} from '@openfun/cunningham-react'; -import { useState } from 'react'; -import { useTranslation } from 'react-i18next'; - -import { Box, Text } from '@/components'; -import useCunninghamTheme from '@/cunningham/useCunninghamTheme'; - -import { KEY_DOC, KEY_LIST_DOC } from '../api'; -import { useUpdateDoc } from '../api/useUpdateDoc'; -import IconEdit from '../assets/icon-edit.svg'; -import { Doc } from '../types'; - -import { InputDocName } from './InputDocName'; - -interface ModalUpdateDocProps { - onClose: () => void; - doc: Doc; -} - -export const ModalUpdateDoc = ({ onClose, doc }: ModalUpdateDocProps) => { - const { colorsTokens } = useCunninghamTheme(); - const [title, setTitle] = useState(doc.title); - const { toast } = useToastProvider(); - const [docPublic, setDocPublic] = useState(doc.is_public); - const { t } = useTranslation(); - - const { - mutate: updateDoc, - isError, - isPending, - error, - } = useUpdateDoc({ - onSuccess: () => { - toast(t('The document has been updated.'), VariantType.SUCCESS, { - duration: 4000, - }); - onClose(); - }, - listInvalideQueries: [KEY_DOC, KEY_LIST_DOC], - }); - - return ( - onClose()} - > - {t('Cancel')} - - } - onClose={() => onClose()} - rightActions={ - - } - size={ModalSize.MEDIUM} - title={ - - - - {t('Update document "{{documentTitle}}"', { - documentTitle: doc.title, - })} - - - } - > - - - {t('Enter the new name of the selected document.')} - - - - - setDocPublic(!docPublic)} - /> - - - - ); -}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/components/index.ts b/src/frontend/apps/impress/src/features/docs/doc-management/components/index.ts index bbd7b69f..5c19308f 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/components/index.ts +++ b/src/frontend/apps/impress/src/features/docs/doc-management/components/index.ts @@ -1,3 +1,2 @@ -export * from './CardCreateDoc'; export * from './ModalRemoveDoc'; -export * from './ModalUpdateDoc'; +export * from './ModalCreateUpdateDoc'; diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridContainer.tsx b/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridContainer.tsx index 1393d860..880f5652 100644 --- a/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridContainer.tsx +++ b/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridContainer.tsx @@ -1,23 +1,33 @@ import { Button } from '@openfun/cunningham-react'; -import React from 'react'; +import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { Box, Card, StyledLink } from '@/components'; +import { Box, Card } from '@/components'; +import { ModalCreateDoc } from '@/features/docs/doc-management'; import { DocsGrid } from './DocsGrid'; export const DocsGridContainer = () => { const { t } = useTranslation(); + const [isModalCreateOpen, setIsModalCreateOpen] = useState(false); + return ( - - - + + {isModalCreateOpen && ( + setIsModalCreateOpen(false)} /> + )} ); }; diff --git a/src/frontend/apps/impress/src/pages/docs/create.tsx b/src/frontend/apps/impress/src/pages/docs/create.tsx deleted file mode 100644 index fb99074e..00000000 --- a/src/frontend/apps/impress/src/pages/docs/create.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { ReactElement } from 'react'; - -import { Box } from '@/components'; -import { CardCreateDoc } from '@/features/docs/doc-management'; -import { MainLayout } from '@/layouts'; -import { NextPageWithLayout } from '@/types/next'; - -const Page: NextPageWithLayout = () => { - return ( - - - - ); -}; - -Page.getLayout = function getLayout(page: ReactElement) { - return {page}; -}; - -export default Page;