+
+
+
+
+
+
{monthNames[currentMonth]} {currentYear}
+
+
+
+
+
+
+ | Lun |
+ Mar |
+ Mer |
+ Jeu |
+ Ven |
+ Sam |
+ Dim |
+
+
+
+
+ {Array.from({ length: Math.ceil(days.length / 7) }).map((_, weekIndex) => (
+
+ {days.slice(weekIndex * 7, weekIndex * 7 + 7).map((day, index) => {
+ const key = `${currentYear}-${String(currentMonth + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
+ const hasEvent = events[key];
+
+ return (
+ | handleDayClick(day)}
+ >
+ {day || ""}
+ |
+ );
+ })}
+
+ ))}
+
+
+
+ {selectedDay && (
+
+
Événements du {formatDate(selectedDay.date)}
+
+ {selectedDay.events.length > 0 ? (
+
+ {selectedDay.events.map((ev, i) => (
+ - {ev}
+ ))}
+
+ ) : (
+
Aucun événement ce jour-là.
+ )}
+
+ )}
+
+
+
+
+
Liste des Événements à Venir
+ {sortedEvents.length > 0 ? (
+
+ ) : (
+
Aucun événement planifié pour l'instant.
+ )}
+
+
- )
+ );
}
export default HomePage;
\ No newline at end of file
diff --git a/src/pages/Home/HomePage.module.css b/src/pages/Home/HomePage.module.css
index e83a063..7d6a67a 100644
--- a/src/pages/Home/HomePage.module.css
+++ b/src/pages/Home/HomePage.module.css
@@ -1,3 +1,173 @@
-.title {
- color: red;
+.calendarContainer {
+ padding: 20px;
+ font-family: Arial, sans-serif;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.calendarHeader {
+ display: flex;
+ width: 100%;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ gap: 10px;
+}
+
+.calendarHeader p {
+ width: auto;
+ text-align: center;
+ font-weight: bold;
+ font-size: 40px;
+}
+
+.calendarHeader button {
+ top: 50%;
+ left: 50%;
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+ 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);
+ font-size: 15px;
+ color: #019AFF;
+ cursor: pointer;
+}
+
+.calendar {
+ border-collapse: collapse;
+ width: 80%;
+ max-width: 500px;
+}
+
+.calendar th, .calendar td {
+ border: none;
+ padding: 10px;
+ width: 14.2%;
+ line-height: 130%;
+ text-align: center;
+ cursor: pointer;
+}
+
+.today {
+ color: #007bff;
+}
+
+.hasEvent {
+ position: relative;
+}
+
+.hasEvent::before {
+ content: "";
+ position: absolute;
+ left: 50%;
+ bottom: 10px;
+ width: 20px;
+ height: 2px;
+ background-color: #007bff;
+ transform: translateX(-50%);
+ border-radius: 10px;
+}
+
+.hasEvent.selected::before {
+ width: 25px;
+ height: 2px;
+ bottom: 10px;
+}
+
+.selected {
+ position: relative;
+ font-size: 18px;
+ font-weight: 600;
+}
+
+.selected::after {
+ content: "";
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 40px;
+ height: 40px;
+ transform: translate(-50%, -50%);
+ border-radius: 38%;
+ pointer-events: 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);
+}
+
+.eventBox {
+ border-radius: 20px;
+ padding: 15px;
+ margin-top: 16px;
+ 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);
+}
+
+.eventBox ul {
+ list-style-type: disc;
+}
+
+.eventGroup{
+ border-radius: 20px;
+ padding: 15px;
+ margin-top: 16px;
+ 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);
+}
+
+.glassCard {
+ width: 45%;
+ margin: 16px;
+ padding: 10px 20px 10px 20px;
+ height: fit-content;
+ background: rgba(255, 255, 255, 0.65);
+ backdrop-filter: blur(3px);
+ -webkit-backdrop-filter: blur(3px);
+ border-radius: 20px;
+ border: 1px solid rgba(255, 255, 255, 0.3);
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1),
+ inset 0 1px 0 rgba(255, 255, 255, 0.5),
+ inset 0 -1px 0 rgba(255, 255, 255, 0.1),
+ inset 0 0 8px 4px rgba(255, 255, 255, 0.4);
+ overflow: hidden;
+}
+.allContent{
+ display: flex;
+ flex-direction: row;
+}
+
+@media (max-width: 768px) {
+ .glassCard {
+ width: 100%;
+ margin: 0px;
+ margin-top: 16px;
+ margin-bottom: 16px;
+ display: flex;
+ }
+
+
+ .allContent{
+ display: flex;
+ flex-direction: column;
+ }
}
\ No newline at end of file
diff --git a/src/pages/Login/LoginPage.jsx b/src/pages/Login/LoginPage.jsx
index 93154f4..79af77a 100644
--- a/src/pages/Login/LoginPage.jsx
+++ b/src/pages/Login/LoginPage.jsx
@@ -1,8 +1,21 @@
import styles from "./LoginPage.module.css";
import LoginForm from "../../components/loginform/loginForm.jsx";
import Background from "../../components/background/background.jsx";
+import { useEffect, useContext } from "react";
+import { AuthContext } from "../../contexts/auth/AuthContext.js";
+import { useNavigate } from "react-router";
function LoginPage() {
+
+ const { user, loading } = useContext(AuthContext)
+ const navigate = useNavigate();
+
+ useEffect(() => {
+ if (!loading && user) {
+ navigate("/");
+ }
+ }, [loading, user]);
+
return (
diff --git a/src/pages/Profile/ProfilePage.jsx b/src/pages/Profile/ProfilePage.jsx
index 0271d42..aaa1338 100644
--- a/src/pages/Profile/ProfilePage.jsx
+++ b/src/pages/Profile/ProfilePage.jsx
@@ -3,18 +3,11 @@ import styles from "./ProfilePage.module.css";
import { AuthContext } from "../../contexts/auth/AuthContext.js";
import formatDate from "../../utils/date/formatDate.js";
import Task from "../../components/Task/Task";
-import Button from "../../components/ui/button/button.jsx";
-import { useNavigate } from "react-router";
-import ThemeSwitcher from "../../components/ui/themeSwitcher/ThemeSwitcher.jsx";
+import SettingsModal from "../../components/SettingsModal/SettingsModal.jsx";
function ProfilePage() {
- const { user, logout } = useContext(AuthContext);
- const navigate = useNavigate();
-
- const handleLogout = () => {
- logout();
- }
+ const { user } = useContext(AuthContext);
return (
@@ -30,10 +23,6 @@ function ProfilePage() {
{user.name} {user.lastname}
-
-
-
-
@@ -44,9 +33,7 @@ function ProfilePage() {
Mail : {user.email}
Téléphone : {user.phone}
-
+
Vos Événements :
diff --git a/src/pages/Profile/ProfilePage.module.css b/src/pages/Profile/ProfilePage.module.css
index e4e467b..1e7913f 100644
--- a/src/pages/Profile/ProfilePage.module.css
+++ b/src/pages/Profile/ProfilePage.module.css
@@ -38,10 +38,11 @@
}
.topDescription {
- display: flex;
- flex-direction: column;
- gap: 10px;
- margin-bottom: 15px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 10px;
+ margin-bottom: 15px;
}
.infoBlock {
@@ -122,11 +123,6 @@
}
-.modifyIcon {
- height:50px;
- width:50px;
-}
-
.headerProfile {
display: flex;
flex-direction: row;
diff --git a/src/pages/Register/RegisterPage.jsx b/src/pages/Register/RegisterPage.jsx
index cac9e4d..2046c9a 100644
--- a/src/pages/Register/RegisterPage.jsx
+++ b/src/pages/Register/RegisterPage.jsx
@@ -2,9 +2,11 @@ import styles from "./RegisterPage.module.css";
import Background from "../../components/background/background.jsx";
import Input from "../../components/ui/input/input.jsx";
import Button from "../../components/ui/button/button.jsx";
-import { useState } from "react";
+import {useContext, useEffect, useState} from "react";
import register from "../../utils/register.js";
import { useNavigate } from "react-router";
+import { AuthContext } from "../../contexts/auth/AuthContext.js";
+import Modal from "../../components/ui/modal/modal.jsx";
function RegisterPage() {
@@ -12,20 +14,54 @@ function RegisterPage() {
const navigate = useNavigate();
const [email, setEmail] = useState("");
+ const [phone, setPhone] = useState("");
const [password, setPassword] = useState("");
+ const [confirmPassword, setConfirmPassword] = useState("");
const [name, setName] = useState("");
const [lastName, setLastName] = useState("");
+ const [open, setOpen] = useState(false);
+ const [title, setTitle] = useState("");
+ const [message, setMessage] = useState("");
- const [showPassword, setShowPassword] = useState(false);
+ const { user, loading } = useContext(AuthContext)
+ useEffect(() => {
+ if (!loading && user) {
+ navigate("/");
+ }
+ }, [loading, user]);
+
+ const handleModal = (t, m) => {
+ setTitle(t)
+ setMessage(m)
+ setOpen(true);
+ }
async function handleSubmit(e) {
e.preventDefault();
- const res = await register(email, password, name, lastName);
- if (!res || res.status !== 200) throw new Error("Register error");
- navigate("/login");
+
+ if(!(password === confirmPassword)) handleModal("Mot de passe invalide", "Les mots de passes ne conrrespondent pas");
+ else if(password.length < 8) handleModal("Mot de passe invalide", "Le mot de passe doit faire plus de 8 charactères");
+ else {
+
+ const res = await register(email, password, name, lastName, phone);
+
+ if (res.status === 422) {
+ if (res.errors.email) handleModal("Adresse Email invalide", "Le formet de votre adresse Email n'est pas valide");
+ if (res.errors.phone) handleModal("Numéro de téléphone invalide", "Le formet de votre numéro de téléphone n'est pas valide");
+ } else navigate("/login");
+
+ }
}
+ const handlePhone = (e) => {
+ const value = e.target.value;
+ if (value === "" || /^[0-9 +]+$/.test(value)) {
+ setPhone(value);
+ }
+ };
+
+
return
@@ -61,8 +97,22 @@ function RegisterPage() {
style={{ width: '100%' }}
/>
+
- setPassword(e.target.value)} value={password} />
+
+
+
+
+ setPassword(e.target.value)} value={password} placeholder={"Mot de passe"}/>
+
+
+
+ setConfirmPassword(e.target.value)} value={confirmPassword} placeholder={"Confirmer le mot de passe"} />
@@ -72,6 +122,10 @@ function RegisterPage() {
+
setOpen(false)} title={title}>
+ {message}
+
+
}
diff --git a/src/pages/Volunteers/VolunteerCard.jsx b/src/pages/Volunteers/VolunteerCard.jsx
index 9c6f1cf..fe1cf00 100644
--- a/src/pages/Volunteers/VolunteerCard.jsx
+++ b/src/pages/Volunteers/VolunteerCard.jsx
@@ -58,8 +58,8 @@ export default function VolunteerCard({ user }) {
{isExpanded && (
diff --git a/src/router.js b/src/router.js
index bd0c986..f3fdef6 100644
--- a/src/router.js
+++ b/src/router.js
@@ -26,7 +26,7 @@ const router = createBrowserRouter([
Component: HomePage,
},
{
- path: "/stat",
+ path: "/admin",
Component:StatPage,
},
{
diff --git a/src/utils/register.js b/src/utils/register.js
index 313df77..43a8c1d 100644
--- a/src/utils/register.js
+++ b/src/utils/register.js
@@ -1,6 +1,6 @@
import getXSRFToken from "./getXSRF.js";
-export default async function register(email, password, name, lastname) {
+export default async function register(email, password, name, lastname, phone) {
const csrfToken = await getXSRFToken();
try {
@@ -12,19 +12,25 @@ export default async function register(email, password, name, lastname) {
'X-XSRF-TOKEN': csrfToken,
'Accept': 'application/json'
},
- body: JSON.stringify({ email, password, name, lastname }),
+ body: JSON.stringify({ email, password, name, lastname, phone }),
});
- console.log('Code HTTP :', response.status);
-
- if (!response.ok) {
- throw new Error(`Erreur HTTP ${response.status}`);
- }
-
const data = await response.json();
+ if (!response.ok) {
+ if (response.status === 422) {
+ return {
+ status: 422,
+ errors: data.errors
+ };
+ }
+
+ throw new Error(`Erreur HTTP ${response.status}`);
+ }
+
return { status: response.status, data };
+
} catch (error) {
- return error;
+ return { status: "error", error };
}
}
diff --git a/src/utils/searchEvents.js b/src/utils/searchEvents.js
index db4a67f..a9974d0 100644
--- a/src/utils/searchEvents.js
+++ b/src/utils/searchEvents.js
@@ -2,7 +2,7 @@ export default async function searchEvents(query) {
try {
const encodedQuery = encodeURIComponent(query);
const response = await fetch(
- `http://localhost:80/api/events/search?query=${encodedQuery}`,
+ `http://${import.meta.env.VITE_API_URL}/api/events/search?query=${encodedQuery}`,
{
method: 'GET',
credentials: 'include',
diff --git a/src/utils/users/updateUser.js b/src/utils/users/updateUser.js
new file mode 100644
index 0000000..dd2042e
--- /dev/null
+++ b/src/utils/users/updateUser.js
@@ -0,0 +1,32 @@
+import getXSRFToken from "../getXSRF.js";
+
+export default async function updateUser(name, lastname, phone) {
+
+ const csrfToken = await getXSRFToken();
+
+ try {
+ const res = await fetch(`http://${import.meta.env.VITE_API_URL}/api/users/update`, {
+ method: 'POST',
+ credentials: 'include',
+ headers: {
+ 'Accept': 'application/json',
+ 'X-XSRF-TOKEN': csrfToken,
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ name: name,
+ phone: phone,
+ lastname: lastname,
+ })
+ });
+
+ if (!res.ok) {
+ throw new Error(`Erreur serveur : ${res.status}`);
+ }
+
+ return await res.json();
+ } catch (err) {
+ console.error('Erreur :', err);
+ return null;
+ }
+}
\ No newline at end of file