diff --git a/src/main/java/fr/titionfire/ffsaf/data/model/LogModel.java b/src/main/java/fr/titionfire/ffsaf/data/model/LogModel.java index 4d1dd9d..dbb770f 100644 --- a/src/main/java/fr/titionfire/ffsaf/data/model/LogModel.java +++ b/src/main/java/fr/titionfire/ffsaf/data/model/LogModel.java @@ -41,7 +41,7 @@ public class LogModel { } public enum ObjectType { - Membre, Affiliation, Licence, Club, Competition, Register + Membre, Affiliation, Licence, Club, Competition, Register, Selection } } diff --git a/src/main/java/fr/titionfire/ffsaf/data/model/MembreModel.java b/src/main/java/fr/titionfire/ffsaf/data/model/MembreModel.java index d83f232..0e8a420 100644 --- a/src/main/java/fr/titionfire/ffsaf/data/model/MembreModel.java +++ b/src/main/java/fr/titionfire/ffsaf/data/model/MembreModel.java @@ -72,6 +72,10 @@ public class MembreModel implements LoggableModel, CombModel { @Schema(description = "Les licences du membre. (optionnel)") List licences; + @OneToMany(mappedBy = "membre", fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @Schema(description = "Les séléctions du membre. (optionnel)") + List selections; + @Override public String getObjectName() { return fname + " " + lname; diff --git a/src/main/java/fr/titionfire/ffsaf/data/model/SelectionModel.java b/src/main/java/fr/titionfire/ffsaf/data/model/SelectionModel.java new file mode 100644 index 0000000..e4b010b --- /dev/null +++ b/src/main/java/fr/titionfire/ffsaf/data/model/SelectionModel.java @@ -0,0 +1,44 @@ +package fr.titionfire.ffsaf.data.model; + +import fr.titionfire.ffsaf.utils.Categorie; +import io.quarkus.runtime.annotations.RegisterForReflection; +import jakarta.persistence.*; +import lombok.*; +import org.eclipse.microprofile.openapi.annotations.media.Schema; + +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +@RegisterForReflection + +@Entity +@Table(name = "selection") +public class SelectionModel implements LoggableModel { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Schema(description = "L'identifiant de la séléction.") + Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "membre", referencedColumnName = "id") + @Schema(description = "Le membre de la séléction. (optionnel)") + MembreModel membre; + + @Schema(description = "La saison de la séléction.", examples = "2025") + int saison; + + @Schema(description = "Catégorie de la séléction.") + Categorie categorie; + + @Override + public String getObjectName() { + return "selection " + id.toString(); + } + + @Override + public LogModel.ObjectType getObjectType() { + return LogModel.ObjectType.Selection; + } +} diff --git a/src/main/java/fr/titionfire/ffsaf/data/repository/SelectionRepository.java b/src/main/java/fr/titionfire/ffsaf/data/repository/SelectionRepository.java new file mode 100644 index 0000000..0aebfa1 --- /dev/null +++ b/src/main/java/fr/titionfire/ffsaf/data/repository/SelectionRepository.java @@ -0,0 +1,9 @@ +package fr.titionfire.ffsaf.data.repository; + +import fr.titionfire.ffsaf.data.model.SelectionModel; +import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase; +import jakarta.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class SelectionRepository implements PanacheRepositoryBase { +} diff --git a/src/main/java/fr/titionfire/ffsaf/domain/service/MembreService.java b/src/main/java/fr/titionfire/ffsaf/domain/service/MembreService.java index 2f4278e..39fc2b2 100644 --- a/src/main/java/fr/titionfire/ffsaf/domain/service/MembreService.java +++ b/src/main/java/fr/titionfire/ffsaf/domain/service/MembreService.java @@ -7,10 +7,7 @@ import fr.titionfire.ffsaf.data.repository.*; import fr.titionfire.ffsaf.net2.ServerCustom; import fr.titionfire.ffsaf.net2.data.SimpleCombModel; import fr.titionfire.ffsaf.net2.request.SReqComb; -import fr.titionfire.ffsaf.rest.data.MeData; -import fr.titionfire.ffsaf.rest.data.SimpleLicence; -import fr.titionfire.ffsaf.rest.data.SimpleMembre; -import fr.titionfire.ffsaf.rest.data.SimpleMembreInOutData; +import fr.titionfire.ffsaf.rest.data.*; import fr.titionfire.ffsaf.rest.exception.DBadRequestException; import fr.titionfire.ffsaf.rest.exception.DForbiddenException; import fr.titionfire.ffsaf.rest.exception.DInternalError; @@ -590,9 +587,12 @@ public class MembreService { MeData meData = new MeData(); return repository.find("userId = ?1", subject).firstResult() .invoke(meData::setMembre) - .chain(membreModel -> Mutiny.fetch(membreModel.getLicences())) - .map(licences -> licences.stream().map(SimpleLicence::fromModel).toList()) - .invoke(meData::setLicences) + .call(membreModel -> Mutiny.fetch(membreModel.getLicences()) + .map(licences -> licences.stream().map(SimpleLicence::fromModel).toList()) + .invoke(meData::setLicences)) + .call(membreModel -> Mutiny.fetch(membreModel.getSelections()) + .map(licences -> licences.stream().map(SimpleSelection::fromModel).toList()) + .invoke(meData::setSelections)) .map(__ -> meData); } diff --git a/src/main/java/fr/titionfire/ffsaf/domain/service/SelectionService.java b/src/main/java/fr/titionfire/ffsaf/domain/service/SelectionService.java new file mode 100644 index 0000000..7ec979a --- /dev/null +++ b/src/main/java/fr/titionfire/ffsaf/domain/service/SelectionService.java @@ -0,0 +1,64 @@ +package fr.titionfire.ffsaf.domain.service; + +import fr.titionfire.ffsaf.data.model.LogModel; +import fr.titionfire.ffsaf.data.model.MembreModel; +import fr.titionfire.ffsaf.data.model.SelectionModel; +import fr.titionfire.ffsaf.data.repository.CombRepository; +import fr.titionfire.ffsaf.data.repository.SelectionRepository; +import fr.titionfire.ffsaf.rest.data.SimpleSelection; +import io.quarkus.hibernate.reactive.panache.Panache; +import io.quarkus.hibernate.reactive.panache.common.WithSession; +import io.smallrye.mutiny.Uni; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import org.hibernate.reactive.mutiny.Mutiny; + +import java.util.List; +import java.util.function.Consumer; + +@WithSession +@ApplicationScoped +public class SelectionService { + + @Inject + CombRepository combRepository; + + @Inject + SelectionRepository repository; + + @Inject + LoggerService ls; + + public Uni> getSelection(long id, Consumer checkPerm) { + return combRepository.findById(id).invoke(checkPerm) + .chain(combRepository -> Mutiny.fetch(combRepository.getSelections())); + } + + public Uni setSelection(long id, SimpleSelection data) { + if (data.getId() == -1) { + return combRepository.findById(id).chain(membreModel -> { + SelectionModel model = new SelectionModel(); + + model.setMembre(membreModel); + model.setSaison(data.getSaison()); + model.setCategorie(data.getCategorie()); + return Panache.withTransaction(() -> repository.persist(model)) + .call(licenceModel -> ls.logA(LogModel.ActionType.ADD, membreModel.getObjectName(), + licenceModel)); + }); + } else { + return repository.findById(data.getId()).chain(model -> { + ls.logChange("Catégorie", model.getCategorie(), data.getCategorie(), model); + model.setCategorie(data.getCategorie()); + return Panache.withTransaction(() -> repository.persist(model)) + .call(__ -> ls.append()); + }); + } + } + + public Uni deleteSelection(long id) { + return repository.findById(id) + .call(model -> ls.logADelete(model)) + .chain(model -> Panache.withTransaction(() -> repository.delete(model))); + } +} diff --git a/src/main/java/fr/titionfire/ffsaf/rest/LicenceEndpoints.java b/src/main/java/fr/titionfire/ffsaf/rest/LicenceEndpoints.java index efcd9d8..cd8b8e1 100644 --- a/src/main/java/fr/titionfire/ffsaf/rest/LicenceEndpoints.java +++ b/src/main/java/fr/titionfire/ffsaf/rest/LicenceEndpoints.java @@ -101,7 +101,7 @@ public class LicenceEndpoints { @RolesAllowed("federation_admin") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.MULTIPART_FORM_DATA) - @Operation(summary = "Créer une licence", description = "Créer unr licence en fonction de son identifiant et des " + + @Operation(summary = "Créer une licence", description = "Créer une licence en fonction de son identifiant et des " + "informations fournies dans le formulaire (pour les administrateurs)") @APIResponses(value = { @APIResponse(responseCode = "200", description = "La licence a été mise à jour avec succès"), diff --git a/src/main/java/fr/titionfire/ffsaf/rest/SelectionEndpoints.java b/src/main/java/fr/titionfire/ffsaf/rest/SelectionEndpoints.java new file mode 100644 index 0000000..4e3c31e --- /dev/null +++ b/src/main/java/fr/titionfire/ffsaf/rest/SelectionEndpoints.java @@ -0,0 +1,85 @@ +package fr.titionfire.ffsaf.rest; + +import fr.titionfire.ffsaf.data.model.MembreModel; +import fr.titionfire.ffsaf.domain.service.SelectionService; +import fr.titionfire.ffsaf.rest.data.SimpleSelection; +import fr.titionfire.ffsaf.rest.exception.DForbiddenException; +import fr.titionfire.ffsaf.utils.SecurityCtx; +import io.smallrye.mutiny.Uni; +import io.smallrye.mutiny.unchecked.Unchecked; +import jakarta.annotation.security.RolesAllowed; +import jakarta.inject.Inject; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.MediaType; +import org.eclipse.microprofile.openapi.annotations.Operation; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponses; + +import java.util.List; +import java.util.function.Consumer; + +@Path("api/selection") +public class SelectionEndpoints { + + @Inject + SelectionService selectionService; + + @Inject + SecurityCtx securityCtx; + + Consumer checkPerm = Unchecked.consumer(membreModel -> { + if (!securityCtx.roleHas("federation_admin") && !securityCtx.isInClubGroup(membreModel.getClub().getId())) + throw new DForbiddenException(); + }); + + @GET + @Path("{id}") + @RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra", + "ffsaf_selectionneur"}) + @Produces(MediaType.APPLICATION_JSON) + @Operation(summary = "Renvoie les séléctions d'un membre", description = "Renvoie les séléctions d'un membre en fonction " + + "de son identifiant") + @APIResponses(value = { + @APIResponse(responseCode = "200", description = "La liste des séléctions du membre"), + @APIResponse(responseCode = "403", description = "Accès refusé"), + @APIResponse(responseCode = "404", description = "Le membre n'existe pas"), + @APIResponse(responseCode = "500", description = "Erreur interne du serveur") + }) + public Uni> getSelection(@PathParam("id") long id) { + return selectionService.getSelection(id, checkPerm) + .map(selectionModels -> selectionModels.stream().map(SimpleSelection::fromModel).toList()); + } + + @POST + @Path("{id}") + @RolesAllowed({"federation_admin", "ffsaf_selectionneur"}) + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + @Operation(summary = "Créer une séléction", description = "Créer une séléction en fonction de son identifiant et des " + + "informations fournies dans le formulaire (pour les administrateurs)") + @APIResponses(value = { + @APIResponse(responseCode = "200", description = "La séléction a été mise à jour avec succès"), + @APIResponse(responseCode = "403", description = "Accès refusé"), + @APIResponse(responseCode = "404", description = "La séléction n'existe pas"), + @APIResponse(responseCode = "500", description = "Erreur interne du serveur") + }) + public Uni setSelection(@PathParam("id") long id, SimpleSelection data) { + return selectionService.setSelection(id, data).map(SimpleSelection::fromModel); + } + + @DELETE + @Path("{id}") + @RolesAllowed({"federation_admin", "ffsaf_selectionneur"}) + @Produces(MediaType.TEXT_PLAIN) + @Operation(summary = "Supprime une séléction", description = "Supprime une séléction en fonction de son identifiant " + + "(pour les administrateurs)") + @APIResponses(value = { + @APIResponse(responseCode = "204", description = "La séléction a été supprimée avec succès"), + @APIResponse(responseCode = "403", description = "Accès refusé"), + @APIResponse(responseCode = "404", description = "La séléction n'existe pas"), + @APIResponse(responseCode = "500", description = "Erreur interne du serveur") + }) + public Uni deleteSelection(@PathParam("id") long id) { + return selectionService.deleteSelection(id); + } +} diff --git a/src/main/java/fr/titionfire/ffsaf/rest/data/MeData.java b/src/main/java/fr/titionfire/ffsaf/rest/data/MeData.java index ece32cc..7da843e 100644 --- a/src/main/java/fr/titionfire/ffsaf/rest/data/MeData.java +++ b/src/main/java/fr/titionfire/ffsaf/rest/data/MeData.java @@ -44,6 +44,8 @@ public class MeData { private ResultPrivacy resultPrivacy; @Schema(description = "La liste des licences du membre.") private List licences; + @Schema(description = "La liste des séléctions du membre.") + private List selections; public void setMembre(MembreModel membreModel) { this.id = membreModel.getId(); diff --git a/src/main/java/fr/titionfire/ffsaf/rest/data/SimpleSelection.java b/src/main/java/fr/titionfire/ffsaf/rest/data/SimpleSelection.java new file mode 100644 index 0000000..4c37b7a --- /dev/null +++ b/src/main/java/fr/titionfire/ffsaf/rest/data/SimpleSelection.java @@ -0,0 +1,36 @@ +package fr.titionfire.ffsaf.rest.data; + +import fr.titionfire.ffsaf.data.model.SelectionModel; +import fr.titionfire.ffsaf.utils.Categorie; +import io.quarkus.runtime.annotations.RegisterForReflection; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import org.eclipse.microprofile.openapi.annotations.media.Schema; + +@Data +@Builder +@AllArgsConstructor +@RegisterForReflection +public class SimpleSelection { + @Schema(description = "ID de la séléction", examples = "1") + Long id; + @Schema(description = "ID du membre", examples = "1") + Long membre; + @Schema(description = "Saison de la séléction", examples = "2024") + int saison; + @Schema(description = "Catégorie de la séléction", examples = "JUNIOR") + Categorie categorie; + + public static SimpleSelection fromModel(SelectionModel model) { + if (model == null) + return null; + + return new SimpleSelection.SimpleSelectionBuilder() + .id(model.getId()) + .membre(model.getMembre().getId()) + .saison(model.getSaison()) + .categorie(model.getCategorie()) + .build(); + } +} diff --git a/src/main/webapp/src/pages/MePage.jsx b/src/main/webapp/src/pages/MePage.jsx index aac61d3..89f46bb 100644 --- a/src/main/webapp/src/pages/MePage.jsx +++ b/src/main/webapp/src/pages/MePage.jsx @@ -14,7 +14,7 @@ import { } from "@fortawesome/free-solid-svg-icons"; import {CheckField} from "../components/MemberCustomFiels.jsx"; import {toast} from "react-toastify"; -import {apiAxios} from "../utils/Tools.js"; +import {apiAxios, getCatName} from "../utils/Tools.js"; import {useEffect, useState} from "react"; const vite_url = import.meta.env.VITE_URL; @@ -40,7 +40,7 @@ export function MePage() {
- +
@@ -93,10 +93,17 @@ function PhotoCard({data}) { ; } -function SelectCard() { +function SelectCard({userData}) { return
Sélection en équipe de France
+
    + {userData?.selections && userData.selections.sort((a, b) => b.saison - a.saison).map((selection, index) => { + return
    +
    {selection?.saison}-{selection?.saison + 1} en {getCatName(selection?.categorie)}
    +
    + })} +
; } diff --git a/src/main/webapp/src/pages/admin/club/ClubPage.jsx b/src/main/webapp/src/pages/admin/club/ClubPage.jsx index 096e6b8..aa40e94 100644 --- a/src/main/webapp/src/pages/admin/club/ClubPage.jsx +++ b/src/main/webapp/src/pages/admin/club/ClubPage.jsx @@ -100,7 +100,7 @@ function InformationForm({data}) { } return <> -
+
diff --git a/src/main/webapp/src/pages/admin/club/NewClubPage.jsx b/src/main/webapp/src/pages/admin/club/NewClubPage.jsx index 3202060..cb8f792 100644 --- a/src/main/webapp/src/pages/admin/club/NewClubPage.jsx +++ b/src/main/webapp/src/pages/admin/club/NewClubPage.jsx @@ -60,7 +60,7 @@ function InformationForm() { } return <> - +
Nouveau club
diff --git a/src/main/webapp/src/pages/admin/member/InformationForm.jsx b/src/main/webapp/src/pages/admin/member/InformationForm.jsx index 8ac972e..8943be9 100644 --- a/src/main/webapp/src/pages/admin/member/InformationForm.jsx +++ b/src/main/webapp/src/pages/admin/member/InformationForm.jsx @@ -79,7 +79,7 @@ export function InformationForm({data}) { addPhoto(event, formData, send); } - return + return
Information
diff --git a/src/main/webapp/src/pages/admin/member/MemberPage.jsx b/src/main/webapp/src/pages/admin/member/MemberPage.jsx index 302d9a8..9524d8c 100644 --- a/src/main/webapp/src/pages/admin/member/MemberPage.jsx +++ b/src/main/webapp/src/pages/admin/member/MemberPage.jsx @@ -11,6 +11,7 @@ import {apiAxios, errFormater} from "../../../utils/Tools.js"; import {ConfirmDialog} from "../../../components/ConfirmDialog.jsx"; import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; import {faFilePdf} from "@fortawesome/free-solid-svg-icons"; +import {SelectCard} from "./SelectCard.jsx"; const vite_url = import.meta.env.VITE_URL; @@ -58,7 +59,7 @@ export function MemberPage() {
- +
@@ -94,14 +95,3 @@ function PhotoCard({data}) {
; } - -function SelectCard() { - return <> - /*return
-
Sélection en équipe de France
-
-

Web Design

- -
-
;*/ -} diff --git a/src/main/webapp/src/pages/admin/member/SelectCard.jsx b/src/main/webapp/src/pages/admin/member/SelectCard.jsx new file mode 100644 index 0000000..8e6e571 --- /dev/null +++ b/src/main/webapp/src/pages/admin/member/SelectCard.jsx @@ -0,0 +1,208 @@ +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 {faEuroSign, faPen} from "@fortawesome/free-solid-svg-icons"; +import {AxiosError} from "../../../components/AxiosError.jsx"; +import {apiAxios, CatList, errFormater, getCatName, getSaison} from "../../../utils/Tools.js"; +import {toast} from "react-toastify"; + +function selectionReducer(selections, action) { + switch (action.type) { + case 'ADD': + return [ + ...selections, + action.payload + ] + case 'REMOVE': + return selections.filter(selection => selection.id !== action.payload) + case 'UPDATE_OR_ADD': + const index = selections.findIndex(selection => selection.id === action.payload.id) + if (index === -1) { + return [ + ...selections, + action.payload + ] + } else { + selections[index] = action.payload + return [...selections] + } + case 'SORT': + return selections.sort((a, b) => b.saison - a.saison) + default: + throw new Error() + } +} + +export function SelectCard({userData}) { + const setLoading = useLoadingSwitcher() + const {data, error} = useFetch(`/selection/${userData.id}`, setLoading, 1) + + const [modalSelection, setModal] = useState({id: -1, membre: userData.id}) + const [selections, dispatch] = useReducer(selectionReducer, []) + + useEffect(() => { + if (!data) return + for (const dataKey of data) { + dispatch({type: 'UPDATE_OR_ADD', payload: dataKey}) + } + dispatch({type: 'SORT'}) + }, [data]); + + return
+
+
+
Sélection en équipe de France
+
+ +
+
+
+
+
    + {selections.map((selection, index) => { + return
    +
    {selection?.saison}-{selection?.saison + 1} en {getCatName(selection?.categorie)}
    + +
    + })} + {error && } +
+
+ + +
; +} + +function sendSelection(event, dispatch) { + event.preventDefault(); + + const formData = new FormData(event.target); + formData.set('selection', event.target.selection?.value?.length > 0 ? event.target.selection?.value : null) + formData.set('categorie', event.target.categorie?.value) + + toast.promise( + apiAxios.post(`/selection/${event.target.membre.value}`, { + id: event.target.id.value, + membre: event.target.membre.value, + saison: event.target.saison.value, + categorie: event.target.categorie.value, + }), + { + pending: "Enregistrement de la séléction en cours", + success: "Séléction enregistrée avec succès 🎉", + error: { + render({data}) { + return errFormater(data, "Échec de l'enregistrement de la séléction") + } + } + } + ).then(data => { + dispatch({type: 'UPDATE_OR_ADD', payload: data.data}) + dispatch({type: 'SORT'}) + }) + +} + +function removeSelection(id, dispatch) { + toast.promise( + apiAxios.delete(`/selection/${id}`), + { + pending: "Suppression de la séléction en cours", + success: "Séléction supprimée avec succès 🎉", + error: { + render({data}) { + return errFormater(data, "Échec de la suppression de la séléction") + } + } + } + ).then(_ => { + dispatch({type: 'REMOVE', payload: id}) + }) +} + +function ModalContent({selection, dispatch}) { + const [saison, setSaison] = useState(0) + const [cat, setCat] = useState("") + const [isNew, setNew] = useState(true) + + const setSeason = (event) => { + setSaison(Number(event.target.value)) + } + const handleCatChange = (event) => { + setCat(event.target.value); + } + + useEffect(() => { + if (selection.id !== -1) { + setNew(false) + setSaison(selection.saison) + } else { + setNew(true) + setSaison(getSaison()) + } + setCat(selection.categorie) + }, [selection]); + + return sendSelection(e, dispatch)}> + + +
+

Edition de la séléction

+ +
+
+
+ {isNew + ? + : <>{saison} + } + - + {saison + 1} +
+ +
+ + +
+ +
+
+ + + {isNew || } +
+ +} + +function RadioGroupeOnOff({value, onChange, name, text}) { + return
+ {text} + + + + +
; +} diff --git a/src/main/webapp/src/pages/club/club/MyClubPage.jsx b/src/main/webapp/src/pages/club/club/MyClubPage.jsx index 523b0c7..baf26cb 100644 --- a/src/main/webapp/src/pages/club/club/MyClubPage.jsx +++ b/src/main/webapp/src/pages/club/club/MyClubPage.jsx @@ -67,7 +67,7 @@ function InformationForm({data}) { } return <> -
+
Affiliation n°{data.no_affiliation}
diff --git a/src/main/webapp/src/pages/club/member/InformationForm.jsx b/src/main/webapp/src/pages/club/member/InformationForm.jsx index 9446f96..787acb0 100644 --- a/src/main/webapp/src/pages/club/member/InformationForm.jsx +++ b/src/main/webapp/src/pages/club/member/InformationForm.jsx @@ -42,7 +42,7 @@ export function InformationForm({data}) { addPhoto(event, formData, send); } - return + return
Information
diff --git a/src/main/webapp/src/pages/club/member/MemberPage.jsx b/src/main/webapp/src/pages/club/member/MemberPage.jsx index 733e4fc..feb59b6 100644 --- a/src/main/webapp/src/pages/club/member/MemberPage.jsx +++ b/src/main/webapp/src/pages/club/member/MemberPage.jsx @@ -10,6 +10,7 @@ import {apiAxios, errFormater} from "../../../utils/Tools.js"; import {toast} from "react-toastify"; import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; import {faFilePdf} from "@fortawesome/free-solid-svg-icons"; +import {SelectCard} from "./SelectCard.jsx"; const vite_url = import.meta.env.VITE_URL; @@ -56,7 +57,7 @@ export function MemberPage() {
- +
{data.licence == null && @@ -93,14 +94,3 @@ function PhotoCard({data}) {
; } - -function SelectCard() { - return <> - /*return
-
Sélection en équipe de France
-
-

Soon

- -
-
;*/ -} diff --git a/src/main/webapp/src/pages/club/member/SelectCard.jsx b/src/main/webapp/src/pages/club/member/SelectCard.jsx new file mode 100644 index 0000000..a65f839 --- /dev/null +++ b/src/main/webapp/src/pages/club/member/SelectCard.jsx @@ -0,0 +1,27 @@ +import {useLoadingSwitcher} from "../../../hooks/useLoading.jsx"; +import {useFetch} from "../../../hooks/useFetch.js"; +import {getCatName} from "../../../utils/Tools.js"; +import {AxiosError} from "../../../components/AxiosError.jsx"; + +export function SelectCard({userData}) { + const setLoading = useLoadingSwitcher() + const {data, error} = useFetch(`/selection/${userData.id}`, setLoading, 1) + + return
+
+
+
Sélection en équipe de France
+
+
+
+
    + {data && data.sort((a, b) => b.saison - a.saison).map((selection, index) => { + return
    +
    {selection?.saison}-{selection?.saison + 1} en {getCatName(selection?.categorie)}
    +
    + })} + {error && } +
+
+
; +}