From e259f5f93f99b143e12f3faf521d6a8f68fac243 Mon Sep 17 00:00:00 2001 From: p2405951 Date: Thu, 12 Mar 2026 10:45:52 +0100 Subject: [PATCH] convert to TS component eventList + context --- src/contexts/events/EventContext.js | 3 - src/contexts/events/EventContext.ts | 26 ++++++ .../Home/components/EventList/eventItem.jsx | 25 ------ .../Home/components/EventList/eventItem.tsx | 80 +++++++++++++++++ .../Home/components/EventList/eventList.jsx | 35 -------- .../Home/components/EventList/eventList.tsx | 88 +++++++++++++++++++ src/pages/Profile/ProfilePage.tsx | 22 +---- .../VolunteersCard/VolunteerCard.tsx | 37 ++++---- .../Volunteers/interfaces/user.interface.ts | 1 + src/utils/date/formatDateLetter.ts | 4 +- src/utils/users/deleteProfilePhoto.ts | 22 ++++- 11 files changed, 238 insertions(+), 105 deletions(-) delete mode 100644 src/contexts/events/EventContext.js create mode 100644 src/contexts/events/EventContext.ts delete mode 100644 src/pages/Home/components/EventList/eventItem.jsx create mode 100644 src/pages/Home/components/EventList/eventItem.tsx delete mode 100644 src/pages/Home/components/EventList/eventList.jsx create mode 100644 src/pages/Home/components/EventList/eventList.tsx diff --git a/src/contexts/events/EventContext.js b/src/contexts/events/EventContext.js deleted file mode 100644 index 24d62c2..0000000 --- a/src/contexts/events/EventContext.js +++ /dev/null @@ -1,3 +0,0 @@ -import { createContext } from "react"; - -export const EventContext = createContext(null); \ No newline at end of file diff --git a/src/contexts/events/EventContext.ts b/src/contexts/events/EventContext.ts new file mode 100644 index 0000000..f3c7792 --- /dev/null +++ b/src/contexts/events/EventContext.ts @@ -0,0 +1,26 @@ +/*import { createContext } from "react"; + +export const EventContext = createContext(null);*/ + + +import { createContext } from "react"; + +export type Task = { + name: string; + description: string; + start: string | Date; + end: string | Date; +}; + +export type EventGroup = { + date: string; + name: string; + start: string | Date; + tasks: Task[]; +}; + +export type EventContextType = { + events: EventGroup[]; +}; + +export const EventContext = createContext(null); \ No newline at end of file diff --git a/src/pages/Home/components/EventList/eventItem.jsx b/src/pages/Home/components/EventList/eventItem.jsx deleted file mode 100644 index a65f3ee..0000000 --- a/src/pages/Home/components/EventList/eventItem.jsx +++ /dev/null @@ -1,25 +0,0 @@ -import styles from "./eventList.module.css"; -import { formatDateLetter } from "../../../../utils/date/formatDateLetter.js"; -import { useState } from "react"; - -export default function EventItem({ eventGroup }) { - - const [isVisible, setIsVisible] = useState(false); - - return
setIsVisible(!isVisible)}> -
-

{eventGroup.name}

-

{formatDateLetter(eventGroup.start)}

-
- {isVisible && -
    - {eventGroup.tasks.map((task, i) => ( -
  • -

    - {task.name} - {task.description}

    -

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

    -
  • - ))} -
- } -
-} \ No newline at end of file diff --git a/src/pages/Home/components/EventList/eventItem.tsx b/src/pages/Home/components/EventList/eventItem.tsx new file mode 100644 index 0000000..9cd3de9 --- /dev/null +++ b/src/pages/Home/components/EventList/eventItem.tsx @@ -0,0 +1,80 @@ +import styles from "./eventList.module.css"; +import { formatDateLetter } from "../../../../utils/date/formatDateLetter"; +import { useState } from "react"; + +type Task = { + name: string; + description: string; + start: string | Date; + end: string | Date; +}; + +type EventGroup = { + date: string; + name: string; + start: string | Date; + tasks: Task[]; +}; + +type EventItemProps = { + eventGroup: EventGroup; +}; + +export default function EventItem({ eventGroup }: EventItemProps) { + const [isVisible, setIsVisible] = useState(false); + + return ( +
setIsVisible(!isVisible)} + > +
+

{eventGroup.name}

+

{formatDateLetter(eventGroup.start)}

+
+ + {isVisible && ( +
    + {eventGroup.tasks.map((task, i) => ( +
  • +

    + - {task.name} - {task.description} +

    +

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

    +
  • + ))} +
+ )} +
+ ); +} + +/*import styles from "./eventList.module.css"; +import { formatDateLetter } from "../../../../utils/date/formatDateLetter.ts"; +import { useState } from "react"; + +export default function EventItem({ eventGroup }) { + + const [isVisible, setIsVisible] = useState(false); + + return
setIsVisible(!isVisible)}> +
+

{eventGroup.name}

+

{formatDateLetter(eventGroup.start)}

+
+ {isVisible && +
    + {eventGroup.tasks.map((task, i) => ( +
  • +

    - {task.name} - {task.description}

    +

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

    +
  • + ))} +
+ } +
+} +*/ \ No newline at end of file diff --git a/src/pages/Home/components/EventList/eventList.jsx b/src/pages/Home/components/EventList/eventList.jsx deleted file mode 100644 index 9ab2321..0000000 --- a/src/pages/Home/components/EventList/eventList.jsx +++ /dev/null @@ -1,35 +0,0 @@ -import { useMemo } from "react"; -import styles from "./eventList.module.css"; -import EventItem from "./eventItem.jsx"; -import { EventContext } from "../../../../contexts/events/EventContext.js"; -import { useContext } from "react"; - -function EventList() { - // Utilise une valeur par défaut pour `events` si elle est `undefined` - const { events = [] } = useContext(EventContext); - - const sortedEvents = useMemo(() => { - // Vérifie explicitement que `events` est un tableau avant de trier - if (!Array.isArray(events)) return []; - return [...events].sort( - (a, b) => new Date(a.start) - new Date(b.start) - ); - }, [events]); - - return ( -
-

Liste des événements à venir

- {sortedEvents.length > 0 ? ( -
- {sortedEvents.map((eventGroup, index) => ( - - ))} -
- ) : ( -

Aucun événement planifié pour l'instant.

- )} -
- ); -} - -export default EventList; diff --git a/src/pages/Home/components/EventList/eventList.tsx b/src/pages/Home/components/EventList/eventList.tsx new file mode 100644 index 0000000..0fd09ee --- /dev/null +++ b/src/pages/Home/components/EventList/eventList.tsx @@ -0,0 +1,88 @@ +/*import { useMemo } from "react"; +import styles from "./eventList.module.css"; +import EventItem from "./eventItem.jsx"; +import { EventContext } from "../../../../contexts/events/EventContext.js"; +import { useContext } from "react"; + +function EventList() { + // Utilise une valeur par défaut pour `events` si elle est `undefined` + const { events = [] } = useContext(EventContext); + + const sortedEvents = useMemo(() => { + // Vérifie explicitement que `events` est un tableau avant de trier + if (!Array.isArray(events)) return []; + return [...events].sort( + (a, b) => new Date(a.start) - new Date(b.start) + ); + }, [events]); + + return ( +
+

Liste des événements à venir

+ {sortedEvents.length > 0 ? ( +
+ {sortedEvents.map((eventGroup, index) => ( + + ))} +
+ ) : ( +

Aucun événement planifié pour l'instant.

+ )} +
+ ); +} + +export default EventList;*/ +import { useMemo, useContext } from "react"; +import styles from "./eventList.module.css"; +import EventItem from "./eventItem"; +import { EventContext } from "../../../../contexts/events/EventContext"; + +type Task = { + name: string; + description: string; + start: string | Date; + end: string | Date; +}; + +type EventGroup = { + date: string; + name: string; + start: string | Date; + tasks: Task[]; +}; + +type EventContextType = { + events?: EventGroup[]; +}; + +function EventList() { + const { events = [] } = useContext(EventContext) as EventContextType; + + const sortedEvents = useMemo(() => { + if (!Array.isArray(events)) return []; + + return [...events].sort( + (a, b) => + new Date(a.start).getTime() - new Date(b.start).getTime() + ); + }, [events]); + + return ( +
+

Liste des événements à venir

+ + {sortedEvents.length > 0 ? ( +
+ {sortedEvents.map((eventGroup, index) => ( + + ))} +
+ ) : ( +

Aucun événement planifié pour l'instant.

+ )} +
+ ); +} + +export default EventList; \ No newline at end of file diff --git a/src/pages/Profile/ProfilePage.tsx b/src/pages/Profile/ProfilePage.tsx index 3fe6461..4035569 100644 --- a/src/pages/Profile/ProfilePage.tsx +++ b/src/pages/Profile/ProfilePage.tsx @@ -116,24 +116,10 @@ function ProfilePage() { setSuccess(null); } }; - - // Remplacé : handleDeletePicture extrait vers utils/users/deleteProfilePhoto const handleDeletePicture = async () => { - try { - const res = await deleteProfilePhoto(); - if (res.status >= 200 && res.status < 300) { - setProfilePicture(null); - setSuccess("Photo supprimée !"); - setError(null); - await update(); - } else { - setError(res.data?.message || "Erreur lors de la suppression."); - setSuccess(null); - } - } catch (err) { - setError("Erreur réseau."); - setSuccess(null); - } + + deleteProfilePhoto(); + setProfilePicture(null); }; return ( @@ -154,7 +140,7 @@ function ProfilePage() { Modifier la photo {user?.profile_photo_path && ( - )} diff --git a/src/pages/Volunteers/components/VolunteersCard/VolunteerCard.tsx b/src/pages/Volunteers/components/VolunteersCard/VolunteerCard.tsx index a3d5f01..5d3c2e8 100644 --- a/src/pages/Volunteers/components/VolunteersCard/VolunteerCard.tsx +++ b/src/pages/Volunteers/components/VolunteersCard/VolunteerCard.tsx @@ -3,27 +3,28 @@ import { useNavigate } from "react-router"; import Button from "../../../../components/ui/button/button"; import User from "../../interfaces/user.interface" - interface VolunteersCardProps { - user: User; + user: User; } export default function VolunteerCard({ user }: VolunteersCardProps) { + const navigate = useNavigate(); + const handleNavigate = (): void => { navigate(`/profile/${user.id}`) } - const navigate = useNavigate(); + const profilePicture = user.profile_photo_path + ? `${import.meta.env.VITE_API_URL}/storage/${user.profile_photo_path}` + : "/react.svg"; - const handleNavigate = (): void => { navigate(`/profile/${user.id}`) } - - return ( -
-
- profile -

{user.name} {user.lastname}

-
-
-

{user.email}

- -
-
- ); -} + return ( +
+
+ profile +

{user.name} {user.lastname}

+
+
+

{user.email}

+ +
+
+ ); +} \ No newline at end of file diff --git a/src/pages/Volunteers/interfaces/user.interface.ts b/src/pages/Volunteers/interfaces/user.interface.ts index e22a1cd..ce9065a 100644 --- a/src/pages/Volunteers/interfaces/user.interface.ts +++ b/src/pages/Volunteers/interfaces/user.interface.ts @@ -12,5 +12,6 @@ export default interface User { updated_at: string; verified_at: string | null; validate: number; + profile_photo_path?: string | null; tasks: Task[]; } \ No newline at end of file diff --git a/src/utils/date/formatDateLetter.ts b/src/utils/date/formatDateLetter.ts index f4c3f91..c0ee46f 100644 --- a/src/utils/date/formatDateLetter.ts +++ b/src/utils/date/formatDateLetter.ts @@ -51,7 +51,7 @@ export function formatDateLetter(d: string | Date | null | undefined): string { } -export function formatDateLetterJS(d: string): string { +/*export function formatDateLetterJS(d: string): string { const monthNames = [ "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre" @@ -61,5 +61,5 @@ export function formatDateLetterJS(d: string): string { if (!year || !month || !day) return "Date invalide"; return `${day} ${monthNames[parseInt(month, 10) - 1]} ${year}`; -} +}*/ diff --git a/src/utils/users/deleteProfilePhoto.ts b/src/utils/users/deleteProfilePhoto.ts index d0ca642..a5e830f 100644 --- a/src/utils/users/deleteProfilePhoto.ts +++ b/src/utils/users/deleteProfilePhoto.ts @@ -1,10 +1,24 @@ -import fetchWrapper from "../fetchWrapper"; +import getXSRFToken from "../getXSRF.js"; export default async function deleteProfilePhoto(): Promise<{ status: number; ok: boolean; data?: any; error?: string }> { try { - const response = await fetchWrapper("/api/profile-photo", null, "DELETE"); - return { status: response.status || 0, ok: response.status >= 200 && response.status < 300, data: response.data }; + const csrfToken = await getXSRFToken(); + const response = await fetch(`${import.meta.env.VITE_API_URL}/api/profile-photo`, { + method: "DELETE", + headers: { "X-XSRF-TOKEN": decodeURIComponent(csrfToken) }, + credentials: "include", + }); + + const status = response.status; + let data = null; + try { + data = await response.json(); + } catch (e) { + // Pas de JSON dans la réponse + } + + return { status, ok: response.ok, data }; } catch (err: any) { - return { status: 0, ok: false, error: err?.message || "Network error" }; + return { status: 0, ok: false, error: err?.message || "Erreur réseau" }; } }