-
+
diff --git a/src/pages/Admin/components/pendingMembers/PendingMembers.jsx b/src/pages/Admin/components/pendingMembers/PendingMembers.jsx
index 69dc4e4..f8280f6 100644
--- a/src/pages/Admin/components/pendingMembers/PendingMembers.jsx
+++ b/src/pages/Admin/components/pendingMembers/PendingMembers.jsx
@@ -1,11 +1,10 @@
-import React, {useState, useEffect} from "react";
-import Button from "../../../../components/ui/button/button.jsx";
+import React, {useState, useEffect, useContext} from "react";
+import Button from "../../../../components/ui/button/button.tsx";
import styles from "./PendingMembers.module.css";
-import Modal from "../../../../components/ui/modal/modal.jsx";
-import getUserToValidate from "../../../../utils/users/getUserToValidate.js";
-import getUserById from "../../../../utils/users/getUserById.js";
+import Modal from "../../../../components/ui/modal/modal.tsx";
import validateUser from "../../../../utils/users/validateUser.js";
import deleteOtherUser from "../../../../utils/users/deleteOtherUser.js";
+import { PendingMembersContext } from "../../../../contexts/pendingMembers/PendingMembersContext";
function PendingMembers() {
@@ -13,23 +12,10 @@ function PendingMembers() {
const [open, setOpen] = useState(false);
const [message, setMessage] = useState("");
const [title, setTitle] = useState("");
-
- const [pendingMembers, setPendingMembers] = useState([]);
-
- const fetchUsers = async () => {
-
- const result = await getUserToValidate();
- const userIds = result.data;
-
- if (userIds && userIds.length > 0) {
- const users = await Promise.all(userIds.map(id => getUserById(id)));
- const usersData = users.map(u => u.data);
- setPendingMembers(usersData);
- } else setPendingMembers([]);
- }
+ const { pendingMembers, updatePendingMembers } = useContext(PendingMembersContext);
useEffect(() => {
- fetchUsers();
+ updatePendingMembers();
}, []);
const handleValidate = async (id, name) => {
@@ -38,14 +24,12 @@ function PendingMembers() {
if(result.status === 200) {
setTitle("Utilisateur accepté avec succès")
setMessage(`L'utilisateur ${name} a été accepté avec succès`)
- setOpen(true);
} else {
setTitle("Erreur")
setMessage(`Une erreur est survenue durant l'acceptation de l'utilisateur ${name}`)
- setOpen(true);
}
-
- fetchUsers();
+ setOpen(true);
+ updatePendingMembers();
}
const handleRefuse = async (id, name) => {
@@ -61,7 +45,7 @@ function PendingMembers() {
setOpen(true);
}
- fetchUsers();
+ updatePendingMembers();
}
return (
diff --git a/src/pages/Admin/components/registerMember/registerMember.module.css b/src/pages/Admin/components/registerMember/registerMember.module.css
new file mode 100644
index 0000000..b15de9f
--- /dev/null
+++ b/src/pages/Admin/components/registerMember/registerMember.module.css
@@ -0,0 +1,52 @@
+.leftBlock {
+ width: 100%;
+ max-width: 720px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ min-height: calc(100vh - 260px);
+ box-sizing: border-box;
+ padding: 20px;
+ margin: 0 auto;
+}
+
+.registerMemberHeader {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ margin-bottom: 20px;
+}
+
+.registerForm {
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ align-items: stretch;
+}
+
+.registerForm input {
+ width: 100%;
+ box-sizing: border-box;
+}
+
+.registerForm button {
+ width: 100%;
+}
+
+.modalContent {
+ text-align: center;
+}
+
+@media (min-width: 768px) {
+ .leftBlock {
+ width: 70%;
+ }
+}
+
+@media (min-width: 1024px) {
+ .leftBlock {
+ width: 40%;
+ }
+}
diff --git a/src/pages/Admin/components/registerMember/registerMember.tsx b/src/pages/Admin/components/registerMember/registerMember.tsx
new file mode 100644
index 0000000..e233176
--- /dev/null
+++ b/src/pages/Admin/components/registerMember/registerMember.tsx
@@ -0,0 +1,74 @@
+import React, { useState } from "react"
+import styles from "./registerMember.module.css"
+import TextInput from "../../../../components/ui/input/input"
+import Button from "../../../../components/ui/button/button";
+import Response from "../../../../interfaces/response.interface";
+import ResponseData from "./responseData.inteface";
+import adminCreateUser from "../../../../utils/users/adminCreateUser";
+import Modal from "../../../../components/ui/modal/modal";
+
+
+const RegisterMember: React.FC = () => {
+
+ const [name, setName] = useState
("");
+ const [lastname, setLastName] = useState("");
+ const [email, setEmail] = useState("");
+ const [phone, setPhone] = useState("");
+ const [password, setPassword] = useState("");
+
+ const [open, setOpen] = useState(false);
+ const [title, setTitle] = useState("");
+ const [message, setMessage] = useState("");
+
+
+ const handleCreate = async (): Promise => {
+
+ if(name !== "" && lastname !== "" && email !== "" && phone !== "" ) {
+ const response: Response = await adminCreateUser(email, name, lastname, phone);
+ if(response.status === 200) {
+ setPassword(response.data.password);
+ setTitle(`Utilisateur enregistré avec succès`);
+ setMessage(`L'utilisateur ${name} ${lastname} a été enregistré avec le mot de passe: ${response.data.password}`);
+ setOpen(true);
+ } else {
+ setTitle(`Erreur`);
+ setMessage(`Une erreur est survenue lors de l'enregistrement de ${name} ${lastname}`);
+ setOpen(true);
+ }
+ } else {
+ setTitle("Erreur");
+ setMessage("Un des champs n'a pas été rempli");
+ setOpen(true);
+ }
+ }
+
+ const showPassword = (): void => {
+ setTitle(`Mot de passe de ${name} ${lastname}`);
+ setMessage(password);
+ setOpen(true);
+ }
+
+ return
+
+
Enregister un bénévole
+
+
+
+ setName(e.target.value)} />
+ setLastName(e.target.value)} />
+ setEmail(e.target.value)} />
+ setPhone(e.target.value)} />
+
+ {password !== "" && }
+
+
+
+
+
setOpen(false)} title={title}>
+ {message}
+
+
+
+}
+
+export default RegisterMember
\ No newline at end of file
diff --git a/src/pages/Admin/components/registerMember/responseData.inteface.ts b/src/pages/Admin/components/registerMember/responseData.inteface.ts
new file mode 100644
index 0000000..528d1d3
--- /dev/null
+++ b/src/pages/Admin/components/registerMember/responseData.inteface.ts
@@ -0,0 +1,4 @@
+export default interface ResponseData {
+ message: string;
+ password: string;
+}
\ No newline at end of file
diff --git a/src/pages/Events/components/Event/Event.jsx b/src/pages/Events/components/Event/Event.jsx
index e011d56..41181d3 100644
--- a/src/pages/Events/components/Event/Event.jsx
+++ b/src/pages/Events/components/Event/Event.jsx
@@ -1,7 +1,7 @@
import styles from "./Event.module.css";
import { useState, useEffect } from "react";
import { useNavigate } from "react-router";
-import Button from "/src/components/ui/button/button.jsx"
+import Button from "/src/components/ui/button/button"
function Event({event}){
diff --git a/src/pages/Home/components/EventList/eventList.jsx b/src/pages/Home/components/EventList/eventList.jsx
index 975adf9..9ab2321 100644
--- a/src/pages/Home/components/EventList/eventList.jsx
+++ b/src/pages/Home/components/EventList/eventList.jsx
@@ -4,33 +4,32 @@ import EventItem from "./eventItem.jsx";
import { EventContext } from "../../../../contexts/events/EventContext.js";
import { useContext } from "react";
-
function EventList() {
-
- const { events } = useContext(EventContext);
+ // Utilise une valeur par défaut pour `events` si elle est `undefined`
+ const { events = [] } = useContext(EventContext);
const sortedEvents = useMemo(() => {
+ // Vérifie explicitement que `events` est un tableau avant de trier
+ if (!Array.isArray(events)) return [];
return [...events].sort(
(a, b) => new Date(a.start) - new Date(b.start)
);
}, [events]);
-
return (
-
Liste des événements à venir
- {sortedEvents.length > 0 ? (
-
- {sortedEvents.map((eventGroup, index) => (
-
- ))}
-
- ) : (
-
Aucun événement planifié pour l'instant.
- )}
+
Liste des événements à venir
+ {sortedEvents.length > 0 ? (
+
+ {sortedEvents.map((eventGroup, index) => (
+
+ ))}
+
+ ) : (
+
Aucun événement planifié pour l'instant.
+ )}
-
);
}
-export default EventList;
\ No newline at end of file
+export default EventList;
diff --git a/src/pages/Login/components/loginform/loginForm.jsx b/src/pages/Login/components/loginform/loginForm.jsx
index ee2ee6b..b4b3338 100644
--- a/src/pages/Login/components/loginform/loginForm.jsx
+++ b/src/pages/Login/components/loginform/loginForm.jsx
@@ -1,8 +1,8 @@
import { useState, useContext } from "react";
import styles from "./loginForm.module.css";
-import Button from "../../../../components/ui/button/button.jsx";
-import Input from "../../../../components/ui/input/input.jsx";
-import Modal from "../../../../components/ui/modal/modal.jsx";
+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";
diff --git a/src/pages/Profile/ProfilePage.module.css b/src/pages/Profile/ProfilePage.module.css
index 3c5b26b..2bcecee 100644
--- a/src/pages/Profile/ProfilePage.module.css
+++ b/src/pages/Profile/ProfilePage.module.css
@@ -1,57 +1,95 @@
+/* Conteneur principal */
.container {
- width: 100%;
- padding: 12px;
- box-sizing: border-box;
+ width: 100%;
+ padding: 12px;
+ box-sizing: border-box;
+ margin: 0 auto;
}
+
.profileboard {
width: 100%;
padding: 16px;
border-radius: 20px;
box-sizing: border-box;
}
-.settingImage{
- width:100%;
- display: flex;
- justify-content: center;
-}
-.contentWrapper {
+
+.settingImage {
display: flex;
- flex-direction: column;
+ justify-content: center;
align-items: center;
- width: 100%;
+}
+
+.contentWrapper {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ width: 100%;
+ gap: 20px;
}
.profilePictureContainer {
- width: 120px;
- height: 120px;
- margin-bottom: 16px;
+ width: 120px;
+ height: 120px;
+ margin-bottom: 0;
+ position: relative;
+ display: flex;
+ justify-content: center;
}
.profilePicture {
- width: 100%;
- height: 100%;
- border-radius: 50%;
- object-fit: cover;
+ width: 100%;
+ height: 100%;
+ border-radius: 50%;
+ object-fit: cover;
+}
+
+.editPictureButton {
+ margin-top: 16px;
+ padding-top: 12px;
+ padding-bottom: 12px;
+ background: rgba(255, 255, 255, 0.95);
+ border: none;
+ border-radius: 24px;
+ cursor: pointer;
+ font-size: 0.95rem;
+ font-weight: 600;
+ color: #e74c3c;
+ box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15);
+ transition: all 0.3s ease;
+ backdrop-filter: blur(5px);
+ white-space: nowrap;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ width: auto;
+ min-width: 140px;
+}
+
+.editPictureButton:hover {
+ background: rgba(255, 255, 255, 1);
+ transform: translateY(-2px);
+ box-shadow: 0 5px 12px rgba(0, 0, 0, 0.2);
+ color: #c0392b;
}
.description {
- width: 100%;
- text-align: left;
+ width: 100%;
+ text-align: left;
}
-
.headerProfile {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 16px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 16px;
}
.description h2 {
font-size: 1.6rem;
margin-bottom: 10px;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
}
.description button {
@@ -75,84 +113,91 @@
margin: 0;
}
+/* Conteneur des informations principales */
.topDescription {
- display: flex;
- flex-direction: column;
- gap: 12px;
- margin-bottom: 20px;
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ width: 100%;
+ margin-bottom: 20px;
}
+/* Bloc d'informations */
.infoBlock {
- width: 100%;
- padding: 12px;
+ width: 100%;
+ padding: 12px;
+ box-sizing: border-box;
}
-.eventTasks {
- max-height: 0;
- overflow: hidden;
- transition: max-height 0.3s ease, opacity 0.2s ease;
- opacity: 0;
- padding-left: 16px;
-}
-
-.eventTasks.expanded {
- max-height: 500px;
- opacity: 1;
- margin-top: 10px;
+/* Conteneur pour les paramètres */
+.settingImage {
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ margin-top: 16px;
}
+/* Adaptation pour tablette et PC */
@media (min-width: 768px) {
- .contentWrapper {
- flex-direction: row;
- align-items: flex-start;
- }
+ .contentWrapper {
+ flex-direction: row;
+ align-items: flex-start;
+ gap: 24px;
+ }
- .profilePictureContainer {
- width: 150px;
- height: 150px;
- margin-right: 24px;
- margin-bottom: 0;
- }
+ .profilePictureContainer {
+ width: 150px;
+ height: 150px;
+ margin-right: 0;
+ }
- .description {
- width: calc(100% - 180px);
- }
+ .description {
+ width: calc(100% - 180px);
+ }
- .topDescription {
- flex-direction: row;
- justify-content: space-between;
- }
+ .topDescription {
+ flex-direction: row;
+ justify-content: space-between;
+ flex-wrap: wrap;
+ }
- .infoBlock {
- width: 48%;
- }
+ .infoBlock {
+ flex: 1;
+ min-width: calc(50% - 8px);
+ max-width: calc(50% - 8px);
+ }
- .description h2 {
- font-size: 1.8rem;
- }
+ .editPictureButton {
+ margin: 16px auto 0 auto;
+ display: block;
+ }
+
+ .headerProfile h2 {
+ font-size: 1.8rem;
+ }
}
+/* Adaptation pour grand écran */
@media (min-width: 1024px) {
- .container {
- max-width: 1200px;
- margin: 0 auto;
- padding: 24px;
- }
+ .container {
+ max-width: 1200px;
+ padding: 24px;
+ }
- .profileboard {
- padding: 28px;
- }
+ .profileboard {
+ padding: 28px;
+ }
- .profilePictureContainer {
- width: 180px;
- height: 180px;
- }
+ .profilePictureContainer {
+ width: 180px;
+ height: 180px;
+ }
- .description {
- width: calc(100% - 220px);
- }
+ .description {
+ width: calc(100% - 220px);
+ }
- .description h2 {
- font-size: 2rem;
- }
+ .headerProfile h2 {
+ font-size: 2rem;
+ }
}
diff --git a/src/pages/Profile/ProfilePage.tsx b/src/pages/Profile/ProfilePage.tsx
index 84c2211..eddae6a 100644
--- a/src/pages/Profile/ProfilePage.tsx
+++ b/src/pages/Profile/ProfilePage.tsx
@@ -1,42 +1,138 @@
-import { useContext, useEffect } from "react";
+import getXSRFToken from "../../utils/getXSRF.js";
+// import fetchWrapper from "../../utils/fetchWrapper";
+import {useContext, useEffect, useState} from "react";
import styles from "./ProfilePage.module.css";
-
-import { AuthContext } from "../../contexts/auth/AuthContext";
+import {AuthContext} from "../../contexts/auth/AuthContext";
import formatDate from "../../utils/date/formatDate";
+import Task from "../../components/Task/Task";
+import SettingsModal from "./components/SettingsModal/SettingsModal";
+import {useParams} from "react-router";
+import {useNavigate} from "react-router";
+import {useRef} from "react";
+import getUserById from "../../utils/users/getUserById.js";
+import ManageMember from "./components/manageMember/ManageMember.jsx";
+
+import uploadProfilePhoto from "../../utils/users/uploadProfilePhoto";
+import deleteProfilePhoto from "../../utils/users/deleteProfilePhoto.js";
-//import Task from "../../components/Task/Task";
-//import SettingsModal from "./components/SettingsModal/SettingsModal";
interface TaskType {
id: number;
- title?: string;
- completed?: boolean;
- [key: string]: unknown;
+ 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;
+ };
}
+
interface User {
- name: string;
- lastname: string;
- role: string;
- email: string;
- phone: string | null;
- created_at: string;
- tasks: TaskType[];
+ id: number;
+ name: string;
+ lastname: string;
+ role: string;
+ email: string;
+ phone: string | null;
+ created_at: string;
+ isAdmin: boolean;
+ tasks: TaskType[];
+ profile_photo_path?: string | null;
}
interface AuthContextType {
- user: User | null;
- update: () => void;
+ user: User | null;
+ update: () => void;
}
-
-
-function ProfilePage(){
+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 isOwnProfile = !id || user?.id.toString() === id;
useEffect(() => {
- update();
- }, []);
+ (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();
+ }
+ };
+
+ // 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);
+ }
+ };
+
+ // 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);
+ }
+ };
return (
@@ -44,117 +140,69 @@ function ProfilePage(){
+ {isOwnProfile && (
+
+
+ {user?.profile_photo_path && (
+
+ )}
+
+ )}
+
+
+ {error &&
{error}
}
+ {success &&
{success}
}
+
- {user?.name} {user?.lastname}
+ {profileUser?.name} {profileUser?.lastname}
-
-
-
-
-
- Role : {user?.role}
-
-
- Membre depuis :{" "}
- {user && formatDate(user.created_at)}
-
-
-
-
-
- Mail : {user?.email}
-
-
- Téléphone :{" "}
- {user?.phone ?? "Pas de numéro enregistré"}
-
-
-
-
- {/* */}
-
-
-
-
Tâches :
-
- {/* {user && user.tasks.length > 0 ? (
- user.tasks.map((task) => (
-
- ))
- ) : (
-
Aucune tâche pour le moment.
- )}*/}
-
-
-
-
- );
-}
-
-export default ProfilePage;
-
-
-/*import React, { useContext, useEffect } from "react";
-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 SettingsModal from "./components/SettingsModal/SettingsModal.jsx";
-
-function ProfilePage() {
-
- const { user, update } = useContext(AuthContext);
-
- useEffect(() => {
- update();
- }, [])
-
- return (
-
-
-
-
-

-
-
-
-
{user?.name} {user?.lastname}
-
-
-
-
Role : {user?.role}
-
Membre depuis : {user && formatDate(user.created_at)}
-
-
-
Mail : {user?.email}
-
Téléphone : {user?.phone === null ? "Pas de numéro enregistré" : user?.phone}
-
-
-
-
-
-
-
Tâches :
- {user && user.tasks.length > 0 ? (
- user.tasks.map((task, index) => (
-
- ))
- ) : (
-
Aucune tâche pour le moment.
+ {user?.isAdmin && profileUser && !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.
+ )}
@@ -162,4 +210,4 @@ function ProfilePage() {
);
}
-export default ProfilePage;*/
\ No newline at end of file
+export default ProfilePage;
\ No newline at end of file
diff --git a/src/pages/Profile/components/SettingsModal/SettingsModal.jsx b/src/pages/Profile/components/SettingsModal/SettingsModal.jsx
deleted file mode 100644
index 4283559..0000000
--- a/src/pages/Profile/components/SettingsModal/SettingsModal.jsx
+++ /dev/null
@@ -1,86 +0,0 @@
-import Modal from "../../../../components/ui/modal/modal.jsx";
-import Button from "../../../../components/ui/button/button.jsx";
-import styles from "./SettingsModal.module.css"
-import { useContext, useState } from "react";
-import ThemeSwitcher from "../../../../components/ui/themeSwitcher/ThemeSwitcher.jsx";
-import { AuthContext } from "../../../../contexts/auth/AuthContext.js";
-import TextInput from "../../../../components/ui/input/input.jsx";
-import updateUser from "../../../../utils/users/updateUser.js";
-import deleteUser from "../../../../utils/users/deleteUser.js";
-
-
-export default function SettingsModal() {
-
- const { user, logout, update } = useContext(AuthContext);
-
- const [open, setOpen] = useState(false);
- const [isDelete, setIsDelete] = useState(false);
-
- const [name, setName] = useState(user?.name);
- const [lastname, setLastName] = useState(user?.lastname);
- const [phone, setPhone] = useState(user?.phone);
-
- const handleLogout = () => {
- logout();
- }
-
- const handleSubmit = async () => {
- await updateUser(name, lastname, phone);
- update();
- }
-
- const handleDelete = async () => {
- await deleteUser();
- update();
- }
-
- return (
- <>
-
-
-
setOpen(false)}>
-
-
-
-
Compte
-
-
-
-
-
Changer de Prénom
- setName(e.target.value)} type={"text"} />
-
-
-
-
Changer de nom
- setLastName(e.target.value)} type={"text"} />
-
-
-
-
Changer de numéro de téléphone
- setPhone(e.target.value)} type={"text"} />
-
-
-
-
-
-
-
-
Apparence
-
-
-
-
-
-
-
setIsDelete(false)}>
-
-
Êtes vous vraiment sûr de vouloir supprimer votre compte ?
-
-
-
- >
- )
-}
\ No newline at end of file
diff --git a/src/pages/Profile/components/SettingsModal/SettingsModal.module.css b/src/pages/Profile/components/SettingsModal/SettingsModal.module.css
index d6b0b12..7808db3 100644
--- a/src/pages/Profile/components/SettingsModal/SettingsModal.module.css
+++ b/src/pages/Profile/components/SettingsModal/SettingsModal.module.css
@@ -1,73 +1,98 @@
.content {
width: 100%;
- padding: 16px;
+ padding: 20px;
display: flex;
flex-direction: column;
- gap: 20px;
+ gap: 28px;
}
.modifyIcon {
- height: 28px;
- width: 28px;
+ height: 26px;
+ width: 26px;
+ transition: transform 0.2s ease, opacity 0.2s ease;
+}
+
+.modifyIcon:hover {
+ transform: rotate(15deg);
+ opacity: 0.8;
}
.section {
display: flex;
flex-direction: column;
- gap: 12px;
- margin-top: 10px;
+ gap: 16px;
+ padding: 18px;
+ border-radius: 12px;
+ background: var(--glass-bg, rgba(255, 255, 255, 0.25));
+ backdrop-filter: blur(6px);
}
.section h3 {
- font-size: 1.1rem;
- margin-bottom: 5px;
+ font-size: 1.15rem;
+ font-weight: 600;
}
.section h4 {
- font-size: 0.95rem;
+ font-size: 0.9rem;
font-weight: 500;
-}
-
-.submitBtn {
- width: 100%;
- margin-top: 15px;
+ opacity: 0.85;
}
.section button {
width: 100%;
}
-@media (min-width: 600px) {
+.submitBtn {
+ width: 100%;
+ text-align: center;
+ margin-top: 10px;
+}
+
+.alignText {
+ text-align: center;
+ line-height: 1.5;
+}
+
+.section :global(input) {
+ width: 100%;
+ box-sizing: border-box;
+}
+
+@media (min-width: 640px) {
.content {
- padding: 24px;
+ padding: 28px;
+ gap: 32px;
}
- .section h3 {
- font-size: 1.2rem;
+ .section {
+ padding: 22px;
+ gap: 18px;
}
.submitBtn {
width: auto;
align-self: center;
- min-width: 200px;
+ min-width: 220px;
}
.section button {
width: fit-content;
}
}
+
@media (min-width: 900px) {
.content {
- padding: 30px;
- gap: 30px;
+ padding: 36px;
+ gap: 36px;
}
.section {
- gap: 14px;
+ padding: 26px;
+ border-radius: 16px;
}
.modifyIcon {
height: 30px;
width: 30px;
}
-}
+}
\ No newline at end of file
diff --git a/src/pages/Profile/components/SettingsModal/SettingsModal.tsx b/src/pages/Profile/components/SettingsModal/SettingsModal.tsx
new file mode 100644
index 0000000..e028735
--- /dev/null
+++ b/src/pages/Profile/components/SettingsModal/SettingsModal.tsx
@@ -0,0 +1,167 @@
+import {useContext, useState, ChangeEvent} from "react";
+import Modal from "../../../../components/ui/modal/modal";
+import Button from "../../../../components/ui/button/button";
+import styles from "./SettingsModal.module.css";
+import ThemeSwitcher from "../../../../components/ui/themeSwitcher/ThemeSwitcher.jsx";
+import {AuthContext} from "../../../../contexts/auth/AuthContext";
+import TextInput from "../../../../components/ui/input/input";
+import updateUser from "../../../../utils/users/updateUser.js";
+import deleteUser from "../../../../utils/users/deleteUser.js";
+
+interface TaskType {
+ id: number;
+ title?: string;
+ completed?: boolean;
+
+ [key: string]: unknown;
+}
+
+interface User {
+ id: number;
+ name: string;
+ lastname: string;
+ role: string;
+ email: string;
+ phone: string | null;
+ created_at: string;
+ isAdmin: boolean;
+ tasks: TaskType[];
+}
+
+interface AuthContextType {
+ user: User;
+ update: () => void;
+ logout: () => void;
+}
+
+export default function SettingsModal() {
+ const {user, logout, update} = useContext(AuthContext) as AuthContextType;
+
+ const [open, setOpen] = useState
(false);
+ const [isDelete, setIsDelete] = useState(false);
+
+ const [name, setName] = useState(user?.name ?? "");
+ const [lastname, setLastName] = useState(user?.lastname ?? "");
+ const [phone, setPhone] = useState(user?.phone ?? "");
+
+ const handleLogout = (): void => {
+ logout();
+ };
+
+ const handleSubmit = async (): Promise => {
+ await updateUser(name, lastname, phone || null);
+ update();
+ setOpen(false);
+ };
+
+ const handleDelete = async (): Promise => {
+ await deleteUser();
+ update();
+ };
+
+ const handleNameChange = (e: ChangeEvent): void => {
+ setName(e.target.value);
+ };
+
+ const handleLastnameChange = (e: ChangeEvent): void => {
+ setLastName(e.target.value);
+ };
+
+ const handlePhoneChange = (e: ChangeEvent): void => {
+ setPhone(e.target.value);
+ };
+
+
+ return (
+ <>
+
+
+ setOpen(false)}
+ >
+
+
+
Compte
+
+
+
+
+
+
+
Changer de Prénom
+
+
+
+
+
Changer de nom
+
+
+
+
+
Changer de numéro de téléphone
+
+
+
+
+
+
+
+
Apparence
+
+
+
+
+
+ setIsDelete(false)}
+ >
+
+
+ Êtes vous vraiment sûr de vouloir supprimer votre compte ?
+
+
+
+
+ >
+ );
+}
diff --git a/src/pages/VolunteerProfile/components/manageMember/ManageMember.jsx b/src/pages/Profile/components/manageMember/ManageMember.jsx
similarity index 91%
rename from src/pages/VolunteerProfile/components/manageMember/ManageMember.jsx
rename to src/pages/Profile/components/manageMember/ManageMember.jsx
index 6266501..46f8ac2 100644
--- a/src/pages/VolunteerProfile/components/manageMember/ManageMember.jsx
+++ b/src/pages/Profile/components/manageMember/ManageMember.jsx
@@ -1,5 +1,5 @@
-import Button from "../../../../components/ui/button/button.jsx";
-import Modal from "../../../../components/ui/modal/modal.jsx";
+import Button from "../../../../components/ui/button/button.tsx";
+import Modal from "../../../../components/ui/modal/modal.tsx";
import {useContext, useState} from "react";
import styles from "./manageMember.module.css"
import DeactivateMemberBtn from "./deactivateMember/deactivateMemberBtn.jsx";
diff --git a/src/pages/VolunteerProfile/components/manageMember/deactivateMember/deactivateMemberBtn.jsx b/src/pages/Profile/components/manageMember/deactivateMember/deactivateMemberBtn.jsx
similarity index 89%
rename from src/pages/VolunteerProfile/components/manageMember/deactivateMember/deactivateMemberBtn.jsx
rename to src/pages/Profile/components/manageMember/deactivateMember/deactivateMemberBtn.jsx
index ccb8390..2f586f6 100644
--- a/src/pages/VolunteerProfile/components/manageMember/deactivateMember/deactivateMemberBtn.jsx
+++ b/src/pages/Profile/components/manageMember/deactivateMember/deactivateMemberBtn.jsx
@@ -1,5 +1,5 @@
-import Button from "../../../../../components/ui/button/button.jsx";
-import Modal from "../../../../../components/ui/modal/modal.jsx";
+import Button from "../../../../../components/ui/button/button.tsx";
+import Modal from "../../../../../components/ui/modal/modal.tsx";
import { useState } from "react";
import deactivateUser from "../../../../../utils/users/deactivateUser.js"
import { useNavigate } from "react-router";
diff --git a/src/pages/VolunteerProfile/components/manageMember/manageMember.module.css b/src/pages/Profile/components/manageMember/manageMember.module.css
similarity index 100%
rename from src/pages/VolunteerProfile/components/manageMember/manageMember.module.css
rename to src/pages/Profile/components/manageMember/manageMember.module.css
diff --git a/src/pages/VolunteerProfile/components/manageMember/modifyrole/ModifyRole.jsx b/src/pages/Profile/components/manageMember/modifyrole/ModifyRole.jsx
similarity index 93%
rename from src/pages/VolunteerProfile/components/manageMember/modifyrole/ModifyRole.jsx
rename to src/pages/Profile/components/manageMember/modifyrole/ModifyRole.jsx
index bc4d495..9f847f4 100644
--- a/src/pages/VolunteerProfile/components/manageMember/modifyrole/ModifyRole.jsx
+++ b/src/pages/Profile/components/manageMember/modifyrole/ModifyRole.jsx
@@ -1,9 +1,9 @@
import styles from "../manageMember.module.css";
-import Button from "../../../../../components/ui/button/button.jsx";
+import Button from "../../../../../components/ui/button/button.tsx";
import modifyRole from "../../../../../utils/users/modifyRole.js";
import { useState, useEffect } from "react";
import getRoles from "../../../../../utils/getRoles.js";
-import Modal from "../../../../../components/ui/modal/modal.jsx";
+import Modal from "../../../../../components/ui/modal/modal.tsx";
export default function ModifyRole({ user }) {
diff --git a/src/pages/Register/RegisterPage.jsx b/src/pages/Register/RegisterPage.jsx
index f0547c3..48c9751 100644
--- a/src/pages/Register/RegisterPage.jsx
+++ b/src/pages/Register/RegisterPage.jsx
@@ -1,12 +1,12 @@
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 Input from "../../components/ui/input/input.tsx";
+import Button from "../../components/ui/button/button.tsx";
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";
+import Modal from "../../components/ui/modal/modal.tsx";
function RegisterPage() {
diff --git a/src/pages/VolunteerProfile/VolunteerProfilePage.jsx b/src/pages/VolunteerProfile/VolunteerProfilePage.jsx
deleted file mode 100644
index 763b7f7..0000000
--- a/src/pages/VolunteerProfile/VolunteerProfilePage.jsx
+++ /dev/null
@@ -1,84 +0,0 @@
-import styles from "./VolunteerProfilePage.module.css";
-import { useParams, useNavigate } from "react-router";
-import { useEffect, useState, useContext } from "react";
-import getUserById from "../../utils/users/getUserById.js";
-import formatDate from "../../utils/date/formatDate.js";
-import Task from "../../components/Task/Task.jsx";
-import ManageMember from "./components/manageMember/ManageMember.jsx";
-import { AuthContext } from "../../contexts/auth/AuthContext.js";
-
-export default function VolunteerProfilePage() {
- const { id } = useParams();
- const navigate = useNavigate();
- const { user: currentUser } = useContext(AuthContext);
-
- const [user, setUser] = useState(null);
-
- useEffect(() => {
- (async () => {
- 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;
- }
-
- setUser(res.data);
- })();
- }, [id, navigate]);
-
- if (!user) return null;
-
- return (
-
-
-
-
-

-
-
-
-
-
{user.name} {user.lastname}
- {currentUser?.isAdmin && (
-
- )}
-
-
-
-
-
Role : {user.role}
-
Membre depuis : {formatDate(user.created_at)}
-
-
-
Mail : {user.email}
-
- Téléphone :{" "}
- {user.phone ?? "Pas de numéro enregistré"}
-
-
-
-
-
Tâches :
- {user.tasks?.length > 0 ? (
- user.tasks.map((task, index) => (
-
- ))
- ) : (
-
Aucune tâche pour le moment.
- )}
-
-
-
-
- );
-}
diff --git a/src/pages/VolunteerProfile/VolunteerProfilePage.module.css b/src/pages/VolunteerProfile/VolunteerProfilePage.module.css
deleted file mode 100644
index 834af59..0000000
--- a/src/pages/VolunteerProfile/VolunteerProfilePage.module.css
+++ /dev/null
@@ -1,163 +0,0 @@
-.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;
-}
-
-@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/Volunteers/VolunteerCard.jsx b/src/pages/Volunteers/VolunteerCard.jsx
deleted file mode 100644
index 144d708..0000000
--- a/src/pages/Volunteers/VolunteerCard.jsx
+++ /dev/null
@@ -1,78 +0,0 @@
-import React, {useState} from "react";
-import styles from "./VolunteersPage.module.css";
-import formatDate from "../../utils/date/formatDate.js";
-import { useNavigate } from "react-router";
-import Button from "../../components/ui/button/button.jsx";
-
-export default function VolunteerCard({ user }) {
-
- const [isExpanded, setIsExpanded] = useState(false);
-
- const toggleExpand = () => {
- setIsExpanded(!isExpanded);
- };
-
- const navigate = useNavigate();
-
- return (
- setIsExpanded(!isExpanded))}>
-
-
-
- {user?.name}{" "}
- {user?.lastname}
-
-
-
-
-
-
- {!isExpanded ? (
-
-
Rôle : {user?.role}
-
Membre depuis : {user?.created_at && formatDate(user.created_at)}
-
- ) : (
-
-
-

-
-
-
-
-
Rôle : {user?.role}
-
Membre depuis : {user?.created_at && formatDate(user.created_at)}
-
-
-
-
Email : {user?.email}
- {user?.phone &&
Téléphone : {user.phone}
}
-
-
-
- )}
-
-
- {isExpanded && (
-
-
-
- )}
-
-
- );
-
-
-
-}
\ No newline at end of file
diff --git a/src/pages/Volunteers/VolunteersPage.jsx b/src/pages/Volunteers/VolunteersPage.jsx
deleted file mode 100644
index 169275a..0000000
--- a/src/pages/Volunteers/VolunteersPage.jsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import { useState, useEffect } from "react";
-import styles from "./VolunteersPage.module.css";
-import VolunteerCard from "./VolunteerCard.jsx";
-import getAllUser from "../../utils/users/getAllUsers.js";
-import ToolBar from "../../components/ToolBar/ToolBar.jsx";
-import filter from "../../utils/filter.js";
-import getUserById from "../../utils/users/getUserById.js";
-
-function VolunteerPage() {
- const [filters, setFilters] = useState({
- alphabetical: "asc",
- yearOrder: "desc",
- });
- const [users, setUsers] = useState([]);
-
- useEffect(() => {
- (async () => {
- const result = await getAllUser();
-
- if (result.status !== 200 || !Array.isArray(result.data)) {
- console.error("Erreur lors du chargement des utilisateurs", result);
- return;
- }
-
- const usersData = await Promise.all(
- result.data.map(async (id) => {
- const res = await getUserById(id);
-
- if (res.status === 200) {
- return res.data;
- }
- console.warn(`Utilisateur ${id} non récupéré`, res.status);
- return null;
- })
- );
-
- setUsers(usersData.filter(Boolean));
- })();
- }, []);
-
- return (
-
-
-
- {filter(users, filters, "user").map((user, index) => (
-
- ))}
-
-
- );
-}
-
-export default VolunteerPage;
diff --git a/src/pages/Volunteers/VolunteersPage.module.css b/src/pages/Volunteers/VolunteersPage.module.css
index 6ef455b..b953cb5 100644
--- a/src/pages/Volunteers/VolunteersPage.module.css
+++ b/src/pages/Volunteers/VolunteersPage.module.css
@@ -3,33 +3,18 @@
position: relative;
padding: 10px;
}
-.userName {
- display: flex;
- gap: 5px;
- font-weight: bold;
- font-size: 1rem;
- overflow: hidden;
-}
-
-.firstName {
- white-space: nowrap;
- flex-shrink: 0;
-}
-
-.lastName {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- flex-shrink: 1;
- max-width: 100px;
-}
.usersList {
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 10px;
+ display: grid;
+ gap: 16px;
+ width: 100%;
+ grid-template-columns: 1fr;
}
+
+.usersList > * {
+ min-width: 0;
+}
+
.profileboard {
width: 100%;
max-width: 380px;
@@ -140,12 +125,23 @@
}
}
+.loading {
+ width: 100%;
+ text-align: center;
+ font-size: 1.1rem;
+ opacity: 1;
+ color: white;
+}
+
@media screen and (min-width: 1024px) {
.container {
padding: 20px;
}
.usersList {
gap: 20px;
+ grid-template-columns: repeat(3, 1fr);
+ padding-right: 5em;
+ padding-left: 5em;
}
.profileboard {
max-width: 700px;
diff --git a/src/pages/Volunteers/VolunteersPage.tsx b/src/pages/Volunteers/VolunteersPage.tsx
new file mode 100644
index 0000000..ae43fbc
--- /dev/null
+++ b/src/pages/Volunteers/VolunteersPage.tsx
@@ -0,0 +1,81 @@
+import { useEffect, useState } from "react";
+import styles from "./VolunteersPage.module.css";
+import VolunteerCard from "./components/VolunteersCard/VolunteerCard";
+import getAllUser from "../../utils/users/getAllUsers";
+import ToolBar from "../../components/ToolBar/ToolBar";
+import filter from "../../utils/filter";
+import getUserById from "../../utils/users/getUserById";
+import User from "./interfaces/user.interface";
+import Loading from "../../components/ui/loading/loading";
+
+interface Filters {
+ alphabetical: "asc" | "desc";
+ yearOrder: "asc" | "desc";
+}
+
+const VolunteerPage: React.FC = () => {
+ const [filters, setFilters] = useState({
+ alphabetical: "asc",
+ yearOrder: "desc",
+ });
+
+ const [users, setUsers] = useState([]);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ const fetchUsers = async (): Promise => {
+ setLoading(true);
+
+ try {
+ const result = await getAllUser();
+
+ if (result.status !== 200 || !Array.isArray(result.data)) {
+ console.error("Erreur lors du chargement des utilisateurs", result);
+ return;
+ }
+
+ const usersData = await Promise.all(
+ result.data.map(async (id: number): Promise => {
+ const res = await getUserById(id);
+
+ if (res.status === 200) {
+ return res.data as User;
+ }
+
+ console.warn(`Utilisateur ${id} non récupéré`, res.status);
+ return null;
+ })
+ );
+
+ setUsers(usersData.filter((user): user is User => user !== null));
+ } catch (error) {
+ console.error("Erreur réseau", error);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchUsers();
+ }, []);
+
+ if(loading) return ;
+
+ return (
+
+
+
+
+ {filter(users, filters, "user").map((user: User) => (
+
+ ))}
+
+
+
+ );
+};
+
+export default VolunteerPage;
diff --git a/src/pages/Volunteers/components/VolunteersCard/VolunteerCard.tsx b/src/pages/Volunteers/components/VolunteersCard/VolunteerCard.tsx
new file mode 100644
index 0000000..a3d5f01
--- /dev/null
+++ b/src/pages/Volunteers/components/VolunteersCard/VolunteerCard.tsx
@@ -0,0 +1,29 @@
+import styles from "./VolunteersCard.module.css";
+import { useNavigate } from "react-router";
+import Button from "../../../../components/ui/button/button";
+import User from "../../interfaces/user.interface"
+
+
+interface VolunteersCardProps {
+ user: User;
+}
+
+export default function VolunteerCard({ user }: VolunteersCardProps) {
+
+ const navigate = useNavigate();
+
+ const handleNavigate = (): void => { navigate(`/profile/${user.id}`) }
+
+ return (
+
+
+

+
{user.name} {user.lastname}
+
+
+
+ );
+}
diff --git a/src/pages/Volunteers/components/VolunteersCard/VolunteersCard.module.css b/src/pages/Volunteers/components/VolunteersCard/VolunteersCard.module.css
new file mode 100644
index 0000000..4ed1ccf
--- /dev/null
+++ b/src/pages/Volunteers/components/VolunteersCard/VolunteersCard.module.css
@@ -0,0 +1,47 @@
+.volunteerCard {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.header {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ min-width: 0;
+}
+
+.header p {
+ flex: 1;
+ min-width: 0;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.content {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ min-width: 0;
+}
+
+.content p {
+ flex: 1;
+ min-width: 0;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.content button {
+ flex-shrink: 0;
+}
+
+.profilePicture {
+ background-color: #1d1d1f;
+ border-radius: 20px;
+ width: 40px;
+ height: 40px;
+ flex-shrink: 0;
+}
diff --git a/src/pages/Volunteers/interfaces/task.interface.ts b/src/pages/Volunteers/interfaces/task.interface.ts
new file mode 100644
index 0000000..b6206c9
--- /dev/null
+++ b/src/pages/Volunteers/interfaces/task.interface.ts
@@ -0,0 +1,16 @@
+export default interface Task {
+ 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;
+ }
+}
\ No newline at end of file
diff --git a/src/pages/Volunteers/interfaces/user.interface.ts b/src/pages/Volunteers/interfaces/user.interface.ts
new file mode 100644
index 0000000..e22a1cd
--- /dev/null
+++ b/src/pages/Volunteers/interfaces/user.interface.ts
@@ -0,0 +1,16 @@
+import Task from "./task.interface";
+
+export default interface User {
+ id: number;
+ name: string;
+ lastname: string;
+ email: string;
+ role: string;
+ isAdmin: boolean;
+ phone: string | null;
+ created_at: string;
+ updated_at: string;
+ verified_at: string | null;
+ validate: number;
+ tasks: Task[];
+}
\ No newline at end of file
diff --git a/src/pages/eventDetail/components/EventTask/EventTask.jsx b/src/pages/eventDetail/components/EventTask/EventTask.jsx
index bbde7b6..6bea6e0 100644
--- a/src/pages/eventDetail/components/EventTask/EventTask.jsx
+++ b/src/pages/eventDetail/components/EventTask/EventTask.jsx
@@ -1,17 +1,17 @@
import styles from "./eventTask.module.css";
import { formatDateLetter } from "../../../../utils/date/formatDateLetter.js";
-import Button from "../../../../components/ui/button/button.jsx";
+import Button from "../../../../components/ui/button/button.tsx";
import assign from "../../../../utils/tasks/assign.js";
import unAssign from "../../../../utils/tasks/unAssign.js";
import { useContext, useEffect, useState } from "react";
import isAssigned from "../../../../utils/tasks/isAssigned.js";
-import Modal from "../../../../components/ui/modal/modal.jsx";
+import Modal from "../../../../components/ui/modal/modal.tsx";
import { AuthContext } from "../../../../contexts/auth/AuthContext.js";
import DeleteTaskBtn from "../deleteTaskBtn/deleteTaskBtn.jsx";
export default function EventTask({ task, index, eventId }) {
- const { user } = useContext(AuthContext)
+ const { update } = useContext(AuthContext)
const [assigned, setAssigned] = useState(false);
const [open, setOpen] = useState(false);
@@ -33,6 +33,7 @@ export default function EventTask({ task, index, eventId }) {
switch (res.status) {
case 200:
+ update()
setTitle("Inscription réussie")
setMessage(`Vous êtes maintenant inscrit à la tâche ${task.name}`);
setOpen(true);
@@ -58,6 +59,7 @@ export default function EventTask({ task, index, eventId }) {
switch (res.status) {
case 200:
+ update()
setTitle("Désinscription réussie")
setMessage(`Vous n'êtes plus inscrit à la tâche ${task.name}`);
setOpen(true);
diff --git a/src/pages/eventDetail/components/createTaskBtn/createTaskBtn.jsx b/src/pages/eventDetail/components/createTaskBtn/createTaskBtn.jsx
index 8862ada..6ad9d4b 100644
--- a/src/pages/eventDetail/components/createTaskBtn/createTaskBtn.jsx
+++ b/src/pages/eventDetail/components/createTaskBtn/createTaskBtn.jsx
@@ -1,8 +1,8 @@
import styles from "../../eventDetail.module.css";
-import Button from "../../../../components/ui/button/button.jsx";
+import Button from "../../../../components/ui/button/button.tsx";
import {useContext, useState} from "react";
-import TextInput from "../../../../components/ui/input/input.jsx";
-import Modal from "../../../../components/ui/modal/modal.jsx";
+import TextInput from "../../../../components/ui/input/input.tsx";
+import Modal from "../../../../components/ui/modal/modal.tsx";
import createTaskApi from "../../../../utils/tasks/createTask.js";
import {EventDetailContext} from "../../../../contexts/eventDetail/eventDetail.js";
diff --git a/src/pages/eventDetail/components/deleteEventBtn/deleteEventBtn.jsx b/src/pages/eventDetail/components/deleteEventBtn/deleteEventBtn.jsx
index 813a995..c3b4383 100644
--- a/src/pages/eventDetail/components/deleteEventBtn/deleteEventBtn.jsx
+++ b/src/pages/eventDetail/components/deleteEventBtn/deleteEventBtn.jsx
@@ -1,6 +1,6 @@
import styles from "../../eventDetail.module.css";
-import Button from "../../../../components/ui/button/button.jsx";
-import Modal from "../../../../components/ui/modal/modal.jsx";
+import Button from "../../../../components/ui/button/button.tsx";
+import Modal from "../../../../components/ui/modal/modal.tsx";
import { useContext, useState } from "react";
import { EventDetailContext } from "../../../../contexts/eventDetail/eventDetail.js";
import { EventContext } from "../../../../contexts/events/EventContext.js";
diff --git a/src/pages/eventDetail/components/deleteTaskBtn/deleteTaskBtn.jsx b/src/pages/eventDetail/components/deleteTaskBtn/deleteTaskBtn.jsx
index fdad16f..90a749b 100644
--- a/src/pages/eventDetail/components/deleteTaskBtn/deleteTaskBtn.jsx
+++ b/src/pages/eventDetail/components/deleteTaskBtn/deleteTaskBtn.jsx
@@ -1,9 +1,9 @@
import { useContext } from "react";
import { AuthContext } from "../../../../contexts/auth/AuthContext.js";
import { EventDetailContext } from "../../../../contexts/eventDetail/eventDetail.js";
-import Button from "../../../../components/ui/button/button.jsx";
+import Button from "../../../../components/ui/button/button.tsx";
import { useState } from "react";
-import Modal from "../../../../components/ui/modal/modal.jsx";
+import Modal from "../../../../components/ui/modal/modal.tsx";
import styles from "../../eventDetail.module.css";
export default function DeleteTaskBtn({ taskId, eventId, taskName }) {
diff --git a/src/pages/waitValidationPage/ValidationErrorPage.jsx b/src/pages/waitValidationPage/ValidationErrorPage.jsx
index aeff346..3086d77 100644
--- a/src/pages/waitValidationPage/ValidationErrorPage.jsx
+++ b/src/pages/waitValidationPage/ValidationErrorPage.jsx
@@ -1,6 +1,6 @@
import styles from "./validationErrorPage.module.css"
import Background from "../../components/background/background.jsx";
-import Button from "../../components/ui/button/button.jsx";
+import Button from "../../components/ui/button/button.tsx";
import { useContext } from "react";
import { AuthContext } from "../../contexts/auth/AuthContext.js";
import { Navigate, useNavigate, Link } from "react-router";
diff --git a/src/router.js b/src/router.js
index b9137b0..662f8f8 100644
--- a/src/router.js
+++ b/src/router.js
@@ -3,12 +3,11 @@ import Layout from "./layout.jsx";
import HomePage from "./pages/Home/HomePage";
import LoginPage from "./pages/Login/LoginPage";
import RegisterPage from "./pages/Register/RegisterPage.jsx";
-import VolunteersPage from "./pages/Volunteers/VolunteersPage";
+import VolunteersPage from "./pages/Volunteers/VolunteersPage.tsx";
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";
import eventDetail from "./pages/eventDetail/eventDetail.jsx";
import legalNotices from "./pages/LegalNotices/LegalNotices.jsx";
@@ -47,10 +46,6 @@ const router = createBrowserRouter([
path: "/admin",
Component:AdminPage,
},
- {
- path:"/profile",
- Component:ProfilePage,
- },
{
path: "/events",
Component: EventsPage,
@@ -59,9 +54,13 @@ const router = createBrowserRouter([
path: "/volunteers",
Component: VolunteersPage,
},
+ {
+ path:"/profile",
+ Component:ProfilePage,
+ },
{
path: "/profile/:id",
- Component: VolunteerProfilePage,
+ Component: ProfilePage,
},
{
path: "/events/:id",
diff --git a/src/stories/Button.stories.jsx b/src/stories/Button.stories.jsx
index 3f86188..3179067 100644
--- a/src/stories/Button.stories.jsx
+++ b/src/stories/Button.stories.jsx
@@ -1,6 +1,6 @@
import { fn } from 'storybook/test';
-import Button from '../components/ui/button/button.jsx';
+import Button from '../components/ui/button/button.tsx';
export default {
diff --git a/src/stories/Input.stories.jsx b/src/stories/Input.stories.jsx
index 1d3cc0c..86cd833 100644
--- a/src/stories/Input.stories.jsx
+++ b/src/stories/Input.stories.jsx
@@ -1,5 +1,5 @@
import { useState } from "react";
-import TextInput from "../components/ui/input/input.jsx";
+import TextInput from "../components/ui/input/input.tsx";
export default {
diff --git a/src/stories/Loading.stories.jsx b/src/stories/Loading.stories.jsx
new file mode 100644
index 0000000..6986aa8
--- /dev/null
+++ b/src/stories/Loading.stories.jsx
@@ -0,0 +1,13 @@
+import Loading from "../components/ui/loading/loading.tsx";
+
+
+export default {
+ title: 'UI/Loading',
+ component: Loading,
+ parameters: {
+ layout: 'centered',
+ },
+ tags: ['autodocs'],
+};
+
+export const Primary = {};
\ No newline at end of file
diff --git a/src/stories/Modal.stories.jsx b/src/stories/Modal.stories.jsx
index 1ece2ae..0983105 100644
--- a/src/stories/Modal.stories.jsx
+++ b/src/stories/Modal.stories.jsx
@@ -1,5 +1,5 @@
-import Modal from "../components/ui/modal/modal.jsx";
-import Button from "../components/ui/button/button.jsx";
+import Modal from "../components/ui/modal/modal.tsx";
+import Button from "../components/ui/button/button.tsx";
import { useState } from "react";
export default {
diff --git a/src/utils/echo/initEcho.js b/src/utils/echo/initEcho.js
index 9d27b37..4e59d4b 100644
--- a/src/utils/echo/initEcho.js
+++ b/src/utils/echo/initEcho.js
@@ -14,8 +14,31 @@ export default function initEcho() {
encrypted: import.meta.env.VITE_ENCRYPTED === 'true',
cluster: import.meta.env.VITE_CLUSTER,
enabledTransports: ['ws', 'wss'],
+ authorizer: (channel) => {
+ return {
+ authorize: (socketId, callback) => {
+ fetch(`${import.meta.env.VITE_API_URL}/broadcasting/auth`, {
+ method: 'POST',
+ credentials: 'include',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'X-Requested-With': 'XMLHttpRequest',
+ },
+ body: JSON.stringify({
+ socket_id: socketId,
+ channel_name: channel.name,
+ }),
+ })
+ .then(res => res.json())
+ .then(data => callback(null, data))
+ .catch(err => callback(err, null));
+ },
+ };
+ },
});
+
+
window.Echo = echoInstance;
return echoInstance;
}
diff --git a/src/utils/echo/listeners/userCreatedListener.js b/src/utils/echo/listeners/userCreatedListener.js
index e2bb017..a4a36c4 100644
--- a/src/utils/echo/listeners/userCreatedListener.js
+++ b/src/utils/echo/listeners/userCreatedListener.js
@@ -1,4 +1,4 @@
-export const userCreatedListener = (echo, userData, setNotifications, setunreadNotification) => {
+export const userCreatedListener = (echo, userData, setNotifications, setunreadNotification, updatePendingMembers) => {
if (userData.isAdmin) {
const channelName = "users.registration";
echo.private(channelName)
@@ -11,6 +11,7 @@ export const userCreatedListener = (echo, userData, setNotifications, setunreadN
};
setNotifications(prev => [newNotification, ...prev]);
setunreadNotification(true);
+ updatePendingMembers();
});
return channelName;
}
diff --git a/src/utils/fetchWrapper.js b/src/utils/fetchWrapper.js
deleted file mode 100644
index aa9f0a0..0000000
--- a/src/utils/fetchWrapper.js
+++ /dev/null
@@ -1,45 +0,0 @@
-export default async function fetchWrapper(
- path,
- data = null,
- method = "GET",
- headers = {}
-) {
- try {
- const res = await fetch(
- `${import.meta.env.VITE_API_URL}${path}`,
- {
- method,
- credentials: "include",
- headers: {
- "Accept": "application/json",
- "Content-Type": "application/json",
- ...headers,
- },
- body: data ? JSON.stringify(data) : null,
- }
- );
-
- let responseData = null;
-
- try {
- responseData = await res.json();
- } catch (_) {
- responseData = null;
- }
-
- return {
- status: res.status,
- data: responseData,
- };
-
- } catch (err) {
- console.error("❌ Erreur réseau :", err);
-
- return {
- status: 0,
- data: {
- message: "Network error",
- },
- };
- }
-}
diff --git a/src/utils/fetchWrapper.ts b/src/utils/fetchWrapper.ts
new file mode 100644
index 0000000..a130373
--- /dev/null
+++ b/src/utils/fetchWrapper.ts
@@ -0,0 +1,92 @@
+/*export default async function fetchWrapper(path,data = null,method = "GET",headers = {}) {
+ try {
+ const res = await fetch(
+ `${import.meta.env.VITE_API_URL}${path}`,
+ {
+ method,
+ credentials: "include",
+ headers: {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ ...headers,
+ },
+ body: data ? JSON.stringify(data) : null,
+ }
+ );
+
+ let responseData = null;
+
+ try {
+ responseData = await res.json();
+ } catch (_) {
+ responseData = null;
+ }
+
+ return {
+ status: res.status,
+ data: responseData,
+ };
+
+ } catch (err) {
+ console.error("❌ Erreur réseau :", err);
+
+ return {
+ status: 0,
+ data: {
+ message: "Network error",
+ },
+ };
+ }
+}*/
+
+interface FetchResponse {
+ status: number;
+ data: T | null;
+}
+
+export default async function fetchWrapper(
+ path: string,
+ data: any = null,
+ method: string = "GET",
+ headers: Record = {}
+): Promise {
+ try {
+ const res = await fetch(
+ `${import.meta.env.VITE_API_URL}${path}`,
+ {
+ method,
+ credentials: "include",
+ headers: {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ ...headers,
+ },
+ body: data ? JSON.stringify(data) : null,
+ }
+ );
+
+ let responseData = null;
+
+ try {
+ responseData = await res.json();
+ } catch (_) {
+ responseData = null;
+ }
+
+ return {
+ status: res.status,
+ data: responseData,
+ };
+
+ } catch (err) {
+ console.error("❌ Erreur réseau :", err);
+
+ return {
+ status: 0,
+ data: {
+ message: "Network error",
+ },
+ };
+ }
+}
+
diff --git a/src/utils/getXSRF.js b/src/utils/getXSRF.js
deleted file mode 100644
index f1dc5fc..0000000
--- a/src/utils/getXSRF.js
+++ /dev/null
@@ -1,19 +0,0 @@
-export default async function getXSRFToken() {
- const response = await fetch(`${import.meta.env.VITE_API_URL}/sanctum/csrf-cookie`, {
- method: 'GET',
- credentials: 'include'
- });
-
- if (!response.ok && response.status !== 204) {
- throw new Error(`Error : ${response.status}`);
- }
-
- const name = 'XSRF-TOKEN';
- const value = `; ${document.cookie}`;
- const parts = value.split(`; ${name}=`);
- if (parts.length === 2) {
- return decodeURIComponent(parts.pop().split(';').shift());
- }
-
- throw new Error('Error: Invalid XSRF-TOKEN');
-}
diff --git a/src/utils/getXSRF.ts b/src/utils/getXSRF.ts
new file mode 100644
index 0000000..f96606d
--- /dev/null
+++ b/src/utils/getXSRF.ts
@@ -0,0 +1,40 @@
+/*export default async function getXSRFToken() {
+ const response = await fetch(`${import.meta.env.VITE_API_URL}/sanctum/csrf-cookie`, {
+ method: 'GET',
+ credentials: 'include'
+ });
+
+ if (!response.ok && response.status !== 204) {
+ throw new Error(`Error : ${response.status}`);
+ }
+
+ const name = 'XSRF-TOKEN';
+ const value = `; ${document.cookie}`;
+ const parts = value.split(`; ${name}=`);
+ if (parts.length === 2) {
+ return decodeURIComponent(parts.pop().split(';').shift());
+ }
+
+ throw new Error('Error: Invalid XSRF-TOKEN');
+}*/
+
+export default async function getXSRFToken(): Promise {
+ const response = await fetch(`${import.meta.env.VITE_API_URL}/sanctum/csrf-cookie`, {
+ method: 'GET',
+ credentials: 'include'
+ });
+
+ if (!response.ok && response.status !== 204) {
+ throw new Error(`Error : ${response.status}`);
+ }
+
+ const name = 'XSRF-TOKEN';
+ const value = `; ${document.cookie}`;
+ const parts = value.split(`; ${name}=`);
+ if (parts.length === 2) {
+ return decodeURIComponent(parts.pop()!.split(';').shift()!);
+ }
+
+ throw new Error('Error: Invalid XSRF-TOKEN');
+}
+
diff --git a/src/utils/users/adminCreateUser.ts b/src/utils/users/adminCreateUser.ts
new file mode 100644
index 0000000..01860d3
--- /dev/null
+++ b/src/utils/users/adminCreateUser.ts
@@ -0,0 +1,14 @@
+import fetchWrapper from "../fetchWrapper.js";
+import getXSRFToken from "../getXSRF.js";
+import Response from "../../interfaces/response.interface";
+
+export default async function adminCreateUser(email: string, name: string, lastname: string, phone: string): Promise {
+ const csrfToken = await getXSRFToken();
+
+ return fetchWrapper(
+ "/api/users/create",
+ { email, name, lastname, phone },
+ "POST",
+ { "X-XSRF-TOKEN": csrfToken }
+ );
+}
diff --git a/src/utils/users/deleteProfilePhoto.ts b/src/utils/users/deleteProfilePhoto.ts
new file mode 100644
index 0000000..d0ca642
--- /dev/null
+++ b/src/utils/users/deleteProfilePhoto.ts
@@ -0,0 +1,10 @@
+import fetchWrapper from "../fetchWrapper";
+
+export default async function deleteProfilePhoto(): Promise<{ status: number; ok: boolean; data?: any; error?: string }> {
+ try {
+ const response = await fetchWrapper("/api/profile-photo", null, "DELETE");
+ return { status: response.status || 0, ok: response.status >= 200 && response.status < 300, data: response.data };
+ } catch (err: any) {
+ return { status: 0, ok: false, error: err?.message || "Network error" };
+ }
+}
diff --git a/src/utils/users/deleteUser.js b/src/utils/users/deleteUser.js
deleted file mode 100644
index 4cb9dcf..0000000
--- a/src/utils/users/deleteUser.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import fetchWrapper from "../fetchWrapper.js";
-import getXSRFToken from "../getXSRF.js";
-
-export default async function deleteUser() {
- const csrfToken = await getXSRFToken();
-
- return fetchWrapper(
- "/api/users",
- null,
- "DELETE",
- { "X-XSRF-TOKEN": csrfToken }
- );
-}
diff --git a/src/utils/users/deleteUser.ts b/src/utils/users/deleteUser.ts
new file mode 100644
index 0000000..193e5b0
--- /dev/null
+++ b/src/utils/users/deleteUser.ts
@@ -0,0 +1,13 @@
+import fetchWrapper from "../fetchWrapper";
+import getXSRFToken from "../getXSRF";
+
+export default async function deleteUser(): Promise<{status: number;data: any;}> {
+ const csrfToken: string = await getXSRFToken();
+
+ return fetchWrapper(
+ "/api/users",
+ null,
+ "DELETE",
+ { "X-XSRF-TOKEN": csrfToken }
+ );
+}
diff --git a/src/utils/users/replaceProfilePhoto.ts b/src/utils/users/replaceProfilePhoto.ts
new file mode 100644
index 0000000..92569eb
--- /dev/null
+++ b/src/utils/users/replaceProfilePhoto.ts
@@ -0,0 +1,5 @@
+import uploadProfilePhoto from "./uploadProfilePhoto";
+
+export default async function replaceProfilePhoto(file: File) {
+ return uploadProfilePhoto(file);
+}
diff --git a/src/utils/users/updateUser.js b/src/utils/users/updateUser.js
deleted file mode 100644
index af18273..0000000
--- a/src/utils/users/updateUser.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import fetchWrapper from "../fetchWrapper.js";
-import getXSRFToken from "../getXSRF.js";
-
-export default async function updateUser(name, lastname, phone) {
- const csrfToken = await getXSRFToken();
-
- return fetchWrapper(
- "/api/users/update",
- { name, lastname, phone },
- "POST",
- { "X-XSRF-TOKEN": csrfToken }
- );
-}
diff --git a/src/utils/users/updateUser.ts b/src/utils/users/updateUser.ts
new file mode 100644
index 0000000..6714250
--- /dev/null
+++ b/src/utils/users/updateUser.ts
@@ -0,0 +1,33 @@
+/*import fetchWrapper from "../fetchWrapper.js";
+import getXSRFToken from "../getXSRF.js";
+
+export default async function updateUser(name, lastname, phone) {
+ const csrfToken = await getXSRFToken();
+
+ return fetchWrapper(
+ "/api/users/update",
+ { name, lastname, phone },
+ "POST",
+ { "X-XSRF-TOKEN": csrfToken }
+ );
+}*/
+
+import fetchWrapper from "../fetchWrapper";
+import getXSRFToken from "../getXSRF";
+
+interface UserUpdateData {
+ name: string;
+ lastname: string;
+ phone: string | null;
+}
+
+interface RequestHeaders {
+ "X-XSRF-TOKEN": string;
+}
+export default async function updateUser(name: string,lastname: string,phone: string | null): Promise {
+ const csrfToken: string = await getXSRFToken();
+ const userData: UserUpdateData = {name,lastname,phone,};
+ const headers: RequestHeaders = {"X-XSRF-TOKEN": csrfToken,};
+ return fetchWrapper("/api/users/update",userData,"POST",headers);
+}
+
diff --git a/src/utils/users/uploadProfilePhoto.ts b/src/utils/users/uploadProfilePhoto.ts
new file mode 100644
index 0000000..ca252a2
--- /dev/null
+++ b/src/utils/users/uploadProfilePhoto.ts
@@ -0,0 +1,28 @@
+import getXSRFToken from "../getXSRF.js";
+
+export default async function uploadProfilePhoto(file: File): Promise<{ status: number; ok: boolean; data?: any; error?: string }> {
+ const formData = new FormData();
+ formData.append("photo", file);
+
+ try {
+ const csrfToken = await getXSRFToken();
+ const response = await fetch(`${import.meta.env.VITE_API_URL}/api/profile-photo`, {
+ method: "POST",
+ headers: { "X-XSRF-TOKEN": decodeURIComponent(csrfToken) },
+ credentials: "include",
+ body: formData,
+ });
+
+ const status = response.status;
+ let data = null;
+ try {
+ data = await response.json();
+ } catch (e) {
+ // no json
+ }
+
+ return { status, ok: response.ok, data };
+ } catch (err: any) {
+ return { status: 0, ok: false, error: err?.message || "Network error" };
+ }
+}
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts
new file mode 100644
index 0000000..b67473e
--- /dev/null
+++ b/src/vite-env.d.ts
@@ -0,0 +1,6 @@
+///
+
+declare module "*.module.css" {
+ const classes: { [key: string]: string };
+ export default classes;
+}
diff --git a/tsconfig.json b/tsconfig.json
index 693c67f..3417353 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,49 +1,4 @@
{
- // Visit https://aka.ms/tsconfig to read more about this file
- /*"compilerOptions": {*/
- // File Layout
- // "rootDir": "./src",
- // "outDir": "./dist",
-
- // Environment Settings
- // See also https://aka.ms/tsconfig/module
- /*"module": "nodenext",
- "target": "esnext",
- "types": [],*/
- // For nodejs:
- // "lib": ["esnext"],
- // "types": ["node"],
- // and npm install -D @types/node
-
- // Other Outputs
- /*"sourceMap": true,
- "declaration": true,
- "declarationMap": true,*/
-
- // Stricter Typechecking Options
- /*"noUncheckedIndexedAccess": true,
- "exactOptionalPropertyTypes": true,*/
-
- // Style Options
- // "noImplicitReturns": true,
- // "noImplicitOverride": true,
- // "noUnusedLocals": true,
- // "noUnusedParameters": true,
- // "noFallthroughCasesInSwitch": true,
- // "noPropertyAccessFromIndexSignature": true,
-
- // Recommended Options
- /* "strict": true,
- "jsx": "react-jsx",
- "verbatimModuleSyntax": true,
- "isolatedModules": true,
- "noUncheckedSideEffectImports": true,
- "moduleDetection": "force",
- "skipLibCheck": true,
- }
-}
-
-{*/
"compilerOptions": {
"target": "ESNext",
"lib": ["DOM", "DOM.Iterable", "ESNext"],
@@ -52,11 +7,13 @@
"jsx": "react-jsx",
"strict": true,
"isolatedModules": true,
-
- "noUncheckedIndexedAccess": true,
+ "noUncheckedIndexedAccess": false,
"exactOptionalPropertyTypes": true,
-
"resolveJsonModule": true,
- "skipLibCheck": true
- }
+ "skipLibCheck": true,
+ "allowJs": true,
+ "esModuleInterop": true
+ },
+ "include": ["src"]
+ // "exclude": ["**/*.js"]
}