convert to TS component eventList + context
This commit is contained in:
@@ -1,3 +0,0 @@
|
||||
import { createContext } from "react";
|
||||
|
||||
export const EventContext = createContext(null);
|
||||
@@ -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<EventContextType | null>(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 <div key={eventGroup.date} className={`${styles.eventGroup} glassBorder`} onClick={() => setIsVisible(!isVisible)}>
|
||||
<div className={styles.eventTitle}>
|
||||
<p className={styles.title}>{eventGroup.name}</p>
|
||||
<p>{formatDateLetter(eventGroup.start)}</p>
|
||||
</div>
|
||||
{isVisible &&
|
||||
<ul className={styles.eventDetails}>
|
||||
{eventGroup.tasks.map((task, i) => (
|
||||
<li key={i} className={styles.eventTasks}>
|
||||
<p>- {task.name} - {task.description}</p>
|
||||
<p>{formatDateLetter(task.start)} - {formatDateLetter(task.end)}</p>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@@ -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<boolean>(false);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={eventGroup.date}
|
||||
className={`${styles.eventGroup} glassBorder`}
|
||||
onClick={() => setIsVisible(!isVisible)}
|
||||
>
|
||||
<div className={styles.eventTitle}>
|
||||
<p className={styles.title}>{eventGroup.name}</p>
|
||||
<p>{formatDateLetter(eventGroup.start)}</p>
|
||||
</div>
|
||||
|
||||
{isVisible && (
|
||||
<ul className={styles.eventDetails}>
|
||||
{eventGroup.tasks.map((task, i) => (
|
||||
<li key={i} className={styles.eventTasks}>
|
||||
<p>
|
||||
- {task.name} - {task.description}
|
||||
</p>
|
||||
<p>
|
||||
{formatDateLetter(task.start)} - {formatDateLetter(task.end)}
|
||||
</p>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/*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 <div key={eventGroup.date} className={`${styles.eventGroup} glassBorder`} onClick={() => setIsVisible(!isVisible)}>
|
||||
<div className={styles.eventTitle}>
|
||||
<p className={styles.title}>{eventGroup.name}</p>
|
||||
<p>{formatDateLetter(eventGroup.start)}</p>
|
||||
</div>
|
||||
{isVisible &&
|
||||
<ul className={styles.eventDetails}>
|
||||
{eventGroup.tasks.map((task, i) => (
|
||||
<li key={i} className={styles.eventTasks}>
|
||||
<p>- {task.name} - {task.description}</p>
|
||||
<p>{formatDateLetter(task.start)} - {formatDateLetter(task.end)}</p>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
*/
|
||||
@@ -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 (
|
||||
<div className={`${styles.glassCard} glassCard`}>
|
||||
<h2>Liste des événements à venir</h2>
|
||||
{sortedEvents.length > 0 ? (
|
||||
<div className={styles.eventList}>
|
||||
{sortedEvents.map((eventGroup, index) => (
|
||||
<EventItem eventGroup={eventGroup} key={index} />
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<p>Aucun événement planifié pour l'instant.</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default EventList;
|
||||
@@ -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 (
|
||||
<div className={`${styles.glassCard} glassCard`}>
|
||||
<h2>Liste des événements à venir</h2>
|
||||
{sortedEvents.length > 0 ? (
|
||||
<div className={styles.eventList}>
|
||||
{sortedEvents.map((eventGroup, index) => (
|
||||
<EventItem eventGroup={eventGroup} key={index} />
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<p>Aucun événement planifié pour l'instant.</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
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<EventGroup[]>(() => {
|
||||
if (!Array.isArray(events)) return [];
|
||||
|
||||
return [...events].sort(
|
||||
(a, b) =>
|
||||
new Date(a.start).getTime() - new Date(b.start).getTime()
|
||||
);
|
||||
}, [events]);
|
||||
|
||||
return (
|
||||
<div className={`${styles.glassCard} glassCard`}>
|
||||
<h2>Liste des événements à venir</h2>
|
||||
|
||||
{sortedEvents.length > 0 ? (
|
||||
<div className={styles.eventList}>
|
||||
{sortedEvents.map((eventGroup, index) => (
|
||||
<EventItem eventGroup={eventGroup} key={index} />
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<p>Aucun événement planifié pour l'instant.</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default EventList;
|
||||
@@ -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) {
|
||||
|
||||
deleteProfilePhoto();
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -154,7 +140,7 @@ function ProfilePage() {
|
||||
Modifier la photo
|
||||
</button>
|
||||
{user?.profile_photo_path && (
|
||||
<button onClick={handleDeletePicture} className={styles.deletePictureButton}>
|
||||
<button onClick={handleDeletePicture} className={styles.editPictureButton}>
|
||||
Supprimer
|
||||
</button>
|
||||
)}
|
||||
|
||||
@@ -3,21 +3,22 @@ import { useNavigate } from "react-router";
|
||||
import Button from "../../../../components/ui/button/button";
|
||||
import User from "../../interfaces/user.interface"
|
||||
|
||||
|
||||
interface VolunteersCardProps {
|
||||
user: User;
|
||||
}
|
||||
|
||||
export default function VolunteerCard({ user }: VolunteersCardProps) {
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleNavigate = (): void => { navigate(`/profile/${user.id}`) }
|
||||
|
||||
const profilePicture = user.profile_photo_path
|
||||
? `${import.meta.env.VITE_API_URL}/storage/${user.profile_photo_path}`
|
||||
: "/react.svg";
|
||||
|
||||
return (
|
||||
<div className={`glassCard ${styles.volunteerCard}`}>
|
||||
<div className={styles.header}>
|
||||
<img src={"/react.svg"} alt="profile" className={styles.profilePicture} />
|
||||
<img src={profilePicture} alt="profile" className={styles.profilePicture} />
|
||||
<p> {user.name} {user.lastname} </p>
|
||||
</div>
|
||||
<div className={styles.content}>
|
||||
|
||||
@@ -12,5 +12,6 @@ export default interface User {
|
||||
updated_at: string;
|
||||
verified_at: string | null;
|
||||
validate: number;
|
||||
profile_photo_path?: string | null;
|
||||
tasks: Task[];
|
||||
}
|
||||
@@ -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}`;
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
@@ -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" };
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user