From a90d52b44bc533ee0c27a1fae66724d2a9ecafd6 Mon Sep 17 00:00:00 2001 From: p2405951 Date: Tue, 6 Jan 2026 09:32:20 +0100 Subject: [PATCH 01/39] =?UTF-8?q?r=C3=A9cup=C3=A9ration=20modifs=20dev=20s?= =?UTF-8?q?ur=20new=20branch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.exemple | 1 - .../PendingMembers/PendingMembers.jsx | 62 +++++++++++++------ src/utils/users/deleteUser.js | 22 +++++++ src/utils/users/getUserToValidate.js | 21 +++++++ src/utils/users/validateUser | 22 +++++++ 5 files changed, 107 insertions(+), 21 deletions(-) delete mode 100644 .env.exemple create mode 100644 src/utils/users/deleteUser.js create mode 100644 src/utils/users/getUserToValidate.js create mode 100644 src/utils/users/validateUser diff --git a/.env.exemple b/.env.exemple deleted file mode 100644 index 3452b5c..0000000 --- a/.env.exemple +++ /dev/null @@ -1 +0,0 @@ -VITE_API_URL= \ No newline at end of file diff --git a/src/components/PendingMembers/PendingMembers.jsx b/src/components/PendingMembers/PendingMembers.jsx index 27dace2..8b43ca1 100644 --- a/src/components/PendingMembers/PendingMembers.jsx +++ b/src/components/PendingMembers/PendingMembers.jsx @@ -1,38 +1,61 @@ -import React 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"; function pendingMembers() { - const pendingMembers = [ - { name: "Antoine Ordonneau" }, - { name: "Giovanni Josserand" }, - { name: "Quentin T'Jampens" }, - { name: "Quentin T'Jampens" }, - { name: "Quentin T'Jampens" }, - { name: "Quentin T'Jampens" }, - { name: "Quentin T'Jampens" } - ]; + const [pendingMembers, setPendingMembers] = useState([]); + const [loading, setLoading] = useState(true); - const handleValidate = (name) => { - console.log(`Valider ${name}`); + useEffect(() => { + const fetchPendingMembers = async () => { + const userIds = await getInvalidUsers(); + console.log("IDs reçus :", userIds); + + if (userIds && userIds.length > 0) { + const usersWithDetails = await Promise.all( + userIds.map(async (id) => { + const user = await getUserById(id); + console.log("Utilisateur récupéré :", user); + return user; + }) +); + + console.log("Utilisateurs avec détails :", usersWithDetails); + setPendingMembers(usersWithDetails.filter(user => user !== null)); + } + setLoading(false); + }; + fetchPendingMembers(); + }, []); + + const handleValidate = async (id) => { + console.log(`Valider l'utilisateur ID: ${id}`); + setPendingMembers(pendingMembers.filter(member => member.id !== id)); }; - const handleReject = (name) => { - console.log(`Refuser ${name}`); + 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...
; + } + return (

Membres en attente de validation

- {pendingMembers.map((member, index) => ( -
-

{member.name}

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

{member.name} {member.lastname}

- -
@@ -42,5 +65,4 @@ function pendingMembers() {
); } - export default pendingMembers; diff --git a/src/utils/users/deleteUser.js b/src/utils/users/deleteUser.js new file mode 100644 index 0000000..ff88d96 --- /dev/null +++ b/src/utils/users/deleteUser.js @@ -0,0 +1,22 @@ +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', + headers: { + 'Accept': 'application/json', + 'Content-Type': '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; + } +} diff --git a/src/utils/users/getUserToValidate.js b/src/utils/users/getUserToValidate.js new file mode 100644 index 0000000..f619c0b --- /dev/null +++ b/src/utils/users/getUserToValidate.js @@ -0,0 +1,21 @@ +export default async function getUserToValidate() { + try { + const res = await fetch(`http://${import.meta.env.VITE_API_URL}/api/users/invalid`, { + 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; + } +} \ No newline at end of file diff --git a/src/utils/users/validateUser b/src/utils/users/validateUser new file mode 100644 index 0000000..f366a2b --- /dev/null +++ b/src/utils/users/validateUser @@ -0,0 +1,22 @@ +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', + headers: { + 'Accept': 'application/json', + 'Content-Type': '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; + } +} From 101a3bc7b10670b332e4ef302bdb2ad24552d26f Mon Sep 17 00:00:00 2001 From: T'JAMPENS QUENTIN p2406187 Date: Mon, 12 Jan 2026 00:28:54 +0100 Subject: [PATCH 02/39] Change eventDetails path --- src/components/Event/Event.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Event/Event.jsx b/src/components/Event/Event.jsx index 6a75fd1..331f16c 100644 --- a/src/components/Event/Event.jsx +++ b/src/components/Event/Event.jsx @@ -73,7 +73,7 @@ function Event({event}){
{(windowSize.width <= 768 || eventMenu) ? ( - + ) : null}
From bb369c629b7f5ed84dbd66b2ebe6fa0aecade4ff Mon Sep 17 00:00:00 2001 From: T'JAMPENS QUENTIN p2406187 Date: Mon, 12 Jan 2026 00:51:57 +0100 Subject: [PATCH 03/39] Display data --- src/pages/eventDetail/eventDetail.jsx | 64 ++++++++------------ src/pages/eventDetail/eventDetail.module.css | 18 ++---- 2 files changed, 31 insertions(+), 51 deletions(-) diff --git a/src/pages/eventDetail/eventDetail.jsx b/src/pages/eventDetail/eventDetail.jsx index 4d4669a..ac3a780 100644 --- a/src/pages/eventDetail/eventDetail.jsx +++ b/src/pages/eventDetail/eventDetail.jsx @@ -1,37 +1,24 @@ -import {useState} from "react"; +import { useState, useEffect } from "react"; import styles from "./eventDetail.module.css"; import { useParams } from "react-router"; +import getEventById from "../../utils/event/getEventById.js"; +import { formatDateLetter } from "../../utils/date/formatDateLetter.js"; +import Button from "../../components/ui/button/button.jsx"; -function eventDetail() { +function EventDetail() { const params = useParams(); const id = params.id; - const [tasks, setTasks] = useState([ - { text: "Préparer les slides", registered: false }, - { text: "Réserver la salle", registered: false }, - { text: "Envoyer les invitations", registered: false }, - { text: "Tester la configuration technique", registered: false }, - { text: "Organiser le catering", registered: false }, - ]); + const [event, setEvent] = useState(null); - const event = { - title: "Conférence React 2025", - date: "27 Décembre 2025", - location: "Paris, France", - description: "azertyuiop azertyuiop azertyuiop azertyuiop azertyuiop azertyuiop azertyuiop azertyuiop azertyuiop azertyuiop azertyuiop azertyuiop" - }; - - const toggleRegister = (index) => { - setTasks((prevTasks) => - prevTasks.map((task, i) => - i === index - ? { ...task, registered: !task.registered } - : task - ) - ); - }; + useEffect(() => { + (async () => { + const e = await getEventById(id); + setEvent(e); + }) () + }, []) return (
@@ -39,25 +26,24 @@ function eventDetail() {
Illustration événement
-

{event.title}

-

Date: {event.date}

-

Lieu: {event.location}

-

Description: {event.description}

+

{event?.name}

+

{event && formatDateLetter(event.start)}

+

{event?.description}

Tâches

    - {tasks.map((task, index) => ( + {event?.tasks?.map((task, index) => (
  • -
    - {task.text} - +
    +
    + {task.name} +

    {event && formatDateLetter(task.start)} - {event && formatDateLetter(task.end)}

    +

    {task.description}

    +
    + +
  • ))} @@ -67,4 +53,4 @@ function eventDetail() { ); } -export default eventDetail; \ No newline at end of file +export default EventDetail; \ No newline at end of file diff --git a/src/pages/eventDetail/eventDetail.module.css b/src/pages/eventDetail/eventDetail.module.css index 4c81bb5..2b87392 100644 --- a/src/pages/eventDetail/eventDetail.module.css +++ b/src/pages/eventDetail/eventDetail.module.css @@ -38,24 +38,14 @@ flex-shrink: 0; } -.registerButton { - margin-left: auto; - padding: 5px 10px; - border-radius: 12px; - border: none; - cursor: pointer; - background: #019AFF; - color: white; - font-weight: 600; -} - .registerButton:hover { opacity: 0.85; } -.tasksButton { +.task { display: flex; align-items: center; + justify-content: space-between; gap: 16px; } @@ -64,6 +54,10 @@ padding: 0; } +.taskDate { + opacity: 0.5; +} + .tasks li { margin: 16px 0px 16px 0px; padding: 10px 20px 10px 20px; From 00142f1e3e545cc4f7a4623c828b21380b7cbe08 Mon Sep 17 00:00:00 2001 From: T'JAMPENS QUENTIN p2406187 Date: Mon, 12 Jan 2026 14:11:51 +0100 Subject: [PATCH 04/39] Allow user to assign to a task --- src/pages/eventDetail/eventDetail.jsx | 11 ++++++--- src/utils/tasks/assign.js | 32 +++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 src/utils/tasks/assign.js diff --git a/src/pages/eventDetail/eventDetail.jsx b/src/pages/eventDetail/eventDetail.jsx index ac3a780..5ee109d 100644 --- a/src/pages/eventDetail/eventDetail.jsx +++ b/src/pages/eventDetail/eventDetail.jsx @@ -4,6 +4,7 @@ import { useParams } from "react-router"; import getEventById from "../../utils/event/getEventById.js"; import { formatDateLetter } from "../../utils/date/formatDateLetter.js"; import Button from "../../components/ui/button/button.jsx"; +import assign from "../../utils/tasks/assign.js"; function EventDetail() { @@ -20,11 +21,16 @@ function EventDetail() { }) () }, []) + const handleRegisterBtn = async (eventId) => { + console.log(eventId); + await assign(eventId); + } + return (
    - Illustration événement + Illustration événement

    {event?.name}

    {event && formatDateLetter(event.start)}

    @@ -42,8 +48,7 @@ function EventDetail() {

    {event && formatDateLetter(task.start)} - {event && formatDateLetter(task.end)}

    {task.description}

    - - +
    ))} diff --git a/src/utils/tasks/assign.js b/src/utils/tasks/assign.js new file mode 100644 index 0000000..413dc71 --- /dev/null +++ b/src/utils/tasks/assign.js @@ -0,0 +1,32 @@ +import getXSRFToken from "../getXSRF.js"; + + +export default async function assign(taskId) { + + const csrfToken = await getXSRFToken(); + + try { + const res = await fetch(`http://${import.meta.env.VITE_API_URL}/api/events/task/assign`, { + method: 'POST', + credentials: 'include', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'X-XSRF-TOKEN': csrfToken, + }, + body: JSON.stringify({ + task_id: taskId + }), + }); + + 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; + } +} \ No newline at end of file From 8d0174e47ed28fd864a9929cbde1d373d6f648d3 Mon Sep 17 00:00:00 2001 From: T'JAMPENS QUENTIN p2406187 Date: Mon, 12 Jan 2026 14:21:13 +0100 Subject: [PATCH 05/39] Fix user is null --- src/components/SettingsModal/SettingsModal.jsx | 6 +++--- src/pages/Profile/ProfilePage.jsx | 13 +++++++------ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/components/SettingsModal/SettingsModal.jsx b/src/components/SettingsModal/SettingsModal.jsx index e39c64d..dee82e7 100644 --- a/src/components/SettingsModal/SettingsModal.jsx +++ b/src/components/SettingsModal/SettingsModal.jsx @@ -14,9 +14,9 @@ export default function SettingsModal() { const [open, setOpen] = useState(false); - const [name, setName] = useState(user.name); - const [lastname, setLastName] = useState(user.lastname); - const [phone, setPhone] = useState(user.phone); + const [name, setName] = useState(user?.name); + const [lastname, setLastName] = useState(user?.lastname); + const [phone, setPhone] = useState(user?.phone); const handleLogout = () => { logout(); diff --git a/src/pages/Profile/ProfilePage.jsx b/src/pages/Profile/ProfilePage.jsx index a47e87c..f2c54dd 100644 --- a/src/pages/Profile/ProfilePage.jsx +++ b/src/pages/Profile/ProfilePage.jsx @@ -8,6 +8,7 @@ import SettingsModal from "../../components/SettingsModal/SettingsModal.jsx"; function ProfilePage() { const { user } = useContext(AuthContext); + return (
    @@ -21,22 +22,22 @@ function ProfilePage() {
    -

    {user.name} {user.lastname}

    +

    {user?.name} {user?.lastname}

    -

    Role : {user.role}

    -

    Membre depuis : {formatDate(user.created_at)}

    +

    Role : {user?.role}

    +

    Membre depuis : {user && formatDate(user.created_at)}

    -

    Mail : {user.email}

    -

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

    +

    Mail : {user?.email}

    +

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

    Tâches :

    - {user.tasks && user.tasks.length > 0 ? ( + {user && user.tasks.length > 0 ? ( user.tasks.map((task, index) => ( )) From 00c02a4c30f6d00953308cd20bdf76405f6fb6f8 Mon Sep 17 00:00:00 2001 From: T'JAMPENS QUENTIN p2406187 Date: Mon, 12 Jan 2026 14:32:34 +0100 Subject: [PATCH 06/39] Create eventTask component --- src/components/eventTask/EventTask.jsx | 23 +++++++++++ src/components/eventTask/eventTask.module.css | 37 +++++++++++++++++ src/pages/eventDetail/eventDetail.jsx | 16 ++------ src/pages/eventDetail/eventDetail.module.css | 40 +------------------ 4 files changed, 65 insertions(+), 51 deletions(-) create mode 100644 src/components/eventTask/EventTask.jsx create mode 100644 src/components/eventTask/eventTask.module.css diff --git a/src/components/eventTask/EventTask.jsx b/src/components/eventTask/EventTask.jsx new file mode 100644 index 0000000..e6b2a32 --- /dev/null +++ b/src/components/eventTask/EventTask.jsx @@ -0,0 +1,23 @@ +import styles from "./eventTask.module.css"; +import { formatDateLetter } from "../../utils/date/formatDateLetter.js"; +import Button from "../ui/button/button.jsx"; +import assign from "../../utils/tasks/assign.js"; + +export default function EventTask({ task, index }) { + + const handleRegisterBtn = async (eventId) => { + console.log(eventId); + await assign(eventId); + } + + return
    +
    +
    + {task.name} +

    {formatDateLetter(task.start)} - {formatDateLetter(task.end)}

    +

    {task.description}

    +
    + +
    +
    +} \ No newline at end of file diff --git a/src/components/eventTask/eventTask.module.css b/src/components/eventTask/eventTask.module.css new file mode 100644 index 0000000..47fd24a --- /dev/null +++ b/src/components/eventTask/eventTask.module.css @@ -0,0 +1,37 @@ +.task { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; +} + +.taskDate { + opacity: 0.5; +} + +.content { + margin: 16px 0px 16px 0px; + padding: 10px 20px 10px 20px; + border-radius: 20px; + border: none; + background: transparent; + box-shadow: + inset 1.25px 1.25px 1px rgba(255, 255, 255, 1), + inset -1.25px -1.25px 1px rgba(255, 255, 255, 1), + inset -0.25px 0.25px 1px rgba(0, 0, 0, 0.2), + inset 0.25px -0.25px 1px rgba(0, 0, 0, 0.2); + opacity: 0; + animation: fadeInUp 0.6s ease-out forwards; + animation-delay: calc(var(--i) * 0.1s); +} + +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} \ No newline at end of file diff --git a/src/pages/eventDetail/eventDetail.jsx b/src/pages/eventDetail/eventDetail.jsx index 5ee109d..b93bdb3 100644 --- a/src/pages/eventDetail/eventDetail.jsx +++ b/src/pages/eventDetail/eventDetail.jsx @@ -5,6 +5,7 @@ import getEventById from "../../utils/event/getEventById.js"; import { formatDateLetter } from "../../utils/date/formatDateLetter.js"; import Button from "../../components/ui/button/button.jsx"; import assign from "../../utils/tasks/assign.js"; +import EventTask from "../../components/eventTask/EventTask.jsx"; function EventDetail() { @@ -39,20 +40,11 @@ function EventDetail() {

    Tâches

    -
      +
      {event?.tasks?.map((task, index) => ( -
    • -
      -
      - {task.name} -

      {event && formatDateLetter(task.start)} - {event && formatDateLetter(task.end)}

      -

      {task.description}

      -
      - -
      -
    • + ))} -
    +
    ); diff --git a/src/pages/eventDetail/eventDetail.module.css b/src/pages/eventDetail/eventDetail.module.css index 2b87392..edc436f 100644 --- a/src/pages/eventDetail/eventDetail.module.css +++ b/src/pages/eventDetail/eventDetail.module.css @@ -42,45 +42,7 @@ opacity: 0.85; } -.task { - display: flex; - align-items: center; - justify-content: space-between; - gap: 16px; -} - .tasks { list-style: none; padding: 0; -} - -.taskDate { - opacity: 0.5; -} - -.tasks li { - margin: 16px 0px 16px 0px; - padding: 10px 20px 10px 20px; - border-radius: 20px; - border: none; - background: transparent; - box-shadow: - inset 1.25px 1.25px 1px rgba(255, 255, 255, 1), - inset -1.25px -1.25px 1px rgba(255, 255, 255, 1), - inset -0.25px 0.25px 1px rgba(0, 0, 0, 0.2), - inset 0.25px -0.25px 1px rgba(0, 0, 0, 0.2); - opacity: 0; - animation: fadeInUp 0.6s ease-out forwards; - animation-delay: calc(var(--i) * 0.1s); -} - -@keyframes fadeInUp { - from { - opacity: 0; - transform: translateY(10px); - } - to { - opacity: 1; - transform: translateY(0); - } -} +} \ No newline at end of file From e38fdc11ab9210049604f93ec753b8eebc079e4a Mon Sep 17 00:00:00 2001 From: p2405951 Date: Mon, 12 Jan 2026 14:56:01 +0100 Subject: [PATCH 07/39] add responsive+ delete inline style --- .../IncompleteEvent.module.css | 4 +- .../PendingMembers/PendingMembers.jsx | 137 ++++++++++++++++-- .../PendingMembers/PendingMembers.module.css | 4 +- src/components/chart/ParticipationChart.jsx | 83 ++++++++++- .../chart/ParticipationChart.module.css | 123 +++++++++++----- src/utils/users/deleteUser.js | 24 +-- src/utils/users/validateUser | 24 +-- 7 files changed, 314 insertions(+), 85 deletions(-) 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; } From f64c105d4e1c2809bcb8056eeef86ebc8f2ad6a2 Mon Sep 17 00:00:00 2001 From: Giovanni-Josserand Date: Mon, 12 Jan 2026 14:57:32 +0100 Subject: [PATCH 08/39] add informations in footer --- src/components/Footer/Footer.jsx | 47 +++++++++++++++++-- src/components/Footer/Footer.module.css | 5 -- .../createEventBtn/CreateEventBtn.jsx | 1 + src/main.jsx | 2 + 4 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/components/Footer/Footer.jsx b/src/components/Footer/Footer.jsx index 804d6ac..551fdeb 100644 --- a/src/components/Footer/Footer.jsx +++ b/src/components/Footer/Footer.jsx @@ -1,13 +1,52 @@ import styles from "./Footer.module.css" -import {Link} from "react-router"; +import {Link, NavLink} from "react-router"; +import Button from "../ui/button/button.jsx" +import {useContext} from "react"; +import {AuthContext} from "../../contexts/auth/AuthContext.js"; function Footer(){ + const { user } = useContext(AuthContext); + return (
- Contact - RGPD - Mentions légales +
+

Contact

+ {/* TODO: les mettre dans un fichier de configuration */} +

contact@example.com

+

06 68 98 10 56

+
+ +
+ {/* TODO : mettre le nom du fichier dans un fichier de configuration aussi ou pas comme tu veux */} +

Documents

+ + + +
+
+

Liens

+ + Accueil + + + Evènements + + + Bénévoles + + {user?.isAdmin && ( + + Administration + + )} +
) diff --git a/src/components/Footer/Footer.module.css b/src/components/Footer/Footer.module.css index c78d7b9..9ff253f 100644 --- a/src/components/Footer/Footer.module.css +++ b/src/components/Footer/Footer.module.css @@ -13,11 +13,6 @@ gap: 2rem; } -.link { - color: black; - width: fit-content; - text-align: center; -} diff --git a/src/components/createEventBtn/CreateEventBtn.jsx b/src/components/createEventBtn/CreateEventBtn.jsx index fb60a1e..24a75cd 100644 --- a/src/components/createEventBtn/CreateEventBtn.jsx +++ b/src/components/createEventBtn/CreateEventBtn.jsx @@ -24,6 +24,7 @@ export default function CreateEventBtn() { } return <> + {/* TODO : faire le responsive du menu de création d'événement */} setIsOpen(false)}> diff --git a/src/main.jsx b/src/main.jsx index 6b79e8c..79f18b6 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -8,6 +8,8 @@ import { AuthProvider } from "./contexts/auth/authProvider.jsx"; createRoot(document.getElementById('root')).render( + {/* TODO: refaire l'arborescence du frontend */} + {/* TODO: refaire le docker du backend */} From 5059e51e3f4c854d9386754b351dbaa991c5db49 Mon Sep 17 00:00:00 2001 From: p2405951 Date: Mon, 12 Jan 2026 15:02:43 +0100 Subject: [PATCH 09/39] fix scrollbar --- .../chart/ParticipationChart.module.css | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/components/chart/ParticipationChart.module.css b/src/components/chart/ParticipationChart.module.css index 0da2f5c..b35dcab 100644 --- a/src/components/chart/ParticipationChart.module.css +++ b/src/components/chart/ParticipationChart.module.css @@ -167,3 +167,23 @@ font-size: 48px; } } +/* scrollbar */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: transparent; + border-radius: 10px; +} + +::-webkit-scrollbar-thumb { + background: rgba(100, 100, 100, 0.3); + border-radius: 10px; +} + +::-webkit-scrollbar-thumb:hover { + background: rgba(100, 100, 100, 0.5); +} + From f51f7fc69734c789da6f0375b1a2d4a4bd49f115 Mon Sep 17 00:00:00 2001 From: Giovanni-Josserand Date: Mon, 12 Jan 2026 15:04:04 +0100 Subject: [PATCH 10/39] add informations in footer --- src/components/Footer/Footer.jsx | 13 +++++-------- src/components/Footer/Footer.module.css | 4 ++++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/components/Footer/Footer.jsx b/src/components/Footer/Footer.jsx index 551fdeb..6140931 100644 --- a/src/components/Footer/Footer.jsx +++ b/src/components/Footer/Footer.jsx @@ -10,28 +10,25 @@ function Footer(){ return (