diff --git a/.env b/.env new file mode 100644 index 0000000..50dcc6e --- /dev/null +++ b/.env @@ -0,0 +1 @@ +VITE_API_URL=localhost:80 \ No newline at end of file diff --git a/src/components/IncompleteEvent/IncompleteEvent.jsx b/src/components/IncompleteEvent/IncompleteEvent.jsx new file mode 100644 index 0000000..84dc2a9 --- /dev/null +++ b/src/components/IncompleteEvent/IncompleteEvent.jsx @@ -0,0 +1,29 @@ +import React from "react"; +import styles from "./IncompleteEvent.module.css"; + +function IncompleteEvent() { + const incompleteEvents = [ + { title: "Événement A", tasks: "Préparation des flyers" }, + { title: "Événement B", tasks: "Réservation de la salle" }, + { title: "Événement C", tasks: "Communication sur les réseaux" }, + { title: "Événement D", tasks: "Communication sur les réseaux" }, + { title: "Événement E", tasks: "Communication sur les réseaux" }, + { title: "Événement F", tasks: "Communication sur les réseaux" }, + ]; + + return ( +
+

Événements incomplets

+
+ {incompleteEvents.map((event, index) => ( +
+

{event.title}

+

{event.tasks}

+
+ ))} +
+
+ ); +} + +export default IncompleteEvent; diff --git a/src/components/IncompleteEvent/IncompleteEvent.module.css b/src/components/IncompleteEvent/IncompleteEvent.module.css new file mode 100644 index 0000000..e56e1f1 --- /dev/null +++ b/src/components/IncompleteEvent/IncompleteEvent.module.css @@ -0,0 +1,76 @@ +.rightBlock { + width: 100%; +} + +.rightBlock > h2 { + font-size: 29px; +} + +.eventsContainer { + display: flex; + flex-direction: row; + gap: 10px; + margin-top: 15px; + overflow-x: auto; + overflow-y: hidden; + padding-bottom: 10px; + scroll-behavior: smooth; +} + +.eventsContainer::-webkit-scrollbar { + height: 8px; +} + +.eventsContainer::-webkit-scrollbar-track { + background: rgba(0, 0, 0, 0.1); + border-radius: 10px; +} + +.eventsContainer::-webkit-scrollbar-thumb { + background: rgba(30, 96, 249, 0.5); + border-radius: 10px; +} + +.eventsContainer::-webkit-scrollbar-thumb:hover { + background: rgba(30, 96, 249, 0.7); +} + +.eventCard { + min-width: calc((100% - 20px) / 3); + max-width: calc((100% - 20px) / 3); + flex-shrink: 0; + padding: 10px; + text-align: center; + padding-bottom: 200px; + box-sizing: border-box; + opacity: 0; + transform: translateX(20px); + animation: slideInEvent 1s ease forwards; +} + +.eventCard:nth-child(1) { animation-delay: 0s; } +.eventCard:nth-child(2) { animation-delay: 0.1s; } +.eventCard:nth-child(3) { animation-delay: 0.2s; } +.eventCard:nth-child(4) { animation-delay: 0.3s; } +.eventCard:nth-child(5) { animation-delay: 0.4s; } +.eventCard:nth-child(6) { animation-delay: 0.5s; } + +.eventCard > h3 { + font-size: 24px; +} + +@keyframes slideInEvent { + from { opacity: 0; transform: translateX(20px); } + to { opacity: 1; transform: translateX(0); } +} + +@media screen and (max-width: 760px) { + .eventCard { + width: 100%; + height: 200px; + } + + .eventCard h3 { + font-size: 17px; + } +} diff --git a/src/components/PendingMembers/PendingMembers.jsx b/src/components/PendingMembers/PendingMembers.jsx new file mode 100644 index 0000000..27dace2 --- /dev/null +++ b/src/components/PendingMembers/PendingMembers.jsx @@ -0,0 +1,46 @@ +import React from "react"; +import Button from "../ui/button/button"; +import styles from "./PendingMembers.module.css"; + +function pendingMembers() { + const pendingMembers = [ + { name: "Antoine Ordonneau" }, + { name: "Giovanni Josserand" }, + { name: "Quentin T'Jampens" }, + { name: "Quentin T'Jampens" }, + { name: "Quentin T'Jampens" }, + { name: "Quentin T'Jampens" }, + { name: "Quentin T'Jampens" } + ]; + + const handleValidate = (name) => { + console.log(`Valider ${name}`); + }; + + const handleReject = (name) => { + console.log(`Refuser ${name}`); + }; + + return ( +
+

Membres en attente de validation

+
+ {pendingMembers.map((member, index) => ( +
+

{member.name}

+
+ + +
+
+ ))} +
+
+ ); +} + +export default pendingMembers; diff --git a/src/components/PendingMembers/PendingMembers.module.css b/src/components/PendingMembers/PendingMembers.module.css new file mode 100644 index 0000000..974b925 --- /dev/null +++ b/src/components/PendingMembers/PendingMembers.module.css @@ -0,0 +1,73 @@ +.rightBlock { + width: 100%; +} + +.rightBlock > h2 { + font-size: 29px; +} + +.membersContainer { + display: flex; + flex-direction: column; + gap: 10px; + margin-top: 15px; + max-height: 181px; + overflow-y: auto; + padding-right: 5px; + scroll-behavior: smooth; +} + +.membersContainer::-webkit-scrollbar { + width: 8px; +} + +.membersContainer::-webkit-scrollbar-track { + background: rgba(0, 0, 0, 0.1); + border-radius: 10px; +} + +.membersContainer::-webkit-scrollbar-thumb { + background: rgba(255, 0, 0, 0.5); + border-radius: 10px; +} + +.membersContainer::-webkit-scrollbar-thumb:hover { + background: rgba(125, 249, 30, 0.7); +} + +.memberCard { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px; + flex-shrink: 0; + opacity: 0; + transform: translateY(20px); + animation: slideInMember 0.5s ease forwards; +} + +.memberCard:nth-child(1) { animation-delay: 0s; } +.memberCard:nth-child(2) { animation-delay: 0.1s; } +.memberCard:nth-child(3) { animation-delay: 0.2s; } + +.memberCard p { + font-weight: bold; + font-size: 20px; +} + +.buttonGroup { + display: flex; + gap: 10px; + justify-content: right; +} + +@keyframes slideInMember { + from { opacity: 0; transform: translateY(20px); } + to { opacity: 1; transform: translateY(0); } +} + +@media screen and (max-width: 760px) { + .membersContainer { + max-height: 200px; + } +} diff --git a/src/components/chart/ParticipationChart.jsx b/src/components/chart/ParticipationChart.jsx new file mode 100644 index 0000000..7648bf1 --- /dev/null +++ b/src/components/chart/ParticipationChart.jsx @@ -0,0 +1,90 @@ +import React, { useState } from "react"; +import { Doughnut } from "react-chartjs-2"; +import { Chart, ArcElement } from "chart.js"; +import { MenuItem, Select, FormControl } from "@mui/material"; +import styles from "./ParticipationChart.module.css"; + +Chart.register(ArcElement); + +function participationChart() { + const [selected, setSelected] = useState("3"); + const [participationRate, setParticipationRate] = useState(89); + + const chartData = { + labels: ["Progress", "Background"], + datasets: [ + { + data: [participationRate, 100 - participationRate], + backgroundColor: ["#1e60f9ff", "#ffffffff"], + borderWidth: 0, + weight: 10, + cutout: "93%", + circumference: 360, + rotation: -90, + }, + ], + }; + + const chartOptions = { + responsive: true, + plugins: { + legend: { display: false }, + tooltip: { enabled: false }, + }, + animation: { + animateScale: true, + animateRotate: true, + }, + }; + + return ( +
+
+
+ +
+ + + +
+
+
+
+
+ +
{participationRate}%
+
+
+
+ ); +} + +export default participationChart; diff --git a/src/components/chart/ParticipationChart.module.css b/src/components/chart/ParticipationChart.module.css new file mode 100644 index 0000000..9e16164 --- /dev/null +++ b/src/components/chart/ParticipationChart.module.css @@ -0,0 +1,86 @@ +.leftBlock { + width: 40%; + display: flex; + flex-direction: column; + align-items: center; + height: fit-content; +} + +.participationHeader { + display: flex; + align-items: center; + width: 100%; +} + +.partiText { + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 2%; + margin-top: 2%; + animation: slideInEvent 2s; +} + +.partiText label { + font-size: 20px; + text-align: right; + transition: all 0.3s ease; +} + +.chartContainer { + max-width: 80%; + margin: 0 auto; + position: relative; + animation: slideEvent2 2s; +} + +.chartWrapper { + position: relative; + width: 100%; + height: 100%; + display: flex; + justify-content: center; +} + +.chartPercentage { + position: absolute; + top: 50%; + left: 50%; + text-align: center; + transform: translate(-50%, -50%); + font-size: 60px; + font-weight: bold; + color: #333; +} + +@keyframes slideEvent2 { + from { opacity: 0; transform: translateX(-20px); } + to { opacity: 1; transform: translateX(0); } +} + +@keyframes slideInEvent { + from { opacity: 0; transform: translateX(20px); } + to { opacity: 1; transform: translateX(0); } +} + +.formControl { + display: flex; + justify-content: center; + width: 100%; +} + +.formDesign { + margin: 0 auto; + width: fit-content; +} + +@media screen and (max-width: 760px) { + .partiText { + flex-direction: column; + justify-content: center; + } + + .partiText label { + text-align: center; + } +} diff --git a/src/pages/Stat/StatPage.jsx b/src/pages/Stat/StatPage.jsx index 9fe416d..fc2a4ef 100644 --- a/src/pages/Stat/StatPage.jsx +++ b/src/pages/Stat/StatPage.jsx @@ -1,182 +1,26 @@ -import React, { useState, useEffect, useContext } from "react"; -import Dropdown from 'react-bootstrap/Dropdown'; -import { Doughnut } from "react-chartjs-2"; -import { Chart, ArcElement } from "chart.js"; +import React, { useState } from "react"; import styles from "./StatPage.module.css"; -import Button from "./../../components/ui/button/button"; -import { AuthContext } from "../../contexts/auth/AuthContext.js"; -import { useNavigate } from "react-router"; -import { readUsedSize } from "chart.js/helpers"; -import { MenuItem, Select, FormControl, InputLabel } from "@mui/material"; - -Chart.register(ArcElement); +// Importez les composants avec une majuscule +import ParticipationChart from "../../components/chart/ParticipationChart.jsx"; +import IncompleteEvents from "../../components/IncompleteEvent/IncompleteEvent.jsx"; +import PendingMembers from "../../components/PendingMembers/PendingMembers.jsx"; function StatPage() { - - const { user } = useContext(AuthContext); - const navigate = useNavigate(); - - const [months, setMonths] = useState(3); const [selected, setSelected] = useState("3"); const [participationRate, setParticipationRate] = useState(89); - useEffect(() => { - if(!user.isAdmin) navigate("/") - }, []) - const incompleteEvents = [ - { title: "Événement A", tasks: "Préparation des flyers" }, - { title: "Événement B", tasks: "Réservation de la salle" }, - { title: "Événement C", tasks: "Communication sur les réseaux" }, - { title: "Événement D", tasks: "Communication sur les réseaux" }, - { title: "Événement E", tasks: "Communication sur les réseaux" }, - { title: "Événement F", tasks: "Communication sur les réseaux" }, - ]; - const pendingMembers = [ - { name: "Antoine Ordonneau" }, - { name: "Giovanni Josserand" }, - { name: "Quentin T'Jampens" }, - { name: "Quentin T'Jampens" }, - { name: "Quentin T'Jampens" }, - { name: "Quentin T'Jampens" }, - { name: "Quentin T'Jampens" } - ]; - - const handleValidate = (name) => { - console.log(`Valider ${name}`); - }; - const handleReject = (name) => { - console.log(`Refuser ${name}`); - }; - const chartData = { - labels: ["Progress", "Background"], - datasets: [ - { - data: [participationRate, 100 - participationRate], - backgroundColor: ["#1e60f9ff", "#ffffffff"], - borderWidth: 0, - weight: 10, - cutout: "93%", - circumference: 360, - rotation: -90, - }, - ], - }; - const chartOptions = { - responsive: true, - plugins: { - legend: { - display: false, - }, - tooltip: { - enabled: false, - }, - }, - animation: { - animateScale: true, - animateRotate: true, - }, - }; return (
-
-
-
- -
- - - -
- -
-
-
-
- -
- {participationRate}% -
-
-
-
+
-
-

Événements incomplets

-
- {incompleteEvents.map((event, index) => ( -
-

{event.title}

-

{event.tasks}

-
- ))} -
-
-
-

Membres en attente de validation

-
- {pendingMembers.map((member, index) => ( -
-

{member.name}

-
- - -
-
- ))} -
-
+ +
); diff --git a/src/pages/Stat/StatPage.module.css b/src/pages/Stat/StatPage.module.css index 3491259..ced6cdf 100644 --- a/src/pages/Stat/StatPage.module.css +++ b/src/pages/Stat/StatPage.module.css @@ -7,113 +7,6 @@ gap: 20px; } - - -.block { - border-radius: 10px; - padding: 15px; - box-sizing: border-box; -} - -.leftBlock { - width: 40%; - display: flex; - flex-direction: column; - align-items: center; - height: fit-content; -} - -.participationHeader { - display: flex; - align-items: center; - /*justify-content: center;*/ - text-align: center; - margin-bottom: 0px; - width: 100%; -} -.participationHeader #months{ - text-align:center; -} - -.partiText { - display: flex; - align-items: center; - justify-content: center; - margin-bottom: 2%; - margin-top: 2%; - animation: slideInEvent 2s; -} - -.partiText label { - transition: all 0.3s ease; -} - - -.participationHeader label { - font-size: 20px; - text-align: right; -} -.participationHeader p{ - width:fit-content; -} - - -.chartContainer { - max-width: 80%; - margin: 0 auto; - position: relative; - - animation: slideEvent2 2s; -} - -@keyframes slideEvent2 { - from { - opacity: 0; - transform: translateX(-20px); - } - to { - opacity: 1; - transform: translateX(0); - } -} -.chartWrapper { - position: relative; - width: 100%; - height: 100%; - display: flex; - justify-content: center; -} - -.chartPercentage { - position: absolute; - top: 50%; - left: 50%; - text-align: center; - transform: translate(-50%, -50%); - font-size: 60px; - font-weight: bold; - color: #333; -} - -.circularProgress { - width: 100%; - height: 100%; -} - -.progressBackground { - opacity: 0.3; -} - -.progressBar { - transition: stroke-dasharray 0.5s ease; - stroke-linecap: round; -} - -.progressText { - font-weight: bold; - font-family: Arial, sans-serif; -} - .rightSection { width: 60%; display: flex; @@ -121,234 +14,16 @@ gap: 20px; } -.rightBlock { - width: 100%; -} - -.rightBlock > h2 { - font-size: 29px; -} - -.eventsContainer { - display: flex; - flex-direction: row; - gap: 10px; - margin-top: 15px; - overflow-x: auto; - overflow-y: hidden; - padding-bottom: 10px; - scroll-behavior: smooth; -} - -/* Style de la scrollbar horizontale */ -.eventsContainer::-webkit-scrollbar { - height: 8px; -} - -.eventsContainer::-webkit-scrollbar-track { - background: rgba(0, 0, 0, 0.1); - border-radius: 10px; -} - -.eventsContainer::-webkit-scrollbar-thumb { - background: rgba(30, 96, 249, 0.5); - border-radius: 10px; -} - -.eventsContainer::-webkit-scrollbar-thumb:hover { - background: rgba(30, 96, 249, 0.7); -} - -.eventCard { - min-width: calc((100% - 20px) / 3); - max-width: calc((100% - 20px) / 3); - flex-shrink: 0; - padding: 10px; - text-align: center; - padding-bottom: 200px; - box-sizing: border-box; - opacity: 0; - transform: translateX(20px); - animation: slideInEvent 1s ease forwards; -} - -/* animation card */ -.eventCard:nth-child(1) { - animation-delay: 0s; -} - -.eventCard:nth-child(2) { - animation-delay: 0.1s; -} - -.eventCard:nth-child(3) { - animation-delay: 0.2s; -} - -.eventCard:nth-child(4) { - animation-delay: 0.3s; -} - -.eventCard:nth-child(5) { - animation-delay: 0.4s; -} - -.eventCard:nth-child(6) { - animation-delay: 0.5s; -} - - -@keyframes slideInEvent { - from { - opacity: 0; - transform: translateX(20px); - } - to { - opacity: 1; - transform: translateX(0); - } -} - -.eventCard > h3 { - font-size: 24px; -} - -.membersContainer { - display: flex; - flex-direction: column; - gap: 10px; - margin-top: 15px; - max-height: 181px; - overflow-y: auto; - padding-right: 5px; - scroll-behavior: smooth; -} - -/* style scrollbar */ -.membersContainer.membersContainer::-webkit-scrollbar { - width: 8px; -} - -.membersContainer.membersContainer::-webkit-scrollbar-track { - background: rgba(0, 0, 0, 0.1); - border-radius: 10px; -} - -.membersContainer.membersContainer::-webkit-scrollbar-thumb { - background: red; - border-radius: 10px; -} - -.membersContainer.membersContainer::-webkit-scrollbar-thumb:hover { - background: rgba(125, 249, 30, 0.7); -} - -/*//////*/ -.memberCard { - display: flex; - justify-content: space-between; - align-items: center; - padding: 10px; - flex-shrink: 0; - opacity: 0; - transform: translateY(20px); - animation: slideInMember 0.5s ease forwards; -} - -.memberCard:nth-child(1) { - animation-delay: 0s; -} - -.memberCard:nth-child(2) { - animation-delay: 0.1s; -} - -.memberCard:nth-child(3) { - animation-delay: 0.2s; -} - - - - -@keyframes slideInMember { - from { - opacity: 0; - transform: translateY(20px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -.memberCard p { - font-weight: bold; - font-size: 20px; -} - -.buttonGroup { - display: flex; - gap: 10px; - justify-content: right; -} - @media screen and (max-width: 760px) { .container { flex-direction: column; - width:100%; - padding: 0 0 0 0; - /* padding: 10px;*/ - } - - .leftBlock { width: 100%; - margin-top:20px; - height: fit-content; + padding: 0; } - + .rightSection { width: 100%; - margin:0 0 0 0; + margin: 0; margin-bottom: 15px; } - .rightBlock{ - width:100%; - margin-bottom: 0px; - } - - .rightBlock h2 { - font-size: 20px; } - - .eventCard { - width: 100%; - height:200px; - } - .eventCard h3{ - font-size:17px; - } - .donutChart { - width: 120px; - height: 120px; - } - .membersContainer { - max-height: 200px; - } - .partiText{ - flex-direction: column; - justify-content: center; - } - .partiText label{ - text-align: center; - } - .formControl { - display: flex; - justify-content: center; - width: 100%; - } - - .formDesign { - margin: 0 auto; - width: fit-content; - } - } \ No newline at end of file