Compare commits

...
34 Commits
Author SHA1 Message Date
Giovanni dc39113335 add to my own gitea 2026-07-15 18:52:21 +02:00
Giovanni 7a4c2f5015 fix spelling mistake 2026-04-02 10:11:34 +02:00
Giovanni 76f7ed4f8d fix checkbox css 2026-04-02 00:22:04 +02:00
Giovanni c210aec76f adapt pictures for EventCards 2026-04-01 23:52:56 +02:00
Giovanni f1798c496b Merge branch 'features/header' into dev 2026-04-01 23:35:38 +02:00
Giovanni 26bfdb5cb2 Merge branch 'features/eventPhoto' into dev 2026-04-01 23:33:47 +02:00
Giovanni 6bce33e9de add eventPicture 2026-04-01 23:31:12 +02:00
p2405951 089995c84d add ProfilePicture into header when user login 2026-04-01 21:24:37 +02:00
ORDONNEAU Antoine 476f4390fe Merge branch 'dev' into fixcss/VolunteersPage 2026-04-01 18:20:25 +02:00
ORDONNEAU Antoine 483e281acd fixcss de la page Vonlontaire 2026-04-01 18:17:59 +02:00
Giovanni 57d68b43de add confirmEmailChange Page in router 2026-03-28 19:17:34 +01:00
Giovanni 0ef7cfae02 create confirmEmailChange Page 2026-03-28 19:17:27 +01:00
Giovanni dd0c139f16 create confirmEmailChange util 2026-03-28 19:17:19 +01:00
Giovanni b755e0441e create updateUserEmail util 2026-03-28 18:57:10 +01:00
Giovanni 38d2bdca74 create updateUserEmail util 2026-03-28 18:56:39 +01:00
Giovanni 5d7adadf94 add section to update user email in parameters modal 2026-03-28 18:56:24 +01:00
Giovanni d91b7a7d0f add section to update user password in parameters modal 2026-03-28 18:04:33 +01:00
Giovanni 9762c91565 create updateUserPassword util 2026-03-28 18:04:13 +01:00
Giovanni b0792d3bdc add margin to notificationCard 2026-03-28 17:27:28 +01:00
Giovanni df591c2ca1 rename content into message for notifications 2026-03-28 17:25:45 +01:00
Giovanni 60d6f067b4 rename content into message for notifications 2026-03-28 17:24:55 +01:00
Giovanni d23fd55134 rename content into message for notifications 2026-03-28 17:11:27 +01:00
Giovanni ef30e27ad7 use uuid instead of id to delete notifications 2026-03-28 17:02:08 +01:00
Giovanni 1836e66429 update user listener to use native laravel notifications 2026-03-28 15:56:43 +01:00
Giovanni 371b38f3e7 update user listener to use native laravel notifications 2026-03-28 15:56:35 +01:00
Giovanni 6fcf45d4ff delete unecessary admin listener 2026-03-28 15:56:16 +01:00
T'JAMPENS QUENTIN p2406187 d2ad9e348e Merge branch 'feat/update-assign-btn' into dev 2026-03-27 17:00:43 +01:00
T'JAMPENS QUENTIN p2406187 aa9efeff5c Improve AssignUserBtn 2026-03-27 17:00:23 +01:00
T'JAMPENS QUENTIN p2406187 678688774d Merge branch 'feat/update-task' into dev 2026-03-27 16:37:21 +01:00
T'JAMPENS QUENTIN p2406187 2c1da8e93f Create update task component 2026-03-27 16:37:03 +01:00
T'JAMPENS QUENTIN p2406187 f6208cf95d Create update task function 2026-03-27 16:36:55 +01:00
T'JAMPENS QUENTIN p2406187 31f29515fa Merge branch 'feat/update-event' into dev 2026-03-27 16:27:49 +01:00
T'JAMPENS QUENTIN p2406187 49d2a0cc22 Create update event component 2026-03-27 16:27:39 +01:00
T'JAMPENS QUENTIN p2406187 daccc0cda3 Create update event function 2026-03-27 16:27:30 +01:00
226 changed files with 685 additions and 149 deletions
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Generated Regular → Executable
View File
Regular → Executable
View File
Generated Regular → Executable
View File
Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 578 B

After

Width:  |  Height:  |  Size: 578 B

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 222 B

After

Width:  |  Height:  |  Size: 222 B

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 290 B

After

Width:  |  Height:  |  Size: 290 B

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 1009 B

After

Width:  |  Height:  |  Size: 1009 B

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 844 B

After

Width:  |  Height:  |  Size: 844 B

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 376 B

After

Width:  |  Height:  |  Size: 376 B

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 320 B

After

Width:  |  Height:  |  Size: 320 B

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 559 B

After

Width:  |  Height:  |  Size: 559 B

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 475 B

After

Width:  |  Height:  |  Size: 475 B

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 477 B

After

Width:  |  Height:  |  Size: 477 B

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File
+3 -1
View File
@@ -29,7 +29,9 @@ const Background = ({ children, className }: BackgroundProps) => {
useEffect(() => {
const updateTheme = () => {
setTheme(localStorage.getItem("theme") || "light");
const t = localStorage.getItem("theme") || "light";
setTheme(t);
document.body.classList.toggle("dark", t === "dark");
};
updateTheme();
View File
View File
Regular → Executable
View File
View File
Regular → Executable
View File
+5 -1
View File
@@ -14,7 +14,11 @@
position: relative;
justify-content: space-between;
}
.profileImg{
width:40px;
height:40px;
border-radius: 50%;
}
.activeHeaderContent {
Regular → Executable
+16 -9
View File
@@ -5,7 +5,6 @@ import getUserNotifications from "../../utils/notifications/getUserNotifications
import deleteNotificationUser from "../../utils/notifications/deleteNotificationUser.js";
import initEcho from "../../utils/echo/initEcho.js"
import readNotifications from "../../utils/notifications/readNotifications.js";
import { adminNotificationsListener } from "../../utils/echo/listeners/adminNotificationsListener";
import { userNotificationsListener } from "../../utils/echo/listeners/userNotificationsListener.js";
import NotificationCard from "../NotificationCard/NotificationCard";
import { EventContext } from "../../contexts/Events/EventContext.js";
@@ -13,6 +12,7 @@ import { AuthContext } from "../../contexts/Auth/AuthContext.js";
import { PendingMembersContext } from "../../contexts/PendingMembers/PendingMembersContext";
import Notification from "../../interfaces/notification.interface";
function Header() {
const { update, user } = useContext(AuthContext)!;
@@ -23,7 +23,9 @@ function Header() {
const [mobileMenu, setMobileMenu] = useState<boolean>(false);
const [notifications, setNotifications] = useState<Notification[]>([]);
const notificationRef = useRef<HTMLDivElement>(null);
const profileImageUrl = user?.profile_photo_path
? `${import.meta.env.VITE_API_URL}/storage/${user.profile_photo_path}`
: "/person.svg";
useEffect(() => {
if (!user) return;
@@ -35,14 +37,13 @@ function Header() {
try {
const echo = initEcho();
echoInstance = echo;
adminNotificationsListener(echo, user, setNotifications, setunreadNotification, updatePendingMembers);
userNotificationsListener(echo, user, setNotifications, setunreadNotification);
userNotificationsListener(echo, user, setNotifications, setunreadNotification, updatePendingMembers);
const notifData = await getUserNotifications();
const data: Notification[] = notifData || [];
setNotifications(data);
const hasUnread = data.some(n => n.pivot && n.pivot.unread === 1);
const hasUnread = data.some(n => n.read_at === null);
setunreadNotification(hasUnread);
} catch (err) {
console.error("Erreur initialisation Header:", err);
@@ -88,7 +89,7 @@ function Header() {
}
async function deleteNotification(notificationId: number) {
async function deleteNotification(notificationId: string) {
try {
const result = await deleteNotificationUser(notificationId);
if (result) {
@@ -132,15 +133,21 @@ function Header() {
<div className={styles.headerRightContent}>
<button
className={`${styles.bellBtn} ${notificationMenu ? styles.activeBellBtn : ""}`}
onClick={() => {toggleNotificationMenu();}}
onClick={() => { toggleNotificationMenu(); }}
>
<img className={styles.notificationsImg} src="/bell.svg" alt="notifications"/>
<img className={styles.notificationsImg} src="/bell.svg" alt="notifications" />
{unreadNotification && <span className={styles.notificationBadge}></span>}
</button>
<Link to="/profile" className={styles.profileLink}>
<img className={styles.profileImg} src="/person.svg" alt="profile"/>
<img
className={styles.profileImg}
src={profileImageUrl}
alt="profile"
/>
</Link>
</div>
</nav>
+1
View File
@@ -5,6 +5,7 @@
gap: 0.75rem;
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
transition: background 0.2s ease;
margin: 0.5rem 0;
}
.cardHeader {
+4 -4
View File
@@ -5,13 +5,13 @@ import Notification from "../../interfaces/notification.interface";
interface NotificationCardProps {
notifications: Notification[];
deleteNotification: (id: number) => void;
deleteNotification: (id: string) => void;
}
function NotificationCard({ notifications, deleteNotification }: NotificationCardProps) {
return (
notifications.map((notification, index) => (
<div className={`${styles.notificationCard} glassBorder`}key={index}>
<div className={`${styles.notificationCard} glassBorder`} key={index}>
<div className={styles.cardHeader}>
<span className={styles.timeTag}>
Le {formatDate(notification.created_at)} à {formatTime(notification.created_at)}
@@ -25,9 +25,9 @@ function NotificationCard({ notifications, deleteNotification }: NotificationCar
</button>
</div>
<div className={styles.cardContent}>
<div>
<p className={styles.message}>
{notification.content}
{notification.data.message}
</p>
</div>
</div>
View File
View File
View File
Regular → Executable
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
Regular → Executable
View File
Regular → Executable
View File
View File
View File
View File
View File
View File
View File
View File
Regular → Executable
+34 -24
View File
@@ -25,6 +25,38 @@ html {
inset 0 1px 0 rgba(255, 255, 255, 0.3),
inset 0 -1px 0 rgba(255, 255, 255, 0.05),
inset 0 0 8px 4px rgba(255, 255, 255, 0.2);
--glass-border-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);
--glass-border-back: rgba(255, 255, 255, 0.25);
}
body {
margin: 0;
display: flex;
place-items: center;
width:100%;
min-width: 320px;
min-height: 100vh;
}
body.dark {
--glass-back: rgba(160, 160, 160, 0.54);
--glass-border: rgba(160, 160, 160, 0.2);
--glass-shadow: 0 8px 32px rgba(0, 0, 0, 0.1),
inset 0 1px 0 rgba(160, 160, 160, 0.3),
inset 0 -1px 0 rgba(160, 160, 160, 0.05),
inset 0 0 8px 4px rgba(160, 160, 160, 0.2);
--glass-border-shadow:
inset 1.25px 1.25px 1px rgba(180, 180, 180, 0.6),
inset -1.25px -1.25px 1px rgba(180, 180, 180, 0.6),
inset -0.25px 0.25px 1px rgba(0, 0, 0, 0.4),
inset 0.25px -0.25px 1px rgba(0, 0, 0, 0.4);
--glass-border-back: rgba(160, 160, 160, 0.25);
}
.content {
@@ -43,24 +75,6 @@ a {
text-decoration: inherit;
}
body {
margin: 0;
display: flex;
place-items: center;
width:100%;
min-width: 320px;
min-height: 100vh;
}
body.dark {
--glass-back: rgba(191, 191, 191, 0.54);
--glass-border: rgba(191, 191, 191, 0.2);
--glass-shadow: 0 8px 32px rgba(0, 0, 0, 0.1),
inset 0 1px 0 rgba(191, 191, 191, 0.3),
inset 0 -1px 0 rgba(191, 191, 191, 0.05),
inset 0 0 8px 4px rgba(191, 191, 191, 0.2);
}
.glassCard {
padding: 10px 20px 10px 20px;
background: var(--glass-back);
@@ -75,12 +89,8 @@ body.dark {
padding: 10px 20px 10px 20px;
border-radius: 20px;
border: none;
background: rgb(255, 255, 255, 0.25);
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);
background: var(--glass-border-back);
box-shadow: var(--glass-border-shadow);
}
h1 {
Regular → Executable
View File
+7 -5
View File
@@ -1,6 +1,8 @@
export default interface Notification {
id: number;
content: string;
created_at: string | number;
pivot: { unread: number };
}
id: string;
data: {
message: string;
};
read_at: string | null;
created_at: string;
}
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
View File
Regular → Executable
View File
View File
View File
View File
View File
View File
View File
View File
@@ -0,0 +1,26 @@
.title {
color: white;
font-size: xx-large;
margin-bottom: 20px;
}
.content {
display: flex;
flex-direction: column;
z-index: 2;
padding: 10px;
}
.container {
padding: 20px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 15px;
p {
font-size: large;
white-space: pre-line;
}
}
+41
View File
@@ -0,0 +1,41 @@
import { useEffect, useState } from "react";
import { useSearchParams, useNavigate } from "react-router";
import confirmEmailChange from "../../utils/users/confirmEmailChange";
import styles from "./ConfirmEmailChangePage.module.css";
import Background from "../../components/Background/Background";
export default function ConfirmEmailChange() {
const [searchParams] = useSearchParams();
const navigate = useNavigate();
const [message, setMessage] = useState<string>('Validation en cours...');
const [success, setSuccess] = useState<boolean | null>(null);
useEffect(() => {
const token = searchParams.get('token');
if (!token) {
setMessage('Token manquant.');
setSuccess(false);
return;
}
confirmEmailChange(token)
.then(() => {
setMessage('Votre adresse email a bien été mise à jour.\nVous allez être redirigé vers la page de connexion...');
setSuccess(true);
setTimeout(() => navigate('/login'), 3000);
})
.catch(() => {
setMessage('Token invalide ou expiré.');
setSuccess(false);
});
}, []);
return <Background>
<div className={styles.content}>
<h1 className={styles.title}> Validation de votre adresse email </h1>
<div className={`${styles.container} glassCard`}>
<p>{message}</p>
</div>
</div>
</Background>
}
View File
+31 -3
View File
@@ -1,4 +1,4 @@
import { useEffect, useContext } from "react";
import {useEffect, useContext, useRef} from "react";
import styles from "./EventDetailPage.module.css";
import { useParams } from "react-router";
import { formatDateLetter } from "../../utils/date/formatDateLetter";
@@ -7,6 +7,8 @@ import { AuthContext } from "../../contexts/Auth/AuthContext";
import { EventDetailContext } from "../../contexts/EventDetail/EventDetailContext";
import CreateTaskBtn from "./components/CreateTaskBtn/CreateTaskBtn";
import DeleteEventBtn from "./components/DeleteEventBtn/DeleteEventBtn";
import EditEventBtn from "./components/EditEventBtn/EditEventBtn";
import uploadEventPhoto from "../../utils/events/uploadEventPhoto";
function EventDetailPage() {
const params = useParams();
@@ -14,21 +16,46 @@ function EventDetailPage() {
const { user } = useContext(AuthContext) as any;
const { tasks, updateEventInfo, eventInfo } = useContext(EventDetailContext) as any;
const fileInputRef = useRef<HTMLInputElement | null>(null);
const imageUrl = eventInfo?.event_photo_path
? `${import.meta.env.VITE_API_URL}/storage/${eventInfo.event_photo_path}`
: "/empty.png";
console.log(eventInfo);
useEffect(() => {
if (id) {
updateEventInfo(id);
}
}, []);
const handleImageClick = () => {
if (user?.isAdmin && fileInputRef.current) {
fileInputRef.current?.click();
}
};
const handleFileChange = async (e: any) => {
const file = e.target.files[0];
if (!file) return;
await uploadEventPhoto(Number(id), file);
updateEventInfo(id);
};
return (
<div className={styles.allContent}>
<div className={`glassCard`}>
<div className={styles.textImage}>
<img
src="/icons/theme/dark.svg"
alt="Illustration événement"
src={imageUrl}
alt="Photo événement"
className={styles.eventImage}
onClick={handleImageClick}
style={{ cursor: user?.isAdmin ? "pointer" : "default" }}
/>
<input
type="file"
ref={fileInputRef}
style={{ display: "none" }}
onChange={handleFileChange}
/>
<div className={styles.eventInfo}>
@@ -42,6 +69,7 @@ function EventDetailPage() {
{user?.isAdmin && (
<div className={styles.manageEvent}>
<EditEventBtn id={id} />
<DeleteEventBtn id={id} />
<CreateTaskBtn id={id} />
</div>
+17 -15
View File
@@ -55,19 +55,24 @@ export default function AssignUserBtn({ taskId, eventId }: AssignUserBtnProps):
})();
}, []);
const isUserAssigned = (u: User): boolean =>
u.tasks.some(t => t.id === taskId);
const [assignedIds, setAssignedIds] = useState<Set<number>>(new Set());
useEffect(() => {
setAssignedIds(new Set(
users.filter(u => u.tasks.some(t => t.id === taskId)).map(u => u.id)
));
}, [users, taskId]);
const handleAssign = async (selectedUser: User) => {
setAssignedIds(prev => new Set(prev).add(selectedUser.id));
await assignOtherUser(taskId as number, selectedUser.id);
updateEventInfo(eventId)
setOpen(false);
updateEventInfo(eventId);
};
const handleUnassign = async (selectedUser: User) => {
setAssignedIds(prev => { const next = new Set(prev); next.delete(selectedUser.id); return next; });
await unAssignOtherUser(taskId as number, selectedUser.id);
updateEventInfo(eventId)
setOpen(false);
updateEventInfo(eventId);
};
return <>
@@ -75,18 +80,15 @@ export default function AssignUserBtn({ taskId, eventId }: AssignUserBtnProps):
<Modal open={open} onClose={() => setOpen(false)} title={"Assigner un utilisateur à cette tâche"}>
<div className={styles.usersList}>
{loading ? <Loading /> : users.map((user: User, index) => (
<div key={index} className={`${styles.userCard} glassBorder`}>
<p className={styles.userName}>
{user.name} {user.lastname}
</p>
{isUserAssigned(user) ? (
<Button variant={"danger"} onClick={() => handleUnassign(user)}>
{loading ? <Loading /> : users.map((u: User) => (
<div key={u.id} className={`${styles.userCard} glassBorder`}>
<p className={styles.userName}>{u.name} {u.lastname}</p>
{assignedIds.has(u.id) ? (
<Button variant={"danger"} onClick={() => handleUnassign(u)}>
Désassigner
</Button>
) : (
<Button onClick={() => handleAssign(user)}>
<Button onClick={() => handleAssign(u)}>
Assigner
</Button>
)}
View File
View File
View File
View File
@@ -0,0 +1,92 @@
import styles from "../../EventDetailPage.module.css";
import Button from "../../../../components/ui/Button/Button";
import Modal from "../../../../components/ui/Modal/Modal";
import TextInput from "../../../../components/ui/Input/Input";
import { useContext, useState, useEffect } from "react";
import { EventDetailContext } from "../../../../contexts/EventDetail/EventDetailContext";
import updateEvent from "../../../../utils/events/updateEvent";
type EditEventBtnProps = {
id: string | number;
};
export default function EditEventBtn({ id }: EditEventBtnProps) {
const { eventInfo, updateEventInfo } = useContext(EventDetailContext) as any;
const [open, setOpen] = useState(false);
const [name, setName] = useState<string>("");
const [description, setDescription] = useState<string>("");
const [start, setStart] = useState<string>("");
const [end, setEnd] = useState<string>("");
useEffect(() => {
if (open && eventInfo) {
setName(eventInfo.name ?? "");
setDescription(eventInfo.description ?? "");
setStart(eventInfo.start ? eventInfo.start.slice(0, 16) : "");
setEnd(eventInfo.end ? eventInfo.end.slice(0, 16) : "");
}
}, [open, eventInfo]);
const handleSubmit = async () => {
const res = await updateEvent(Number(id), name, description, start, end);
await updateEventInfo(id);
setOpen(false);
};
return (
<>
<Button
variant={"default"}
className={styles.manageBtn}
onClick={() => setOpen(true)}
>
Modifier
</Button>
<Modal open={open} onClose={() => setOpen(false)} title={"Modifier l'événement"}>
<div className={styles.modalContent}>
<div>
<p>Nom</p>
<TextInput
value={name}
onChange={(e: any) => setName(e.target.value)}
placeholder="Nom de l'événement"
/>
</div>
<div>
<p>Description</p>
<TextInput
value={description}
onChange={(e: any) => setDescription(e.target.value)}
placeholder="Description"
/>
</div>
<div>
<p>Début</p>
<TextInput
type="datetime-local"
value={start}
onChange={(e: any) => setStart(e.target.value)}
/>
</div>
<div>
<p>Fin</p>
<TextInput
type="datetime-local"
value={end}
onChange={(e: any) => setEnd(e.target.value)}
/>
</div>
<Button variant="default" onClick={handleSubmit}>
Confirmer
</Button>
</div>
</Modal>
</>
);
}
@@ -0,0 +1,124 @@
import { useContext, useEffect, useState } from "react";
import { AuthContext } from "../../../../contexts/Auth/AuthContext";
import { EventDetailContext } from "../../../../contexts/EventDetail/EventDetailContext";
import Button from "../../../../components/ui/Button/Button";
import Modal from "../../../../components/ui/Modal/Modal";
import TextInput from "../../../../components/ui/Input/Input";
import styles from "../../EventDetailPage.module.css";
import updateTask from "../../../../utils/tasks/updateTask";
type EditTaskBtnProps = {
taskId: number;
eventId: number | string;
};
export default function EditTaskBtn({ taskId, eventId }: EditTaskBtnProps) {
const { user } = useContext(AuthContext) as any;
const { tasks, updateEventInfo } = useContext(EventDetailContext) as any;
const task = tasks?.find((t: any) => t.id === taskId);
const [open, setOpen] = useState(false);
const [name, setName] = useState<string>("");
const [description, setDescription] = useState<string>("");
const [start, setStart] = useState<string>("");
const [end, setEnd] = useState<string>("");
const [location, setLocation] = useState<string>("");
const [maxParticipants, setMaxParticipants] = useState<string>("");
useEffect(() => {
if (open && task) {
setName(task.name ?? "");
setDescription(task.description ?? "");
setStart(task.start ? task.start.slice(0, 16) : "");
setEnd(task.end ? task.end.slice(0, 16) : "");
setLocation(task.location ?? "");
setMaxParticipants(task.max_participants?.toString() ?? "");
}
}, [open, task]);
if (!user?.isAdmin) return null;
const handleSubmit = async () => {
await updateTask(taskId, {
name,
description,
start,
end,
location,
max_participants: Number(maxParticipants),
});
await updateEventInfo(eventId);
setOpen(false);
};
return (
<>
<Button variant={"default"} onClick={() => setOpen(true)}>
Modifier
</Button>
<Modal open={open} onClose={() => setOpen(false)} title={"Modifier la tâche"}>
<div className={styles.modalContent}>
<div>
<p>Nom</p>
<TextInput
value={name}
onChange={(e: any) => setName(e.target.value)}
placeholder="Nom de la tâche"
/>
</div>
<div>
<p>Description</p>
<TextInput
value={description}
onChange={(e: any) => setDescription(e.target.value)}
placeholder="Description"
/>
</div>
<div>
<p>Lieu</p>
<TextInput
value={location}
onChange={(e: any) => setLocation(e.target.value)}
placeholder="Lieu"
/>
</div>
<div>
<p>Participants max</p>
<TextInput
type="number"
value={maxParticipants}
onChange={(e: any) => setMaxParticipants(e.target.value)}
placeholder="Participants max"
/>
</div>
<div>
<p>Début</p>
<TextInput
type="datetime-local"
value={start}
onChange={(e: any) => setStart(e.target.value)}
/>
</div>
<div>
<p>Fin</p>
<TextInput
type="datetime-local"
value={end}
onChange={(e: any) => setEnd(e.target.value)}
/>
</div>
<Button variant="default" onClick={handleSubmit}>
Confirmer
</Button>
</div>
</Modal>
</>
);
}
View File

Some files were not shown because too many files have changed in this diff Show More