permissions review

This commit is contained in:
2026-01-14 22:44:07 +01:00
parent 8aaf8e08a2
commit 9a0959e1cb
16 changed files with 131 additions and 41 deletions
-1
View File
@@ -45,7 +45,6 @@ export default function Footer(){
</div>
</footer>
{/* TODO : mettre nos noms dans un fichier de configuration */}
<Modal title={"Réalisé par"} open={isCopyrightModal} onClose={() => setIsCopyrightModal(false)}>
<section className={styles.section}>
<div className={styles.inputContainer}>
+3 -7
View File
@@ -9,7 +9,6 @@ import getUserNotifications from "../../utils/notifications/getUserNotifications
import deleteNotificationUser from "../../utils/notifications/deleteNotificationUser.js";
import initEcho from "../../utils/echo/initEcho.js"
import readNotifications from "../../utils/notifications/readNotifications.js";
import getUser from "../../utils/getUser.js";
import { userCreatedListener } from "../../utils/echo/listeners/userCreatedListener";
import { userNotificationsListener } from "../../utils/echo/listeners/userNotificationsListener.js";
import NotificationCard from "../NotificationCard/NotificationCard.jsx";
@@ -28,10 +27,7 @@ function Header() {
async function initializeHeader() {
try {
const [userData, notifData] = await Promise.all([
getUser(),
getUserNotifications()
]);
const notifData = await getUserNotifications();
const data = notifData || [];
setNotifications(data);
@@ -42,8 +38,8 @@ function Header() {
echoInstance = echo;
const activeChannels = [
userCreatedListener(echo, userData, setNotifications, setunreadNotification),
userNotificationsListener(echo, userData, setNotifications, setunreadNotification),
userCreatedListener(echo, user, setNotifications, setunreadNotification),
userNotificationsListener(echo, user, setNotifications, setunreadNotification),
];
channelsToLeave = activeChannels.filter(name => name !== null);
@@ -5,7 +5,7 @@ import styles from "./PendingMembers.module.css";
import getUserToValidate from "../../utils/users/getUserToValidate";
import getUserById from "../../utils/users/getUserById";
import validateUser from "../../utils/users/validateUser";
import deleteUser from "../../utils/users/deleteUser";
import deleteOtherUser from "../../utils/users/deleteOtherUser.js";
function PendingMembers() {
const [pendingMembers, setPendingMembers] = useState([]);
@@ -55,7 +55,7 @@ function PendingMembers() {
setActionLoading(id);
setError(null);
try {
const result = await deleteUser(id);
const result = await deleteOtherUser(id);
if (result.success) {
removeMember(id);
} else {
+1 -1
View File
@@ -65,7 +65,7 @@ function SearchBar() {
<div className={styles.elementList}>
{searchResults.map((result, i) => (
(location.pathname.includes("events")) ? (
<Link to={`/event/` + result.id}>
<Link to={`/events/` + result.id}>
<div className={styles.searchedEvent} key={i}>
<div className={`${styles.eventImageDiv}`}>
{result.image == null ? (
@@ -6,6 +6,7 @@ import ThemeSwitcher from "../ui/themeSwitcher/ThemeSwitcher.jsx";
import { AuthContext } from "../../contexts/auth/AuthContext.js";
import TextInput from "../ui/input/input.jsx";
import updateUser from "../../utils/users/updateUser.js";
import deleteUser from "../../utils/users/deleteUser.js";
export default function SettingsModal() {
@@ -13,6 +14,7 @@ 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);
@@ -27,6 +29,11 @@ export default function SettingsModal() {
update();
}
const handleDelete = async () => {
await deleteUser();
update();
}
return (
<>
<Button variant={"transparent"} onClick={() => setOpen(!open)}>
@@ -39,6 +46,7 @@ export default function SettingsModal() {
<div className={styles.section}>
<h3>Compte</h3>
<Button variant={"danger"} onClick={handleLogout}> Déconnexion </Button>
<Button variant={"danger"} onClick={() => setIsDelete(true)}> Supprimer le compte </Button>
<div className={styles.section}>
<h4>Changer de Prénom</h4>
@@ -65,6 +73,14 @@ export default function SettingsModal() {
</div>
</div>
</Modal>
<Modal title={"Validation"} open={isDelete} onClose={() => setIsDelete(false)}>
<div className={styles.section}>
<p className={styles.alignText}> Êtes vous vraiment sûr de vouloir supprimer votre compte ?</p>
<Button variant={"danger"} className={styles.submitBtn} onClick={handleDelete}>Confirmer</Button>
</div>
</Modal>
</>
)
}
@@ -21,3 +21,8 @@
.submitBtn {
align-self: center;
}
.alignText{
text-align: center;
}
+4 -3
View File
@@ -1,12 +1,13 @@
import styles from "./ToolBar.module.css"
import Filter from "../Filter/Filter.jsx";
import {useEffect, useState} from "react";
import {useContext, useEffect, useState} from "react";
import SearchBar from "../SearchBar/SearchBar.jsx";
import CreateEventBtn from "../createEventBtn/CreateEventBtn.jsx";
import Button from "../ui/button/button.jsx";
import {AuthContext} from "../../contexts/auth/AuthContext.js";
function ToolBar({setFilters, filters, showCreate = true}) {
const { user } = useContext(AuthContext);
const [isFilterVisible, setIsFilterVisible] = useState(false);
const [isSearchVisible, setIsSearchVisible] = useState(false);
const toggleFilters = () => {
@@ -37,7 +38,7 @@ function ToolBar({setFilters, filters, showCreate = true}) {
</div>
) : null}
<div className={styles.eventsButtons}>
{showCreate ? (
{showCreate && user.isAdmin ? (
<CreateEventBtn />
) : null}
+12 -7
View File
@@ -1,12 +1,15 @@
import Button from "../ui/button/button.jsx";
import Modal from "../ui/modal/modal.jsx";
import { useState } from "react";
import {useContext, useState} from "react";
import styles from "./manageMember.module.css"
import DeleteMemberBtn from "./deleteMember/deleteMemberBtn.jsx";
import DeactivateMemberBtn from "./deactivateMember/deactivateMemberBtn.jsx";
import ModifyRole from "./modifyrole/ModifyRole.jsx";
import {AuthContext} from "../../contexts/auth/AuthContext.js";
export default function ManageMember({ user }) {
export default function ManageMember({ userToManage }) {
const { user } = useContext(AuthContext);
const [open, setOpen] = useState(false);
@@ -16,16 +19,18 @@ export default function ManageMember({ user }) {
<p>Gérer</p>
</Button>
<Modal open={open} onClose={() => setOpen(false)} title={`Gestion de l'utilisateur ${user.name}`}>
<Modal open={open} onClose={() => setOpen(false)} title={`Gestion de l'utilisateur ${userToManage.name}`}>
{(user.id != userToManage.id) ? (
<div className={styles.manageSection}>
<h3>Supprimer le compte</h3>
<DeleteMemberBtn name={user.name} id={user.id} className={styles.manageBlockContent} />
<h3>Désactiver le compte</h3>
<DeactivateMemberBtn name={userToManage.name} id={userToManage.id} className={styles.manageBlockContent} />
</div>
) : null}
<div className={styles.manageSection}>
<h3>Modifier le rôle</h3>
<ModifyRole user={user} />
<ModifyRole user={userToManage} />
</div>
</Modal>
</>
@@ -1,16 +1,16 @@
import Button from "../../ui/button/button.jsx";
import Modal from "../../ui/modal/modal.jsx";
import { useState } from "react";
import deleteUser from "../../../utils/users/deleteUser.js"
import deactivateUser from "../../../utils/users/deactivateUser.js"
import { useNavigate } from "react-router";
export default function DeleteMemberBtn({ name, id, ...props }) {
export default function DeactivateMemberBtn({ name, id, ...props }) {
const [open, setOpen] = useState(false);
const navigate = useNavigate();
const delMember = async () => {
const result = await deleteUser(id);
const deactivateMember = async () => {
const result = await deactivateUser(id);
if (result.status === 200 || result.status === 204) {
setOpen(false);
@@ -19,12 +19,12 @@ export default function DeleteMemberBtn({ name, id, ...props }) {
}
return <div {...props}>
<Button variant={"danger"} onClick={() => setOpen(true)}>Supprimer</Button>
<Button variant={"danger"} onClick={() => setOpen(true)}>Désactiver</Button>
<Modal open={open} onClose={() => setOpen(false)} title={"Supprimer"}>
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 15 }}>
<p>Etes-vous sur de vouloir supprimer le compte {name} ?</p>
<Button variant={"danger"} onClick={delMember}>Supprimer</Button>
<p>Etes-vous sur de vouloir désactiver le compte {name} ?</p>
<Button variant={"danger"} onClick={deactivateMember}>Désactiver</Button>
</div>
</Modal>
</div>
@@ -45,7 +45,7 @@ export default function VolunteerProfilePage() {
<div className={styles.description}>
<div className={styles.headerProfile}>
<h2> {user.name} {user.lastname} </h2>
{currentUser?.isAdmin && <ManageMember user={user} />}
{currentUser?.isAdmin && <ManageMember userToManage={user} />}
</div>
<div className={styles.topDescription}>
<div className={`${styles.infoBlock} glassBorder`}>
@@ -3,7 +3,7 @@ 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";
import { Navigate, useNavigate, Link } from "react-router";
export default function ValidationErrorPage() {
@@ -22,7 +22,11 @@ export default function ValidationErrorPage() {
<h1 className={styles.title}> Votre compte n'a pas été validé </h1>
<div className={`${styles.container} glassCard`}>
<p> Votre compte n'a pas encore été validé, veuillez attendre la vérification de votre compte par un membre autorisé. </p>
<p> Contact : contact@example.com </p>
<p> Contact :
<Link to={"https://comite.beaupont.fr/contactez-nous"} className={styles.link}>
https://comite.beaupont.fr/contactez-nous
</Link>
</p>
<Button variant={"danger"} onClick={handleLogout}> Déconnexion </Button>
</div>
</div>
@@ -1,5 +1,5 @@
export const userCreatedListener = (echo, userData, setNotifications, setunreadNotification) => {
if (userData.isAdmin || userData.role === "Gérant") {
if (userData.isAdmin) {
const channelName = "users.registration";
echo.private(channelName)
.listen(".users.registration", (event) => {
@@ -1,5 +1,4 @@
export const userNotificationsListener = (echo, userData, setNotifications, setunreadNotification) => {
if (!userData?.id) return null;
const channelName = `user.${userData.id}`;
+34
View File
@@ -0,0 +1,34 @@
import getXSRFToken from "../getXSRF.js";
export default async function deactivateUser(userId) {
const csrfToken = await getXSRFToken();
try {
const response = await fetch(`${import.meta.env.VITE_API_URL}/api/users/${userId}/deactivate`, {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken,
'Accept': 'application/json'
},
body: JSON.stringify({
id: userId
})
});
const data = await response.json();
if (!response.ok) {
return {
status: response.status,
errors: data.errors || data.message
};
}
return { status: response.status, data };
} catch (error) {
return { status: 500, error };
}
}
+34
View File
@@ -0,0 +1,34 @@
import getXSRFToken from "../getXSRF.js";
export default async function deleteOtherUser(userId) {
const csrfToken = await getXSRFToken();
try {
const response = await fetch(`${import.meta.env.VITE_API_URL}/api/users/${userId}`, {
method: 'DELETE',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken,
'Accept': 'application/json'
},
body: JSON.stringify({
id: userId
})
});
const data = await response.json();
if (!response.ok) {
return {
status: response.status,
errors: data.errors || data.message
};
}
return { status: response.status, data };
} catch (error) {
return { status: 500, error };
}
}
+3 -6
View File
@@ -1,20 +1,17 @@
import getXSRFToken from "../getXSRF.js";
export default async function deleteUser(userId) {
export default async function deleteUser() {
const csrfToken = await getXSRFToken();
try {
const response = await fetch(`${import.meta.env.VITE_API_URL}/api/users/${userId}`, {
const response = await fetch(`${import.meta.env.VITE_API_URL}/api/users`, {
method: 'DELETE',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken,
'Accept': 'application/json'
},
body: JSON.stringify({
id: userId
})
}
});
const data = await response.json();