Skip to content

Commit c2d6e60

Browse files
committed
♻️(frontend) add user from side modal
We move the add user functionality to a side modal. The side modal is opened from the share button.
1 parent ff83223 commit c2d6e60

File tree

17 files changed

+241
-152
lines changed

17 files changed

+241
-152
lines changed

src/frontend/apps/e2e/__tests__/app-impress/common.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,7 @@ export const addNewMember = async (
8080
response.status() === 200,
8181
);
8282

83-
await page.getByLabel('Open the document options').click();
84-
await page.getByRole('button', { name: 'Add members' }).click();
83+
await page.getByRole('button', { name: 'Share' }).click();
8584

8685
const inputSearch = page.getByLabel(/Find a member to add to the document/);
8786

@@ -98,8 +97,8 @@ export const addNewMember = async (
9897
await page.getByRole('option', { name: users[index].email }).click();
9998

10099
// Choose a role
101-
await page.getByRole('radio', { name: role }).click();
102-
100+
await page.getByRole('combobox', { name: /Choose a role/ }).click();
101+
await page.getByRole('option', { name: role }).click();
103102
await page.getByRole('button', { name: 'Validate' }).click();
104103

105104
await expect(

src/frontend/apps/e2e/__tests__/app-impress/doc-header.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,5 +76,6 @@ test.describe('Doc Header', () => {
7676
card.getByText('Owners: [email protected] / [email protected]'),
7777
).toBeVisible();
7878
await expect(card.getByText('Your role: Owner')).toBeVisible();
79+
await expect(page.getByRole('button', { name: 'Share' })).toBeVisible();
7980
});
8081
});

src/frontend/apps/e2e/__tests__/app-impress/doc-add-members.spec.ts renamed to src/frontend/apps/e2e/__tests__/app-impress/doc-member-create.spec.ts

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,15 @@ test.beforeEach(async ({ page }) => {
66
await page.goto('/');
77
});
88

9-
test.describe('Document add users', () => {
9+
test.describe('Document create member', () => {
1010
test('it selects 2 users and 1 invitation', async ({ page, browserName }) => {
1111
const responsePromise = page.waitForResponse(
1212
(response) =>
1313
response.url().includes('/users/?q=user') && response.status() === 200,
1414
);
1515
await createDoc(page, 'select-multi-users', browserName, 1);
1616

17-
await page.getByLabel('Open the document options').click();
18-
await page.getByRole('button', { name: 'Add members' }).click();
17+
await page.getByRole('button', { name: 'Share' }).click();
1918

2019
const inputSearch = page.getByLabel(/Find a member to add to the document/);
2120
await expect(inputSearch).toBeVisible();
@@ -56,12 +55,14 @@ test.describe('Document add users', () => {
5655
await expect(page.getByLabel(`Remove ${email}`)).toBeVisible();
5756

5857
// Check roles are displayed
59-
await expect(page.getByText(/Choose a role/)).toBeVisible();
60-
await expect(page.getByRole('radio', { name: 'Reader' })).toBeChecked();
61-
await expect(page.getByRole('radio', { name: 'Owner' })).toBeVisible();
58+
await page.getByRole('combobox', { name: /Choose a role/ }).click();
59+
60+
await expect(page.getByRole('option', { name: 'Reader' })).toBeVisible();
61+
await expect(page.getByRole('option', { name: 'Editor' })).toBeVisible();
6262
await expect(
63-
page.getByRole('radio', { name: 'Administrator' }),
63+
page.getByRole('option', { name: 'Administrator' }),
6464
).toBeVisible();
65+
await expect(page.getByRole('option', { name: 'Owner' })).toBeVisible();
6566
});
6667

6768
test('it sends a new invitation and adds a new user', async ({
@@ -75,8 +76,7 @@ test.describe('Document add users', () => {
7576

7677
await createDoc(page, 'user-invitation', browserName, 1);
7778

78-
await page.getByLabel('Open the document options').click();
79-
await page.getByRole('button', { name: 'Add members' }).click();
79+
await page.getByRole('button', { name: 'Share' }).click();
8080

8181
const inputSearch = page.getByLabel(/Find a member to add to the document/);
8282

@@ -93,7 +93,8 @@ test.describe('Document add users', () => {
9393
await page.getByRole('option', { name: user.email }).click();
9494

9595
// Choose a role
96-
await page.getByRole('radio', { name: 'Administrator' }).click();
96+
await page.getByRole('combobox', { name: /Choose a role/ }).click();
97+
await page.getByRole('option', { name: 'Administrator' }).click();
9798

9899
const responsePromiseCreateInvitation = page.waitForResponse(
99100
(response) =>
@@ -127,8 +128,7 @@ test.describe('Document add users', () => {
127128

128129
await createDoc(page, 'user-twice', browserName, 1);
129130

130-
await page.getByLabel('Open the document options').click();
131-
await page.getByRole('button', { name: 'Add members' }).click();
131+
await page.getByRole('button', { name: 'Share' }).click();
132132

133133
const inputSearch = page.getByLabel(/Find a member to add to the document/);
134134
await inputSearch.fill('user');
@@ -139,7 +139,8 @@ test.describe('Document add users', () => {
139139
await page.getByRole('option', { name: user.email }).click();
140140

141141
// Choose a role
142-
await page.getByRole('radio', { name: 'Owner' }).click();
142+
await page.getByRole('combobox', { name: /Choose a role/ }).click();
143+
await page.getByRole('option', { name: 'Owner' }).click();
143144

144145
const responsePromiseAddMember = page.waitForResponse(
145146
(response) =>
@@ -154,10 +155,8 @@ test.describe('Document add users', () => {
154155
const responseAddMember = await responsePromiseAddMember;
155156
expect(responseAddMember.ok()).toBeTruthy();
156157

157-
await page.getByLabel('Open the document options').click();
158-
await page.getByRole('button', { name: 'Add members' }).click();
159-
160158
await inputSearch.fill('user');
159+
await expect(page.getByText('Loading...')).toBeHidden();
161160
await expect(page.getByRole('option', { name: user.email })).toBeHidden();
162161
});
163162

@@ -167,8 +166,7 @@ test.describe('Document add users', () => {
167166
}) => {
168167
await createDoc(page, 'invitation-twice', browserName, 1);
169168

170-
await page.getByLabel('Open the document options').click();
171-
await page.getByRole('button', { name: 'Add members' }).click();
169+
await page.getByRole('button', { name: 'Share' }).click();
172170

173171
const inputSearch = page.getByLabel(/Find a member to add to the document/);
174172

@@ -177,7 +175,8 @@ test.describe('Document add users', () => {
177175
await page.getByRole('option', { name: email }).click();
178176

179177
// Choose a role
180-
await page.getByRole('radio', { name: 'Owner' }).click();
178+
await page.getByRole('combobox', { name: /Choose a role/ }).click();
179+
await page.getByRole('option', { name: 'Owner' }).click();
181180

182181
const responsePromiseCreateInvitation = page.waitForResponse(
183182
(response) =>
@@ -191,10 +190,8 @@ test.describe('Document add users', () => {
191190
const responseCreateInvitation = await responsePromiseCreateInvitation;
192191
expect(responseCreateInvitation.ok()).toBeTruthy();
193192

194-
await page.getByLabel('Open the document options').click();
195-
await page.getByRole('button', { name: 'Add members' }).click();
196-
197193
await inputSearch.fill(email);
194+
await expect(page.getByText('Loading...')).toBeHidden();
198195
await expect(page.getByRole('option', { name: email })).toBeHidden();
199196
});
200197
});

src/frontend/apps/e2e/__tests__/app-impress/doc-tools.spec.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -216,11 +216,10 @@ test.describe('Doc Tools', () => {
216216

217217
await expect(page.locator('h2').getByText('Mocked document')).toBeVisible();
218218

219+
await expect(page.getByRole('button', { name: 'Share' })).toBeVisible();
220+
219221
await page.getByLabel('Open the document options').click();
220222

221-
await expect(
222-
page.getByRole('button', { name: 'Add members' }),
223-
).toBeVisible();
224223
await expect(
225224
page.getByRole('button', { name: 'Generate PDF' }),
226225
).toBeVisible();
@@ -267,11 +266,10 @@ test.describe('Doc Tools', () => {
267266

268267
await expect(page.locator('h2').getByText('Mocked document')).toBeVisible();
269268

269+
await expect(page.getByRole('button', { name: 'Share' })).toBeHidden();
270+
270271
await page.getByLabel('Open the document options').click();
271272

272-
await expect(
273-
page.getByRole('button', { name: 'Add members' }),
274-
).toBeHidden();
275273
await expect(
276274
page.getByRole('button', { name: 'Generate PDF' }),
277275
).toBeVisible();
@@ -318,11 +316,11 @@ test.describe('Doc Tools', () => {
318316

319317
await expect(page.locator('h2').getByText('Mocked document')).toBeVisible();
320318

319+
await expect(page.getByRole('button', { name: 'Share' })).toBeHidden();
320+
321321
await page.getByLabel('Open the document options').click();
322322

323-
await expect(
324-
page.getByRole('button', { name: 'Add members' }),
325-
).toBeHidden();
323+
await expect(page.getByRole('button', { name: 'Share' })).toBeHidden();
326324
await expect(
327325
page.getByRole('button', { name: 'Generate PDF' }),
328326
).toBeVisible();

src/frontend/apps/impress/src/components/SideModal.tsx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,23 @@ import { createGlobalStyle } from 'styled-components';
55
interface SideModalStyleProps {
66
side: 'left' | 'right';
77
width: string;
8+
$css?: string;
89
}
910

1011
const SideModalStyle = createGlobalStyle<SideModalStyleProps>`
12+
@keyframes slidein {
13+
from {
14+
transform: translateX(100%);
15+
}
16+
17+
to {
18+
transform: translateX(0%);
19+
}
20+
}
21+
1122
& .c__modal{
23+
animation: slidein 0.7s;
24+
1225
width: ${({ width }) => width};
1326
${({ side }) => side === 'right' && 'left: auto;'};
1427
@@ -17,6 +30,8 @@ const SideModalStyle = createGlobalStyle<SideModalStyleProps>`
1730
display: flex;
1831
flex-direction: column;
1932
}
33+
34+
${({ $css }) => $css}
2035
}
2136
`;
2237

@@ -28,11 +43,12 @@ export const SideModal = ({
2843
children,
2944
side = 'right',
3045
width = '35vw',
46+
$css,
3147
...modalProps
3248
}: PropsWithChildren<SideModalProps>) => {
3349
return (
3450
<>
35-
<SideModalStyle width={width} side={side} />
51+
<SideModalStyle width={width} side={side} $css={$css} />
3652
<Modal {...modalProps} size={ModalSize.FULL}>
3753
{children}
3854
</Modal>

src/frontend/apps/impress/src/components/Text.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export interface TextProps extends BoxProps {
1414
'p' | 'span' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
1515
>;
1616
$elipsis?: boolean;
17+
$isMaterialIcon?: boolean;
1718
$weight?: CSSProperties['fontWeight'];
1819
$textAlign?: CSSProperties['textAlign'];
1920
// eslint-disable-next-line @typescript-eslint/ban-types
@@ -56,9 +57,17 @@ export const TextStyled = styled(Box)<TextProps>`
5657
`;
5758

5859
export const Text = ({
60+
className,
61+
$isMaterialIcon,
5962
...props
6063
}: ComponentPropsWithRef<typeof TextStyled>) => {
6164
return (
62-
<TextStyled as="span" $theme="greyscale" $variation="text" {...props} />
65+
<TextStyled
66+
as="span"
67+
$theme="greyscale"
68+
$variation="text"
69+
className={`${className || ''}${$isMaterialIcon ? ' material-icons' : ''}`}
70+
{...props}
71+
/>
6372
);
6473
};

src/frontend/apps/impress/src/cunningham/cunningham-style.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,10 @@ input:-webkit-autofill:focus {
477477
padding: 1.5rem 1rem;
478478
}
479479

480+
.c__modal--full .c__modal__content {
481+
overflow-y: auto;
482+
}
483+
480484
/**
481485
* Toast
482486
*/

src/frontend/apps/impress/src/features/docs/doc-header/components/DocHeader.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export const DocHeader = ({ doc }: DocHeaderProps) => {
3131
<Box $padding="small" $direction="row" $align="center">
3232
<StyledLink href="/">
3333
<Text
34-
className="material-icons"
34+
$isMaterialIcon
3535
$theme="primary"
3636
$size="2rem"
3737
$css={`&:hover {background-color: ${colorsTokens()['primary-100']}; };`}
@@ -82,7 +82,9 @@ export const DocHeader = ({ doc }: DocHeaderProps) => {
8282
{t('Owners:')}{' '}
8383
<strong>
8484
{doc.accesses
85-
.filter((access) => access.role === Role.OWNER)
85+
.filter(
86+
(access) => access.role === Role.OWNER && access.user.email,
87+
)
8688
.map((access, index, accesses) => (
8789
<Fragment key={`access-${index}`}>
8890
{access.user.email}{' '}

src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@ import { Box, DropButton, IconOptions, Text } from '@/components';
66
import {
77
Doc,
88
ModalRemoveDoc,
9+
ModalShare,
910
ModalUpdateDoc,
10-
currentDocRole,
1111
} from '@/features/docs/doc-management';
12-
import { ModalAddMembers } from '@/features/docs/members/members-add';
1312
import { ModalGridMembers } from '@/features/docs/members/members-grid/';
1413

1514
import { ModalPDF } from './ModalPDF';
@@ -20,15 +19,29 @@ interface DocToolBoxProps {
2019

2120
export const DocToolBox = ({ doc }: DocToolBoxProps) => {
2221
const { t } = useTranslation();
23-
const [isModalAddMembersOpen, setIsModalAddMembersOpen] = useState(false);
2422
const [isModalGridMembersOpen, setIsModalGridMembersOpen] = useState(false);
23+
const [isModalShareOpen, setIsModalShareOpen] = useState(false);
2524
const [isModalUpdateOpen, setIsModalUpdateOpen] = useState(false);
2625
const [isModalRemoveOpen, setIsModalRemoveOpen] = useState(false);
2726
const [isModalPDFOpen, setIsModalPDFOpen] = useState(false);
2827
const [isDropOpen, setIsDropOpen] = useState(false);
2928

3029
return (
31-
<Box $margin={{ left: 'auto' }}>
30+
<Box
31+
$margin={{ left: 'auto' }}
32+
$direction="row"
33+
$align="center"
34+
$gap="1rem"
35+
>
36+
{doc.abilities.manage_accesses && (
37+
<Button
38+
onClick={() => {
39+
setIsModalShareOpen(true);
40+
}}
41+
>
42+
{t('Share')}
43+
</Button>
44+
)}
3245
<DropButton
3346
button={
3447
<IconOptions
@@ -42,17 +55,6 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
4255
<Box>
4356
{doc.abilities.manage_accesses && (
4457
<>
45-
<Button
46-
onClick={() => {
47-
setIsModalAddMembersOpen(true);
48-
setIsDropOpen(false);
49-
}}
50-
color="primary-text"
51-
icon={<span className="material-icons">person_add</span>}
52-
size="small"
53-
>
54-
<Text $theme="primary">{t('Add members')}</Text>
55-
</Button>
5658
<Button
5759
onClick={() => {
5860
setIsModalGridMembersOpen(true);
@@ -105,19 +107,15 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
105107
</Button>
106108
</Box>
107109
</DropButton>
110+
{isModalShareOpen && (
111+
<ModalShare onClose={() => setIsModalShareOpen(false)} doc={doc} />
112+
)}
108113
{isModalGridMembersOpen && (
109114
<ModalGridMembers
110115
onClose={() => setIsModalGridMembersOpen(false)}
111116
doc={doc}
112117
/>
113118
)}
114-
{isModalAddMembersOpen && (
115-
<ModalAddMembers
116-
onClose={() => setIsModalAddMembersOpen(false)}
117-
doc={doc}
118-
currentRole={currentDocRole(doc.abilities)}
119-
/>
120-
)}
121119
{isModalPDFOpen && (
122120
<ModalPDF onClose={() => setIsModalPDFOpen(false)} doc={doc} />
123121
)}

0 commit comments

Comments
 (0)