Merge branch 'features/filter' into 'features/eventsPage'
Features/filter See merge request sae-but2/2025-26/gestion-benevoles-association/Frontend!15
This commit is contained in:
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#000000"><path d="m80-280 150-400h86l150 400h-82l-34-96H196l-32 96H80Zm140-164h104l-48-150h-6l-50 150Zm328 164v-76l202-252H556v-72h282v76L638-352h202v72H548ZM360-760l120-120 120 120H360ZM480-80 360-200h240L480-80Z"/></svg>
|
||||
|
After Width: | Height: | Size: 320 B |
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor">
|
||||
<path d="M 480,-880 360,-760 H 600 Z M 360,-200 480,-80 600,-200 Z" />
|
||||
<path d="M 71.679924,-674.40094 H 398.50264 v 60.67705 l -208.59362,252.3436 h 214.5832 v 75.7812 H 65.690344 v -60.67705 L 274.28397,-598.61973 H 71.679924 Z" />
|
||||
<path d="M 769.04932,-356.43238 H 612.27858 l -24.73957,70.83329 H 486.75782 l 144.01033,-388.80185 h 119.53118 l 144.01033,388.80185 H 793.52847 Z m -131.77076,-72.13537 h 106.51035 l -53.12496,-154.68741 z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 545 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#000000"><path d="M340-160q-125 0-212.5-87.5T40-460q0-125 87.5-212.5T340-760q52 0 98 16.5t84 45.5l42-42 56 56-42 42q29 38 45.5 84.5T640-460q0 125-87.5 212.5T340-160Zm440 0L640-300l56-56 44 44v-488h80v487l43-43 57 56-140 140ZM240-800v-80h200v80H240Zm100 560q92 0 156-64t64-156q0-92-64-156t-156-64q-92 0-156 64t-64 156q0 92 64 156t156 64Zm-40-180h80v-200h-80v200Zm40-40Z"/></svg>
|
||||
|
After Width: | Height: | Size: 475 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#000000"><path d="M340-160q-125 0-212.5-87.5T40-460q0-125 87.5-212.5T340-760q52 0 98 16.5t84 45.5l42-42 56 56-42 42q29 38 45.5 84.5T640-460q0 125-87.5 212.5T340-160Zm400 0v-488l-44 44-56-56 140-140 140 140-57 56-43-43v487h-80ZM240-800v-80h200v80H240Zm100 560q92 0 156-64t64-156q0-92-64-156t-156-64q-92 0-156 64t-64 156q0 92 64 156t156 64Zm-40-180h80v-200h-80v200Zm40-40Z"/></svg>
|
||||
|
After Width: | Height: | Size: 477 B |
@@ -0,0 +1,61 @@
|
||||
import styles from "./Filter.module.css";
|
||||
|
||||
function Filter({isFilterVisible, filters, setFilters}){
|
||||
const setAlphabeticalOrder = (order) => {
|
||||
setFilters(prev => ({
|
||||
...prev,
|
||||
alphabetical : prev.alphabetical === order ? null : order
|
||||
}));
|
||||
};
|
||||
|
||||
const setYearOrder = (order) => {
|
||||
setFilters(prev => ({
|
||||
...prev,
|
||||
yearOrder: prev.yearOrder === order ? null : order
|
||||
}));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`${styles.filterContainer} ${isFilterVisible ? styles.filterOpen : styles.filterClose}`}>
|
||||
<abbr title="Tri alphabétique croissant (A à Z)">
|
||||
<button className={`${styles.filterTag} glassCard ${filters.alphabetical !== "asc" ? "" : styles.active}`}
|
||||
onClick={() => setAlphabeticalOrder("asc")}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor">
|
||||
<path d="m80-280 150-400h86l150 400h-82l-34-96H196l-32 96H80Zm140-164h104l-48-150h-6l-50 150Zm328 164v-76l202-252H556v-72h282v76L638-352h202v72H548ZM360-760l120-120 120 120H360ZM480-80 360-200h240L480-80Z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</abbr>
|
||||
|
||||
<abbr title="Tri alphabétique décroissant (Z à A)">
|
||||
<button className={`${styles.filterTag} glassCard ${filters.alphabetical !== "desc" ? "" : styles.active}`}
|
||||
onClick={() => setAlphabeticalOrder("desc")}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor">
|
||||
<path d="M 480,-880 360,-760 H 600 Z M 360,-200 480,-80 600,-200 Z" />
|
||||
<path d="M 71.679924,-674.40094 H 398.50264 v 60.67705 l -208.59362,252.3436 h 214.5832 v 75.7812 H 65.690344 v -60.67705 L 274.28397,-598.61973 H 71.679924 Z" />
|
||||
<path d="M 769.04932,-356.43238 H 612.27858 l -24.73957,70.83329 H 486.75782 l 144.01033,-388.80185 h 119.53118 l 144.01033,388.80185 H 793.52847 Z m -131.77076,-72.13537 h 106.51035 l -53.12496,-154.68741 z" />
|
||||
</svg>
|
||||
</button>
|
||||
</abbr>
|
||||
|
||||
<abbr title="Tri chronologique croissant (du plus ancien au plus récent)">
|
||||
<button className={`${styles.filterTag} glassCard ${filters.yearOrder !== "asc" ? "" : styles.active}`}
|
||||
onClick={() => setYearOrder("asc")}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor">
|
||||
<path d="M340-160q-125 0-212.5-87.5T40-460q0-125 87.5-212.5T340-760q52 0 98 16.5t84 45.5l42-42 56 56-42 42q29 38 45.5 84.5T640-460q0 125-87.5 212.5T340-160Zm400 0v-488l-44 44-56-56 140-140 140 140-57 56-43-43v487h-80ZM240-800v-80h200v80H240Zm100 560q92 0 156-64t64-156q0-92-64-156t-156-64q-92 0-156 64t-64 156q0 92 64 156t156 64Zm-40-180h80v-200h-80v200Zm40-40Z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</abbr>
|
||||
|
||||
<abbr title="Tri chronologique décroissant (du plus récent au plus ancien)">
|
||||
<button className={`${styles.filterTag} glassCard ${filters.yearOrder !== "desc" ? "" : styles.active}`}
|
||||
onClick={() => setYearOrder("desc")}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor">
|
||||
<path d="M340-160q-125 0-212.5-87.5T40-460q0-125 87.5-212.5T340-760q52 0 98 16.5t84 45.5l42-42 56 56-42 42q29 38 45.5 84.5T640-460q0 125-87.5 212.5T340-160Zm440 0L640-300l56-56 44 44v-488h80v487l43-43 57 56-140 140ZM240-800v-80h200v80H240Zm100 560q92 0 156-64t64-156q0-92-64-156t-156-64q-92 0-156 64t-64 156q0 92 64 156t156 64Zm-40-180h80v-200h-80v200Zm40-40Z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</abbr>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Filter;
|
||||
@@ -0,0 +1,64 @@
|
||||
.filterContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
overflow: hidden;
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
transition: max-height 0.5s ease, opacity 0.8s ease, transform 0.5s ease;
|
||||
}
|
||||
|
||||
.filterOpen {
|
||||
max-height: 200px;
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.filterClose{
|
||||
max-height: 200px;
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
|
||||
|
||||
.filterTag {
|
||||
border: none;
|
||||
background: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
|
||||
.filterTag:focus {
|
||||
outline: none;
|
||||
}
|
||||
.filterTag:focus-visible {
|
||||
outline: 2px solid black;
|
||||
}
|
||||
|
||||
.filterTag:hover {
|
||||
cursor: pointer;
|
||||
svg{
|
||||
fill: #019AFF;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.filterTag svg {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
|
||||
.active {
|
||||
border: 1px solid #019AFF;
|
||||
}
|
||||
|
||||
.active svg {
|
||||
fill: #019AFF;
|
||||
transform: scale(1);
|
||||
}
|
||||
+4
-4
@@ -25,7 +25,7 @@
|
||||
.content {
|
||||
padding: 1.5rem;
|
||||
z-index: 1;
|
||||
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,9 +49,9 @@ body {
|
||||
|
||||
.glassCard {
|
||||
width: 100%;
|
||||
padding: 10px 20px 10px 20px;
|
||||
padding: 10px 10px 10px 10px;
|
||||
height: fit-content;
|
||||
background: rgba(255, 255, 255, 0.65);
|
||||
background: rgba(184, 184, 184, 0.65);
|
||||
backdrop-filter: blur(3px);
|
||||
-webkit-backdrop-filter: blur(3px);
|
||||
border-radius: 20px;
|
||||
@@ -60,7 +60,7 @@ body {
|
||||
0 8px 32px rgba(0, 0, 0, 0.1),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.5),
|
||||
inset 0 -1px 0 rgba(255, 255, 255, 0.1),
|
||||
inset 0 0 8px 4px rgba(255, 255, 255, 0.4);
|
||||
inset 0 0 30px 4px rgba(255, 255, 255, 0.4);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
import {useState} from "react";
|
||||
import Event from "../../components/Event/Event.jsx";
|
||||
import {Link} from "react-router";
|
||||
import styles from "./EventsPage.module.css"
|
||||
import styles from "./EventsPage.module.css";
|
||||
import Filter from "../../components/Filter/Filter.jsx";
|
||||
|
||||
|
||||
|
||||
function EventsPage(){
|
||||
const [events, setEvents] = useState([
|
||||
const [isFilterVisible, setIsFilterVisible] = useState(false);
|
||||
const toggleFilters = () => {
|
||||
setIsFilterVisible(prev => !prev);
|
||||
};
|
||||
|
||||
const [filters, setFilters] = useState({
|
||||
alphabetical: "asc",
|
||||
yearOrder: "asc",
|
||||
});
|
||||
|
||||
const [events] = useState([
|
||||
{
|
||||
id: 1,
|
||||
name: "Marathon de la Ville",
|
||||
@@ -15,16 +26,16 @@ function EventsPage(){
|
||||
tasks: [
|
||||
{
|
||||
name: "Inscription des participants",
|
||||
start: "08:00",
|
||||
end: "10:00",
|
||||
start: "2018-09-24 22:21:20",
|
||||
end: "2018-09-24 22:21:20",
|
||||
place: "Centre sportif",
|
||||
description: "Accueillir et enregistrer tous les coureurs.",
|
||||
volunteers_count: 5
|
||||
},
|
||||
{
|
||||
name: "Distribution des dossards",
|
||||
start: "09:00",
|
||||
end: "11:00",
|
||||
start: "2018-09-24 22:21:20",
|
||||
end: "2018-09-24 22:21:20",
|
||||
place: "Salle principale",
|
||||
description: "Remettre les dossards et goodies aux participants.",
|
||||
volunteers_count: 3
|
||||
@@ -39,16 +50,16 @@ function EventsPage(){
|
||||
tasks: [
|
||||
{
|
||||
name: "Montage de la scène",
|
||||
start: "10:00",
|
||||
end: "14:00",
|
||||
start: "2018-09-24 22:21:20",
|
||||
end: "2018-09-24 22:21:20",
|
||||
place: "Parc central",
|
||||
description: "Installer la scène, les éclairages et le son.",
|
||||
volunteers_count: 6
|
||||
},
|
||||
{
|
||||
name: "Accueil du public",
|
||||
start: "14:00",
|
||||
end: "20:00",
|
||||
start: "2018-09-24 22:21:20",
|
||||
end: "2018-09-24 22:21:20",
|
||||
place: "Entrée principale",
|
||||
description: "Vérifier les billets et orienter les visiteurs.",
|
||||
volunteers_count: 4
|
||||
@@ -63,24 +74,24 @@ function EventsPage(){
|
||||
tasks: [
|
||||
{
|
||||
name: "Préparation des salles",
|
||||
start: "07:00",
|
||||
end: "09:00",
|
||||
start: "2018-09-24 22:21:20",
|
||||
end: "2018-09-24 22:21:20",
|
||||
place: "Campus Tech",
|
||||
description: "Installer les chaises, projecteurs et matériel pour les conférences.",
|
||||
volunteers_count: 4
|
||||
},
|
||||
{
|
||||
name: "Accueil des intervenants",
|
||||
start: "08:30",
|
||||
end: "10:00",
|
||||
start: "2018-09-24 22:21:20",
|
||||
end: "2018-09-24 22:21:20",
|
||||
place: "Hall principal",
|
||||
description: "Assister les speakers et orienter vers les salles.",
|
||||
volunteers_count: 2
|
||||
},
|
||||
{
|
||||
name: "Gestion du buffet",
|
||||
start: "12:00",
|
||||
end: "14:00",
|
||||
start: "2018-09-24 22:21:20",
|
||||
end: "2018-09-24 22:21:20",
|
||||
place: "Salle de restauration",
|
||||
description: "Distribuer boissons et repas aux participants.",
|
||||
volunteers_count: 3
|
||||
@@ -95,16 +106,16 @@ function EventsPage(){
|
||||
tasks: [
|
||||
{
|
||||
name: "Installation du matériel",
|
||||
start: "09:00",
|
||||
end: "10:00",
|
||||
start: "2018-09-24 22:21:20",
|
||||
end: "2018-09-24 22:21:20",
|
||||
place: "Jardin partagé",
|
||||
description: "Préparer outils et terreaux pour les participants.",
|
||||
volunteers_count: 2
|
||||
},
|
||||
{
|
||||
name: "Encadrement des participants",
|
||||
start: "10:00",
|
||||
end: "12:00",
|
||||
start: "2018-09-24 22:21:20",
|
||||
end: "2018-09-24 22:21:20",
|
||||
place: "Jardin partagé",
|
||||
description: "Aider et conseiller sur la plantation et l’entretien.",
|
||||
volunteers_count: 3
|
||||
@@ -119,48 +130,48 @@ function EventsPage(){
|
||||
tasks: [
|
||||
{
|
||||
name: "Accueil et enregistrement",
|
||||
start: "08:00",
|
||||
end: "12:00",
|
||||
start: "2020-09-24 22:21:20",
|
||||
end: "2020-09-24 22:21:20",
|
||||
place: "Salle municipale",
|
||||
description: "Enregistrer les donneurs et expliquer le processus.",
|
||||
volunteers_count: 4
|
||||
},
|
||||
{
|
||||
name: "Préparation des salles",
|
||||
start: "07:30",
|
||||
end: "08:00",
|
||||
start: "2018-09-24 22:21:20",
|
||||
end: "2018-09-24 22:21:20",
|
||||
place: "Salle municipale",
|
||||
description: "Installer les lits, tables et matériel médical.",
|
||||
volunteers_count: 3
|
||||
},
|
||||
{
|
||||
name: "Assistance post-don",
|
||||
start: "12:00",
|
||||
end: "16:00",
|
||||
start: "2018-09-24 22:21:20",
|
||||
end: "2018-09-24 22:21:20",
|
||||
place: "Salle municipale",
|
||||
description: "Accompagner les donneurs après le don et proposer des rafraîchissements.",
|
||||
volunteers_count: 2
|
||||
},
|
||||
{
|
||||
name: "Accueil et enregistrement",
|
||||
start: "08:00",
|
||||
end: "12:00",
|
||||
start: "2020-09-24 22:21:20",
|
||||
end: "2020-09-24 22:21:20",
|
||||
place: "Salle municipale",
|
||||
description: "Enregistrer les donneurs et expliquer le processus.",
|
||||
volunteers_count: 4
|
||||
},
|
||||
{
|
||||
name: "Préparation des salles",
|
||||
start: "07:30",
|
||||
end: "08:00",
|
||||
start: "2018-09-24 22:21:20",
|
||||
end: "2018-09-24 22:21:20",
|
||||
place: "Salle municipale",
|
||||
description: "Installer les lits, tables et matériel médical.",
|
||||
volunteers_count: 3
|
||||
},
|
||||
{
|
||||
name: "Assistance post-don",
|
||||
start: "12:00",
|
||||
end: "16:00",
|
||||
start: "2018-09-24 22:21:20",
|
||||
end: "2018-09-24 22:21:20",
|
||||
place: "Salle municipale",
|
||||
description: "Accompagner les donneurs après le don et proposer des rafraîchissements.",
|
||||
volunteers_count: 2
|
||||
@@ -169,12 +180,50 @@ function EventsPage(){
|
||||
},
|
||||
]);
|
||||
|
||||
const compareDate = (dateA, dateB) => {
|
||||
const dA = new Date(dateA);
|
||||
const dB = new Date(dateB);
|
||||
|
||||
if (filters.yearOrder === "asc") {
|
||||
return dB - dA;
|
||||
} else {
|
||||
return dA - dB;
|
||||
}
|
||||
};
|
||||
|
||||
const sortedEvents = [...events].sort((a, b) => {
|
||||
const sortedATasks = a.tasks.sort((taskA, taskB) =>
|
||||
compareDate(taskA.start, taskB.start)
|
||||
);
|
||||
const sortedBTasks = b.tasks.sort((taskA, taskB) =>
|
||||
compareDate(taskA.start, taskB.start)
|
||||
);
|
||||
|
||||
const timeComparison = compareDate(
|
||||
sortedATasks[0].start,
|
||||
sortedBTasks[0].start
|
||||
);
|
||||
|
||||
if (timeComparison !== 0) {
|
||||
return timeComparison;
|
||||
}
|
||||
|
||||
if (filters.alphabetical !== null) {
|
||||
return filters.alphabetical === "asc"
|
||||
? a.name.localeCompare(b.name)
|
||||
: b.name.localeCompare(a.name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div className={styles.eventsContainer}>
|
||||
<div className={styles.eventsList}>
|
||||
{events.map((event, index) => (
|
||||
{sortedEvents.map((event, index) => (
|
||||
<Event key={index} event={event} />
|
||||
))}
|
||||
</div>
|
||||
@@ -184,11 +233,16 @@ function EventsPage(){
|
||||
className={`${styles.createButton} glassCard`}>
|
||||
+
|
||||
</Link>
|
||||
<button className={`${styles.sortButton} glassCard`}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor">
|
||||
<path d="M440-160q-17 0-28.5-11.5T400-200v-240L168-736q-15-20-4.5-42t36.5-22h560q26 0 36.5 22t-4.5 42L560-440v240q0 17-11.5 28.5T520-160h-80Zm40-308 198-252H282l198 252Zm0 0Z"/>
|
||||
</svg>
|
||||
</button>
|
||||
<div className={`${styles.filterContainer} ${isFilterVisible ? "glassCard" : ""}`}>
|
||||
<button className={`${isFilterVisible ? "" : styles.mobileFilter} ${styles.sortButton} glassCard`} onClick={toggleFilters}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor">
|
||||
<path d="M440-160q-17 0-28.5-11.5T400-200v-240L168-736q-15-20-4.5-42t36.5-22h560q26 0 36.5 22t-4.5 42L560-440v240q0 17-11.5 28.5T520-160h-80Zm40-308 198-252H282l198 252Zm0 0Z"/>
|
||||
</svg>
|
||||
</button>
|
||||
<div className={styles.filterMenu}>
|
||||
<Filter isFilterVisible={isFilterVisible} filters={filters} setFilters={setFilters}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -23,6 +23,17 @@
|
||||
}
|
||||
|
||||
|
||||
.filterContainer{
|
||||
padding: 0;
|
||||
border-radius: 30px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.filterMenu{
|
||||
padding: 5px 5px 5px 5px;
|
||||
}
|
||||
|
||||
|
||||
.createButton, .sortButton {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -44,9 +55,12 @@
|
||||
fill: #019AFF;
|
||||
}
|
||||
|
||||
.createButton:hover, .sortButton:hover {
|
||||
transform: translateY(-5px);
|
||||
.sortButton:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.createButton:hover, .mobileFilter:hover {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user