permissions review
This commit is contained in:
@@ -45,7 +45,6 @@ export default function Footer(){
|
|||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
{/* TODO : mettre nos noms dans un fichier de configuration */}
|
|
||||||
<Modal title={"Réalisé par"} open={isCopyrightModal} onClose={() => setIsCopyrightModal(false)}>
|
<Modal title={"Réalisé par"} open={isCopyrightModal} onClose={() => setIsCopyrightModal(false)}>
|
||||||
<section className={styles.section}>
|
<section className={styles.section}>
|
||||||
<div className={styles.inputContainer}>
|
<div className={styles.inputContainer}>
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import getUserNotifications from "../../utils/notifications/getUserNotifications
|
|||||||
import deleteNotificationUser from "../../utils/notifications/deleteNotificationUser.js";
|
import deleteNotificationUser from "../../utils/notifications/deleteNotificationUser.js";
|
||||||
import initEcho from "../../utils/echo/initEcho.js"
|
import initEcho from "../../utils/echo/initEcho.js"
|
||||||
import readNotifications from "../../utils/notifications/readNotifications.js";
|
import readNotifications from "../../utils/notifications/readNotifications.js";
|
||||||
import getUser from "../../utils/getUser.js";
|
|
||||||
import { userCreatedListener } from "../../utils/echo/listeners/userCreatedListener";
|
import { userCreatedListener } from "../../utils/echo/listeners/userCreatedListener";
|
||||||
import { userNotificationsListener } from "../../utils/echo/listeners/userNotificationsListener.js";
|
import { userNotificationsListener } from "../../utils/echo/listeners/userNotificationsListener.js";
|
||||||
import NotificationCard from "../NotificationCard/NotificationCard.jsx";
|
import NotificationCard from "../NotificationCard/NotificationCard.jsx";
|
||||||
@@ -28,10 +27,7 @@ function Header() {
|
|||||||
|
|
||||||
async function initializeHeader() {
|
async function initializeHeader() {
|
||||||
try {
|
try {
|
||||||
const [userData, notifData] = await Promise.all([
|
const notifData = await getUserNotifications();
|
||||||
getUser(),
|
|
||||||
getUserNotifications()
|
|
||||||
]);
|
|
||||||
|
|
||||||
const data = notifData || [];
|
const data = notifData || [];
|
||||||
setNotifications(data);
|
setNotifications(data);
|
||||||
@@ -42,8 +38,8 @@ function Header() {
|
|||||||
echoInstance = echo;
|
echoInstance = echo;
|
||||||
|
|
||||||
const activeChannels = [
|
const activeChannels = [
|
||||||
userCreatedListener(echo, userData, setNotifications, setunreadNotification),
|
userCreatedListener(echo, user, setNotifications, setunreadNotification),
|
||||||
userNotificationsListener(echo, userData, setNotifications, setunreadNotification),
|
userNotificationsListener(echo, user, setNotifications, setunreadNotification),
|
||||||
];
|
];
|
||||||
channelsToLeave = activeChannels.filter(name => name !== null);
|
channelsToLeave = activeChannels.filter(name => name !== null);
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import styles from "./PendingMembers.module.css";
|
|||||||
import getUserToValidate from "../../utils/users/getUserToValidate";
|
import getUserToValidate from "../../utils/users/getUserToValidate";
|
||||||
import getUserById from "../../utils/users/getUserById";
|
import getUserById from "../../utils/users/getUserById";
|
||||||
import validateUser from "../../utils/users/validateUser";
|
import validateUser from "../../utils/users/validateUser";
|
||||||
import deleteUser from "../../utils/users/deleteUser";
|
import deleteOtherUser from "../../utils/users/deleteOtherUser.js";
|
||||||
|
|
||||||
function PendingMembers() {
|
function PendingMembers() {
|
||||||
const [pendingMembers, setPendingMembers] = useState([]);
|
const [pendingMembers, setPendingMembers] = useState([]);
|
||||||
@@ -55,7 +55,7 @@ function PendingMembers() {
|
|||||||
setActionLoading(id);
|
setActionLoading(id);
|
||||||
setError(null);
|
setError(null);
|
||||||
try {
|
try {
|
||||||
const result = await deleteUser(id);
|
const result = await deleteOtherUser(id);
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
removeMember(id);
|
removeMember(id);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ function SearchBar() {
|
|||||||
<div className={styles.elementList}>
|
<div className={styles.elementList}>
|
||||||
{searchResults.map((result, i) => (
|
{searchResults.map((result, i) => (
|
||||||
(location.pathname.includes("events")) ? (
|
(location.pathname.includes("events")) ? (
|
||||||
<Link to={`/event/` + result.id}>
|
<Link to={`/events/` + result.id}>
|
||||||
<div className={styles.searchedEvent} key={i}>
|
<div className={styles.searchedEvent} key={i}>
|
||||||
<div className={`${styles.eventImageDiv}`}>
|
<div className={`${styles.eventImageDiv}`}>
|
||||||
{result.image == null ? (
|
{result.image == null ? (
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import ThemeSwitcher from "../ui/themeSwitcher/ThemeSwitcher.jsx";
|
|||||||
import { AuthContext } from "../../contexts/auth/AuthContext.js";
|
import { AuthContext } from "../../contexts/auth/AuthContext.js";
|
||||||
import TextInput from "../ui/input/input.jsx";
|
import TextInput from "../ui/input/input.jsx";
|
||||||
import updateUser from "../../utils/users/updateUser.js";
|
import updateUser from "../../utils/users/updateUser.js";
|
||||||
|
import deleteUser from "../../utils/users/deleteUser.js";
|
||||||
|
|
||||||
|
|
||||||
export default function SettingsModal() {
|
export default function SettingsModal() {
|
||||||
@@ -13,6 +14,7 @@ export default function SettingsModal() {
|
|||||||
const { user, logout, update } = useContext(AuthContext);
|
const { user, logout, update } = useContext(AuthContext);
|
||||||
|
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
const [isDelete, setIsDelete] = useState(false);
|
||||||
|
|
||||||
const [name, setName] = useState(user?.name);
|
const [name, setName] = useState(user?.name);
|
||||||
const [lastname, setLastName] = useState(user?.lastname);
|
const [lastname, setLastName] = useState(user?.lastname);
|
||||||
@@ -27,6 +29,11 @@ export default function SettingsModal() {
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleDelete = async () => {
|
||||||
|
await deleteUser();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button variant={"transparent"} onClick={() => setOpen(!open)}>
|
<Button variant={"transparent"} onClick={() => setOpen(!open)}>
|
||||||
@@ -39,6 +46,7 @@ export default function SettingsModal() {
|
|||||||
<div className={styles.section}>
|
<div className={styles.section}>
|
||||||
<h3>Compte</h3>
|
<h3>Compte</h3>
|
||||||
<Button variant={"danger"} onClick={handleLogout}> Déconnexion </Button>
|
<Button variant={"danger"} onClick={handleLogout}> Déconnexion </Button>
|
||||||
|
<Button variant={"danger"} onClick={() => setIsDelete(true)}> Supprimer le compte </Button>
|
||||||
|
|
||||||
<div className={styles.section}>
|
<div className={styles.section}>
|
||||||
<h4>Changer de Prénom</h4>
|
<h4>Changer de Prénom</h4>
|
||||||
@@ -65,6 +73,14 @@ export default function SettingsModal() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</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>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -20,4 +20,9 @@
|
|||||||
|
|
||||||
.submitBtn {
|
.submitBtn {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.alignText{
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
import styles from "./ToolBar.module.css"
|
import styles from "./ToolBar.module.css"
|
||||||
import Filter from "../Filter/Filter.jsx";
|
import Filter from "../Filter/Filter.jsx";
|
||||||
import {useEffect, useState} from "react";
|
import {useContext, useEffect, useState} from "react";
|
||||||
import SearchBar from "../SearchBar/SearchBar.jsx";
|
import SearchBar from "../SearchBar/SearchBar.jsx";
|
||||||
import CreateEventBtn from "../createEventBtn/CreateEventBtn.jsx";
|
import CreateEventBtn from "../createEventBtn/CreateEventBtn.jsx";
|
||||||
import Button from "../ui/button/button.jsx";
|
import Button from "../ui/button/button.jsx";
|
||||||
|
import {AuthContext} from "../../contexts/auth/AuthContext.js";
|
||||||
|
|
||||||
function ToolBar({setFilters, filters, showCreate = true}) {
|
function ToolBar({setFilters, filters, showCreate = true}) {
|
||||||
|
const { user } = useContext(AuthContext);
|
||||||
const [isFilterVisible, setIsFilterVisible] = useState(false);
|
const [isFilterVisible, setIsFilterVisible] = useState(false);
|
||||||
const [isSearchVisible, setIsSearchVisible] = useState(false);
|
const [isSearchVisible, setIsSearchVisible] = useState(false);
|
||||||
const toggleFilters = () => {
|
const toggleFilters = () => {
|
||||||
@@ -37,7 +38,7 @@ function ToolBar({setFilters, filters, showCreate = true}) {
|
|||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
<div className={styles.eventsButtons}>
|
<div className={styles.eventsButtons}>
|
||||||
{showCreate ? (
|
{showCreate && user.isAdmin ? (
|
||||||
<CreateEventBtn />
|
<CreateEventBtn />
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import Button from "../ui/button/button.jsx";
|
import Button from "../ui/button/button.jsx";
|
||||||
import Modal from "../ui/modal/modal.jsx";
|
import Modal from "../ui/modal/modal.jsx";
|
||||||
import { useState } from "react";
|
import {useContext, useState} from "react";
|
||||||
import styles from "./manageMember.module.css"
|
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 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);
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
|
||||||
@@ -16,16 +19,18 @@ export default function ManageMember({ user }) {
|
|||||||
<p>Gérer</p>
|
<p>Gérer</p>
|
||||||
</Button>
|
</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}`}>
|
||||||
|
|
||||||
<div className={styles.manageSection}>
|
{(user.id != userToManage.id) ? (
|
||||||
<h3>Supprimer le compte</h3>
|
<div className={styles.manageSection}>
|
||||||
<DeleteMemberBtn name={user.name} id={user.id} className={styles.manageBlockContent} />
|
<h3>Désactiver le compte</h3>
|
||||||
</div>
|
<DeactivateMemberBtn name={userToManage.name} id={userToManage.id} className={styles.manageBlockContent} />
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
<div className={styles.manageSection}>
|
<div className={styles.manageSection}>
|
||||||
<h3>Modifier le rôle</h3>
|
<h3>Modifier le rôle</h3>
|
||||||
<ModifyRole user={user} />
|
<ModifyRole user={userToManage} />
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
</>
|
</>
|
||||||
|
|||||||
+7
-7
@@ -1,16 +1,16 @@
|
|||||||
import Button from "../../ui/button/button.jsx";
|
import Button from "../../ui/button/button.jsx";
|
||||||
import Modal from "../../ui/modal/modal.jsx";
|
import Modal from "../../ui/modal/modal.jsx";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import deleteUser from "../../../utils/users/deleteUser.js"
|
import deactivateUser from "../../../utils/users/deactivateUser.js"
|
||||||
import { useNavigate } from "react-router";
|
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 [open, setOpen] = useState(false);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const delMember = async () => {
|
const deactivateMember = async () => {
|
||||||
const result = await deleteUser(id);
|
const result = await deactivateUser(id);
|
||||||
|
|
||||||
if (result.status === 200 || result.status === 204) {
|
if (result.status === 200 || result.status === 204) {
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
@@ -19,12 +19,12 @@ export default function DeleteMemberBtn({ name, id, ...props }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return <div {...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"}>
|
<Modal open={open} onClose={() => setOpen(false)} title={"Supprimer"}>
|
||||||
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 15 }}>
|
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 15 }}>
|
||||||
<p>Etes-vous sur de vouloir supprimer le compte {name} ?</p>
|
<p>Etes-vous sur de vouloir désactiver le compte {name} ?</p>
|
||||||
<Button variant={"danger"} onClick={delMember}>Supprimer</Button>
|
<Button variant={"danger"} onClick={deactivateMember}>Désactiver</Button>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
@@ -45,7 +45,7 @@ export default function VolunteerProfilePage() {
|
|||||||
<div className={styles.description}>
|
<div className={styles.description}>
|
||||||
<div className={styles.headerProfile}>
|
<div className={styles.headerProfile}>
|
||||||
<h2> {user.name} {user.lastname} </h2>
|
<h2> {user.name} {user.lastname} </h2>
|
||||||
{currentUser?.isAdmin && <ManageMember user={user} />}
|
{currentUser?.isAdmin && <ManageMember userToManage={user} />}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.topDescription}>
|
<div className={styles.topDescription}>
|
||||||
<div className={`${styles.infoBlock} glassBorder`}>
|
<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 Button from "../../components/ui/button/button.jsx";
|
||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
import { AuthContext } from "../../contexts/auth/AuthContext.js";
|
import { AuthContext } from "../../contexts/auth/AuthContext.js";
|
||||||
import { Navigate, useNavigate } from "react-router";
|
import { Navigate, useNavigate, Link } from "react-router";
|
||||||
|
|
||||||
export default function ValidationErrorPage() {
|
export default function ValidationErrorPage() {
|
||||||
|
|
||||||
@@ -22,7 +22,11 @@ export default function ValidationErrorPage() {
|
|||||||
<h1 className={styles.title}> Votre compte n'a pas été validé </h1>
|
<h1 className={styles.title}> Votre compte n'a pas été validé </h1>
|
||||||
<div className={`${styles.container} glassCard`}>
|
<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> 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>
|
<Button variant={"danger"} onClick={handleLogout}> Déconnexion </Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export const userCreatedListener = (echo, userData, setNotifications, setunreadNotification) => {
|
export const userCreatedListener = (echo, userData, setNotifications, setunreadNotification) => {
|
||||||
if (userData.isAdmin || userData.role === "Gérant") {
|
if (userData.isAdmin) {
|
||||||
const channelName = "users.registration";
|
const channelName = "users.registration";
|
||||||
echo.private(channelName)
|
echo.private(channelName)
|
||||||
.listen(".users.registration", (event) => {
|
.listen(".users.registration", (event) => {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
export const userNotificationsListener = (echo, userData, setNotifications, setunreadNotification) => {
|
export const userNotificationsListener = (echo, userData, setNotifications, setunreadNotification) => {
|
||||||
if (!userData?.id) return null;
|
|
||||||
|
|
||||||
const channelName = `user.${userData.id}`;
|
const channelName = `user.${userData.id}`;
|
||||||
|
|
||||||
|
|||||||
@@ -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 };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,17 @@
|
|||||||
import getXSRFToken from "../getXSRF.js";
|
import getXSRFToken from "../getXSRF.js";
|
||||||
|
|
||||||
export default async function deleteUser(userId) {
|
export default async function deleteUser() {
|
||||||
const csrfToken = await getXSRFToken();
|
const csrfToken = await getXSRFToken();
|
||||||
|
|
||||||
try {
|
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',
|
method: 'DELETE',
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'X-XSRF-TOKEN': csrfToken,
|
'X-XSRF-TOKEN': csrfToken,
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json'
|
||||||
},
|
}
|
||||||
body: JSON.stringify({
|
|
||||||
id: userId
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|||||||
Reference in New Issue
Block a user