-
-
Prénom
+
+
+
Dispose déjà d'une licence
+
+ setSwitchOn(!switchOn)}/>
-
-
-
-
Email
+ {switchOn &&
+
-
-
-
OU
-
-
- N° Licence
-
-
-
+ }
+
+ >
}
export function DemandeAffOk() {
diff --git a/src/main/webapp/src/pages/MemberList.jsx b/src/main/webapp/src/pages/MemberList.jsx
index 8fbd771..98e8d95 100644
--- a/src/main/webapp/src/pages/MemberList.jsx
+++ b/src/main/webapp/src/pages/MemberList.jsx
@@ -9,6 +9,7 @@ import {Checkbox} from "../components/MemberCustomFiels.jsx";
import axios from "axios";
import {apiAxios} from "../utils/Tools.js";
import {toast} from "react-toastify";
+import {SearchBar} from "../components/SearchBar.jsx";
const removeDiacritics = str => {
return str
@@ -106,41 +107,6 @@ export function MemberList({source}) {
>
}
-function SearchBar({search}) {
- const [searchInput, setSearchInput] = useState("");
-
- const handelChange = (e) => {
- setSearchInput(e.target.value);
- }
-
- const handleKeyDown = (event) => {
- if (event.key === 'Enter') {
- searchMember();
- }
- }
-
- const searchMember = () => {
- search(removeDiacritics(searchInput));
- }
-
- useEffect(() => {
- const delayDebounceFn = setTimeout(() => {
- searchMember();
- }, 750)
- return () => clearTimeout(delayDebounceFn)
- }, [searchInput])
-
- return
-}
-
function MakeCentralPanel({data, visibleMember, navigate, showLicenceState, page}) {
const pages = []
for (let i = 1; i <= data.page_count; i++) {
diff --git a/src/main/webapp/src/pages/admin/AdminRoot.jsx b/src/main/webapp/src/pages/admin/AdminRoot.jsx
index e2860ed..063c17e 100644
--- a/src/main/webapp/src/pages/admin/AdminRoot.jsx
+++ b/src/main/webapp/src/pages/admin/AdminRoot.jsx
@@ -4,6 +4,10 @@ import {LoadingProvider} from "../../hooks/useLoading.jsx";
import {MemberList} from "../MemberList.jsx";
import {MemberPage} from "./member/MemberPage.jsx";
import {NewMemberPage} from "./member/NewMemberPage.jsx";
+import {ClubList} from "./club/ClubList.jsx";
+import {AffiliationReqPage} from "./affiliation/AffiliationReqPage.jsx";
+import {NewClubPage} from "./club/NewClubPage.jsx";
+import {ClubPage} from "./club/ClubPage.jsx";
export function AdminRoot() {
return <>
@@ -28,6 +32,22 @@ export function getAdminChildren() {
path: 'member/new',
element:
},
+ {
+ path: 'club',
+ element:
+ },
+ {
+ path: 'club/:id',
+ element:
+ },
+ {
+ path: 'affiliation/request',
+ element:
+ },
+ {
+ path: 'club/new',
+ element:
+ },
{
path: 'b',
element:
Admin B
diff --git a/src/main/webapp/src/pages/admin/affiliation/AffiliationReqPage.jsx b/src/main/webapp/src/pages/admin/affiliation/AffiliationReqPage.jsx
new file mode 100644
index 0000000..443e68e
--- /dev/null
+++ b/src/main/webapp/src/pages/admin/affiliation/AffiliationReqPage.jsx
@@ -0,0 +1,16 @@
+import {useNavigate} from "react-router-dom";
+
+export function AffiliationReqPage() {
+ const navigate = useNavigate();
+
+ return <>
+
Page affiliation
+
navigate("/admin/affiliation")}>
+ « retour
+
+
+ >
+}
\ No newline at end of file
diff --git a/src/main/webapp/src/pages/admin/club/AffiliationCard.jsx b/src/main/webapp/src/pages/admin/club/AffiliationCard.jsx
new file mode 100644
index 0000000..e392e9c
--- /dev/null
+++ b/src/main/webapp/src/pages/admin/club/AffiliationCard.jsx
@@ -0,0 +1,187 @@
+import {useLoadingSwitcher} from "../../../hooks/useLoading.jsx";
+import {useFetch} from "../../../hooks/useFetch.js";
+import {useEffect, useReducer, useState} from "react";
+import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
+import {faPen} from "@fortawesome/free-solid-svg-icons";
+import {AxiosError} from "../../../components/AxiosError.jsx";
+import {CheckField, TextField} from "../../../components/MemberCustomFiels.jsx";
+import {apiAxios, getSaison} from "../../../utils/Tools.js";
+import {Input} from "../../../components/Input.jsx";
+import {toast} from "react-toastify";
+
+function affiliationReducer(affiliation, action) {
+ switch (action.type) {
+ case 'ADD':
+ return [
+ ...affiliation,
+ action.payload
+ ]
+ case 'REMOVE':
+ return affiliation.filter(affiliation => affiliation.id !== action.payload)
+ case 'UPDATE_OR_ADD':
+ const index = affiliation.findIndex(affiliation => affiliation.id === action.payload.id)
+ if (index === -1) {
+ return [
+ ...affiliation,
+ action.payload
+ ]
+ } else {
+ affiliation[index] = action.payload
+ return [...affiliation]
+ }
+ case 'SORT':
+ return affiliation.sort((a, b) => b.saison - a.saison)
+ default:
+ throw new Error()
+ }
+}
+
+export function AffiliationCard({clubData}) {
+ const setLoading = useLoadingSwitcher()
+ const {data, error} = useFetch(`/affiliation/${clubData.id}`, setLoading, 1)
+
+ const [modalAffiliation, setModal] = useState({id: -1, club: clubData.id})
+ const [affiliations, dispatch] = useReducer(affiliationReducer, [])
+
+ useEffect(() => {
+ if (!data) return
+ for (const dataKey of data) {
+ dispatch({type: 'UPDATE_OR_ADD', payload: dataKey})
+ }
+ dispatch({type: 'SORT'})
+ }, [data]);
+
+ return
+
+
+
Affiliation
+
+ setModal({id: -1, club: clubData.id})}>Ajouter
+
+
+
+
+
+
+
+
;
+}
+
+function sendAffiliation(event, dispatch) {
+ event.preventDefault();
+
+ const formData = new FormData(event.target);
+ toast.promise(
+ apiAxios.post(`/affiliation/${formData.get('membre')}`, formData), // TODO
+ {
+ pending: "Enregistrement de l'affiliation en cours",
+ success: "Affiliation enregistrée avec succès 🎉",
+ error: "Échec de l'enregistrement de l'affiliation 😕"
+ }
+ ).then(data => {
+ dispatch({type: 'UPDATE_OR_ADD', payload: data.data})
+ dispatch({type: 'SORT'})
+ })
+
+}
+
+function removeAffiliation(id, dispatch) {
+ toast.promise(
+ apiAxios.delete(`/affiliation/${id}`),
+ {
+ pending: "Suppression de l'affiliation en cours",
+ success: "Affiliation supprimée avec succès 🎉",
+ error: "Échec de la suppression de l'affiliation 😕"
+ }
+ ).then(_ => {
+ dispatch({type: 'REMOVE', payload: id})
+ })
+}
+
+function ModalContent({affiliation, dispatch}) {
+ const [saison, setSaison] = useState(0)
+ const [validate, setValidate] = useState(false)
+ const [isNew, setNew] = useState(true)
+ const setSeason = (event) => {
+ setSaison(Number(event.target.value))
+ }
+ const handleValidateChange = (event) => {
+ setValidate(event.target.value === 'true');
+ }
+
+ useEffect(() => {
+ if (affiliation.id !== -1) {
+ setNew(false)
+ setSaison(affiliation.saison)
+ setValidate(affiliation.validate)
+ } else {
+ setNew(true)
+ setSaison(getSaison())
+ setValidate(false)
+ }
+ }, [affiliation]);
+
+ return
+}
+
+function RadioGroupeOnOff({value, onChange, name, text}) {
+ return
+ {text}
+
+ Non
+
+ Oui
+
;
+}
\ No newline at end of file
diff --git a/src/main/webapp/src/pages/admin/club/ClubList.jsx b/src/main/webapp/src/pages/admin/club/ClubList.jsx
new file mode 100644
index 0000000..80c0e9b
--- /dev/null
+++ b/src/main/webapp/src/pages/admin/club/ClubList.jsx
@@ -0,0 +1,192 @@
+import {useLocation, useNavigate} from "react-router-dom";
+import {useEffect, useState} from "react";
+import {useLoadingSwitcher} from "../../../hooks/useLoading.jsx";
+import {useFetch} from "../../../hooks/useFetch.js";
+import {toast} from "react-toastify";
+import {apiAxios} from "../../../utils/Tools.js";
+import {AxiosError} from "../../../components/AxiosError.jsx";
+import {Checkbox} from "../../../components/MemberCustomFiels.jsx";
+import {ThreeDots} from "react-loader-spinner";
+import {SearchBar} from "../../../components/SearchBar.jsx";
+
+export function ClubList() {
+ const {hash} = useLocation();
+ const navigate = useNavigate();
+ let page = Number(hash.substring(1));
+ page = (page > 0) ? page : 1;
+
+ const [clubData, setClubData] = useState([]);
+ const [affiliationData, setAffiliationData] = useState([]);
+ const [showAffiliationState, setShowAffiliationState] = useState(false);
+ const [countryFilter, setCountryFilter] = useState("");
+ const [lastSearch, setLastSearch] = useState("");
+
+ const setLoading = useLoadingSwitcher()
+ const {data, error, refresh} = useFetch(`/club/find?page=${page}`, setLoading, 1)
+
+
+ useEffect(() => {
+ refresh(`/club/find?page=${page}&search=${lastSearch}&country=${countryFilter}`);
+ }, [hash, countryFilter]);
+
+ useEffect(() => {
+ if (!data)
+ return;
+ const data2 = [];
+ for (const e of data.result) {
+ data2.push({
+ id: e.id,
+ name: e.name,
+ country: e.country,
+ shieldURL: e.shieldURL,
+ no_affiliation: e.no_affiliation,
+ affiliation: showAffiliationState ? affiliationData.find(licence => licence.club === e.id) : null
+ })
+ }
+ setClubData(data2);
+ }, [data, affiliationData]);
+
+ useEffect(() => {
+ if (!showAffiliationState)
+ return;
+
+ toast.promise(
+ apiAxios.get(`/affiliation/current`),
+ {
+ pending: "Chargement des affiliation...",
+ success: "Affiliation chargées",
+ error: "Impossible de charger les affiliations"
+ })
+ .then(data => {
+ setAffiliationData(data.data);
+ });
+ }, [showAffiliationState]);
+
+ const search = (search) => {
+ if (search === lastSearch)
+ return;
+ setLastSearch(search);
+ refresh(`/club/find?page=${page}&search=${search}&country=${countryFilter}`);
+ }
+
+ return <>
+
Club
+
+
+
+
+ {data
+ ?
+ : error
+ ?
+ :
+ }
+
+
+
+ navigate("../affiliation/request")}>Demande en cours
+ navigate("new")}>Ajouter une affiliation
+
+
+
+
+
+ >
+}
+
+function MakeCentralPanel({data, visibleclub, navigate, showAffiliationState, page}) {
+ const pages = []
+ for (let i = 1; i <= data.page_count; i++) {
+ pages.push(
+ navigate("#" + i)}>{i}
+ );
+ }
+
+ return <>
+
+
Ligne {((page - 1) * data.page_size) + 1} à {
+ (page * data.page_size > data.result_count) ? data.result_count : (page * data.page_size)} (page {page} sur {data.page_count})
+
+ {visibleclub.map(club => ())}
+
+
+
+
+
+
+ navigate("#" + (page - 1))}>«
+ {pages}
+ = data.page_count) ? " disabled" : "")}>
+ navigate("#" + (page + 1))}>»
+
+
+
+ >
+}
+
+function MakeRow({club, showAffiliationState, navigate}) {
+ const rowContent = <>
+
+
{String(club.no_affiliation).padStart(5, '0')}
+
+
+
{club.country}
+ >
+
+ if (showAffiliationState && club.affiliation != null) {
+ return
navigate("" + club.id)}>{rowContent}
+ } else {
+ return
navigate("" + club.id)}>
+ {rowContent}
+
+ }
+}
+
+let allCountry = []
+
+function FiltreBar({showAffiliationState, setShowAffiliationState, data, countryFilter, setCountryFilter}) {
+ useEffect(() => {
+ if (!data)
+ return;
+ allCountry.push(...data.result.map((e) => e.club?.name))
+ allCountry = allCountry.filter((value, index, self) => self.indexOf(value) === index).filter(value => value != null).sort()
+ }, [data]);
+
+ return
+
+
+
+
+ setCountryFilter(event.target.value)}>
+ --- tout les pays ---
+ {allCountry && allCountry.map((value, index) => {
+ return {value}
+ })
+ }
+
+
+
+}
+
+function Def() {
+ return
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/src/main/webapp/src/pages/admin/club/ClubPage.jsx b/src/main/webapp/src/pages/admin/club/ClubPage.jsx
new file mode 100644
index 0000000..0269304
--- /dev/null
+++ b/src/main/webapp/src/pages/admin/club/ClubPage.jsx
@@ -0,0 +1,128 @@
+import {useNavigate, useParams} from "react-router-dom";
+import {LoadingProvider, useLoadingSwitcher} from "../../../hooks/useLoading.jsx";
+import {useFetch} from "../../../hooks/useFetch.js";
+import {toast} from "react-toastify";
+import {apiAxios} from "../../../utils/Tools.js";
+import {ConfirmDialog} from "../../../components/ConfirmDialog.jsx";
+import {AxiosError} from "../../../components/AxiosError.jsx";
+import {AffiliationCard} from "./AffiliationCard.jsx";
+import {CheckField, CountryList, TextField} from "../../../components/MemberCustomFiels.jsx";
+
+import {MapContainer, Marker, Popup, TileLayer, useMap} from 'react-leaflet'
+
+const vite_url = import.meta.env.VITE_URL;
+
+export function ClubPage() {
+ const {id} = useParams()
+ const navigate = useNavigate();
+
+ const setLoading = useLoadingSwitcher()
+ const {data, error} = useFetch(`/club/${id}`, setLoading, 1)
+
+ const handleRm = () => {
+ toast.promise(
+ apiAxios.delete(`/club/${id}`),
+ {
+ pending: "Suppression du club en cours...",
+ success: "Club supprimé avec succès 🎉",
+ error: "Échec de la suppression du club 😕"
+ }
+ ).then(_ => {
+ navigate("/admin/club")
+ })
+ }
+
+ return <>
+
Page membre
+
navigate("/admin/club")}>
+ « retour
+
+ {data
+ ?
+
+
+
+
+
+
+
+ Supprimer le compte
+
+
+
+
+
+
+ : error &&
+ }
+ >
+}
+
+function InformationForm({data}) {
+ return
+
Licence n°{data.no_affiliation}
+
+
+
+
+
+
+
+
+
+
+
+ Blason
+
+
+
Laissez vide pour ne rien changer.
+
+
+
+
+
+
+
+
+
+
+
;
+}
+ // https://annuaire-entreprises.data.gouv.fr/entreprise/la-mesnie-des-chevaliers-de-st-georges-et-de-st-michel-500213731
+const position = [51.505, -0.09]
+function MainMap() {
+ function handleReturnCurrentPosition() {
+ console.log("I have clicked return button!!");
+ //const newCurrentPositionId = uuidv4();
+ //setReturnCurrentPosition(newCurrentPositionId);
+ //console.log(newCurrentPositionId);
+ }
+
+ return (
+ <>
+
+
+
+
+ A pretty CSS3 popup. Easily customizable.
+
+
+
+ Return current position
+
+ >
+ )
+}
+
+function SearchBarMap() {
+ return <>
+ >
+}
\ No newline at end of file
diff --git a/src/main/webapp/src/pages/admin/club/NewClubPage.jsx b/src/main/webapp/src/pages/admin/club/NewClubPage.jsx
new file mode 100644
index 0000000..20fe771
--- /dev/null
+++ b/src/main/webapp/src/pages/admin/club/NewClubPage.jsx
@@ -0,0 +1,16 @@
+import {useNavigate} from "react-router-dom";
+
+export function NewClubPage() {
+ const navigate = useNavigate();
+
+ return <>
+ Page affiliation
+ navigate("/admin/affiliation")}>
+ « retour
+
+
+ >
+}
\ No newline at end of file
diff --git a/src/main/webapp/src/pages/admin/member/InformationForm.jsx b/src/main/webapp/src/pages/admin/member/InformationForm.jsx
index 21545b0..3c62e9c 100644
--- a/src/main/webapp/src/pages/admin/member/InformationForm.jsx
+++ b/src/main/webapp/src/pages/admin/member/InformationForm.jsx
@@ -2,7 +2,7 @@ import {useLoadingSwitcher} from "../../../hooks/useLoading.jsx";
import {apiAxios} from "../../../utils/Tools.js";
import {toast} from "react-toastify";
import imageCompression from "browser-image-compression";
-import {BirthDayField, OptionField, TextField} from "../../../components/MemberCustomFiels.jsx";
+import {BirthDayField, CountryList, OptionField, TextField} from "../../../components/MemberCustomFiels.jsx";
import {ClubSelect} from "../../../components/ClubSelect.jsx";
export function addPhoto(event, formData, send) {
@@ -74,8 +74,7 @@ export function InformationForm({data}) {
type="email"/>
-
+
@@ -86,7 +85,11 @@ export function InformationForm({data}) {
MEMBRE: 'Membre',
PRESIDENT: 'Président',
TRESORIER: 'Trésorier',
- SECRETAIRE: 'Secrétaire'
+ SECRETAIRE: 'Secrétaire',
+ VPRESIDENT: 'Vise-Président',
+ VTRESORIER: 'Vise-Trésorier',
+ VSECRETAIRE: 'Vise-Secrétaire',
+ MEMBREBUREAU: 'Membre bureau'
}}/>
diff --git a/src/main/webapp/src/pages/club/member/InformationForm.jsx b/src/main/webapp/src/pages/club/member/InformationForm.jsx
index 404c078..7d9f96f 100644
--- a/src/main/webapp/src/pages/club/member/InformationForm.jsx
+++ b/src/main/webapp/src/pages/club/member/InformationForm.jsx
@@ -3,7 +3,7 @@
import {useLoadingSwitcher} from "../../../hooks/useLoading.jsx";
import {apiAxios} from "../../../utils/Tools.js";
import {toast} from "react-toastify";
-import {BirthDayField, OptionField, TextField} from "../../../components/MemberCustomFiels.jsx";
+import {BirthDayField, CountryList, OptionField, TextField} from "../../../components/MemberCustomFiels.jsx";
import {addPhoto} from "../../admin/member/InformationForm.jsx";
export function InformationForm({data}) {
@@ -52,8 +52,7 @@ export function InformationForm({data}) {
type="email"/>
-
+