🚚(frontend) change visibility in share modal

We stop to propose to make the document public
from the doc creation modal.
We now propose to change the visibility of
the document from the share modal.
This commit is contained in:
Anthony LC
2024-09-06 18:03:19 +02:00
committed by Anthony LC
parent 459cb5e2e2
commit 4321511631
14 changed files with 184 additions and 88 deletions

View File

@@ -13,6 +13,10 @@ and this project adheres to
- 🛂(frontend) access public docs without being logged #235
## Changed
- 🚚(frontend) change visibility in share modal #235
## [1.3.0] - 2024-09-05

View File

@@ -55,14 +55,19 @@ export const createDoc = async (
})
.fill(randomDocs[i]);
if (isPublic) {
await page.getByText('Is it public ?').click();
}
await expect(buttonCreate).toBeEnabled();
await buttonCreate.click();
await expect(page.locator('h2').getByText(randomDocs[i])).toBeVisible();
if (isPublic) {
await page.getByRole('button', { name: 'Share' }).click();
await page.getByText('Doc private').click();
await page.locator('.c__modal__backdrop').click({
position: { x: 0, y: 0 },
});
}
}
return randomDocs;

View File

@@ -21,8 +21,6 @@ test.describe('Doc Create', () => {
).toBeVisible();
await expect(card.getByLabel('Document name')).toBeVisible();
await expect(card.getByText('Is it public ?')).toBeVisible();
await expect(
card.getByRole('button', {
name: 'Create the document',
@@ -46,14 +44,8 @@ test.describe('Doc Create', () => {
await expect(buttonCreateHomepage).toBeVisible();
});
test('create a new public doc', async ({ page, browserName }) => {
const [docTitle] = await createDoc(
page,
'My new doc',
browserName,
1,
true,
);
test('it creates a doc', async ({ page, browserName }) => {
const [docTitle] = await createDoc(page, 'My new doc', browserName, 1);
expect(await page.locator('title').textContent()).toMatch(
/My new doc - Docs/,
@@ -69,11 +61,5 @@ test.describe('Doc Create', () => {
await expect(datagrid.getByLabel('Loading data')).toBeHidden();
await expect(datagrid.getByText(docTitle)).toBeVisible();
const row = datagrid.getByRole('row').filter({
hasText: docTitle,
});
await expect(row.getByRole('cell').nth(0)).toHaveText('Public');
});
});

View File

@@ -65,13 +65,7 @@ test.describe('Doc Header', () => {
});
test('it updates the doc', async ({ page, browserName }) => {
const [randomDoc] = await createDoc(
page,
'doc-update',
browserName,
1,
true,
);
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();
@@ -85,12 +79,7 @@ test.describe('Doc Header', () => {
page.locator('h2').getByText(`Update document "${randomDoc}"`),
).toBeVisible();
await expect(
page.getByRole('checkbox', { name: 'Is it public ?' }),
).toBeChecked();
await page.getByText('Document name').fill(`${randomDoc}-updated`);
await page.getByText('Is it public ?').click();
await page
.getByRole('button', {
@@ -116,8 +105,8 @@ test.describe('Doc Header', () => {
.click();
await expect(
page.getByRole('checkbox', { name: 'Is it public ?' }),
).not.toBeChecked();
page.getByRole('textbox', { name: 'Document name' }),
).toHaveValue(`${randomDoc}-updated`);
});
test('it deletes the doc', async ({ page, browserName }) => {

View File

@@ -1,6 +1,6 @@
import { expect, test } from '@playwright/test';
import { createDoc, keyCloakSignIn } from './common';
import { keyCloakSignIn } from './common';
test.describe('Doc Routing', () => {
test.beforeEach(async ({ page }) => {
@@ -56,34 +56,4 @@ test.describe('Doc Routing: Not loggued', () => {
}),
).toBeVisible();
});
test('A public doc is accessible even when not authentified.', async ({
page,
browserName,
}) => {
await page.goto('/');
await keyCloakSignIn(page, browserName);
const [docTitle] = await createDoc(
page,
'My new doc',
browserName,
1,
true,
);
const urlDoc = page.url();
await page
.getByRole('button', {
name: 'Logout',
})
.click();
await expect(page.getByRole('button', { name: 'Sign in' })).toBeVisible();
await page.goto(urlDoc);
await expect(page.locator('h2').getByText(docTitle)).toBeVisible();
});
});

View File

@@ -0,0 +1,74 @@
import { expect, test } from '@playwright/test';
import { createDoc, keyCloakSignIn } from './common';
test.describe('Doc Visibility', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/');
});
test('Make a public doc', async ({ page, browserName }) => {
const [docTitle] = await createDoc(
page,
'My new doc',
browserName,
1,
true,
);
const header = page.locator('header').first();
await header.locator('h2').getByText('Docs').click();
const datagrid = page
.getByLabel('Datagrid of the documents page 1')
.getByRole('table');
await expect(datagrid.getByLabel('Loading data')).toBeHidden();
await expect(datagrid.getByText(docTitle)).toBeVisible();
const row = datagrid.getByRole('row').filter({
hasText: docTitle,
});
await expect(row.getByRole('cell').nth(0)).toHaveText('Public');
});
});
test.describe('Doc Visibility: Not loggued', () => {
test.use({ storageState: { cookies: [], origins: [] } });
test('A public doc is accessible even when not authentified.', async ({
page,
browserName,
}) => {
await page.goto('/');
await keyCloakSignIn(page, browserName);
const [docTitle] = await createDoc(
page,
'My new doc',
browserName,
1,
true,
);
await expect(
page.getByText('The document visiblitity has been updated.'),
).toBeVisible();
const urlDoc = page.url();
await page
.getByRole('button', {
name: 'Logout',
})
.click();
await expect(page.getByRole('button', { name: 'Sign in' })).toBeVisible();
await page.goto(urlDoc);
await expect(page.locator('h2').getByText(docTitle)).toBeVisible();
});
});

View File

@@ -340,6 +340,10 @@ const config = {
'forms-checkbox': {
'border-radius': '0',
color: 'var(--c--theme--colors--primary-text)',
text: {
color: 'var(--c--theme--colors--greyscale-text)',
size: 'var(--c--theme--font--sizes--t)',
},
},
'forms-datepicker': {
'border-radius': '0',

View File

@@ -308,6 +308,11 @@ input:-webkit-autofill:focus {
transition: all 0.8s ease-in-out;
}
.c__checkbox .c__field__text {
color: var(--c--components--forms-checkbox--text--color);
font-size: var(--c--components--forms-checkbox--text--size);
}
/**
* Button
*/

View File

@@ -463,6 +463,10 @@
);
--c--components--forms-checkbox--border-radius: 0;
--c--components--forms-checkbox--color: var(--c--theme--colors--primary-text);
--c--components--forms-checkbox--text--color: var(
--c--theme--colors--greyscale-text
);
--c--components--forms-checkbox--text--size: var(--c--theme--font--sizes--t);
--c--components--forms-datepicker--border-radius: 0;
--c--components--forms-fileuploader--border-radius: 0;
--c--components--forms-field--color: var(--c--theme--colors--primary-text);

View File

@@ -469,6 +469,10 @@ export const tokens = {
'forms-checkbox': {
'border-radius': '0',
color: 'var(--c--theme--colors--primary-text)',
text: {
color: 'var(--c--theme--colors--greyscale-text)',
size: 'var(--c--theme--font--sizes--t)',
},
},
'forms-datepicker': { 'border-radius': '0' },
'forms-fileuploader': { 'border-radius': '0' },

View File

@@ -6,17 +6,13 @@ import { Doc } from '../types';
import { KEY_LIST_DOC } from './useDocs';
export type CreateDocParam = Pick<Doc, 'title' | 'is_public'>;
export type CreateDocParam = Pick<Doc, 'title'>;
export const createDoc = async ({
title,
is_public,
}: CreateDocParam): Promise<Doc> => {
export const createDoc = async ({ title }: CreateDocParam): Promise<Doc> => {
const response = await fetchAPI(`documents/`, {
method: 'POST',
body: JSON.stringify({
title,
is_public,
}),
});

View File

@@ -0,0 +1,65 @@
import {
Switch,
VariantType,
useToastProvider,
} from '@openfun/cunningham-react';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Box, Card, IconBG } from '@/components';
import { KEY_DOC, KEY_LIST_DOC, useUpdateDoc } from '../api';
import { Doc } from '../types';
interface DocVisibilityProps {
doc: Doc;
}
export const DocVisibility = ({ doc }: DocVisibilityProps) => {
const { t } = useTranslation();
const [docPublic, setDocPublic] = useState(doc.is_public);
const { toast } = useToastProvider();
const api = useUpdateDoc({
onSuccess: () => {
toast(
t('The document visiblitity has been updated.'),
VariantType.SUCCESS,
{
duration: 4000,
},
);
},
listInvalideQueries: [KEY_LIST_DOC],
});
return (
<Card
$margin="tiny"
$padding="small"
aria-label={t('Doc visibility card')}
$direction="row"
$align="center"
$justify="space-between"
>
<Box $direction="row" $gap="1rem">
<IconBG iconName="public" $margin="none" />
<Switch
label={t(docPublic ? 'Doc public' : 'Doc private')}
defaultChecked={docPublic}
onChange={() => {
api.mutate({
id: doc.id,
is_public: !docPublic,
});
setDocPublic(!docPublic);
}}
text={t(
docPublic
? 'Anyone on the internet with the link can view'
: 'Only for people with access',
)}
/>
</Box>
</Card>
);
};

View File

@@ -3,7 +3,6 @@ import {
Button,
Modal,
ModalSize,
Switch,
VariantType,
useToastProvider,
} from '@openfun/cunningham-react';
@@ -44,9 +43,8 @@ export const ModalCreateDoc = ({ onClose }: ModalCreateDocProps) => {
onClose,
isPublic: false,
titleModal: t('Create a new document'),
validate: (title, is_public) =>
validate: (title) =>
api.mutate({
is_public,
title,
}),
...api,
@@ -85,9 +83,8 @@ export const ModalUpdateDoc = ({ onClose, doc }: ModalUpdateDocProps) => {
titleModal: t('Update document "{{documentTitle}}"', {
documentTitle: doc.title,
}),
validate: (title, is_public) =>
validate: (title) =>
api.mutate({
is_public,
title,
id: doc.id,
}),
@@ -99,10 +96,9 @@ export const ModalUpdateDoc = ({ onClose, doc }: ModalUpdateDocProps) => {
type ModalDoc<T> = {
buttonText: string;
isPublic: boolean;
onClose: () => void;
titleModal: string;
validate: (title: string, is_public: boolean) => void;
validate: (title: string) => void;
initialTitle?: string;
infoText?: string;
} & UseMutationResult<Doc, APIError<unknown>, T, unknown>;
@@ -111,7 +107,6 @@ const ModalDoc = <T,>({
buttonText,
infoText,
initialTitle,
isPublic,
onClose,
titleModal,
validate,
@@ -121,8 +116,6 @@ const ModalDoc = <T,>({
const { t } = useTranslation();
const [title, setTitle] = useState(initialTitle || '');
const [docPublic, setDocPublic] = useState(isPublic);
return (
<Modal
isOpen
@@ -144,7 +137,7 @@ const ModalDoc = <T,>({
aria-label={buttonText}
color="primary"
fullWidth
onClick={() => validate(title, docPublic)}
onClick={() => validate(title)}
>
{buttonText}
</Button>
@@ -177,12 +170,6 @@ const ModalDoc = <T,>({
setDocName: setTitle,
}}
/>
<Switch
label={t('Is it public ?')}
labelSide="right"
defaultChecked={docPublic}
onChange={() => setDocPublic(!docPublic)}
/>
</Box>
</Box>
</Modal>

View File

@@ -10,6 +10,8 @@ import { MemberList } from '@/features/docs/members/members-list';
import { Doc } from '../types';
import { currentDocRole } from '../utils';
import { DocVisibility } from './DocVisibility';
const ModalShareStyle = createGlobalStyle`
& .c__modal__scroller{
background: #FAFAFA;
@@ -66,6 +68,7 @@ export const ModalShare = ({ onClose, doc }: ModalShareProps) => {
</Card>
}
>
<DocVisibility doc={doc} />
<AddMembers doc={doc} currentRole={currentDocRole(doc.abilities)} />
<InvitationList doc={doc} />
<MemberList doc={doc} />