Merge branch 'style/volunteersPage' into 'dev'
Style/volunteerspage See merge request sae-but2/2025-26/gestion-benevoles-association/Frontend!77
This commit is contained in:
@@ -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.tsx";
|
||||
|
||||
export default function VolunteerCard({ user }) {
|
||||
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
|
||||
const toggleExpand = () => {
|
||||
setIsExpanded(!isExpanded);
|
||||
};
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<div className={`${styles.profileboard} glassCard`} onClick={(() => setIsExpanded(!isExpanded))}>
|
||||
|
||||
<div className={styles.header}>
|
||||
<h2 className={styles.userName}>
|
||||
<span className={styles.firstName}>{user?.name}</span>{" "}
|
||||
<span className={styles.lastName}>{user?.lastname}</span>
|
||||
</h2>
|
||||
|
||||
<Button
|
||||
variant={"transparent"}
|
||||
onClick={toggleExpand}
|
||||
className={`${isExpanded ? styles.moreButtonClicked : ""}`}
|
||||
>
|
||||
{">"}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className={styles.mainContent}>
|
||||
{!isExpanded ? (
|
||||
<div className={styles.basicInfo}>
|
||||
<p><strong>Rôle :</strong> {user?.role}</p>
|
||||
<p><strong>Membre depuis :</strong> {user?.created_at && formatDate(user.created_at)}</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className={styles.expandedContent}>
|
||||
<div className={styles.profilePictureContainer}>
|
||||
<img src={"/react.svg"} alt="profile" className={styles.profilePicture} />
|
||||
</div>
|
||||
|
||||
<div className={styles.textInfo}>
|
||||
<div className={styles.basicInfo}>
|
||||
<p><strong>Rôle :</strong> {user?.role}</p>
|
||||
<p><strong>Membre depuis :</strong> {user?.created_at && formatDate(user.created_at)}</p>
|
||||
</div>
|
||||
|
||||
<div className={styles.contactInfo}>
|
||||
<p><strong>Email :</strong> {user?.email}</p>
|
||||
{user?.phone && <p><strong>Téléphone :</strong> {user.phone}</p>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{isExpanded && (
|
||||
<div className={styles.bottomBar}>
|
||||
<Button
|
||||
onClick={() => navigate(`/profile/${user.id}`)}
|
||||
variant="primary"
|
||||
>
|
||||
Voir plus
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -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 (
|
||||
<div className={styles.container}>
|
||||
<ToolBar setFilters={setFilters} filters={filters} showCreate={false} />
|
||||
<div className={styles.usersList}>
|
||||
{filter(users, filters, "user").map((user, index) => (
|
||||
<VolunteerCard key={user.id ?? index} user={user} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default VolunteerPage;
|
||||
@@ -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;
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
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";
|
||||
|
||||
interface Filters {
|
||||
alphabetical: "asc" | "desc";
|
||||
yearOrder: "asc" | "desc";
|
||||
}
|
||||
|
||||
const VolunteerPage: React.FC = () => {
|
||||
const [filters, setFilters] = useState<Filters>({
|
||||
alphabetical: "asc",
|
||||
yearOrder: "desc",
|
||||
});
|
||||
|
||||
const [users, setUsers] = useState<User[]>([]);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchUsers = async (): Promise<void> => {
|
||||
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<User | null> => {
|
||||
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();
|
||||
}, []);
|
||||
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<ToolBar
|
||||
setFilters={setFilters}
|
||||
filters={filters}
|
||||
showCreate={false}
|
||||
/>
|
||||
|
||||
<div className={styles.usersList}>
|
||||
{loading ? (
|
||||
<div className={styles.loading}>Chargement des bénévoles…</div>
|
||||
) : (
|
||||
filter(users, filters, "user").map((user: User) => (
|
||||
<VolunteerCard key={user.id} user={user} />
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default VolunteerPage;
|
||||
@@ -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 (
|
||||
<div className={`glassCard ${styles.volunteerCard}`}>
|
||||
<div className={styles.header}>
|
||||
<img src={"/react.svg"} alt="profile" className={styles.profilePicture} />
|
||||
<p> {user.name} {user.lastname} </p>
|
||||
</div>
|
||||
<div className={styles.content}>
|
||||
<p> {user.email} </p>
|
||||
<Button variant={"primary"} onClick={handleNavigate}>Voir</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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[];
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@ 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";
|
||||
|
||||
Reference in New Issue
Block a user