diff --git a/src/components/IncompleteEvent/IncompleteEvent.module.css b/src/components/IncompleteEvent/IncompleteEvent.module.css index b3f1d70..cce5be6 100644 --- a/src/components/IncompleteEvent/IncompleteEvent.module.css +++ b/src/components/IncompleteEvent/IncompleteEvent.module.css @@ -27,7 +27,7 @@ list-style-type: circle; } -.eventsContainer::-webkit-scrollbar { +/*.eventsContainer::-webkit-scrollbar { height: 8px; } @@ -43,7 +43,7 @@ .eventsContainer::-webkit-scrollbar-thumb:hover { background: rgba(30, 96, 249, 0.7); -} +}*/ .eventCard { min-width: calc((100% - 20px) / 3); diff --git a/src/components/PendingMembers/PendingMembers.jsx b/src/components/PendingMembers/PendingMembers.jsx index 8b43ca1..828a056 100644 --- a/src/components/PendingMembers/PendingMembers.jsx +++ b/src/components/PendingMembers/PendingMembers.jsx @@ -1,8 +1,10 @@ -import React, { useState, useEffect } from "react"; +/*import React, { useState, useEffect } from "react"; import Button from "../ui/button/button"; import styles from "./PendingMembers.module.css"; import getInvalidUsers from "../../utils/users/getUserToValidate"; import getUserById from "../../utils/users/getUserById"; +import validateUser from "../../utils/users/validateUser"; +import deleteUser from "../../utils/users/deleteUser"; function pendingMembers() { const [pendingMembers, setPendingMembers] = useState([]); @@ -30,15 +32,31 @@ function pendingMembers() { fetchPendingMembers(); }, []); - const handleValidate = async (id) => { - console.log(`Valider l'utilisateur ID: ${id}`); - setPendingMembers(pendingMembers.filter(member => member.id !== id)); - }; +const handleReject = async (id) => { + const res = await deleteUser(id); + + if (!res.ok) { + console.error(res.status, res.data); + alert(res.data?.message || "Action refusée"); + return; + } + + setPendingMembers(prev => prev.filter(u => u.id !== id)); +}; + +const handleValidate = async (id) => { + const res = await validateUser(id); + + if (!res.ok) { + alert(res.data?.message || "Validation refusée"); + return; + } + + setPendingMembers(prev => prev.filter(u => u.id !== id)); +}; + + - const handleReject = async (id) => { - console.log(`Refuser l'utilisateur ID: ${id}`); - setPendingMembers(pendingMembers.filter(member => member.id !== id)); - }; if (loading) { return
Chargement des membres en attente...
; @@ -65,4 +83,103 @@ function pendingMembers() { ); } -export default pendingMembers; +export default pendingMembers;*/ +import React, { useState, useEffect } from "react"; +import Button from "../ui/button/button"; +import styles from "./PendingMembers.module.css"; + +import getInvalidUsers from "../../utils/users/getUserToValidate"; +import getUserById from "../../utils/users/getUserById"; +import validateUser from "../../utils/users/validateUser"; +import deleteUser from "../../utils/users/deleteUser"; + +function PendingMembers() { + const [pendingMembers, setPendingMembers] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const fetchPendingMembers = async () => { + setLoading(true); + + const userIds = await getInvalidUsers(); + + if (userIds && userIds.length > 0) { + const users = await Promise.all( + userIds.map((id) => getUserById(id)) + ); + setPendingMembers(users.filter(Boolean)); + } else { + setPendingMembers([]); + } + + setLoading(false); + }; + + fetchPendingMembers(); + }, []); + + const handleValidate = async (id) => { + const ok = await validateUser(id); + + if (!ok) return; + + setPendingMembers((prev) => + prev.filter((member) => member.id !== id) + ); + }; + + const handleReject = async (id) => { + const ok = await deleteUser(id); + + if (!ok) return; + + setPendingMembers((prev) => + prev.filter((member) => member.id !== id) + ); + }; + + if (loading) { + return
Chargement des membres en attente...
; + } + + return ( +
+

Membres en attente de validation

+ +
+ {pendingMembers.length === 0 && ( +

Aucun membre en attente

+ )} + + {pendingMembers.map((member) => ( +
+

+ {member.name} {member.lastname} +

+ +
+ + + +
+
+ ))} +
+
+ ); +} + +export default PendingMembers; diff --git a/src/components/PendingMembers/PendingMembers.module.css b/src/components/PendingMembers/PendingMembers.module.css index 9eaef39..c87d933 100644 --- a/src/components/PendingMembers/PendingMembers.module.css +++ b/src/components/PendingMembers/PendingMembers.module.css @@ -18,7 +18,7 @@ } -.membersContainer::-webkit-scrollbar { +/*.membersContainer::-webkit-scrollbar { width: 8px; } @@ -34,7 +34,7 @@ .membersContainer::-webkit-scrollbar-thumb:hover { background: rgba(125, 249, 30, 0.7); -} +}*/ .memberCard { display: flex; diff --git a/src/components/chart/ParticipationChart.jsx b/src/components/chart/ParticipationChart.jsx index 7ebd731..cfee6da 100644 --- a/src/components/chart/ParticipationChart.jsx +++ b/src/components/chart/ParticipationChart.jsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +/*import React, { useState } from "react"; import { Doughnut } from "react-chartjs-2"; import { Chart, ArcElement } from "chart.js"; import { MenuItem, Select, FormControl } from "@mui/material"; @@ -87,4 +87,83 @@ function participationChart() { ); } -export default participationChart; +export default participationChart;*/ +import React, { useState } from "react"; +import { Doughnut } from "react-chartjs-2"; +import { Chart, ArcElement } from "chart.js"; +import { MenuItem, Select, FormControl } from "@mui/material"; +import styles from "./ParticipationChart.module.css"; + +Chart.register(ArcElement); + +function ParticipationChart() { + const [selected, setSelected] = useState("3"); + const [participationRate, setParticipationRate] = useState(78); + + const chartData = { + labels: ["Progress", "Background"], + datasets: [ + { + data: [participationRate, 100 - participationRate], + backgroundColor: ["#1e60f9ff", "#ffffffff"], + borderWidth: 0, + weight: 10, + cutout: "93%", + circumference: 360, + rotation: -90, + }, + ], + }; + + const chartOptions = { + responsive: true, + maintainAspectRatio: true, + plugins: { + legend: { display: false }, + tooltip: { enabled: false }, + }, + animation: { + animateScale: true, + animateRotate: true, + }, + }; + + return ( +
+
+
+ +
+ + + +
+
+
+
+
+ +
{participationRate}%
+
+
+
+ ); +} + +export default ParticipationChart; + diff --git a/src/components/chart/ParticipationChart.module.css b/src/components/chart/ParticipationChart.module.css index 7fa3515..0da2f5c 100644 --- a/src/components/chart/ParticipationChart.module.css +++ b/src/components/chart/ParticipationChart.module.css @@ -3,15 +3,18 @@ display: flex; flex-direction: column; align-items: center; - height: calc(100vh - 260px); - /* Exemple: calc(100vh - 60px) */ - margin-bottom: auto; + height: 100%; + min-height: calc(100vh - 260px); + box-sizing: border-box; + padding: 20px; + margin: 0; } .participationHeader { display: flex; align-items: center; width: 100%; + margin-bottom: 10px; } .partiText { @@ -27,14 +30,15 @@ .partiText label { font-size: 20px; - text-align: right; + text-align: center; transition: all 0.3s ease; + width: 100%; } - .chartContainer { - max-width: 80%; - width: 400px; + width: 80%; + max-width: 400px; height: auto; + aspect-ratio: 1/1; margin: 0 auto; position: relative; animation: slideEvent2 2s; @@ -59,12 +63,70 @@ color: #333; } +.formControl { + display: flex; + justify-content: center; + width: 100%; + margin-top: 10px; +} + +.formDesign { + margin: 0 auto; + width: fit-content; +} + +.selectRoot { + width: 100px; + height: 35px; + font-size: 19px; + border:none; +} + +.selectRoot .MuiOutlinedInput-notchedOutline { + border: none; +} + +.selectRoot .MuiSelect-select { + padding: 8px; + padding-right: 24px; +} + +.selectRoot .MuiSvgIcon-root { + font-size: 20px; +} + +.selectRoot .MuiMenu-paper { + border-radius: 7px; + width: 100px; + max-width: 100px; +} + +.selectRoot .MuiMenuItem-root { + font-size: 18px; +} + +.selectMenuPaper { + border-radius: 7px; + width: 100px; + max-width: 120px; + max-height: 300px; + overflow-y: auto; + border:none; +} + +.selectMenuItem { + font-size: 18px; + min-height: 40px; + display: flex; + align-items: center; +} + + @keyframes slideEvent2 { from { opacity: 0; transform: translateX(-20px); } - to { opacity: 1; transform: translateX(0); @@ -76,45 +138,32 @@ opacity: 0; transform: translateX(20px); } - to { opacity: 1; transform: translateX(0); } } -.formControl { - display: flex; - justify-content: center; - width: 100%; -} - -.formDesign { - margin: 0 auto; - width: fit-content; -} - @media screen and (max-width: 760px) { - .partiText { - flex-direction: column; - justify-content: center; + .leftBlock { + width: 100%; + height: auto; + min-height: auto; + margin-bottom: 20px; + } + + .chartContainer { + width: 90%; + max-width: 300px; + height: auto; + aspect-ratio: 1/1; } .partiText label { - text-align: center; + font-size: 18px; } - .leftBlock { - width: 100%; - display: flex; - flex-direction: column; - align-items: center; - height: fit-content; - margin-bottom: auto; - margin-top: 30px; + .chartPercentage { + font-size: 48px; } - .chartContainer{ - height:fit-content; - } - -} \ No newline at end of file +} diff --git a/src/utils/users/deleteUser.js b/src/utils/users/deleteUser.js index ff88d96..b8ae5b2 100644 --- a/src/utils/users/deleteUser.js +++ b/src/utils/users/deleteUser.js @@ -1,22 +1,14 @@ export default async function deleteUser(userId) { - try { - const res = await fetch(`http://${import.meta.env.VITE_API_URL}/api/users/${userId}`, { - method: 'DELETE', - credentials: 'include', + const res = await fetch( + `http://${import.meta.env.VITE_API_URL}/api/users/${userId}`, + { + method: "DELETE", + credentials: "include", headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json', + 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 lors de la suppression :', err); - return null; - } + return res.ok; } diff --git a/src/utils/users/validateUser b/src/utils/users/validateUser index f366a2b..f5611c8 100644 --- a/src/utils/users/validateUser +++ b/src/utils/users/validateUser @@ -1,22 +1,14 @@ export default async function validateUser(userId) { - try { - const res = await fetch(`http://${import.meta.env.VITE_API_URL}/api/users/${userId}/validate`, { - method: 'POST', - credentials: 'include', + const res = await fetch( + `http://${import.meta.env.VITE_API_URL}/api/users/${userId}/validate`, + { + method: "POST", + credentials: "include", headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json', + 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 lors de la validation :', err); - return null; - } + return res.ok; }