- );
-}
-
-export default HomePage;
diff --git a/src/pages/Home/HomePage.tsx b/src/pages/Home/HomePage.tsx
new file mode 100644
index 0000000..a34d095
--- /dev/null
+++ b/src/pages/Home/HomePage.tsx
@@ -0,0 +1,12 @@
+import styles from "./HomePage.module.css";
+import Calendar from "./components/Calendar/Calendar";
+import EventList from "./components/EventList/EventList";
+import { ReactNode } from "react";
+
+export default function HomePage(): ReactNode {
+
+ return
+
+
+
+}
diff --git a/src/pages/Home/components/Calendar/Calendar.jsx b/src/pages/Home/components/Calendar/Calendar.jsx
index ba80de5..66f7a7b 100644
--- a/src/pages/Home/components/Calendar/Calendar.jsx
+++ b/src/pages/Home/components/Calendar/Calendar.jsx
@@ -1,9 +1,8 @@
import {useState, useMemo, useEffect, useContext} from "react";
import styles from "./Calendar.module.css";
import {formatDateLetterJS} from "../../../../utils/date/formatDateLetter.js";
-import Button from "../../../../components/ui/Button/Button";
import {AuthContext} from "../../../../contexts/Auth/AuthContext.ts";
-import ExportBtn from "./ExportBtn.tsx";
+import ExportBtn from "../../../../components/ExportCalendarBtn/ExportBtn.tsx";
function
Calendar() {
diff --git a/src/pages/Home/components/Calendar/ExportBtn.tsx b/src/pages/Home/components/Calendar/ExportBtn.tsx
deleted file mode 100644
index c5192aa..0000000
--- a/src/pages/Home/components/Calendar/ExportBtn.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import Button from "../../../../components/ui/Button/Button";
-import styles from "../../HomePage.module.css"
-import { useContext } from "react";
-import { AuthContext, AuthContextType } from "../../../../contexts/Auth/AuthContext";
-import { APP_CONFIG } from "../../../../config/appConfig";
-
-export default function ExportBtn() {
-
- const { user } = useContext(AuthContext) as AuthContextType;
- const calendarUrl = `${import.meta.env.VITE_API_URL}/api/export/ics/${user?.id}`;
-
- return
-}
\ No newline at end of file
diff --git a/src/pages/LegalNotices/LegalNoticesPage.jsx b/src/pages/LegalNotices/LegalNoticesPage.tsx
similarity index 99%
rename from src/pages/LegalNotices/LegalNoticesPage.jsx
rename to src/pages/LegalNotices/LegalNoticesPage.tsx
index 4adf1a0..38aa86d 100644
--- a/src/pages/LegalNotices/LegalNoticesPage.jsx
+++ b/src/pages/LegalNotices/LegalNoticesPage.tsx
@@ -37,4 +37,4 @@ export default function legalNoticesPage() {
);
-}
\ No newline at end of file
+}
diff --git a/src/pages/PageNotFound/PageNotFoundPage.jsx b/src/pages/PageNotFound/PageNotFoundPage.tsx
similarity index 61%
rename from src/pages/PageNotFound/PageNotFoundPage.jsx
rename to src/pages/PageNotFound/PageNotFoundPage.tsx
index 5957cb5..afee5d0 100644
--- a/src/pages/PageNotFound/PageNotFoundPage.jsx
+++ b/src/pages/PageNotFound/PageNotFoundPage.tsx
@@ -1,4 +1,4 @@
-import Background from "../../components/Background/Background.jsx";
+import Background from "../../components/Background/Background";
import styles from "./PageNotFoundPage.module.css"
import { useNavigate } from "react-router";
import { APP_CONFIG } from "../../config/appConfig.js";
@@ -12,14 +12,14 @@ export default function PageNotFoundPage() {
Page non trouvée
- Désolé, la page que vous recherchez n’existe pas ou n’est plus disponible.
+ Désolé, la page que vous recherchez n'existe pas ou n'est plus disponible.
Vous pouvez :
- - Vérifier l’URL pour une éventuelle erreur de saisie.
- - Revenir à l’accueil navigate("/")} className={styles.redirectSpan}>ici.
+ - Vérifier l'URL pour une éventuelle erreur de saisie.
+ - Revenir à l'accueil navigate("/")} className={styles.redirectSpan}>ici.
diff --git a/src/pages/RGPD/RGPDPage.jsx b/src/pages/RGPD/RGPDPage.tsx
similarity index 82%
rename from src/pages/RGPD/RGPDPage.jsx
rename to src/pages/RGPD/RGPDPage.tsx
index 69d5dd5..e0a81bb 100644
--- a/src/pages/RGPD/RGPDPage.jsx
+++ b/src/pages/RGPD/RGPDPage.tsx
@@ -12,8 +12,8 @@ export default function RGPDPage() {
Le présent site web est un outil de gestion des bénévoles permettant notamment :
-
L’inscription et la gestion des profils bénévoles
-
L’organisation d’événements ou de missions
+
L'inscription et la gestion des profils bénévoles
+
L'organisation d'événements ou de missions
La communication avec les bénévoles
Le suivi des participations
@@ -33,15 +33,15 @@ export default function RGPDPage() {
2. Responsable du traitement
Le responsable du traitement des données personnelles est Monsieur FRÈRE Robin
- Il est responsable de la collecte et de l’utilisation des données personnelles conformément au Règlement Général sur la Protection des Données (RGPD – UE 2016/679).
+ Il est responsable de la collecte et de l'utilisation des données personnelles conformément au Règlement Général sur la Protection des Données (RGPD – UE 2016/679).
3. Données personnelles collectées
-
Les données susceptibles d’être collectées sont notamment :
+
Les données susceptibles d'être collectées sont notamment :
-
Les données d’identification : nom, prénom, adresse email et numéro de téléphone.
+
Les données d'identification : nom, prénom, adresse email et numéro de téléphone.
Les données techniques : adresse IP, données de connexion (logs) et type de navigateur et appareil.
@@ -63,8 +63,8 @@ export default function RGPDPage() {
5. Base légale du traitement
Les traitements reposent sur :
-
Le consentement de l’utilisateur
-
L’intérêt légitime de l’organisme (gestion des bénévoles)
+
Le consentement de l'utilisateur
+
L'intérêt légitime de l'organisme (gestion des bénévoles)
Une obligation légale, le cas échéant
@@ -73,7 +73,7 @@ export default function RGPDPage() {
6. Durée de conservation
Les données sont conservées :
-
Pendant la durée de l’engagement bénévole
+
Pendant la durée de l'engagement bénévole
Puis archivées ou supprimées au plus tard 3 ans après la dernière activité ou contact
Les logs techniques sont conservés pour une durée maximale de 2 mois.
@@ -83,10 +83,10 @@ export default function RGPDPage() {
7. Destinataires des données
Les données sont accessibles uniquement :
-
Aux personnes habilitées de l’organisme
+
Aux personnes habilitées de l'organisme
Aux prestataires techniques (hébergement, maintenance), strictement nécessaires
-
Aucune donnée n’est vendue ou cédée à des tiers.
+
Aucune donnée n'est vendue ou cédée à des tiers.
@@ -96,7 +96,7 @@ export default function RGPDPage() {
Siège social : 2 rue Kellermann - 59100 Roubaix - France
Site web : www.ovh.com
-
L’hébergeur garantit un niveau de sécurité conforme au RGPD.
+
L'hébergeur garantit un niveau de sécurité conforme au RGPD.
@@ -113,11 +113,11 @@ export default function RGPDPage() {
10. Droits des utilisateurs
Conformément au RGPD, vous disposez des droits suivants :
-
Droit d’accès à vos données
+
Droit d'accès à vos données
Droit de rectification
-
Droit à l’effacement (droit à l’oubli)
+
Droit à l'effacement (droit à l'oubli)
Droit à la limitation du traitement
-
Droit d’opposition
+
Droit d'opposition
Droit à la portabilité des données
@@ -126,7 +126,7 @@ export default function RGPDPage() {
11. Réclamation
Si vous estimez que vos droits ne sont pas respectés, vous pouvez introduire une réclamation auprès de la :
- CNIL – Commission Nationale de l’Informatique et des Libertés
+ CNIL – Commission Nationale de l'Informatique et des Libertés
Site : https://www.cnil.fr
@@ -140,4 +140,4 @@ export default function RGPDPage() {
);
-}
\ No newline at end of file
+}
diff --git a/src/pages/WaitValidation/WaitValidationPage.jsx b/src/pages/WaitValidation/WaitValidationPage.tsx
similarity index 92%
rename from src/pages/WaitValidation/WaitValidationPage.jsx
rename to src/pages/WaitValidation/WaitValidationPage.tsx
index 2972391..1480cb7 100644
--- a/src/pages/WaitValidation/WaitValidationPage.jsx
+++ b/src/pages/WaitValidation/WaitValidationPage.tsx
@@ -1,5 +1,5 @@
import styles from "./WaitValidationPage.module.css"
-import Background from "../../components/Background/Background.jsx";
+import Background from "../../components/Background/Background";
import Button from "../../components/ui/Button/Button";
import { useContext } from "react";
import { AuthContext } from "../../contexts/Auth/AuthContext.js";
@@ -7,7 +7,7 @@ import { Navigate, useNavigate, Link } from "react-router";
export default function WaitValidationPage() {
- const { logout, user } = useContext(AuthContext);
+ const { logout, user } = useContext(AuthContext)!;
const navigate = useNavigate();
const handleLogout = async () => {
@@ -38,4 +38,4 @@ export default function WaitValidationPage() {
-}
\ No newline at end of file
+}
diff --git a/src/router.js b/src/router.js
index 11c3bb8..e17bf44 100644
--- a/src/router.js
+++ b/src/router.js
@@ -1,6 +1,6 @@
import { createBrowserRouter } from "react-router";
import Layout from "./layout.jsx";
-import HomePage from "./pages/Home/HomePage";
+import HomePage from "./pages/Home/HomePage.tsx";
import LoginPage from "./pages/Login/LoginPage";
import RegisterPage from "./pages/Register/RegisterPage.jsx";
import VolunteersPage from "./pages/Volunteers/VolunteersPage";
@@ -10,7 +10,7 @@ import AdminPage from "./pages/Admin/AdminPage.jsx";
import WaitValidationPage from "./pages/WaitValidation/WaitValidationPage.jsx";
import PageNotFoundPage from "./pages/PageNotFound/PageNotFoundPage.jsx";
import eventDetail from "./pages/EventDetail/EventDetailPage.tsx";
-import legalNotices from "./pages/LegalNotices/LegalNoticesPage.jsx";
+import legalNotices from "./pages/LegalNotices/LegalNoticesPage.tsx";
import RGPDPage from "./pages/RGPD/RGPDPage.jsx";
const router = createBrowserRouter([
diff --git a/src/utils/date/formatDate.ts b/src/utils/date/formatDate.ts
index 5a14daa..8f4bf1b 100644
--- a/src/utils/date/formatDate.ts
+++ b/src/utils/date/formatDate.ts
@@ -1,4 +1,6 @@
-export default function formatDate(d: string | Date): string {
+export default function formatDate(d: string | Date | number | null | undefined): string {
+ if (!d) return "Date inconnue";
+
const date = d instanceof Date ? d : new Date(d);
const jj = String(date.getUTCDate()).padStart(2, "0");
diff --git a/src/utils/date/formatTime.ts b/src/utils/date/formatTime.ts
index 93311b9..561d03a 100644
--- a/src/utils/date/formatTime.ts
+++ b/src/utils/date/formatTime.ts
@@ -1,5 +1,5 @@
-export default function formatTime(d: string | Date | null | undefined): string {
+export default function formatTime(d: string | Date | number | null | undefined): string {
if (!d) return "Heure inconnue";
const date = d instanceof Date ? d : new Date(d);
diff --git a/src/utils/echo/listeners/adminNotificationsListener.js b/src/utils/echo/listeners/adminNotificationsListener.js
new file mode 100644
index 0000000..5210122
--- /dev/null
+++ b/src/utils/echo/listeners/adminNotificationsListener.js
@@ -0,0 +1,24 @@
+export const adminNotificationsListener = (echo, userData, setNotifications, setUnreadNotification, updatePendingMembers) => {
+ if (userData.isAdmin) {
+ const channelName = "users.admin";
+
+ const handleNotification = (id, content) => {
+ const newNotification = {
+ id,
+ content,
+ created_at: new Date().toISOString(),
+ pivot: { unread: 1 }
+ };
+ setNotifications(prev => [newNotification, ...prev]);
+ setUnreadNotification(true);
+ };
+
+ echo.private(channelName)
+ .listen(".users.registration", (event) => {
+ handleNotification(event.notificationId, `Nouvelle demande d'inscription : ${event.user.name} ${event.user.lastname}`);
+ updatePendingMembers();
+ });
+ return channelName;
+ }
+ return null;
+};
\ No newline at end of file
diff --git a/src/utils/echo/listeners/userCreatedListener.js b/src/utils/echo/listeners/userCreatedListener.js
deleted file mode 100644
index a4a36c4..0000000
--- a/src/utils/echo/listeners/userCreatedListener.js
+++ /dev/null
@@ -1,19 +0,0 @@
-export const userCreatedListener = (echo, userData, setNotifications, setunreadNotification, updatePendingMembers) => {
- if (userData.isAdmin) {
- const channelName = "users.registration";
- echo.private(channelName)
- .listen(".users.registration", (event) => {
- const newNotification = {
- id: Date.now(),
- content: `Nouvelle demande d'inscription : ${event.user.name} ${event.user.lastname}`,
- created_at: Date.now(),
- pivot: { unread: 1 }
- };
- setNotifications(prev => [newNotification, ...prev]);
- setunreadNotification(true);
- updatePendingMembers();
- });
- return channelName;
- }
- return null;
-};
\ No newline at end of file
diff --git a/src/utils/echo/listeners/userNotificationsListener.js b/src/utils/echo/listeners/userNotificationsListener.js
index 7d94483..f9ec96b 100644
--- a/src/utils/echo/listeners/userNotificationsListener.js
+++ b/src/utils/echo/listeners/userNotificationsListener.js
@@ -1,46 +1,37 @@
-export const userNotificationsListener = (echo, userData, setNotifications, setunreadNotification) => {
+export const userNotificationsListener = (echo, userData, setNotifications, setUnreadNotification) => {
const channelName = `user.${userData.id}`;
+ const handleNotification = (id, content) => {
+
+ const newNotification = {
+ id,
+ content,
+ created_at: new Date().toISOString(),
+ pivot: { unread: 1 }
+ };
+
+ setNotifications(prev => [newNotification, ...prev]);
+ setUnreadNotification(true);
+ };
+
return echo.private(channelName)
.listen('.event.participation.cancelled', (event) => {
- const newNotification = {
- id: Date.now(),
- content: `L'événement ${event.event.name} a été supprimé ! Vous n'y participez donc plus.`,
- created_at: Date.now(),
- pivot: { unread: 1 }
- };
- setNotifications(prev => [newNotification, ...prev]);
- setunreadNotification(true);
+ handleNotification(event.notificationId,`L'événement ${event.event.name} a été supprimé. Vous n'y participez donc plus.`);
})
.listen(`.task.participation.cancelled`, (event) => {
- const newNotification = {
- id: Date.now(),
- content: `La tâche ${event.task.name} de l'événement ${event.event.name} a été supprimé ! Vous n'y participez donc plus.`,
- created_at: Date.now(),
- pivot: { unread: 1 }
- };
- setNotifications(prev => [newNotification, ...prev]);
- setunreadNotification(true);
+ handleNotification(event.notificationId,`La tâche ${event.task.name} de l'événement ${event.event.name} a été supprimée. Vous n'y participez donc plus.`);
})
.listen('.volunteer.assigned.to.task', (event) => {
- const newNotification = {
- id: Date.now(),
- content: `Vous avez été assigné à la tâche ${event.task.name} de l'événement ${event.event.name}`,
- created_at: Date.now(),
- pivot: { unread: 1 }
- };
- setNotifications(prev => [newNotification, ...prev]);
- setunreadNotification(true);
+ handleNotification(event.notificationId,`Vous avez été assigné à la tâche ${event.task.name} de l'événement ${event.event.name}.`);
})
.listen('.volunteer.unassigned.to.task', (event) => {
- const newNotification = {
- id: Date.now(),
- content: `Vous avez été désassigné de la tâche ${event.task.name} de l'événement ${event.event.name}`,
- created_at: Date.now(),
- pivot: { unread: 1 }
- };
- setNotifications(prev => [newNotification, ...prev]);
- setunreadNotification(true);
+ handleNotification(event.notificationId,`Vous avez été désassigné de la tâche ${event.task.name} de l'événement ${event.event.name}.`);
+ })
+ .listen('.volunteer.role.updated', (event) => {
+ handleNotification(event.notificationId, `Votre rôle a changé pour : ${event.role} `);
+ })
+ .listen('.task.date.updated', (event) => {
+ handleNotification(event.notificationId,`La date de la tâche ${event.task.name} de l'événement ${event.event.name} à été mis à jour. Cette tâche aura maintenant lieu du ${event.start} au ${event.end}.`);
});
};
\ No newline at end of file
diff --git a/src/utils/users/toggleEmailNotifications.ts b/src/utils/users/toggleEmailNotifications.ts
new file mode 100644
index 0000000..1fa8744
--- /dev/null
+++ b/src/utils/users/toggleEmailNotifications.ts
@@ -0,0 +1,13 @@
+import fetchWrapper from "../fetchWrapper";
+import getXSRFToken from "../getXSRF";
+
+export default async function toggleEmailNotifications(id: number) {
+ const csrfToken = await getXSRFToken();
+
+ return fetchWrapper(
+ `/api/users/${id}/email-notifications`,
+ {},
+ "PATCH",
+ { "X-XSRF-TOKEN": csrfToken }
+ );
+}
\ No newline at end of file
diff --git a/src/utils/users/toggleWebNotifications.ts b/src/utils/users/toggleWebNotifications.ts
new file mode 100644
index 0000000..a068c0b
--- /dev/null
+++ b/src/utils/users/toggleWebNotifications.ts
@@ -0,0 +1,13 @@
+import fetchWrapper from "../fetchWrapper";
+import getXSRFToken from "../getXSRF";
+
+export default async function toggleWebNotifications(id: number) {
+ const csrfToken = await getXSRFToken();
+
+ return fetchWrapper(
+ `/api/users/${id}/web-notifications`,
+ {},
+ "PATCH",
+ { "X-XSRF-TOKEN": csrfToken }
+ );
+}
\ No newline at end of file