Merge branch 'dev' of https://iutbg-gitlab.iutbourg.univ-lyon1.fr/sae-but2/2025-26/gestion-benevoles-association/frontend into dev
This commit is contained in:
Generated
+28
@@ -1109,6 +1109,12 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@kurkle/color": {
|
||||||
|
"version": "0.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz",
|
||||||
|
"integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@mdx-js/react": {
|
"node_modules/@mdx-js/react": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.1.tgz",
|
||||||
@@ -2684,6 +2690,18 @@
|
|||||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chart.js": {
|
||||||
|
"version": "4.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz",
|
||||||
|
"integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@kurkle/color": "^0.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"pnpm": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/check-error": {
|
"node_modules/check-error": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz",
|
||||||
@@ -4421,6 +4439,16 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-chartjs-2": {
|
||||||
|
"version": "5.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.3.1.tgz",
|
||||||
|
"integrity": "sha512-h5IPXKg9EXpjoBzUfyWJvllMjG2mQ4EiuHQFhms/AjUm0XSZHhyRy2xVmLXHKrtcdrPO4mnGqRtYoD0vp95A0A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"chart.js": "^4.1.1",
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-docgen": {
|
"node_modules/react-docgen": {
|
||||||
"version": "8.0.2",
|
"version": "8.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-8.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-8.0.2.tgz",
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#000000"><path d="M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 376 B |
@@ -42,17 +42,20 @@ function Event({event}){
|
|||||||
<div className={styles.eventInfos}>
|
<div className={styles.eventInfos}>
|
||||||
<p className={styles.eventTitle}>{event.name}</p>
|
<p className={styles.eventTitle}>{event.name}</p>
|
||||||
<p>{event.description}</p>
|
<p>{event.description}</p>
|
||||||
<ul className={eventMenu ? styles.eventMenuOpen : styles.eventMenuClose}>
|
{event.tasks != null ? (
|
||||||
{event.tasks.length > 0 && (
|
<div className={eventMenu ? styles.eventMenuOpen : styles.eventMenuClose}>
|
||||||
<>
|
<ul>
|
||||||
{event.tasks.slice(0, 5).map((task, index) => (
|
{event.tasks
|
||||||
<li key={index}> {task.name} </li>
|
.slice(0,5)
|
||||||
|
.map((task, index) => (
|
||||||
|
<li key={index}> - {task.name}</li>
|
||||||
))}
|
))}
|
||||||
|
{event.tasks.length > 5 ? (
|
||||||
{event.tasks.length > 5 && <li>...</li>}
|
<li>...</li>
|
||||||
</>
|
) : null}
|
||||||
)}
|
</ul>
|
||||||
</ul>
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{windowSize.width > 768 ? (
|
{windowSize.width > 768 ? (
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
.eventContainerTop {
|
.eventContainerTop {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.eventContainerBottom{
|
.eventContainerBottom{
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import styles from "./SearchBar.module.css"
|
||||||
|
import {Link} from "react-router";
|
||||||
|
import {useEffect, useState} from "react";
|
||||||
|
import searchEvents from "../../utils/searchEvents.js";
|
||||||
|
|
||||||
|
function SearchBar() {
|
||||||
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
|
const [searchResults, setSearchResults] = useState([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const performSearch = async (query) => {
|
||||||
|
if (query.trim() === '') {
|
||||||
|
setSearchResults([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await searchEvents(query);
|
||||||
|
if (data) {
|
||||||
|
setSearchResults(data);
|
||||||
|
} else {
|
||||||
|
setSearchResults([]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const handler = setTimeout(() => {
|
||||||
|
performSearch(searchQuery);
|
||||||
|
}, 300);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearTimeout(handler);
|
||||||
|
};
|
||||||
|
}, [searchQuery]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`${styles.searchBarContainer} glassCard`}>
|
||||||
|
<form className={styles.searchBarForm} onSubmit={(event) => event.preventDefault()}>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24px" viewBox="0 -960 960 960" fill="#currentColor">
|
||||||
|
<path
|
||||||
|
d="M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z"/>
|
||||||
|
</svg>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Rechercher un événement"
|
||||||
|
value={searchQuery}
|
||||||
|
onChange={(event) => setSearchQuery(event.target.value)}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div className={styles.lineContainer}>
|
||||||
|
{searchResults.length > 0 ? (
|
||||||
|
<div className={styles.line}></div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{searchResults.map((result, i) => (
|
||||||
|
<Link to={`/event/` + event.id}>
|
||||||
|
<div className={styles.searchedEvent} key={i}>
|
||||||
|
<div className={`${styles.eventImageDiv}`}>
|
||||||
|
{result.image == null ? (
|
||||||
|
<img src="empty.png" className={styles.eventImage} alt="Pas de photo de l'événement" />
|
||||||
|
) : (
|
||||||
|
<img src={result.image + `.png`} alt="Photo de l'événement" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<p>{result.name}</p>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SearchBar;
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
.searchBarContainer{
|
||||||
|
position: fixed;
|
||||||
|
top: 10rem;
|
||||||
|
z-index: 100;
|
||||||
|
width: 60%;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchBarForm{
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.eventImageDiv {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-right: 1rem;
|
||||||
|
width: auto;
|
||||||
|
height: 2rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchedEvent{
|
||||||
|
display: flex;
|
||||||
|
padding: 0.5rem;
|
||||||
|
border-radius: 15px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchedEvent:hover {
|
||||||
|
background: #afafaf;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchedEvent p {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
text-decoration: none;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.lineContainer{
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line{
|
||||||
|
height: 0;
|
||||||
|
width: 96%;
|
||||||
|
border: #606060 solid 1px;
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eventImage {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchBarForm input{
|
||||||
|
background: none;
|
||||||
|
box-shadow: none;
|
||||||
|
height: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchBarForm input:focus{
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import styles from "./ToolBar.module.css"
|
||||||
|
import {Link} from "react-router";
|
||||||
|
import Filter from "../Filter/Filter.jsx";
|
||||||
|
import {useEffect, useState} from "react";
|
||||||
|
import SearchBar from "../SearchBar/SearchBar.jsx";
|
||||||
|
|
||||||
|
|
||||||
|
function ToolBar({setFilters, filters}) {
|
||||||
|
const [isFilterVisible, setIsFilterVisible] = useState(false);
|
||||||
|
const [isSearchVisible, setIsSearchVisible] = useState(false);
|
||||||
|
const toggleFilters = () => {
|
||||||
|
setIsFilterVisible(prev => !prev);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isSearchVisible) {
|
||||||
|
document.documentElement.style.overflow = 'hidden';
|
||||||
|
} else {
|
||||||
|
document.documentElement.style.overflow = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.documentElement.style.overflow = '';
|
||||||
|
};
|
||||||
|
}, [isSearchVisible]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{isSearchVisible ? (
|
||||||
|
<div className={styles.searchBarContainer}>
|
||||||
|
<div className={styles.searchBarOverlay} onClick={() => setIsSearchVisible(false)}></div>
|
||||||
|
<SearchBar/>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
<div className={styles.eventsButtons}>
|
||||||
|
<Link
|
||||||
|
to="/event/create"
|
||||||
|
className={`${styles.createButton} glassCard`}>
|
||||||
|
+
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<button className={`${styles.searchButton} glassCard`} onClick={() => setIsSearchVisible(true)}>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="#currentColor">
|
||||||
|
<path d="M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z"/>
|
||||||
|
</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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ToolBar;
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
.eventsButtons {
|
||||||
|
overflow: visible;
|
||||||
|
position: fixed;
|
||||||
|
top: 10rem;
|
||||||
|
right: 2rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
|
width: fit-content;
|
||||||
|
height: fit-content;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.filterContainer{
|
||||||
|
padding: 0;
|
||||||
|
border-radius: 30px;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filterMenu{
|
||||||
|
padding: 5px 5px 5px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.createButton, .searchButton, .sortButton {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border: none;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 55px;
|
||||||
|
height: 55px;
|
||||||
|
transition: all 0.5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.createButton {
|
||||||
|
font-size: 2rem;
|
||||||
|
color: #019AFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.createButton:hover, .searchButton:hover, .mobileFilter:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.searchBarOverlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 100;
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
}
|
||||||
|
.searchBarContainer{
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sortButton svg, .searchButton svg {
|
||||||
|
transform: scale(0.8);
|
||||||
|
fill: #019AFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.sortButton:focus, .searchButton:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
.eventsButtons {
|
||||||
|
flex-direction: row;
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
align-items: flex-start;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filterContainer{
|
||||||
|
display: flex;
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filterMenu{
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.createButton:hover, .searchButton:hover, .mobileFilter:hover {
|
||||||
|
transform: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-2
@@ -1,10 +1,13 @@
|
|||||||
* {
|
* {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
@@ -19,12 +22,14 @@
|
|||||||
@media screen and (max-width: 768px) {
|
@media screen and (max-width: 768px) {
|
||||||
.content{
|
.content{
|
||||||
padding: 0.7rem;
|
padding: 0.7rem;
|
||||||
z-index:1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
|||||||
@@ -1,52 +1,21 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import Event from "../../components/Event/Event.jsx";
|
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";
|
import ToolBar from "../../components/ToolBar/ToolBar.jsx";
|
||||||
|
import filter from "../../utils/filter.js";
|
||||||
import getAllEvents from "../../utils/event/getAllEvents.js";
|
import getAllEvents from "../../utils/event/getAllEvents.js";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function EventsPage(){
|
function EventsPage(){
|
||||||
const [isFilterVisible, setIsFilterVisible] = useState(false);
|
|
||||||
const toggleFilters = () => {
|
|
||||||
setIsFilterVisible(prev => !prev);
|
|
||||||
};
|
|
||||||
|
|
||||||
const [filters, setFilters] = useState({
|
const [filters, setFilters] = useState({
|
||||||
alphabetical: "asc",
|
alphabetical: "asc",
|
||||||
yearOrder: "asc",
|
yearOrder: "asc",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const [events, setEvents] = useState([]);
|
const [events, setEvents] = useState([]);
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
name: "Marathon de la Ville",
|
|
||||||
description: "Participez au marathon annuel et soutenez les associations locales.",
|
|
||||||
image: null,
|
|
||||||
tasks: [
|
|
||||||
{
|
|
||||||
name: "Inscription des participants",
|
|
||||||
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: "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
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
@@ -55,71 +24,12 @@ 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 (
|
return (
|
||||||
<div className={styles.eventsContainer}>
|
<div className={styles.eventsContainer}>
|
||||||
<div className={styles.eventsButtons}>
|
<ToolBar setFilters={setFilters} filters={filters}/>
|
||||||
<Link
|
|
||||||
to="/event/create"
|
|
||||||
className={`${styles.createButton} glassCard`}>
|
|
||||||
+
|
|
||||||
</Link>
|
|
||||||
<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 className={styles.eventsList}>
|
<div className={styles.eventsList}>
|
||||||
{events.map((event, index) => (
|
{filter(events, filters).map((event, index) => (
|
||||||
<Event key={index} event={event} />
|
<Event key={index} event={event} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
.eventsContainer {
|
.eventsContainer {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -8,92 +9,3 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.eventsButtons {
|
|
||||||
overflow: visible;
|
|
||||||
position: fixed;
|
|
||||||
top: 10rem;
|
|
||||||
right: 2rem;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-end;
|
|
||||||
width: fit-content;
|
|
||||||
height: fit-content;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.filterContainer{
|
|
||||||
padding: 0;
|
|
||||||
border-radius: 30px;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filterMenu{
|
|
||||||
padding: 5px 5px 5px 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.createButton, .sortButton {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
border: none;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 55px;
|
|
||||||
height: 55px;
|
|
||||||
transition: all 0.5s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.createButton {
|
|
||||||
font-size: 2rem;
|
|
||||||
color: #019AFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sortButton svg {
|
|
||||||
transform: scale(0.8);
|
|
||||||
fill: #019AFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sortButton:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.createButton:hover, .mobileFilter:hover {
|
|
||||||
transform: translateY(-5px);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.sortButton:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
.sortButton:focus-visible {
|
|
||||||
outline: 2px solid black;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
|
||||||
.eventsButtons {
|
|
||||||
flex-direction: row;
|
|
||||||
position: relative;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
align-items: flex-start;
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filterContainer{
|
|
||||||
display: flex;
|
|
||||||
width: fit-content;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filterMenu{
|
|
||||||
width: fit-content;
|
|
||||||
}
|
|
||||||
|
|
||||||
.createButton:hover, .mobileFilter:hover {
|
|
||||||
transform: none !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
function filter(elements, filters) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return [...elements].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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default filter;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
export default async function getUserNotifications() {
|
export default async function getUserNotifications() {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
'http://localhost:8000/api/users/1/notifications',
|
'http://localhost:80/api/users/1/notifications',
|
||||||
{
|
{
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
export default async function searchEvents(query) {
|
||||||
|
try {
|
||||||
|
const encodedQuery = encodeURIComponent(query);
|
||||||
|
const response = await fetch(
|
||||||
|
`http://localhost:80/api/events/search?query=${encodedQuery}`,
|
||||||
|
{
|
||||||
|
method: 'GET',
|
||||||
|
credentials: 'include',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const data = await response.json();
|
||||||
|
return data.hits.map(hit => hit.document);
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Erreur :", err);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user