From 552e1d9337ae5f36bdc06c2d4a43ab4f3110a42f Mon Sep 17 00:00:00 2001 From: T'JAMPENS QUENTIN p2406187 Date: Mon, 12 Jan 2026 22:37:21 +0100 Subject: [PATCH 1/6] create manageMember btn --- public/icons/tools.svg | 2 ++ src/components/manageMember/ManageMember.jsx | 21 +++++++++++++++++++ .../manageMember/manageMember.module.css | 8 +++++++ .../VolunteerProfile/VolunteerProfilePage.jsx | 7 ++++++- 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 public/icons/tools.svg create mode 100644 src/components/manageMember/ManageMember.jsx create mode 100644 src/components/manageMember/manageMember.module.css diff --git a/public/icons/tools.svg b/public/icons/tools.svg new file mode 100644 index 0000000..2f2d697 --- /dev/null +++ b/public/icons/tools.svg @@ -0,0 +1,2 @@ + +tools \ No newline at end of file diff --git a/src/components/manageMember/ManageMember.jsx b/src/components/manageMember/ManageMember.jsx new file mode 100644 index 0000000..2f240b0 --- /dev/null +++ b/src/components/manageMember/ManageMember.jsx @@ -0,0 +1,21 @@ +import Button from "../ui/button/button.jsx"; +import Modal from "../ui/modal/modal.jsx"; +import { useState } from "react"; +import styles from "./manageMember.module.css" + + +export default function ManageMember({ user }) { + + const [open, setOpen] = useState(false); + + return <> + + + setOpen(false)} title={`Gestion de l'utilisateur ${user.name}`}> + + + +} \ No newline at end of file diff --git a/src/components/manageMember/manageMember.module.css b/src/components/manageMember/manageMember.module.css new file mode 100644 index 0000000..d97bfd5 --- /dev/null +++ b/src/components/manageMember/manageMember.module.css @@ -0,0 +1,8 @@ +.icon { + width: 24px; +} + +.manageBtn { + display: flex; + flex-direction: row; +} \ No newline at end of file diff --git a/src/pages/VolunteerProfile/VolunteerProfilePage.jsx b/src/pages/VolunteerProfile/VolunteerProfilePage.jsx index 1f18805..b6e49a4 100644 --- a/src/pages/VolunteerProfile/VolunteerProfilePage.jsx +++ b/src/pages/VolunteerProfile/VolunteerProfilePage.jsx @@ -1,10 +1,12 @@ import styles from "./VolunteerProfilePage.module.css" import { useParams } from "react-router"; -import { useEffect, useState } from "react"; +import { useEffect, useState, useContext } from "react"; import getUserById from "../../utils/users/getUserById.js"; import formatDate from "../../utils/date/formatDate.js"; import Task from "../../components/Task/Task.jsx"; import { useNavigate } from "react-router"; +import ManageMember from "../../components/manageMember/ManageMember.jsx"; +import { AuthContext } from "../../contexts/auth/AuthContext.js"; export default function VolunteerProfilePage() { @@ -13,6 +15,8 @@ export default function VolunteerProfilePage() { const navigate = useNavigate(); + const { user: currentUser } = useContext(AuthContext); + const [user, setUser] = useState({}); useEffect(() => { @@ -41,6 +45,7 @@ export default function VolunteerProfilePage() {

{user.name} {user.lastname}

+ {currentUser?.isAdmin && }
From 0ff475a86d59d71a660c8bc3c5504d69f2ea41dd Mon Sep 17 00:00:00 2001 From: T'JAMPENS QUENTIN p2406187 Date: Mon, 12 Jan 2026 23:47:45 +0100 Subject: [PATCH 2/6] Create delete user btn --- src/components/manageMember/ManageMember.jsx | 5 +++ .../deleteMember/deleteMemberBtn.jsx | 31 +++++++++++++++++ .../manageMember/manageMember.module.css | 7 ++++ src/utils/users/deleteUser.js | 34 +++++++++++++++++++ 4 files changed, 77 insertions(+) create mode 100644 src/components/manageMember/deleteMember/deleteMemberBtn.jsx create mode 100644 src/utils/users/deleteUser.js diff --git a/src/components/manageMember/ManageMember.jsx b/src/components/manageMember/ManageMember.jsx index 2f240b0..33d73ca 100644 --- a/src/components/manageMember/ManageMember.jsx +++ b/src/components/manageMember/ManageMember.jsx @@ -2,6 +2,7 @@ import Button from "../ui/button/button.jsx"; import Modal from "../ui/modal/modal.jsx"; import { useState } from "react"; import styles from "./manageMember.module.css" +import DeleteMemberBtn from "./deleteMember/deleteMemberBtn.jsx"; export default function ManageMember({ user }) { @@ -16,6 +17,10 @@ export default function ManageMember({ user }) { setOpen(false)} title={`Gestion de l'utilisateur ${user.name}`}> +
+

Supprimer le compte

+ +
} \ No newline at end of file diff --git a/src/components/manageMember/deleteMember/deleteMemberBtn.jsx b/src/components/manageMember/deleteMember/deleteMemberBtn.jsx new file mode 100644 index 0000000..26561a2 --- /dev/null +++ b/src/components/manageMember/deleteMember/deleteMemberBtn.jsx @@ -0,0 +1,31 @@ +import Button from "../../ui/button/button.jsx"; +import Modal from "../../ui/modal/modal.jsx"; +import { useState } from "react"; +import deleteUser from "../../../utils/users/deleteUser.js" +import { useNavigate } from "react-router"; + +export default function DeleteMemberBtn({ name, id }) { + + const [open, setOpen] = useState(false); + const navigate = useNavigate(); + + const delMember = async () => { + const result = await deleteUser(id); + + if (result.status === 200 || result.status === 204) { + setOpen(false); + navigate("/volunteers"); + } + } + + return <> + + + setOpen(false)} title={"Supprimer"}> +
+

Etes-vous sur de vouloir supprimer le compte {name} ?

+ +
+
+ +} \ No newline at end of file diff --git a/src/components/manageMember/manageMember.module.css b/src/components/manageMember/manageMember.module.css index d97bfd5..9fb20df 100644 --- a/src/components/manageMember/manageMember.module.css +++ b/src/components/manageMember/manageMember.module.css @@ -5,4 +5,11 @@ .manageBtn { display: flex; flex-direction: row; +} + +.manageSection { + display: flex; + flex-direction: column; + gap: 8px; + margin: 1.5em; } \ No newline at end of file diff --git a/src/utils/users/deleteUser.js b/src/utils/users/deleteUser.js new file mode 100644 index 0000000..4e3f24d --- /dev/null +++ b/src/utils/users/deleteUser.js @@ -0,0 +1,34 @@ +import getXSRFToken from "../getXSRF.js"; + +export default async function deleteUser(userId) { + const csrfToken = await getXSRFToken(); + + try { + const response = await fetch(`${import.meta.env.VITE_API_URL}/api/users/${userId}`, { + method: 'DELETE', + credentials: 'include', + headers: { + 'Content-Type': 'application/json', + 'X-XSRF-TOKEN': csrfToken, + 'Accept': 'application/json' + }, + body: JSON.stringify({ + id: userId + }) + }); + + const data = await response.json(); + + if (!response.ok) { + return { + status: response.status, + errors: data.errors || data.message + }; + } + + return { status: response.status, data }; + + } catch (error) { + return { status: 500, error }; + } +} From a607591a94e0a9b34a789b93268d3cdb738b51a1 Mon Sep 17 00:00:00 2001 From: T'JAMPENS QUENTIN p2406187 Date: Tue, 13 Jan 2026 09:02:11 +0100 Subject: [PATCH 3/6] Add glassBorders --- src/pages/VolunteerProfile/VolunteerProfilePage.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/VolunteerProfile/VolunteerProfilePage.jsx b/src/pages/VolunteerProfile/VolunteerProfilePage.jsx index b6e49a4..4c24a51 100644 --- a/src/pages/VolunteerProfile/VolunteerProfilePage.jsx +++ b/src/pages/VolunteerProfile/VolunteerProfilePage.jsx @@ -48,11 +48,11 @@ export default function VolunteerProfilePage() { {currentUser?.isAdmin && }
-
+

Role : {user.role}

Membre depuis : {formatDate(user.created_at)}

-
+

Mail : {user.email}

Téléphone : {user.phone === null ? "Pas de numéro enregistré" : user.phone}

From 6bb4b62e4db05a17d3522b13aa3d99ac40af0d14 Mon Sep 17 00:00:00 2001 From: T'JAMPENS QUENTIN p2406187 Date: Tue, 13 Jan 2026 09:05:28 +0100 Subject: [PATCH 4/6] Add margin --- src/components/manageMember/ManageMember.jsx | 2 +- .../manageMember/deleteMember/deleteMemberBtn.jsx | 6 +++--- src/components/manageMember/manageMember.module.css | 4 ++++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/components/manageMember/ManageMember.jsx b/src/components/manageMember/ManageMember.jsx index 33d73ca..0f9e4a9 100644 --- a/src/components/manageMember/ManageMember.jsx +++ b/src/components/manageMember/ManageMember.jsx @@ -19,7 +19,7 @@ export default function ManageMember({ user }) {

Supprimer le compte

- +
diff --git a/src/components/manageMember/deleteMember/deleteMemberBtn.jsx b/src/components/manageMember/deleteMember/deleteMemberBtn.jsx index 26561a2..aa686aa 100644 --- a/src/components/manageMember/deleteMember/deleteMemberBtn.jsx +++ b/src/components/manageMember/deleteMember/deleteMemberBtn.jsx @@ -4,7 +4,7 @@ import { useState } from "react"; import deleteUser from "../../../utils/users/deleteUser.js" import { useNavigate } from "react-router"; -export default function DeleteMemberBtn({ name, id }) { +export default function DeleteMemberBtn({ name, id, ...props }) { const [open, setOpen] = useState(false); const navigate = useNavigate(); @@ -18,7 +18,7 @@ export default function DeleteMemberBtn({ name, id }) { } } - return <> + return
setOpen(false)} title={"Supprimer"}> @@ -27,5 +27,5 @@ export default function DeleteMemberBtn({ name, id }) {
- +
} \ No newline at end of file diff --git a/src/components/manageMember/manageMember.module.css b/src/components/manageMember/manageMember.module.css index 9fb20df..ca9639d 100644 --- a/src/components/manageMember/manageMember.module.css +++ b/src/components/manageMember/manageMember.module.css @@ -12,4 +12,8 @@ flex-direction: column; gap: 8px; margin: 1.5em; +} + +.manageBlockContent { + margin: 0.5em; } \ No newline at end of file From 28cc9c13ebfcbf11e5956e588256467a70c07d2b Mon Sep 17 00:00:00 2001 From: T'JAMPENS QUENTIN p2406187 Date: Tue, 13 Jan 2026 11:51:05 +0100 Subject: [PATCH 5/6] Modify role --- src/components/manageMember/ManageMember.jsx | 42 ++++++++++++++++++- .../manageMember/manageMember.module.css | 24 +++++++++++ src/utils/getRoles.js | 21 ++++++++++ src/utils/users/modifyRole.js | 30 +++++++++++++ 4 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 src/utils/getRoles.js create mode 100644 src/utils/users/modifyRole.js diff --git a/src/components/manageMember/ManageMember.jsx b/src/components/manageMember/ManageMember.jsx index 0f9e4a9..0485ad8 100644 --- a/src/components/manageMember/ManageMember.jsx +++ b/src/components/manageMember/ManageMember.jsx @@ -1,13 +1,29 @@ import Button from "../ui/button/button.jsx"; import Modal from "../ui/modal/modal.jsx"; -import { useState } from "react"; +import { useState, useEffect } from "react"; import styles from "./manageMember.module.css" import DeleteMemberBtn from "./deleteMember/deleteMemberBtn.jsx"; - +import getRoles from "../../utils/getRoles.js" +import modifyRole from "../../utils/users/modifyRole.js"; export default function ManageMember({ user }) { const [open, setOpen] = useState(false); + const [roles, setRoles] = useState([]); + const [selectedRole, setSelectedRole] = useState(3); + + useEffect(() => { + if (!open) return; + + getRoles().then(data => { + if (data) setRoles(data); + }); + }, [open]); + + const handleRoleUpdate = async () => { + const res = await modifyRole(selectedRole, user.id); + console.log(res); + }; return <>
+ +
+

Modifier le rôle

+ +
+ + + +
+
} \ No newline at end of file diff --git a/src/components/manageMember/manageMember.module.css b/src/components/manageMember/manageMember.module.css index ca9639d..6f59f30 100644 --- a/src/components/manageMember/manageMember.module.css +++ b/src/components/manageMember/manageMember.module.css @@ -16,4 +16,28 @@ .manageBlockContent { margin: 0.5em; +} + +.modifyRole { + display: flex; + flex-direction: row; + justify-content: space-evenly; + align-items: center; +} + +.select { + width: 70%; + padding: 10px 14px; + + font-size: 14px; + font-weight: 500; + color: #1d1d1f; + + background-color: #ffffff; + border: 1px solid #d2d2d7; + border-radius: 10px; + + appearance: none; + -webkit-appearance: none; + -moz-appearance: none; } \ No newline at end of file diff --git a/src/utils/getRoles.js b/src/utils/getRoles.js new file mode 100644 index 0000000..5d6d3d6 --- /dev/null +++ b/src/utils/getRoles.js @@ -0,0 +1,21 @@ +export default async function getRoles() { + try { + const res = await fetch(`${import.meta.env.VITE_API_URL}/api/roles`, { + method: 'GET', + credentials: 'include', + headers: { + 'Accept': 'application/json' + } + }); + + if (!res.ok) { + throw new Error(`Erreur serveur : ${res.status}`); + } + + const data = await res.json(); + return data; + } catch (err) { + console.error('Erreur :', err); + return null; + } +} diff --git a/src/utils/users/modifyRole.js b/src/utils/users/modifyRole.js new file mode 100644 index 0000000..e95ac3f --- /dev/null +++ b/src/utils/users/modifyRole.js @@ -0,0 +1,30 @@ +import getXSRFToken from "../getXSRF.js"; + +export default async function modifyRole(role, userId) { + + const csrfToken = await getXSRFToken(); + + try { + const res = await fetch(`${import.meta.env.VITE_API_URL}/api/users/${userId}/role`, { + method: 'POST', + credentials: 'include', + headers: { + 'Accept': 'application/json', + 'X-XSRF-TOKEN': csrfToken, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + role: role, + }) + }); + + if (!res.ok) { + throw new Error(`Erreur serveur : ${res.status}`); + } + + return await res.json(); + } catch (err) { + console.error('Erreur :', err); + return null; + } +} \ No newline at end of file From 33430ca04e3ee0c1dac868737448ccad4921806e Mon Sep 17 00:00:00 2001 From: T'JAMPENS QUENTIN p2406187 Date: Tue, 13 Jan 2026 22:51:10 +0100 Subject: [PATCH 6/6] Show modal on modify + split component --- src/components/manageMember/ManageMember.jsx | 38 +----------- .../manageMember/manageMember.module.css | 4 ++ .../manageMember/modifyrole/ModifyRole.jsx | 59 +++++++++++++++++++ src/utils/users/modifyRole.js | 43 +++++++------- 4 files changed, 89 insertions(+), 55 deletions(-) create mode 100644 src/components/manageMember/modifyrole/ModifyRole.jsx diff --git a/src/components/manageMember/ManageMember.jsx b/src/components/manageMember/ManageMember.jsx index 0485ad8..04bef13 100644 --- a/src/components/manageMember/ManageMember.jsx +++ b/src/components/manageMember/ManageMember.jsx @@ -1,29 +1,14 @@ import Button from "../ui/button/button.jsx"; import Modal from "../ui/modal/modal.jsx"; -import { useState, useEffect } from "react"; +import { useState } from "react"; import styles from "./manageMember.module.css" import DeleteMemberBtn from "./deleteMember/deleteMemberBtn.jsx"; -import getRoles from "../../utils/getRoles.js" -import modifyRole from "../../utils/users/modifyRole.js"; +import ModifyRole from "./modifyrole/ModifyRole.jsx"; export default function ManageMember({ user }) { const [open, setOpen] = useState(false); - const [roles, setRoles] = useState([]); - const [selectedRole, setSelectedRole] = useState(3); - useEffect(() => { - if (!open) return; - - getRoles().then(data => { - if (data) setRoles(data); - }); - }, [open]); - - const handleRoleUpdate = async () => { - const res = await modifyRole(selectedRole, user.id); - console.log(res); - }; return <> -
+
diff --git a/src/components/manageMember/manageMember.module.css b/src/components/manageMember/manageMember.module.css index 6f59f30..fc250ad 100644 --- a/src/components/manageMember/manageMember.module.css +++ b/src/components/manageMember/manageMember.module.css @@ -40,4 +40,8 @@ appearance: none; -webkit-appearance: none; -moz-appearance: none; +} + +.modalContent { + text-align: center; } \ No newline at end of file diff --git a/src/components/manageMember/modifyrole/ModifyRole.jsx b/src/components/manageMember/modifyrole/ModifyRole.jsx new file mode 100644 index 0000000..11ecdf3 --- /dev/null +++ b/src/components/manageMember/modifyrole/ModifyRole.jsx @@ -0,0 +1,59 @@ +import styles from "../manageMember.module.css"; +import Button from "../../ui/button/button.jsx"; +import modifyRole from "../../../utils/users/modifyRole.js"; +import { useState, useEffect } from "react"; +import getRoles from "../../../utils/getRoles.js"; +import Modal from "../../ui/modal/modal.jsx"; + +export default function ModifyRole({ user }) { + + const [roles, setRoles] = useState([]); + const [selectedRole, setSelectedRole] = useState(3); + const [open, setOpen] = useState(false); + const [title, setTitle] = useState(""); + const [description, setDescription] = useState(""); + + useEffect(() => { + getRoles().then(data => { + if (data) setRoles(data); + }); + }, []) + + + const handleRoleUpdate = async () => { + const res = await modifyRole(selectedRole, user.id); + + if (res.success) { + setDescription("Rôle modifié avec succès"); + setTitle("Modification") + setOpen(true); + } else { + setDescription("Erreur lors de la modification du rôle"); + setTitle("Erreur") + setOpen(true); + } + }; + + + return
+ + + + + setOpen(false)} title={title}> +

{description}

+
+
+} \ No newline at end of file diff --git a/src/utils/users/modifyRole.js b/src/utils/users/modifyRole.js index e95ac3f..e0c9ae8 100644 --- a/src/utils/users/modifyRole.js +++ b/src/utils/users/modifyRole.js @@ -1,30 +1,33 @@ import getXSRFToken from "../getXSRF.js"; + export default async function modifyRole(role, userId) { - - const csrfToken = await getXSRFToken(); - try { - const res = await fetch(`${import.meta.env.VITE_API_URL}/api/users/${userId}/role`, { - method: 'POST', - credentials: 'include', - headers: { - 'Accept': 'application/json', - 'X-XSRF-TOKEN': csrfToken, - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - role: role, - }) - }); + const csrfToken = await getXSRFToken(); + + const res = await fetch( + `${import.meta.env.VITE_API_URL}/api/users/${userId}/role`, + { + method: 'POST', + credentials: 'include', + headers: { + 'Accept': 'application/json', + 'X-XSRF-TOKEN': csrfToken, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ role }), + } + ); + + const data = await res.json(); if (!res.ok) { - throw new Error(`Erreur serveur : ${res.status}`); + return { success: false, error: data.message ?? "Erreur serveur" }; } - return await res.json(); + return { success: true, data }; } catch (err) { - console.error('Erreur :', err); - return null; + console.error(err); + return { success: false, error: "Erreur réseau" }; } -} \ No newline at end of file +}