From c7a2133eed510c94e450d617c58ca8c8910f62c1 Mon Sep 17 00:00:00 2001 From: Thibaut Valentin Date: Wed, 17 Jul 2024 23:11:59 +0200 Subject: [PATCH] feat: club page wip: edit af request --- .../ffsaf/domain/service/ClubService.java | 76 ++++++++- .../titionfire/ffsaf/rest/ClubEndpoints.java | 36 +++- .../titionfire/ffsaf/rest/CombEndpoints.java | 26 --- .../ffsaf/rest/data/RenewAffData.java | 45 +++++ .../ffsaf/rest/from/AffiliationForm.java | 4 - .../ffsaf/rest/from/PartClubForm.java | 27 +++ src/main/webapp/src/components/Nav.jsx | 2 +- src/main/webapp/src/pages/DemandeAff.jsx | 158 +++++++++++++----- .../webapp/src/pages/admin/club/ClubPage.jsx | 2 +- src/main/webapp/src/pages/club/ClubRoot.jsx | 5 +- .../src/pages/club/club/AffiliationCard.jsx | 95 +++++++++++ .../webapp/src/pages/club/club/ClubPage.jsx | 158 ------------------ .../webapp/src/pages/club/club/MyClubPage.jsx | 117 +++++++++++++ 13 files changed, 507 insertions(+), 244 deletions(-) create mode 100644 src/main/java/fr/titionfire/ffsaf/rest/data/RenewAffData.java delete mode 100644 src/main/java/fr/titionfire/ffsaf/rest/from/AffiliationForm.java create mode 100644 src/main/java/fr/titionfire/ffsaf/rest/from/PartClubForm.java create mode 100644 src/main/webapp/src/pages/club/club/AffiliationCard.jsx delete mode 100644 src/main/webapp/src/pages/club/club/ClubPage.jsx create mode 100644 src/main/webapp/src/pages/club/club/MyClubPage.jsx diff --git a/src/main/java/fr/titionfire/ffsaf/domain/service/ClubService.java b/src/main/java/fr/titionfire/ffsaf/domain/service/ClubService.java index ef72137..3553079 100644 --- a/src/main/java/fr/titionfire/ffsaf/domain/service/ClubService.java +++ b/src/main/java/fr/titionfire/ffsaf/domain/service/ClubService.java @@ -2,18 +2,19 @@ package fr.titionfire.ffsaf.domain.service; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; +import fr.titionfire.ffsaf.data.model.AffiliationModel; import fr.titionfire.ffsaf.data.model.ClubModel; +import fr.titionfire.ffsaf.data.model.MembreModel; import fr.titionfire.ffsaf.data.repository.ClubRepository; import fr.titionfire.ffsaf.data.repository.CombRepository; import fr.titionfire.ffsaf.net2.ServerCustom; import fr.titionfire.ffsaf.net2.data.SimpleClubModel; import fr.titionfire.ffsaf.net2.request.SReqClub; +import fr.titionfire.ffsaf.rest.data.RenewAffData; import fr.titionfire.ffsaf.rest.data.SimpleClubList; import fr.titionfire.ffsaf.rest.from.FullClubForm; -import fr.titionfire.ffsaf.utils.Contact; -import fr.titionfire.ffsaf.utils.PageResult; -import fr.titionfire.ffsaf.utils.RoleAsso; -import fr.titionfire.ffsaf.utils.Utils; +import fr.titionfire.ffsaf.rest.from.PartClubForm; +import fr.titionfire.ffsaf.utils.*; import io.quarkus.hibernate.reactive.panache.Panache; import io.quarkus.hibernate.reactive.panache.PanacheQuery; import io.quarkus.hibernate.reactive.panache.common.WithSession; @@ -25,10 +26,14 @@ import io.smallrye.mutiny.unchecked.Unchecked; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.ws.rs.BadRequestException; +import jakarta.ws.rs.ForbiddenException; +import jakarta.ws.rs.NotFoundException; import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.jwt.JsonWebToken; import org.hibernate.reactive.mutiny.Mutiny; import java.util.Collection; +import java.util.Comparator; import java.util.HashMap; import java.util.List; @@ -114,6 +119,44 @@ public class ClubService { return repository.find("clubId", clubId).firstResult(); } + public Uni getOfUser(JsonWebToken idToken) { + return combRepository.find("userId = ?1", idToken.getSubject()).firstResult().invoke(Unchecked.consumer(m -> { + if (m == null || m.getClub() == null) + throw new NotFoundException("Club not found"); + })) + .map(MembreModel::getClub) + .call(club -> Mutiny.fetch(club.getContact())); + } + + public Uni updateOfUser(JsonWebToken idToken, PartClubForm form) { + TypeReference> typeRef = new TypeReference<>() { + }; + + return combRepository.find("userId = ?1", idToken.getSubject()).firstResult().invoke(Unchecked.consumer(m -> { + if (m == null || m.getClub() == null) + throw new NotFoundException("Club not found"); + if (!GroupeUtils.isInClubGroup(m.getClub().getId(), idToken)) + throw new ForbiddenException(); + })) + .map(MembreModel::getClub) + .call(club -> Mutiny.fetch(club.getContact())) + .chain(Unchecked.function(club -> { + club.setContact_intern(form.getContact_intern()); + club.setAddress(form.getAddress()); + + try { + club.setContact(MAPPER.readValue(form.getContact(), typeRef)); + } catch (JsonProcessingException e) { + throw new BadRequestException(); + } + + club.setTraining_location(form.getTraining_location()); + club.setTraining_day_time(form.getTraining_day_time()); + return Panache.withTransaction(() -> repository.persist(club)); + })) + .map(__ -> "OK"); + } + public Uni update(long id, FullClubForm input) { return repository.findById(id).call(m -> Mutiny.fetch(m.getContact())) .onItem().transformToUni(Unchecked.function(m -> { @@ -201,4 +244,29 @@ public class ClubService { .call(__ -> Utils.deleteMedia(id, media, "ppClub")) .call(__ -> Utils.deleteMedia(id, media, "clubStatus")); } + + public Uni getRenewData(long id) { + RenewAffData data = new RenewAffData(); + + return repository.findById(id) + .call(clubModel -> Mutiny.fetch(clubModel.getAffiliations())) + .invoke(clubModel -> { + data.setName(clubModel.getName()); + data.setSiret(clubModel.getSIRET()); + data.setRna(clubModel.getRNA()); + data.setAddress(clubModel.getAddress()); + data.setSaison( + clubModel.getAffiliations().stream().max(Comparator.comparing(AffiliationModel::getSaison)) + .map(AffiliationModel::getSaison).map(i -> Math.min(i + 1, Utils.getSaison() + 1)) + .orElse(Utils.getSaison())); + }) + .chain(club -> combRepository.list("club = ?1", club)) + .invoke(combs -> data.setMembers(combs.stream() + .filter(o -> o.getRole() != null && o.getRole().level >= RoleAsso.MEMBREBUREAU.level) + .sorted((o1, o2) -> o2.getRole().level - o1.getRole().level) + .limit(3) + .map(RenewAffData.RenewMember::new) + .toList())) + .map(o -> data); + } } diff --git a/src/main/java/fr/titionfire/ffsaf/rest/ClubEndpoints.java b/src/main/java/fr/titionfire/ffsaf/rest/ClubEndpoints.java index abb255f..0472054 100644 --- a/src/main/java/fr/titionfire/ffsaf/rest/ClubEndpoints.java +++ b/src/main/java/fr/titionfire/ffsaf/rest/ClubEndpoints.java @@ -3,9 +3,11 @@ package fr.titionfire.ffsaf.rest; import fr.titionfire.ffsaf.data.model.ClubModel; import fr.titionfire.ffsaf.domain.service.ClubService; import fr.titionfire.ffsaf.net2.data.SimpleClubModel; +import fr.titionfire.ffsaf.rest.data.RenewAffData; import fr.titionfire.ffsaf.rest.data.SimpleClub; import fr.titionfire.ffsaf.rest.data.SimpleClubList; import fr.titionfire.ffsaf.rest.from.FullClubForm; +import fr.titionfire.ffsaf.rest.from.PartClubForm; import fr.titionfire.ffsaf.utils.Contact; import fr.titionfire.ffsaf.utils.GroupeUtils; import fr.titionfire.ffsaf.utils.PageResult; @@ -44,11 +46,15 @@ public class ClubEndpoints { @ConfigProperty(name = "upload_dir") String media; - Consumer checkPerm = Unchecked.consumer(membreModel -> { - if (!securityIdentity.getRoles().contains("federation_admin") && !GroupeUtils.isInClubGroup(membreModel.getId(), + Consumer checkPerm = Unchecked.consumer(clubModel -> { + if (!securityIdentity.getRoles().contains("federation_admin") && !GroupeUtils.isInClubGroup(clubModel.getId(), idToken)) throw new ForbiddenException(); }); + Consumer checkPerm2 = Unchecked.consumer(id -> { + if (!securityIdentity.getRoles().contains("federation_admin") && !GroupeUtils.isInClubGroup(id, idToken)) + throw new ForbiddenException(); + }); @GET @Path("/no_detail") @@ -125,7 +131,6 @@ public class ClubEndpoints { @Produces(MediaType.TEXT_PLAIN) @Consumes(MediaType.MULTIPART_FORM_DATA) public Uni addAdminClub(FullClubForm input) { - System.out.println(input); return clubService.add(input) .invoke(Unchecked.consumer(id -> { if (id == null) throw new InternalError("Fail to create club data"); @@ -152,6 +157,31 @@ public class ClubEndpoints { return clubService.delete(id); } + @GET + @Path("/me") + @RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"}) + @Produces(MediaType.APPLICATION_JSON) + public Uni getOfUser() { + return clubService.getOfUser(idToken).map(SimpleClub::fromModel) + .invoke(m -> m.setContactMap(Contact.toSite())); + } + + @PUT + @Path("/me") + @RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"}) + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.MULTIPART_FORM_DATA) + public Uni setClubOfUser(PartClubForm form) { + return clubService.updateOfUser(idToken, form); + } + + @GET + @Path("/renew/{id}") + @RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"}) + @Produces(MediaType.APPLICATION_JSON) + public Uni getOfUser(@PathParam("id") long id) { + return Uni.createFrom().item(id).invoke(checkPerm2).chain(__ -> clubService.getRenewData(id)); + } @GET @Path("{clubId}/logo") diff --git a/src/main/java/fr/titionfire/ffsaf/rest/CombEndpoints.java b/src/main/java/fr/titionfire/ffsaf/rest/CombEndpoints.java index 0882952..95654ec 100644 --- a/src/main/java/fr/titionfire/ffsaf/rest/CombEndpoints.java +++ b/src/main/java/fr/titionfire/ffsaf/rest/CombEndpoints.java @@ -198,32 +198,6 @@ public class CombEndpoints { return membreService.delete(id, idToken); } - private Future replacePhoto(long id, byte[] input) { - return CompletableFuture.supplyAsync(() -> { - try (InputStream is = new BufferedInputStream(new ByteArrayInputStream(input))) { - String mimeType = URLConnection.guessContentTypeFromStream(is); - String[] detectedExtensions = MimeTypes.findExtensionsByMimeTypes(mimeType, false); - if (detectedExtensions.length == 0) - throw new IOException("Fail to detect file extension for MIME type " + mimeType); - - FilenameFilter filter = (directory, filename) -> filename.startsWith(String.valueOf(id)); - File[] files = new File(media, "ppMembre").listFiles(filter); - if (files != null) { - for (File file : files) { - //noinspection ResultOfMethodCallIgnored - file.delete(); - } - } - - String extension = "." + detectedExtensions[0]; - Files.write(new File(media, "ppMembre/" + id + extension).toPath(), input); - return "OK"; - } catch (IOException e) { - return e.getMessage(); - } - }); - } - @GET @Path("{id}/photo") @RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"}) diff --git a/src/main/java/fr/titionfire/ffsaf/rest/data/RenewAffData.java b/src/main/java/fr/titionfire/ffsaf/rest/data/RenewAffData.java new file mode 100644 index 0000000..02ce7cc --- /dev/null +++ b/src/main/java/fr/titionfire/ffsaf/rest/data/RenewAffData.java @@ -0,0 +1,45 @@ +package fr.titionfire.ffsaf.rest.data; + +import fr.titionfire.ffsaf.data.model.MembreModel; +import fr.titionfire.ffsaf.utils.RoleAsso; +import io.quarkus.runtime.annotations.RegisterForReflection; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@RegisterForReflection +public class RenewAffData { + String name; + Long siret; + String rna; + String address; + int saison; + List members; + + + @Data + @AllArgsConstructor + @RegisterForReflection + public static class RenewMember { + String lname; + String fname; + String email; + int licence; + RoleAsso role; + + public RenewMember(MembreModel o) { + this.lname = o.getLname(); + this.fname = o.getFname(); + this.email = o.getEmail(); + this.licence = o.getLicence(); + this.role = o.getRole(); + } + } +} diff --git a/src/main/java/fr/titionfire/ffsaf/rest/from/AffiliationForm.java b/src/main/java/fr/titionfire/ffsaf/rest/from/AffiliationForm.java deleted file mode 100644 index cfda16d..0000000 --- a/src/main/java/fr/titionfire/ffsaf/rest/from/AffiliationForm.java +++ /dev/null @@ -1,4 +0,0 @@ -package fr.titionfire.ffsaf.rest.from; - -public class AffiliationForm { -} diff --git a/src/main/java/fr/titionfire/ffsaf/rest/from/PartClubForm.java b/src/main/java/fr/titionfire/ffsaf/rest/from/PartClubForm.java new file mode 100644 index 0000000..c4c68db --- /dev/null +++ b/src/main/java/fr/titionfire/ffsaf/rest/from/PartClubForm.java @@ -0,0 +1,27 @@ +package fr.titionfire.ffsaf.rest.from; + +import jakarta.ws.rs.FormParam; +import lombok.Getter; +import lombok.ToString; + +@ToString +@Getter +public class PartClubForm { + @FormParam("id") + private String id = null; + + @FormParam("contact") + private String contact = null; + + @FormParam("training_location") + private String training_location = null; + + @FormParam("training_day_time") + private String training_day_time = null; + + @FormParam("contact_intern") + private String contact_intern = null; + + @FormParam("address") + private String address = null; +} diff --git a/src/main/webapp/src/components/Nav.jsx b/src/main/webapp/src/components/Nav.jsx index 371ec21..2b3a4f4 100644 --- a/src/main/webapp/src/components/Nav.jsx +++ b/src/main/webapp/src/components/Nav.jsx @@ -54,8 +54,8 @@ function ClubMenu() { Club
    +
  • Mon club
  • Member
  • -
  • B
} diff --git a/src/main/webapp/src/pages/DemandeAff.jsx b/src/main/webapp/src/pages/DemandeAff.jsx index 722c917..66a4e9e 100644 --- a/src/main/webapp/src/pages/DemandeAff.jsx +++ b/src/main/webapp/src/pages/DemandeAff.jsx @@ -1,8 +1,9 @@ -import {useState} from "react"; +import {useEffect, useState} from "react"; import {apiAxios, getSaison} from "../utils/Tools.js"; import {toast} from "react-toastify"; -import {useNavigate} from "react-router-dom"; +import {useLocation, useNavigate} from "react-router-dom"; import {RoleList} from "../components/MemberCustomFiels.jsx"; +import {useAuth} from "../hooks/useAuth.jsx"; const notUpperCase = ["de", "la", "le", "les", "des", "du", "d'", "l'", "sur"]; @@ -40,13 +41,38 @@ function reconstruireAdresse(infos) { export function DemandeAff() { + const {hash} = useLocation(); const navigate = useNavigate(); + const [initData, setInitData] = useState(null) + const [needFile, setNeedFile] = useState(true) + + useEffect(() => { + if (hash.startsWith("#d")) { + const data = JSON.parse(decodeURI(hash.substring(2))); + setInitData(data) + setNeedFile(false) + } else if (hash.startsWith("#e")) { + apiAxios.get(`/affiliation/request/${hash.substring(2)}`).then(data => { + for (let i = 0; i < data.data.members.length; i++) { + if (data.data.members[i].licence === -1) + data.data.members[i].licence = "" + } + setInitData(data.data) + setNeedFile(false) + }).catch(_ => { + setInitData({}) + }) + } else { + setInitData({}) + } + }, []); const submit = (event) => { event.preventDefault() const formData = new FormData(event.target) formData.append("m1_role", event.target.m1_role?.value) formData.append("rna", event.target.rna?.value) + formData.append("siret", event.target.siret?.value) let error = false; for (let i = 1; i <= 3; i++) { @@ -59,16 +85,44 @@ export function DemandeAff() { return; } - toast.promise( - apiAxios.post(`/affiliation/request`, formData, {headers: {'Accept': '*/*'}}), - { - pending: "Enregistrement de la demande d'affiliation en cours", - success: "Demande d'affiliation enregistrée avec succès 🎉", - error: "Échec de la demande d'affiliation 😕" - } - ).then(_ => { - navigate("/affiliation/ok") - }) + if (event.nativeEvent.submitter.value === "undo") { + toast.promise( + apiAxios.delete(`/affiliation/request/${initData.id}`), + { + pending: "Annulation de la demande d'affiliation en cours", + success: "Demande d'affiliation annulée avec succès 🎉", + error: "Échec de l'annulation de la demande d'affiliation 😕" + } + ).then(_ => { + navigate("/club/me") + }) + }else if (event.nativeEvent.submitter.value === "edit") { + formData.append("id", initData.id) + + toast.promise( + apiAxios.put(`/affiliation/request/edit`, formData), + { + pending: "Enregistrement des modifications en cours", + success: "Modifications enregistrées avec succès 🎉", + error: "Échec de l'enregistrement des modifications 😕" + } + ).then(_ => { + navigate("/club/me") + }) + }else { + formData.append("id", -1) + + toast.promise( + apiAxios.post(`/affiliation/request`, formData, {headers: {'Accept': '*/*'}}), + { + pending: "Enregistrement de la demande d'affiliation en cours", + success: "Demande d'affiliation enregistrée avec succès 🎉", + error: "Échec de la demande d'affiliation 😕" + } + ).then(_ => { + navigate("/affiliation/ok") + }) + } } return
@@ -91,46 +145,59 @@ export function DemandeAff() { -
+ {initData &&

L'association

- +

Membre n°1

- +

Membre n°2

- +

Membre n°3

- +
-

Après validation de votre demande, vous recevrez un identifiant et mot de passe provisoire pour - accéder à votre espace FFSAF

+ {!initData.id &&

Après validation de votre demande, vous recevrez un identifiant et mot de passe provisoire pour + accéder à votre espace FFSAF

} Notez que pour finaliser votre affiliation, il vous faudra :
  • Disposer d’au moins trois membres licenciés, dont le président
  • S'être acquitté des cotisations prévues par les règlements fédéraux
-
-
- + + {!initData.id ? +
+
+ +
+
: +
+
+ +
+
+ +
-
+ }
-
+
}
} -function AssoInfo() { +function AssoInfo({initData, needFile}) { const [denomination, setDenomination] = useState("") - const [siret, setSiret] = useState("") - const [rna, setRna] = useState("") + const [siret, setSiret] = useState(initData.siret ? String(initData.siret) : "") + const [rna, setRna] = useState(initData.rna ? initData.rna : "") const [rnaEnable, setRnaEnable] = useState(false) - const [adresse, setAdresse] = useState("") - const [saison, setSaison] = useState(getSaison()) + const [adresse, setAdresse] = useState(initData.address ? initData.address : "") + const [saison, setSaison] = useState(initData.saison ? initData.saison : getSaison()) const fetchSiret = () => { if (siret.length < 14) { @@ -150,7 +217,8 @@ function AssoInfo() { setDenomination(data2.denomination) setRnaEnable(data2.identifiant_association === null) setRna(data2.identifiant_association ? data2.identifiant_association : "") - setAdresse(reconstruireAdresse(data2.etablissement_siege)) + if (!initData.saison || adresse === "") + setAdresse(reconstruireAdresse(data2.etablissement_siege)) }) } @@ -178,13 +246,13 @@ function AssoInfo() { Nom de l'association* + aria-describedby="basic-addon1" required defaultValue={initData.name ? initData.name : ""}/>
N° SIRET* - setSiret(e.target.value)} defaultValue={500213731}/> + setSiret(e.target.value)}/> @@ -218,25 +286,25 @@ function AssoInfo() {
- +
+ required={needFile}/>
; } -function MembreInfo({role}) { - const [switchOn, setSwitchOn] = useState(false); +function MembreInfo({role, initData}) { + const [switchOn, setSwitchOn] = useState(!!initData.licence); return <>
- @@ -251,22 +319,22 @@ function MembreInfo({role}) {
- +
+ name={role + "_prenom"} defaultValue={initData.fname ? initData.fname : ""} required/>
+ name={role + "_mail"} defaultValue={initData.email ? initData.email : ""} required/>
@@ -283,7 +351,7 @@ function MembreInfo({role}) {
+ name={role + "_licence"} defaultValue={initData.licence ? Number(initData.licence) : ""} required/>
diff --git a/src/main/webapp/src/pages/admin/club/ClubPage.jsx b/src/main/webapp/src/pages/admin/club/ClubPage.jsx index 2f751d3..0257dec 100644 --- a/src/main/webapp/src/pages/admin/club/ClubPage.jsx +++ b/src/main/webapp/src/pages/admin/club/ClubPage.jsx @@ -129,7 +129,7 @@ function InformationForm({data}) {
- + +
+
+
+
+
    + {data && data.sort((a, b) => b.saison - a.saison).map((affiliation, index) => { + return
    +
    {affiliation?.saison}-{affiliation?.saison + 1}
    + +
    + })} + {error && } +
+
+ + +
; +} + +function ModalContent({affiliation}) { + const navigate = useNavigate(); + + return <> + {affiliation &&
+
+

Etat de l'affiliation

+ +
+
+
+ {affiliation.saison || 0} + - + {(affiliation.saison || 0) + 1} +
+
+ État de la demande + {affiliation.validate ? Validée : + <> + En attente + + } +
+
+
+ +
+
+ } + +} \ No newline at end of file diff --git a/src/main/webapp/src/pages/club/club/ClubPage.jsx b/src/main/webapp/src/pages/club/club/ClubPage.jsx deleted file mode 100644 index d7196b4..0000000 --- a/src/main/webapp/src/pages/club/club/ClubPage.jsx +++ /dev/null @@ -1,158 +0,0 @@ -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 {CountryList, TextField} from "../../../components/MemberCustomFiels.jsx"; - -import {useRef, useState} from "react"; -import {LocationEditor, LocationEditorModal} from "../../../components/Club/LocationEditor.jsx"; -import {ContactEditor} from "../../../components/Club/ContactEditor.jsx"; -import {HoraireEditor} from "../../../components/Club/HoraireEditor.jsx"; -import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; -import {faFilePdf} from "@fortawesome/free-solid-svg-icons"; - -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 club

- - {data - ?
-
-
- - - -
-
- -
- -
- -
-
-
- : error && - } - -} - -function InformationForm({data}) { - const [switchOn, setSwitchOn] = useState(data.international); - const [modal, setModal] = useState({id: -1}) - const locationModalCallback = useRef(null) - - const handleSubmit = (event) => { - event.preventDefault(); - - const formData = new FormData(event.target); - - toast.promise( - apiAxios.put(`/club/${data.id}`, formData), - { - pending: "Enregistrement du club en cours", - success: "Club enregistrée avec succès 🎉", - error: "Échec de l'enregistrement du club 😕" - } - ) - } - - return <> -
- -
- - - -} diff --git a/src/main/webapp/src/pages/club/club/MyClubPage.jsx b/src/main/webapp/src/pages/club/club/MyClubPage.jsx new file mode 100644 index 0000000..2842adb --- /dev/null +++ b/src/main/webapp/src/pages/club/club/MyClubPage.jsx @@ -0,0 +1,117 @@ +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 {CountryList, TextField} from "../../../components/MemberCustomFiels.jsx"; + +import {useRef, useState} from "react"; +import {LocationEditor, LocationEditorModal} from "../../../components/Club/LocationEditor.jsx"; +import {ContactEditor} from "../../../components/Club/ContactEditor.jsx"; +import {HoraireEditor} from "../../../components/Club/HoraireEditor.jsx"; +import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; +import {faFilePdf} from "@fortawesome/free-solid-svg-icons"; + +const vite_url = import.meta.env.VITE_URL; + +export function MyClubPage() { + const setLoading = useLoadingSwitcher() + const {data, error} = useFetch(`/club/me`, setLoading, 1) + + return <> +

Mon club

+ {data + ?
+
+
+ + + +
+
+ +
+
+
+ : error && + } + +} + +function InformationForm({data}) { + const [modal, setModal] = useState({id: -1}) + const locationModalCallback = useRef(null) + + const handleSubmit = (event) => { + event.preventDefault(); + + const formData = new FormData(event.target); + + toast.promise( + apiAxios.put(`/club/me`, formData), + { + pending: "Enregistrement des modifications en cours", + success: "Modifications enregistrées avec succès 🎉", + error: "Échec de l'enregistrement des modifications 😕" + } + ) + } + + return <> +
+
+ +
Affiliation n°{data.no_affiliation}
+
+ + + + {!data.international && <> + + + } + +
+
+ avatar +
+ +
Pour modifier les informations ci-dessus, merci de contacter la FFSAF par mail.
+
+ + {!data.international && <> + + + + + + + + } +
+
+
+ +
+
+
+
+ + + +}