Skip to content

Commit 594966f

Browse files
committed
refactor: update form
1 parent 735dab4 commit 594966f

2 files changed

Lines changed: 138 additions & 116 deletions

File tree

apps/web/src/features/admin/pages/ManageUsersPage.tsx

Lines changed: 9 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { useState } from 'react';
22

33
import { snakeToCamelCase } from '@douglasneuroinformatics/libjs';
4-
import { Button, ClientTable, Form, Heading, SearchBar, Sheet } from '@douglasneuroinformatics/libui/components';
4+
import { Button, ClientTable, Heading, SearchBar, Sheet } from '@douglasneuroinformatics/libui/components';
55
import { useTranslation } from '@douglasneuroinformatics/libui/hooks';
6-
import { $UpdateUserData, type User } from '@opendatacapture/schemas/user';
6+
import type { User } from '@opendatacapture/schemas/user';
77
import { Link } from 'react-router-dom';
88

99
import { PageHeader } from '@/components/PageHeader';
@@ -13,6 +13,7 @@ import { useAppStore } from '@/store';
1313
import { useDeleteUserMutation } from '../hooks/useDeleteUserMutation';
1414
import { useUpdateUserMutation } from '../hooks/useUpdateUserMutation';
1515
import { useUsersQuery } from '../hooks/useUsersQuery';
16+
import { UpdateUserForm } from './UpdateUserForm';
1617

1718
export const ManageUsersPage = () => {
1819
const currentUser = useAppStore((store) => store.currentUser);
@@ -89,127 +90,19 @@ export const ManageUsersPage = () => {
8990
</Sheet.Description>
9091
</Sheet.Header>
9192
<Sheet.Body className="grid gap-4">
92-
<Form
93-
additionalButtons={{
94-
left: (
95-
<Button
96-
className="w-full"
97-
disabled={currentUserIsSelected}
98-
type="button"
99-
variant="danger"
100-
onClick={() => {
101-
deleteUserMutation.mutate({ id: selectedUser!.id });
102-
setSelectedUser(null);
103-
}}
104-
>
105-
{t('core.delete')}
106-
</Button>
107-
)
108-
}}
109-
content={[
110-
{
111-
description: t({
112-
en: 'IMPORTANT: These permissions are not specific to any group. To manage granular permissions, please use the API.',
113-
fr: "IMPORTANT : Ces autorisations ne sont pas spécifiques à un groupe. Pour gérer des autorisations granulaires, veuillez utiliser l'API."
114-
}),
115-
fields: {
116-
additionalPermissions: {
117-
fieldset: {
118-
action: {
119-
kind: 'string',
120-
label: t({
121-
en: 'Action',
122-
fr: 'Action'
123-
}),
124-
options: {
125-
create: t({
126-
en: 'Create',
127-
fr: 'Créer'
128-
}),
129-
delete: t({
130-
en: 'Delete',
131-
fr: 'Effacer'
132-
}),
133-
manage: t({
134-
en: 'Manage (All)',
135-
fr: 'Gérer (Tout)'
136-
}),
137-
read: t({
138-
en: 'Read',
139-
fr: 'Lire'
140-
}),
141-
update: t({
142-
en: 'Update',
143-
fr: 'Mettre à jour'
144-
})
145-
},
146-
variant: 'select'
147-
},
148-
subject: {
149-
kind: 'string',
150-
label: t({
151-
en: 'Resource',
152-
fr: 'Resource'
153-
}),
154-
options: {
155-
all: t({
156-
en: 'All',
157-
fr: 'Tous'
158-
}),
159-
Assignment: t({
160-
en: 'Assignment',
161-
fr: 'Devoir'
162-
}),
163-
Group: t({
164-
en: 'Group',
165-
fr: 'Groupe'
166-
}),
167-
Instrument: t({
168-
en: 'Instrument',
169-
fr: 'Instrument'
170-
}),
171-
InstrumentRecord: t({
172-
en: 'Instrument Record',
173-
fr: "Enregistrement de l'instrument"
174-
}),
175-
Session: t({
176-
en: 'Session',
177-
fr: 'Session'
178-
}),
179-
Subject: t({
180-
en: 'Subject',
181-
fr: 'Client'
182-
}),
183-
User: t({
184-
en: 'User',
185-
fr: 'Utilisateur'
186-
})
187-
},
188-
variant: 'select'
189-
}
190-
},
191-
kind: 'record-array',
192-
label: t({
193-
en: 'Permission',
194-
fr: 'Autorisations supplémentaires'
195-
})
196-
}
197-
},
198-
title: t({
199-
en: 'Authorization',
200-
fr: 'Autorisation'
201-
})
202-
}
203-
]}
93+
<UpdateUserForm
94+
disableDelete={currentUserIsSelected}
20495
initialValues={
20596
selectedUser?.additionalPermissions.length
20697
? {
20798
additionalPermissions: selectedUser.additionalPermissions
20899
}
209100
: undefined
210101
}
211-
submitBtnLabel={t('core.save')}
212-
validationSchema={$UpdateUserData.pick({ additionalPermissions: true }).required()}
102+
onDelete={() => {
103+
deleteUserMutation.mutate({ id: selectedUser!.id });
104+
setSelectedUser(null);
105+
}}
213106
onSubmit={(data) => {
214107
void updateUserMutation.mutateAsync({ data, id: selectedUser!.id }).then(() => {
215108
setSelectedUser(null);
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import { Button, Form } from '@douglasneuroinformatics/libui/components';
2+
import { useTranslation } from '@douglasneuroinformatics/libui/hooks';
3+
import type { FormTypes } from '@opendatacapture/runtime-core';
4+
import { $UpdateUserData } from '@opendatacapture/schemas/user';
5+
import type { Promisable } from 'type-fest';
6+
import type { z } from 'zod';
7+
8+
const $UpdateUserFormData = $UpdateUserData.pick({ additionalPermissions: true }).required();
9+
10+
type UpdateUserFormData = z.infer<typeof $UpdateUserFormData>;
11+
12+
export const UpdateUserForm: React.FC<{
13+
disableDelete: boolean;
14+
initialValues?: FormTypes.PartialNullableData<UpdateUserFormData>;
15+
onDelete: () => void;
16+
onSubmit: (data: UpdateUserFormData) => Promisable<void>;
17+
}> = ({ disableDelete, initialValues, onDelete, onSubmit }) => {
18+
const { t } = useTranslation();
19+
return (
20+
<Form
21+
additionalButtons={{
22+
left: (
23+
<Button className="w-full" disabled={disableDelete} type="button" variant="danger" onClick={onDelete}>
24+
{t('core.delete')}
25+
</Button>
26+
)
27+
}}
28+
content={[
29+
{
30+
description: t({
31+
en: 'IMPORTANT: These permissions are not specific to any group. To manage granular permissions, please use the API.',
32+
fr: "IMPORTANT : Ces autorisations ne sont pas spécifiques à un groupe. Pour gérer des autorisations granulaires, veuillez utiliser l'API."
33+
}),
34+
fields: {
35+
additionalPermissions: {
36+
fieldset: {
37+
action: {
38+
kind: 'string',
39+
label: t({
40+
en: 'Action',
41+
fr: 'Action'
42+
}),
43+
options: {
44+
create: t({
45+
en: 'Create',
46+
fr: 'Créer'
47+
}),
48+
delete: t({
49+
en: 'Delete',
50+
fr: 'Effacer'
51+
}),
52+
manage: t({
53+
en: 'Manage (All)',
54+
fr: 'Gérer (Tout)'
55+
}),
56+
read: t({
57+
en: 'Read',
58+
fr: 'Lire'
59+
}),
60+
update: t({
61+
en: 'Update',
62+
fr: 'Mettre à jour'
63+
})
64+
},
65+
variant: 'select'
66+
},
67+
subject: {
68+
kind: 'string',
69+
label: t({
70+
en: 'Resource',
71+
fr: 'Resource'
72+
}),
73+
options: {
74+
all: t({
75+
en: 'All',
76+
fr: 'Tous'
77+
}),
78+
Assignment: t({
79+
en: 'Assignment',
80+
fr: 'Devoir'
81+
}),
82+
Group: t({
83+
en: 'Group',
84+
fr: 'Groupe'
85+
}),
86+
Instrument: t({
87+
en: 'Instrument',
88+
fr: 'Instrument'
89+
}),
90+
InstrumentRecord: t({
91+
en: 'Instrument Record',
92+
fr: "Enregistrement de l'instrument"
93+
}),
94+
Session: t({
95+
en: 'Session',
96+
fr: 'Session'
97+
}),
98+
Subject: t({
99+
en: 'Subject',
100+
fr: 'Client'
101+
}),
102+
User: t({
103+
en: 'User',
104+
fr: 'Utilisateur'
105+
})
106+
},
107+
variant: 'select'
108+
}
109+
},
110+
kind: 'record-array',
111+
label: t({
112+
en: 'Permission',
113+
fr: 'Autorisations supplémentaires'
114+
})
115+
}
116+
},
117+
title: t({
118+
en: 'Authorization',
119+
fr: 'Autorisation'
120+
})
121+
}
122+
]}
123+
initialValues={initialValues}
124+
submitBtnLabel={t('core.save')}
125+
validationSchema={$UpdateUserFormData}
126+
onSubmit={onSubmit}
127+
/>
128+
);
129+
};

0 commit comments

Comments
 (0)