diff --git a/src/components/Task/Task.module.css b/src/components/Task/Task.module.css index 052d0a3..b8489f6 100644 --- a/src/components/Task/Task.module.css +++ b/src/components/Task/Task.module.css @@ -2,7 +2,6 @@ width: 100%; padding: 12px; margin-bottom: 10px; - border-radius: 8px; } .content { diff --git a/src/components/Task/Task.tsx b/src/components/Task/Task.tsx index 7c939b2..daf805d 100644 --- a/src/components/Task/Task.tsx +++ b/src/components/Task/Task.tsx @@ -52,7 +52,7 @@ const Task: React.FC = ({ task }) => { }, [task.events_id]); return ( -
+

diff --git a/src/pages/Admin/components/IncompleteEvent/IncompleteEvent.jsx b/src/pages/Admin/components/IncompleteEvent/IncompleteEvent.jsx index 5548ea6..698f3b4 100644 --- a/src/pages/Admin/components/IncompleteEvent/IncompleteEvent.jsx +++ b/src/pages/Admin/components/IncompleteEvent/IncompleteEvent.jsx @@ -11,7 +11,7 @@ function IncompleteEvent() {

Derniers événements

{events.map((event) => ( -
+

{event.name}

{new Date(event.start).toLocaleDateString("fr-FR")} - {new Date(event.end).toLocaleDateString("fr-FR")} diff --git a/src/pages/Admin/components/IncompleteEvent/IncompleteEvent.module.css b/src/pages/Admin/components/IncompleteEvent/IncompleteEvent.module.css index 85849fc..e9c76d2 100644 --- a/src/pages/Admin/components/IncompleteEvent/IncompleteEvent.module.css +++ b/src/pages/Admin/components/IncompleteEvent/IncompleteEvent.module.css @@ -29,17 +29,18 @@ transform: translateX(20px); animation: slideInEvent 1s ease forwards; flex-shrink: 0; + padding: 10px; } .eventCard ul { align-items: center; - margin-left: 8%; - padding-left: 15px; + margin-left: 5%; } .eventCard ul li { text-align: left; list-style-type: circle; + list-style: none; } .eventCard > h3 { diff --git a/src/pages/Admin/components/pendingMembers/PendingMembers.jsx b/src/pages/Admin/components/pendingMembers/PendingMembers.jsx index f8280f6..6db113a 100644 --- a/src/pages/Admin/components/pendingMembers/PendingMembers.jsx +++ b/src/pages/Admin/components/pendingMembers/PendingMembers.jsx @@ -58,7 +58,7 @@ function PendingMembers() { {pendingMembers.map((member, index) => ( -

+

{member.name} {member.lastname}

diff --git a/src/pages/Home/components/Calendar/calendar.jsx b/src/pages/Home/components/Calendar/calendar.jsx index abe2fd1..faccbac 100644 --- a/src/pages/Home/components/Calendar/calendar.jsx +++ b/src/pages/Home/components/Calendar/calendar.jsx @@ -5,10 +5,11 @@ import {EventContext} from "../../../../contexts/events/EventContext.js"; import Button from "../../../../components/ui/button/button.jsx"; import {AuthContext} from "../../../../contexts/auth/AuthContext.ts"; -function Calendar() { - +function +Calendar() { const { user } = useContext(AuthContext); + const calendarUrl = `${import.meta.env.VITE_API_URL}/api/export/ics/${user.id}`; const monthNames = [ "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", @@ -18,7 +19,7 @@ function Calendar() { const today = new Date(); const [currentMonth, setCurrentMonth] = useState(today.getMonth()); - const [currentYear] = useState(today.getFullYear()); + const [currentYear, setCurrentYear] = useState(today.getFullYear()); const [selectedDay, setSelectedDay] = useState(null); const eventsByDate = useMemo(() => { @@ -67,9 +68,31 @@ function Calendar() {
- +

{monthNames[currentMonth]} {currentYear}

- +
@@ -129,15 +152,18 @@ function Calendar() { )} )} - + > + Exporter + + ); diff --git a/src/pages/Home/components/Calendar/calendar.module.css b/src/pages/Home/components/Calendar/calendar.module.css index 81f529e..b70ac34 100644 --- a/src/pages/Home/components/Calendar/calendar.module.css +++ b/src/pages/Home/components/Calendar/calendar.module.css @@ -150,10 +150,22 @@ display: none; } -.exportbtn{ +.exportbox{ + width: 100%; + padding: 15px; margin-top: 16px; + display: flex; + align-items: center; } +.exportbtn { + display: flex; + align-items: center; + max-height: 30px; +} + + + @media (max-width: 768px) { .glassCard { width: 100%; diff --git a/src/pages/Home/components/EventList/eventItem.jsx b/src/pages/Home/components/EventList/eventItem.jsx new file mode 100644 index 0000000..107dff3 --- /dev/null +++ b/src/pages/Home/components/EventList/eventItem.jsx @@ -0,0 +1,26 @@ +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/eventList.module.css b/src/pages/Home/components/EventList/eventList.module.css index fe49f9f..7a39bf7 100644 --- a/src/pages/Home/components/EventList/eventList.module.css +++ b/src/pages/Home/components/EventList/eventList.module.css @@ -68,9 +68,12 @@ h2{ } .eventTasks { - display: flex; - flex-direction: row; - justify-content: space-between; + list-style: none; + margin: 10px; +} + +.taskDate{ + font-size: 13px; } @media (max-width: 768px) { diff --git a/src/pages/Login/components/loginform/loginForm.jsx b/src/pages/Login/components/loginform/loginForm.jsx new file mode 100644 index 0000000..667b081 --- /dev/null +++ b/src/pages/Login/components/loginform/loginForm.jsx @@ -0,0 +1,52 @@ +import { useState, useContext } from "react"; +import styles from "./loginForm.module.css"; +import Button from "../../../../components/ui/button/button.tsx"; +import Input from "../../../../components/ui/input/input.tsx"; +import Modal from "../../../../components/ui/modal/modal.tsx"; +import { useNavigate } from "react-router"; +import { AuthContext } from "../../../../contexts/auth/AuthContext.js"; + + +function LoginForm({ className }) { + + const navigate = useNavigate(); + const { login } = useContext(AuthContext); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [open , setOpen] = useState(false); + + async function handleSubmit() { + const res = await login(email, password); + if (res.status === 401 || res.status === 422) setOpen(true); + else navigate("/"); + } + + return ( +
+
+ setEmail(e.target.value)} + style={{ width: '100%' }} + /> +
+
+ setPassword(e.target.value)} value={password} placeholder={"Mot de passe"} /> +
+ +
+ + +
+ + setOpen(false)}> +

L'Email ou le mot de passe est incorrect

+
+
+ ); +} + +export default LoginForm; + diff --git a/src/pages/Profile/ProfilePage.tsx b/src/pages/Profile/ProfilePage.tsx index 4035569..722f4bd 100644 --- a/src/pages/Profile/ProfilePage.tsx +++ b/src/pages/Profile/ProfilePage.tsx @@ -17,20 +17,20 @@ import deleteProfilePhoto from "../../utils/users/deleteProfilePhoto.js"; interface TaskType { - id: number; - name: string; - description: string; - location: string; - start: string; - end: string; - max_participants: number; - events_id: number; - created_at: string; - updated_at: string; - pivot: { - user_id: number; - task_id: number; - }; + id: number; + name: string; + description: string; + location: string; + start: string; + end: string; + max_participants: number; + events_id: number; + created_at: string; + updated_at: string; + pivot: { + user_id: number; + task_id: number; + }; } @@ -53,149 +53,162 @@ interface AuthContextType { } function ProfilePage() { - const navigate = useNavigate(); - const { id } = useParams(); - const { user, update } = useContext(AuthContext) as AuthContextType; - const [profileUser, setProfileUser] = useState(null); - const [profilePicture, setProfilePicture] = useState(null); - const [error, setError] = useState(null); - const [success, setSuccess] = useState(null); - const fileInputRef = useRef(null); + const navigate = useNavigate(); + const {id} = useParams(); + const {user, update} = useContext(AuthContext) as AuthContextType; + const [profileUser, setProfileUser] = useState(null); + const [profilePicture, setProfilePicture] = useState(null); + const [error, setError] = useState(null); + const [success, setSuccess] = useState(null); + const fileInputRef = useRef(null); - const isOwnProfile = !id || user?.id.toString() === id; + const isOwnProfile = !id || user?.id.toString() === id; - useEffect(() => { - (async () => { - console.log(JSON.stringify(import.meta.env.VITE_API_URL)); - if (!isOwnProfile && id) { - const res = await getUserById(id); - if (res.status === 404) { - navigate("/404"); - return; + useEffect(() => { + (async () => { + if (!isOwnProfile && id) { + const res = await getUserById(id); + if (res.status === 404) { + navigate("/404"); + return; + } + if (res.status !== 200) { + console.error("Erreur lors du chargement du profil", res); + return; + } + setProfileUser(res.data); + } else { + update(); + setProfileUser(user); + if (user?.profile_photo_path) { + setProfilePicture(`${import.meta.env.VITE_API_URL}/storage/${user.profile_photo_path}`); + } + } + })(); + }, [user, id]); + + const handleEditPictureClick = () => { + if (fileInputRef.current) { + fileInputRef.current.click(); } - if (res.status !== 200) { - console.error("Erreur lors du chargement du profil", res); - return; + }; + + // Remplacé : handleFileChange extrait vers utils/users/uploadProfilePhoto + const handleFileChange = async (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (!file) return; + + try { + const res = await uploadProfilePhoto(file); + if (res.ok) { + setProfilePicture(`${import.meta.env.VITE_API_URL}/storage/${res.data.profile_photo_path}`); + setSuccess("Photo mise à jour !"); + setError(null); + await update(); + } else { + setError(res.data?.message || res.error || "Erreur lors de l'upload."); + setSuccess(null); + } + } catch (err) { + setError("Erreur réseau."); + setSuccess(null); } - setProfileUser(res.data); - } else { - //update(); - setProfileUser(user); - if (user?.profile_photo_path) { - setProfilePicture(`${import.meta.env.VITE_API_URL}/storage/${user.profile_photo_path}`); - //setProfilePicture(`${import.meta.env.VITE_API_URL}/${user.profile_photo_path}`); + }; + + // 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); } - } - })(); - }, [user, id]); + }; - const handleEditPictureClick = () => { - if (fileInputRef.current) { - fileInputRef.current.click(); - } - }; + return ( +
+
+
+
+ Photo de profil +
- const handleFileChange = async (e: React.ChangeEvent) => { - const file = e.target.files?.[0]; - if (!file) return; + {isOwnProfile && ( +
+ + {user?.profile_photo_path && ( + + )} +
+ )} - try { - const res = await uploadProfilePhoto(file); - if (res.ok) { - setProfilePicture(`${import.meta.env.VITE_API_URL}/storage/${res.data.profile_photo_path}`); - //setProfilePicture(`${import.meta.env.VITE_API_URL}/${res.data.profile_photo_path}`); - setSuccess("Photo mise à jour !"); - setError(null); - await update(); - } else { - setError(res.data?.message || res.error || "Erreur lors de l'upload."); - setSuccess(null); - } - } catch (err) { - setError("Erreur réseau."); - setSuccess(null); - } - }; - const handleDeletePicture = async () => { - - deleteProfilePhoto(); - setProfilePicture(null); - }; + + {error &&

{error}

} + {success &&

{success}

} - return ( -
-
-
-
- Photo de profil -
+
+
+

+ {profileUser?.name} {profileUser?.lastname} +

+ {user?.isAdmin && profileUser && !isOwnProfile && ( + + )} +
- {isOwnProfile && ( -
- - {user?.profile_photo_path && ( - - )} -
- )} +
+
+

Role : {profileUser?.role}

+

Membre depuis : {profileUser && formatDate(profileUser.created_at)} +

+
- - {error &&

{error}

} - {success &&

{success}

} +
+

Mail : {profileUser?.email}

+

Téléphone : {profileUser?.phone ?? "Non renseigné"}

+
-
-
-

- {profileUser?.name} {profileUser?.lastname} -

- {user?.isAdmin && profileUser && !isOwnProfile && ( - - )} -
+ {isOwnProfile && ( +
+ +
+ )} +
-
-
-

Role : {profileUser?.role}

-

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

-
- -
-

Mail : {profileUser?.email}

-

Téléphone : {profileUser?.phone ?? "Non renseigné"}

-
- - {isOwnProfile && ( -
- +

Tâches :

+ {profileUser?.tasks.length ? ( + profileUser.tasks.map((task) =>) + ) : ( +

Aucune tâche.

+ )} +
- )}
- -

Tâches :

- {profileUser?.tasks.length ? ( - profileUser.tasks.map((task) => ) - ) : ( -

Aucune tâche.

- )} -
-
-
- ); + ); } export default ProfilePage; \ No newline at end of file