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 1/7] 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 2/7] 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 3/7] 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 4/7] 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 5/7] 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 6d155828194ac52e9e8b96f43a4a113fe436c282 Mon Sep 17 00:00:00 2001 From: T'JAMPENS QUENTIN p2406187 Date: Mon, 12 Jan 2026 15:35:22 +0100 Subject: [PATCH 6/7] Show task is assigned to user + fix assign user --- src/components/eventTask/EventTask.jsx | 53 +++++++++++++++++-- src/components/eventTask/eventTask.module.css | 4 ++ src/pages/eventDetail/eventDetail.jsx | 7 --- src/utils/tasks/assign.js | 49 +++++++++-------- src/utils/tasks/isAssigned.js | 24 +++++++++ 5 files changed, 104 insertions(+), 33 deletions(-) create mode 100644 src/utils/tasks/isAssigned.js diff --git a/src/components/eventTask/EventTask.jsx b/src/components/eventTask/EventTask.jsx index e6b2a32..a4b9eb6 100644 --- a/src/components/eventTask/EventTask.jsx +++ b/src/components/eventTask/EventTask.jsx @@ -2,14 +2,51 @@ 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"; +import { useEffect, useState } from "react"; +import isAssigned from "../../utils/tasks/isAssigned.js"; +import Modal from "../ui/modal/modal.jsx"; export default function EventTask({ task, index }) { - const handleRegisterBtn = async (eventId) => { - console.log(eventId); - await assign(eventId); + const [assigned, setAssigned] = useState(false); + const [open, setOpen] = useState(false); + const [title, setTitle] = useState(""); + const [message, setMessage] = useState(""); + + async function checkAssign() { + const data = await isAssigned(task.id); + setAssigned(data?.assigned); } + useEffect(() => { + checkAssign(); + }, []) + + const handleRegisterBtn = async () => { + const res = await assign(task.id); + checkAssign(); + + switch (res.status) { + case 200: + setTitle("Inscription réussie") + setMessage(`Vous êtes maintenant inscrit à la tâche ${task.name}`); + setOpen(true); + break; + + case 409: + setTitle("Erreur lors de l'inscription") + setMessage("Vous êtes déjà inscrit à cette tâche") + setOpen(true); + break; + + case 403: + setTitle("Erreur lors de l'inscription") + setMessage("Le nombre maximum d'inscription pour cette tâche à été atteint") + setOpen(true); + break; + } + }; + return
    @@ -17,7 +54,15 @@ export default function EventTask({ task, index }) {

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

    {task.description}

    - + {assigned ? + + : + + }
    + + +

    {message}

    +
    } \ No newline at end of file diff --git a/src/components/eventTask/eventTask.module.css b/src/components/eventTask/eventTask.module.css index 47fd24a..10d2fa7 100644 --- a/src/components/eventTask/eventTask.module.css +++ b/src/components/eventTask/eventTask.module.css @@ -25,6 +25,10 @@ animation-delay: calc(var(--i) * 0.1s); } +.modalContent { + text-align: center; +} + @keyframes fadeInUp { from { opacity: 0; diff --git a/src/pages/eventDetail/eventDetail.jsx b/src/pages/eventDetail/eventDetail.jsx index b93bdb3..acaddaa 100644 --- a/src/pages/eventDetail/eventDetail.jsx +++ b/src/pages/eventDetail/eventDetail.jsx @@ -3,8 +3,6 @@ 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"; -import assign from "../../utils/tasks/assign.js"; import EventTask from "../../components/eventTask/EventTask.jsx"; @@ -22,11 +20,6 @@ function EventDetail() { }) () }, []) - const handleRegisterBtn = async (eventId) => { - console.log(eventId); - await assign(eventId); - } - return (
    diff --git a/src/utils/tasks/assign.js b/src/utils/tasks/assign.js index 413dc71..88f1ba8 100644 --- a/src/utils/tasks/assign.js +++ b/src/utils/tasks/assign.js @@ -1,32 +1,37 @@ 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 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 + }), + } + ); const data = await res.json(); - return data; + + return { + status: res.status, + message: data?.message ?? null, + }; + } catch (err) { - console.error('Erreur :', err); - return null; + console.error("❌ Erreur réseau :", err); + return { + status: 0, + message: "Network error", + }; } -} \ No newline at end of file +} diff --git a/src/utils/tasks/isAssigned.js b/src/utils/tasks/isAssigned.js new file mode 100644 index 0000000..3b938a1 --- /dev/null +++ b/src/utils/tasks/isAssigned.js @@ -0,0 +1,24 @@ +export default async function isAssigned(taskId) { + try { + const res = await fetch( + `http://${import.meta.env.VITE_API_URL}/api/events/tasks/${taskId}/assigned`, + { + method: 'GET', + credentials: 'include', + headers: { + 'Accept': 'application/json', + }, + } + ); + + if (!res.ok) { + throw new Error(`Erreur serveur : ${res.status}`); + } + + return await res.json(); + + } catch (err) { + console.error('Erreur :', err); + return null; + } +} From 6165978ef391ba9562cc5e1c405835c5e70a8b7e Mon Sep 17 00:00:00 2001 From: T'JAMPENS QUENTIN p2406187 Date: Mon, 12 Jan 2026 15:50:48 +0100 Subject: [PATCH 7/7] Add unassign btn --- src/components/eventTask/EventTask.jsx | 26 +++++++++++++++--- src/utils/tasks/unAssign.js | 37 ++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 src/utils/tasks/unAssign.js diff --git a/src/components/eventTask/EventTask.jsx b/src/components/eventTask/EventTask.jsx index a4b9eb6..fd75379 100644 --- a/src/components/eventTask/EventTask.jsx +++ b/src/components/eventTask/EventTask.jsx @@ -2,6 +2,7 @@ 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"; +import unAssign from "../../utils/tasks/unAssign.js"; import { useEffect, useState } from "react"; import isAssigned from "../../utils/tasks/isAssigned.js"; import Modal from "../ui/modal/modal.jsx"; @@ -24,13 +25,13 @@ export default function EventTask({ task, index }) { const handleRegisterBtn = async () => { const res = await assign(task.id); - checkAssign(); switch (res.status) { case 200: setTitle("Inscription réussie") setMessage(`Vous êtes maintenant inscrit à la tâche ${task.name}`); setOpen(true); + setAssigned(true); break; case 409: @@ -47,6 +48,25 @@ export default function EventTask({ task, index }) { } }; + const handleUnassign = async () => { + const res = await unAssign(task.id); + + switch (res.status) { + case 200: + setTitle("Désinscription réussie") + setMessage(`Vous n'êtes plus inscrit à la tâche ${task.name}`); + setOpen(true); + setAssigned(false); + break; + + case 409: + setTitle("Erreur lors de la désinscription") + setMessage(`Vous n'êtes pas inscrit à cette tâche`); + setOpen(true); + break; + } + }; + return
    @@ -55,9 +75,9 @@ export default function EventTask({ task, index }) {

    {task.description}

    {assigned ? - + : - + }
    diff --git a/src/utils/tasks/unAssign.js b/src/utils/tasks/unAssign.js new file mode 100644 index 0000000..509ec82 --- /dev/null +++ b/src/utils/tasks/unAssign.js @@ -0,0 +1,37 @@ +import getXSRFToken from "../getXSRF.js"; + +export default async function unAssign(taskId) { + const csrfToken = await getXSRFToken(); + + try { + const res = await fetch( + `http://${import.meta.env.VITE_API_URL}/api/events/task/unassign`, + { + method: 'POST', + credentials: 'include', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'X-XSRF-TOKEN': csrfToken, + }, + body: JSON.stringify({ + task_id: taskId + }), + } + ); + + const data = await res.json(); + + return { + status: res.status, + message: data?.message ?? null, + }; + + } catch (err) { + console.error("❌ Erreur réseau :", err); + return { + status: 0, + message: "Network error", + }; + } +}