diff --git a/src/components/Header/Header.jsx b/src/components/Header/Header.jsx
index 03a1161..d467539 100644
--- a/src/components/Header/Header.jsx
+++ b/src/components/Header/Header.jsx
@@ -1,7 +1,8 @@
import styles from "./Header.module.css"
import { Link, NavLink } from "react-router";
-import { useEffect, useRef, useState } from "react";
+import {useContext, useEffect, useRef, useState} from "react";
import getUserNotifications from "../../utils/getUserNotifications.js";
+import {AuthContext} from "../../contexts/auth/AuthContext.js";
function Header() {
const [notificationMenu, setnotificationMenu] = useState(false);
@@ -10,6 +11,7 @@ function Header() {
const [notifications, setNotifications] = useState([{"content" : "ok"}, {"content" : "pourquoi pas antoine"}]);
const notificationRef = useRef(null);
+ const { user } = useContext(AuthContext);
useEffect(() => {
@@ -41,7 +43,7 @@ function Header() {
@@ -84,6 +89,9 @@ function Header() {
isActive ? styles.activeLink : styles.link}>
Bénévoles
+ {user.isAdmin && isActive ? styles.activeLink : styles.link}>
+ Administration
+ }
@@ -114,7 +122,7 @@ function Header() {
className={styles.closeBtn}
onClick={() => setNotifications(prev => prev.filter((_, i) => i !== index))}
>
-
+
))
diff --git a/src/components/ToolBar/ToolBar.jsx b/src/components/ToolBar/ToolBar.jsx
index d1f069f..67ff494 100644
--- a/src/components/ToolBar/ToolBar.jsx
+++ b/src/components/ToolBar/ToolBar.jsx
@@ -1,8 +1,8 @@
import styles from "./ToolBar.module.css"
-import {Link} from "react-router";
import Filter from "../Filter/Filter.jsx";
import {useEffect, useState} from "react";
import SearchBar from "../SearchBar/SearchBar.jsx";
+import CreateEventBtn from "../createEventBtn/CreateEventBtn.jsx";
function ToolBar({setFilters, filters, showCreate = true}) {
@@ -37,11 +37,7 @@ function ToolBar({setFilters, filters, showCreate = true}) {
) : null}
{showCreate ? (
-
- +
-
+
) : null}
- Vos Événements :
+ Tâches :
{user.tasks && user.tasks.length > 0 ? (
user.tasks.map((task, index) => (
diff --git a/src/pages/VolunteerProfile/VolunteerProfilePage.jsx b/src/pages/VolunteerProfile/VolunteerProfilePage.jsx
new file mode 100644
index 0000000..1f18805
--- /dev/null
+++ b/src/pages/VolunteerProfile/VolunteerProfilePage.jsx
@@ -0,0 +1,69 @@
+import styles from "./VolunteerProfilePage.module.css"
+import { useParams } from "react-router";
+import { useEffect, useState } from "react";
+import getUserById from "../../utils/users/getUserById.js";
+import formatDate from "../../utils/date/formatDate.js";
+import Task from "../../components/Task/Task.jsx";
+import { useNavigate } from "react-router";
+
+export default function VolunteerProfilePage() {
+
+ const params = useParams();
+ const id = params.id;
+
+ const navigate = useNavigate();
+
+ const [user, setUser] = useState({});
+
+ useEffect(() => {
+ (async () => {
+ const result = await getUserById(id);
+ if (result?.error === 'not_found') {
+ navigate("/404");
+ } else {
+ setUser(result);
+ }
+ })();
+ }, [id]);
+
+
+
+ return
+
+
+
+

+
+
+
+
{user.name} {user.lastname}
+
+
+
+
Role : {user.role}
+
Membre depuis : {formatDate(user.created_at)}
+
+
+
Mail : {user.email}
+
Téléphone : {user.phone === null ? "Pas de numéro enregistré" : user.phone}
+
+
+
+
Tâches :
+ {user.tasks && user.tasks.length > 0 ? (
+ user.tasks.map((task, index) => (
+
+ ))
+ ) : (
+
Aucune tâche pour le moment.
+ )}
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/src/pages/VolunteerProfile/VolunteerProfilePage.module.css b/src/pages/VolunteerProfile/VolunteerProfilePage.module.css
new file mode 100644
index 0000000..e9861dc
--- /dev/null
+++ b/src/pages/VolunteerProfile/VolunteerProfilePage.module.css
@@ -0,0 +1,164 @@
+.container {
+ width: 100%;
+ padding: 10px;
+ box-sizing: border-box;
+}
+
+.profileboard {
+ width: 100%;
+ padding: 15px;
+ border-radius: 20px;
+ box-sizing: border-box;
+}
+
+.contentWrapper {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ width: 100%;
+}
+
+.profilePictureContainer {
+ width: 120px;
+ height: 120px;
+ margin-bottom: 15px;
+}
+
+.profilePicture {
+ width: 100%;
+ height: 100%;
+ border-radius: 50%;
+ object-fit: cover;
+}
+
+.description {
+ width: 100%;
+ text-align: left;
+ margin-left:4%;
+}
+
+.topDescription {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 10px;
+ margin-bottom: 15px;
+}
+
+.infoBlock {
+ width: 100%;
+ background: rgba(255, 255, 255, 0.1);
+ padding: 10px;
+ border-radius: 5px;
+}
+
+.eventTasks {
+ max-height: 0;
+ overflow: hidden;
+ transition: max-height 0.3s ease-out, opacity 0.2s ease;
+ opacity: 0;
+ padding-left: 20px;
+}
+
+.eventTasks.expanded {
+ max-height: 500px;
+ opacity: 1;
+ margin-top: 10px;
+}
+.description h2{
+ font-size:30px;
+
+}
+.profilePicture{
+ width:90%;
+}
+
+.settingsBtns {
+ display: flex;
+ gap: 5px;
+ justify-content: right;
+}
+
+@media screen and (min-width: 768px) {
+ .contentWrapper {
+ flex-direction: row;
+ justify-content: flex-start;
+ align-items: flex-start;
+ }
+
+ .profilePictureContainer {
+ width: 150px;
+ height: 150px;
+ margin-right: 20px;
+ margin-bottom: 0;
+ }
+
+ .description {
+ width: calc(100% - 170px);
+ margin-left:4%;
+ }
+
+ .topDescription {
+ flex-direction: row;
+ justify-content: space-between;
+ }
+
+ .infoBlock {
+ width: 48%;
+ }
+
+ .event {
+ padding: 15px;
+ }
+ .description h2{
+ font-size:30px;
+ }
+ .profilePicture{
+ width:90%;
+ }
+}
+.description button{
+ width:50px;
+ height:50px;
+
+}
+
+.headerProfile {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 20px;
+}
+
+/* Desktop (1024px et plus) */
+@media screen and (min-width: 1024px) {
+ .container {
+ max-width: 100%;
+ margin: 0 auto;
+ padding: 20px;
+ }
+
+ .profileboard {
+ padding: 25px;
+ }
+
+ .profilePictureContainer {
+ width: 30%;
+ height:auto;
+ }
+ .profilePicture{
+ width:90%;
+ }
+ .description {
+ width: calc(100% - 200px);
+ margin-left:4%;
+ }
+
+ .event {
+ padding: 18px;
+ }
+ .description h2{
+ font-size:30px;
+ }
+}
diff --git a/src/pages/waitValidationPage/ValidationErrorPage.jsx b/src/pages/waitValidationPage/ValidationErrorPage.jsx
new file mode 100644
index 0000000..15995e9
--- /dev/null
+++ b/src/pages/waitValidationPage/ValidationErrorPage.jsx
@@ -0,0 +1,30 @@
+import styles from "./validationErrorPage.module.css"
+import Background from "../../components/background/background.jsx";
+import Button from "../../components/ui/button/button.jsx";
+import { useContext } from "react";
+import { AuthContext } from "../../contexts/auth/AuthContext.js";
+import { Navigate, useNavigate } from "react-router";
+
+export default function ValidationErrorPage() {
+
+ const { logout, user } = useContext(AuthContext);
+ const navigate = useNavigate();
+
+ const handleLogout = async () => {
+ await logout();
+ navigate("/login");
+ }
+
+ if(user && user.validate === 1) return ;
+
+ return
+
+
Votre compte n'a pas été validé
+
+
Votre compte n'a pas encore été validé, veuillez attendre la vérification de votre compte par un membre autorisé.
+
Contact : contact@example.com
+
Déconnexion
+
+
+
+}
\ No newline at end of file
diff --git a/src/pages/waitValidationPage/validationErrorPage.module.css b/src/pages/waitValidationPage/validationErrorPage.module.css
new file mode 100644
index 0000000..e4a398d
--- /dev/null
+++ b/src/pages/waitValidationPage/validationErrorPage.module.css
@@ -0,0 +1,25 @@
+.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;
+ }
+}
\ No newline at end of file
diff --git a/src/router.js b/src/router.js
index f54d582..73e049e 100644
--- a/src/router.js
+++ b/src/router.js
@@ -7,6 +7,9 @@ import VolunteersPage from "./pages/Volunteers/VolunteersPage";
import ProfilePage from "./pages/Profile/ProfilePage";
import EventsPage from "./pages/Events/EventsPage.jsx";
import AdminPage from "./pages/Admin/AdminPage.jsx";
+import ValidationErrorPage from "./pages/waitValidationPage/ValidationErrorPage.jsx";
+import VolunteerProfilePage from "./pages/VolunteerProfile/VolunteerProfilePage.jsx";
+import PageNotFound from "./pages/PageNotFound/PageNotFound.jsx";
const router = createBrowserRouter([
{
@@ -17,6 +20,18 @@ const router = createBrowserRouter([
path: "/register",
Component: RegisterPage,
},
+ {
+ path: "/error/validation",
+ Component: ValidationErrorPage
+ },
+ {
+ path: "/*",
+ Component: PageNotFound,
+ },
+ {
+ path: "/404",
+ Component: PageNotFound,
+ },
{
path: "/",
Component: Layout,
@@ -41,6 +56,10 @@ const router = createBrowserRouter([
path: "/volunteers",
Component: VolunteersPage,
},
+ {
+ path: "/profile/:id",
+ Component: VolunteerProfilePage,
+ }
]
}
])
diff --git a/src/stories/ThemeSwitcher.stories.jsx b/src/stories/ThemeSwitcher.stories.jsx
new file mode 100644
index 0000000..f285b15
--- /dev/null
+++ b/src/stories/ThemeSwitcher.stories.jsx
@@ -0,0 +1,20 @@
+import ThemeSwitcher from "../components/ui/themeSwitcher/ThemeSwitcher.jsx";
+import Background from "../components/background/background.jsx";
+
+export default {
+ title: 'UI/ThemeSwitcher',
+ component: ThemeSwitcher,
+ parameters: {
+ layout: 'centered',
+ },
+ tags: ['autodocs'],
+};
+
+const ThemeSwitcherRender = () => {
+ return
+
+
+};
+
+export const Default = () => ;
+
diff --git a/src/utils/event/createEvent.js b/src/utils/event/createEvent.js
new file mode 100644
index 0000000..4098dd7
--- /dev/null
+++ b/src/utils/event/createEvent.js
@@ -0,0 +1,36 @@
+import getXSRFToken from "../getXSRF.js";
+
+export default async function createEvent(name, description) {
+ const csrfToken = await getXSRFToken();
+
+ try {
+ const response = await fetch(`http://${import.meta.env.VITE_API_URL}/api/events/create`, {
+ method: 'POST',
+ credentials: 'include',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'X-XSRF-TOKEN': csrfToken,
+ 'Accept': 'application/json'
+ },
+ body: JSON.stringify({ name, description }),
+ });
+
+ 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 { status: "error", error };
+ }
+}
diff --git a/src/utils/users/getUserById.js b/src/utils/users/getUserById.js
index 59af94a..1fad659 100644
--- a/src/utils/users/getUserById.js
+++ b/src/utils/users/getUserById.js
@@ -1,4 +1,4 @@
-export default async function getUserById (id) {
+export default async function getUserById(id) {
try {
const res = await fetch(`http://${import.meta.env.VITE_API_URL}/api/users/${id}`, {
method: 'GET',
@@ -9,12 +9,15 @@ export default async function getUserById (id) {
});
if (!res.ok) {
+ if (res.status === 404) {
+ return { error: 'not_found' };
+ }
throw new Error(`Erreur serveur : ${res.status}`);
}
return await res.json();
} catch (err) {
console.error('Erreur :', err);
- return null;
+ return { error: 'server_error' };
}
-}
\ No newline at end of file
+}