Skip to content

Commit f601ac8

Browse files
fix: allow multiple departements for members (#312)
* fix: allow multiple departements for members * fix: fix error on create user
1 parent 1f05f6a commit f601ac8

10 files changed

Lines changed: 181 additions & 29 deletions

File tree

package-lock.json

Lines changed: 18 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"react-datepicker": "^4.7.0",
5555
"react-dom": "17.0.2",
5656
"react-icons": "^4.3.1",
57+
"react-multi-select-component": "^4.2.5",
5758
"remixicon": "^2.5.0",
5859
"sass": "^1.44.0",
5960
"superjson": "^1.8.0",
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- AlterTable
2+
ALTER TABLE "User" ADD COLUMN "departements" TEXT;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/*
2+
Warnings:
3+
4+
- The `departements` column on the `User` table would be dropped and recreated. This will lead to data loss if there is data in the column.
5+
6+
*/
7+
-- AlterTable
8+
ALTER TABLE "User" DROP COLUMN "departements",
9+
ADD COLUMN "departements" TEXT[];

prisma/schema.prisma

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ model User {
223223
commentaires Commentaire[]
224224
role Role?
225225
departement String?
226+
departements String[]
226227
}
227228

228229
model Session {

src/components/AddUtilisateur.tsx

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { Select } from "@dataesr/react-dsfr";
22
import type { User } from "@prisma/client";
3+
import _ from "lodash";
34
import * as React from "react";
5+
import { MultiSelect } from "react-multi-select-component";
46
import styles from "src/components/AddUtilisateur.module.scss";
57
import {
68
ALL_DEPARTEMENTS,
@@ -12,11 +14,6 @@ interface Props {
1214
saveUser: (e: React.FormEvent, formData: User) => void;
1315
}
1416

15-
interface Option {
16-
label: string | null;
17-
value: string;
18-
}
19-
2017
const AddUser: React.FC<Props> = ({ saveUser }) => {
2118
const [formData, setFormData] = React.useState<User>({
2219
departement: "",
@@ -30,16 +27,24 @@ const AddUser: React.FC<Props> = ({ saveUser }) => {
3027
role: "",
3128
});
3229

33-
const handleForm = (e: React.FormEvent<HTMLInputElement>): void => {
30+
const [selected, setSelected] = React.useState([]);
31+
32+
const handleSelect = () => {
3433
setFormData({
3534
...formData,
36-
[e.target.id]: e.currentTarget.value,
35+
departements: _.map(selected, "key"),
3736
});
3837
};
3938

40-
const defaultDepartement: Option = {
41-
label: "Département",
42-
value: "",
39+
React.useEffect(() => {
40+
handleSelect();
41+
}, [selected]);
42+
43+
const handleForm = (e: React.FormEvent<HTMLInputElement>): void => {
44+
setFormData({
45+
...formData,
46+
[e.target.id]: e.currentTarget.value,
47+
});
4348
};
4449

4550
return (
@@ -116,20 +121,18 @@ const AddUser: React.FC<Props> = ({ saveUser }) => {
116121
Département
117122
</label>
118123
<div className="selectDpt">
119-
<Select
120-
id="departement"
121-
name="departement"
122-
selected={formData.departement ? formData.departement : ""}
123-
options={[defaultDepartement].concat(
124-
ALL_DEPARTEMENTS.map((u) => ({
125-
key: u,
126-
label: frenchDepartementName(u),
127-
value: u,
128-
}))
129-
)}
130-
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
131-
handleForm(event);
124+
<MultiSelect
125+
options={ALL_DEPARTEMENTS.map((u) => ({
126+
key: u,
127+
label: frenchDepartementName(u),
128+
value: u,
129+
}))}
130+
value={selected}
131+
hasSelectAll={false}
132+
onChange={(value) => {
133+
setSelected(value as React.SetStateAction<never[]>);
132134
}}
135+
labelledBy="Département(s)"
133136
/>
134137
</div>
135138
</div>

src/components/Utilisateurs.tsx

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import type { User } from "@prisma/client";
2+
import _ from "lodash";
23
import Link from "next/link";
34
import React from "react";
5+
import { MultiSelect } from "react-multi-select-component";
46
import AddUser from "src/components/AddUtilisateur";
5-
import { frenchDepartementName } from "src/lib/helpers";
6-
import { createUser, removeUser } from "src/lib/queries";
7+
import { ALL_DEPARTEMENTS, frenchDepartementName } from "src/lib/helpers";
8+
import { createUser, removeUser, updateUser } from "src/lib/queries";
79
import styles from "src/styles/commissions.module.scss";
810

911
interface Props {
@@ -16,6 +18,36 @@ interface RowProps {
1618
}
1719

1820
const UserRow: React.FC<RowProps> = ({ user, deleteUser }) => {
21+
const [changeDep, setDepartementChange] = React.useState<boolean>(false);
22+
const [selected, setSelected] = React.useState(
23+
user.departements.map((departement) => {
24+
return {
25+
key: departement,
26+
label: frenchDepartementName(departement),
27+
value: departement,
28+
};
29+
})
30+
);
31+
const [newUser, changeUser] = React.useState<User>(user);
32+
const [mountedRef, setMountedRef] = React.useState<boolean>(false);
33+
34+
React.useEffect(() => {
35+
changeUser({
36+
...user,
37+
departements: _.map(selected, "key"),
38+
});
39+
}, [selected]);
40+
41+
React.useEffect(() => {
42+
setMountedRef(true);
43+
});
44+
45+
React.useEffect(() => {
46+
if (mountedRef && newUser.id) {
47+
updateUser(newUser);
48+
}
49+
}, [newUser]);
50+
1951
return (
2052
<div className={`${styles.rowUser} card`}>
2153
<div>
@@ -33,7 +65,44 @@ const UserRow: React.FC<RowProps> = ({ user, deleteUser }) => {
3365
<b>{user.role}</b>
3466
</div>
3567
<div>
36-
<b>{user.departement ? frenchDepartementName(user.departement) : ""}</b>
68+
{changeDep ? (
69+
<MultiSelect
70+
options={ALL_DEPARTEMENTS.map((u) => ({
71+
key: u,
72+
label: frenchDepartementName(u),
73+
value: u,
74+
}))}
75+
value={selected}
76+
hasSelectAll={false}
77+
onChange={(value) => {
78+
setSelected(
79+
value as React.SetStateAction<
80+
{ key: string; label: string; value: string }[]
81+
>
82+
);
83+
setDepartementChange(!changeDep);
84+
}}
85+
labelledBy="Département(s)"
86+
/>
87+
) : (
88+
<span>
89+
{newUser.departements.map((departement) => (
90+
<b key={departement}>
91+
<li key={departement}>{frenchDepartementName(departement)}</li>
92+
</b>
93+
))}
94+
<br />
95+
{user.role === "MEMBRE" && (
96+
<button
97+
onClick={() => {
98+
setDepartementChange(!changeDep);
99+
}}
100+
>
101+
Modifier
102+
</button>
103+
)}
104+
</span>
105+
)}
37106
</div>
38107
<div>
39108
<Link href={`/utilisateurs`}>
@@ -65,6 +134,8 @@ const Utilisateurs: React.FC<Props> = ({ allUsers }) => {
65134
e.preventDefault();
66135
const user: User = {
67136
departement: formData.departement,
137+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
138+
departements: formData.departements || [""],
68139
email: formData.email,
69140
emailVerified: new Date(),
70141
nom: formData.nom,

src/lib/queries.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,23 @@ const createUser = (user: User) => {
511511
});
512512
};
513513

514+
const updateUser = (user: User) => {
515+
window
516+
.fetch(`/api/users`, {
517+
body: JSON.stringify(user),
518+
method: "PUT",
519+
})
520+
.then((r) => {
521+
if (!r.ok) {
522+
throw Error(`got status ${r.status}`);
523+
}
524+
return r;
525+
})
526+
.catch((e) => {
527+
throw e;
528+
});
529+
};
530+
514531
const removeUser = (id: number) => {
515532
window
516533
.fetch(`/api/users`, {
@@ -748,5 +765,6 @@ export {
748765
updateEnfant,
749766
updateEnfants,
750767
updatePieceDossierEnfant,
768+
updateUser,
751769
uploadZip,
752770
};

src/pages/api/users/index.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ const handler: NextApiHandler = async (req, res) => {
1717
await post(req, res);
1818
} else if (req.method == "DELETE") {
1919
await remove(req, res);
20+
} else if (req.method == "PUT") {
21+
await update(req, res);
2022
} else {
2123
res.status(405).end();
2224
return;
@@ -46,6 +48,31 @@ const remove: NextApiHandler = async (req, res) => {
4648
}
4749
};
4850

51+
const update: NextApiHandler = async (req, res) => {
52+
if (typeof req.body !== "string") {
53+
res.status(400).end();
54+
return;
55+
}
56+
57+
const parsed = JSON.parse(req.body);
58+
if (!parsed) {
59+
res.status(400).end();
60+
return;
61+
}
62+
63+
const userId = parsed.id;
64+
65+
console.log("id : ", userId);
66+
const updatedUser = await prisma.user.update({
67+
data: {
68+
departements: parsed.departements,
69+
},
70+
where: { id: userId },
71+
});
72+
73+
res.status(200).json(superjson.stringify(updatedUser));
74+
};
75+
4976
const get: NextApiHandler = async (req, res) => {
5077
const role = req.query.role;
5178
const allUsers =

src/pages/api/users/search/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ const get: NextApiHandler = async (req, res) => {
2424
if (typeof departement === "string") {
2525
const allUsers = await prisma.user.findMany({
2626
orderBy: { name: "asc" },
27-
where: { departement: departement },
27+
where: {
28+
departements: {
29+
has: departement,
30+
},
31+
},
2832
});
2933
res.status(200).json(superjson.stringify(allUsers));
3034
} else {

0 commit comments

Comments
 (0)