🔥(frontend) remove useless update title codes

We can now update the title directly in the header,
so we don't need the update title modal anymore.
We remove the buttons to trigger the modal
and the modal itself.
This commit is contained in:
Anthony LC
2024-10-01 16:00:14 +02:00
committed by Anthony LC
parent 90027d3a5a
commit 4d2a73556a
7 changed files with 40 additions and 387 deletions

View File

@@ -212,26 +212,6 @@ test.describe('Documents Grid', () => {
).toHaveText(/.*/);
});
test('it updates document', async ({ page }) => {
const datagrid = page
.getByLabel('Datagrid of the documents page 1')
.getByRole('table');
const docRow = datagrid.getByRole('row').nth(1).getByRole('cell');
const docName = await docRow.nth(1).textContent();
await docRow.getByLabel('Open the document options').click();
await page.getByText('Update document').click();
await page.getByLabel('Document name').fill(`${docName} updated`);
await page.getByText('Validate the modification').click();
await expect(datagrid.getByText(`${docName} updated`)).toBeVisible();
});
test('it deletes the document', async ({ page }) => {
const datagrid = page
.getByLabel('Datagrid of the documents page 1')
@@ -241,11 +221,9 @@ test.describe('Documents Grid', () => {
const docName = await docRow.nth(1).textContent();
await docRow.getByLabel('Open the document options').click();
await page
await docRow
.getByRole('button', {
name: 'Delete document',
name: 'Delete the document',
})
.click();

View File

@@ -65,49 +65,15 @@ test.describe('Doc Header', () => {
await expect(page.getByRole('button', { name: 'Share' })).toBeVisible();
});
test('it updates the doc', async ({ page, browserName }) => {
test('it updates the title doc', async ({ page, browserName }) => {
const [randomDoc] = await createDoc(page, 'doc-update', browserName, 1);
await expect(page.locator('h2').getByText(randomDoc)).toBeVisible();
await page.getByLabel('Open the document options').click();
await page
.getByRole('button', {
name: 'Update document',
})
.click();
await page.getByRole('heading', { name: randomDoc }).fill(' ');
await page.getByText('Created at ').click();
await expect(
page.locator('h2').getByText(`Update document "${randomDoc}"`),
page.getByRole('heading', { name: 'Untitled document' }),
).toBeVisible();
await page.getByText('Document name').fill(`${randomDoc}-updated`);
await page
.getByRole('button', {
name: 'Validate the modification',
})
.click();
await expect(
page.getByText('The document has been updated.'),
).toBeVisible();
const docTitle = await goToGridDoc(page, {
title: `${randomDoc}-updated`,
});
await expect(page.locator('h2').getByText(docTitle)).toBeVisible();
await page.getByLabel('Open the document options').click();
await page
.getByRole('button', {
name: 'Update document',
})
.click();
await expect(
page.getByRole('textbox', { name: 'Document name' }),
).toHaveValue(`${randomDoc}-updated`);
});
test('it deletes the doc', async ({ page, browserName }) => {
@@ -167,16 +133,15 @@ test.describe('Doc Header', () => {
await goToGridDoc(page);
await expect(page.locator('h2').getByText('Mocked document')).toBeVisible();
await expect(
page.locator('h2').getByText('Mocked document'),
).toHaveAttribute('contenteditable');
await expect(page.getByRole('button', { name: 'Share' })).toBeVisible();
await page.getByLabel('Open the document options').click();
await expect(page.getByRole('button', { name: 'Export' })).toBeVisible();
await expect(
page.getByRole('button', { name: 'Update document' }),
).toBeVisible();
await expect(
page.getByRole('button', { name: 'Delete document' }),
).toBeHidden();
@@ -199,16 +164,15 @@ test.describe('Doc Header', () => {
await goToGridDoc(page);
await expect(page.locator('h2').getByText('Mocked document')).toBeVisible();
await expect(
page.locator('h2').getByText('Mocked document'),
).toHaveAttribute('contenteditable');
await expect(page.getByRole('button', { name: 'Share' })).toBeHidden();
await page.getByLabel('Open the document options').click();
await expect(page.getByRole('button', { name: 'Export' })).toBeVisible();
await expect(
page.getByRole('button', { name: 'Update document' }),
).toBeVisible();
await expect(
page.getByRole('button', { name: 'Delete document' }),
).toBeHidden();
@@ -231,7 +195,9 @@ test.describe('Doc Header', () => {
await goToGridDoc(page);
await expect(page.locator('h2').getByText('Mocked document')).toBeVisible();
await expect(
page.locator('h2').getByText('Mocked document'),
).not.toHaveAttribute('contenteditable');
await expect(page.getByRole('button', { name: 'Share' })).toBeHidden();
@@ -239,9 +205,6 @@ test.describe('Doc Header', () => {
await expect(page.getByRole('button', { name: 'Share' })).toBeHidden();
await expect(page.getByRole('button', { name: 'Export' })).toBeVisible();
await expect(
page.getByRole('button', { name: 'Update document' }),
).toBeHidden();
await expect(
page.getByRole('button', { name: 'Delete document' }),
).toBeHidden();

View File

@@ -8,7 +8,6 @@ import {
Doc,
ModalRemoveDoc,
ModalShare,
ModalUpdateDoc,
} from '@/features/docs/doc-management';
import { ModalPDF } from './ModalExport';
@@ -20,7 +19,6 @@ interface DocToolBoxProps {
export const DocToolBox = ({ doc }: DocToolBoxProps) => {
const { t } = useTranslation();
const [isModalShareOpen, setIsModalShareOpen] = useState(false);
const [isModalUpdateOpen, setIsModalUpdateOpen] = useState(false);
const [isModalRemoveOpen, setIsModalRemoveOpen] = useState(false);
const [isModalPDFOpen, setIsModalPDFOpen] = useState(false);
const [isDropOpen, setIsDropOpen] = useState(false);
@@ -53,32 +51,6 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
isOpen={isDropOpen}
>
<Box>
{doc.abilities.partial_update && (
<Button
onClick={() => {
setIsModalUpdateOpen(true);
setIsDropOpen(false);
}}
color="primary-text"
icon={<span className="material-icons">edit</span>}
size="small"
>
<Text $theme="primary">{t('Update document')}</Text>
</Button>
)}
{doc.abilities.destroy && (
<Button
onClick={() => {
setIsModalRemoveOpen(true);
setIsDropOpen(false);
}}
color="primary-text"
icon={<span className="material-icons">delete</span>}
size="small"
>
<Text $theme="primary">{t('Delete document')}</Text>
</Button>
)}
{doc.abilities.versions_list && (
<Button
onClick={() => {
@@ -116,6 +88,19 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
>
<Text $theme="primary">{t('Export')}</Text>
</Button>
{doc.abilities.destroy && (
<Button
onClick={() => {
setIsModalRemoveOpen(true);
setIsDropOpen(false);
}}
color="primary-text"
icon={<span className="material-icons">delete</span>}
size="small"
>
<Text $theme="primary">{t('Delete document')}</Text>
</Button>
)}
</Box>
</DropButton>
{isModalShareOpen && (
@@ -124,9 +109,6 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
{isModalPDFOpen && (
<ModalPDF onClose={() => setIsModalPDFOpen(false)} doc={doc} />
)}
{isModalUpdateOpen && (
<ModalUpdateDoc onClose={() => setIsModalUpdateOpen(false)} doc={doc} />
)}
{isModalRemoveOpen && (
<ModalRemoveDoc onClose={() => setIsModalRemoveOpen(false)} doc={doc} />
)}

View File

@@ -1,54 +0,0 @@
import { Input, Loader } from '@openfun/cunningham-react';
import { useEffect, useState } from 'react';
import { APIError } from '@/api';
import { Box, TextErrors } from '@/components';
interface InputDocNameProps {
error: APIError | null;
isError: boolean;
isPending: boolean;
label: string;
setDocName: (newDocName: string) => void;
defaultValue?: string;
}
export const InputDocName = ({
defaultValue,
error,
isError,
isPending,
label,
setDocName,
}: InputDocNameProps) => {
const [isInputError, setIsInputError] = useState(isError);
useEffect(() => {
if (isError) {
setIsInputError(true);
}
}, [isError]);
return (
<>
<Input
fullWidth
type="text"
label={label}
defaultValue={defaultValue}
onChange={(e) => {
setDocName(e.target.value);
setIsInputError(false);
}}
rightIcon={<span className="material-icons">edit</span>}
state={isInputError ? 'error' : 'default'}
/>
{isError && error && <TextErrors causes={error.cause} />}
{isPending && (
<Box $align="center">
<Loader />
</Box>
)}
</>
);
};

View File

@@ -1,176 +0,0 @@
import {
Alert,
Button,
Modal,
ModalSize,
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 (
<ModalDoc
{...{
buttonText: t('Create the document'),
onClose,
isPublic: false,
titleModal: t('Create a new document'),
validate: (title) =>
api.mutate({
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 (
<ModalDoc
{...{
buttonText: t('Validate the modification'),
onClose,
initialTitle: doc.title,
infoText: t('Enter the new name of the selected document.'),
titleModal: t('Update document "{{documentTitle}}"', {
documentTitle: doc.title,
}),
validate: (title) =>
api.mutate({
title,
id: doc.id,
}),
...api,
}}
/>
);
};
type ModalDoc<T> = {
buttonText: string;
onClose: () => void;
titleModal: string;
validate: (title: string) => void;
initialTitle?: string;
infoText?: string;
} & UseMutationResult<Doc, APIError<unknown>, T, unknown>;
const ModalDoc = <T,>({
buttonText,
infoText,
initialTitle,
onClose,
titleModal,
validate,
...api
}: ModalDoc<T>) => {
const { colorsTokens } = useCunninghamTheme();
const { t } = useTranslation();
const [title, setTitle] = useState(initialTitle || '');
return (
<Modal
isOpen
closeOnClickOutside
hideCloseButton
leftActions={
<Button
aria-label={t('Close the modal')}
color="secondary"
fullWidth
onClick={() => onClose()}
>
{t('Cancel')}
</Button>
}
onClose={() => onClose()}
rightActions={
<Button
aria-label={buttonText}
color="primary"
fullWidth
onClick={() => validate(title)}
>
{buttonText}
</Button>
}
size={ModalSize.MEDIUM}
title={
<Box $align="center" $gap="1rem" $margin={{ bottom: '2.5rem' }}>
<IconEdit width={48} color={colorsTokens()['primary-text']} />
<Text as="h2" $size="h3" $margin="none">
{titleModal}
</Text>
</Box>
}
>
<Box $margin={{ bottom: 'xl' }} $gap="1rem">
{infoText && (
<Alert canClose={false} type={VariantType.INFO}>
<Text>{infoText}</Text>
</Alert>
)}
<Box $gap="1rem">
<InputDocName
label={t('Document name')}
defaultValue={title}
{...{
error: api.error,
isError: api.isError,
isPending: api.isPending,
setDocName: setTitle,
}}
/>
</Box>
</Box>
</Modal>
);
};

View File

@@ -1,3 +1,2 @@
export * from './ModalCreateUpdateDoc';
export * from './ModalRemoveDoc';
export * from './ModalShare';

View File

@@ -2,12 +2,7 @@ import { Button } from '@openfun/cunningham-react';
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Box, DropButton, IconOptions, Text } from '@/components';
import {
Doc,
ModalRemoveDoc,
ModalUpdateDoc,
} from '@/features/docs/doc-management';
import { Doc, ModalRemoveDoc } from '@/features/docs/doc-management';
interface DocsGridActionsProps {
doc: Doc;
@@ -15,58 +10,24 @@ interface DocsGridActionsProps {
export const DocsGridActions = ({ doc }: DocsGridActionsProps) => {
const { t } = useTranslation();
const [isModalUpdateOpen, setIsModalUpdateOpen] = useState(false);
const [isModalRemoveOpen, setIsModalRemoveOpen] = useState(false);
const [isDropOpen, setIsDropOpen] = useState(false);
if (!doc.abilities.partial_update && !doc.abilities.destroy) {
if (!doc.abilities.destroy) {
return null;
}
return (
<>
<DropButton
button={
<IconOptions
isOpen={isDropOpen}
aria-label={t('Open the document options')}
/>
}
onOpenChange={(isOpen) => setIsDropOpen(isOpen)}
isOpen={isDropOpen}
>
<Box>
{doc.abilities.partial_update && (
<Button
onClick={() => {
setIsModalUpdateOpen(true);
setIsDropOpen(false);
}}
color="primary-text"
icon={<span className="material-icons">edit</span>}
size="small"
>
<Text $theme="primary">{t('Update document')}</Text>
</Button>
)}
{doc.abilities.destroy && (
<Button
onClick={() => {
setIsModalRemoveOpen(true);
setIsDropOpen(false);
}}
color="primary-text"
icon={<span className="material-icons">delete</span>}
size="small"
>
<Text $theme="primary">{t('Delete document')}</Text>
</Button>
)}
</Box>
</DropButton>
{isModalUpdateOpen && (
<ModalUpdateDoc onClose={() => setIsModalUpdateOpen(false)} doc={doc} />
)}
<Button
onClick={() => {
setIsModalRemoveOpen(true);
}}
color="tertiary-text"
icon={<span className="material-icons">delete</span>}
size="small"
style={{ padding: '0rem' }}
aria-label={t('Delete the document')}
/>
{isModalRemoveOpen && (
<ModalRemoveDoc onClose={() => setIsModalRemoveOpen(false)} doc={doc} />
)}