diff --git a/src/main/java/fr/titionfire/ffsaf/data/model/ClubModel.java b/src/main/java/fr/titionfire/ffsaf/data/model/ClubModel.java index 91b533f..6b38d76 100644 --- a/src/main/java/fr/titionfire/ffsaf/data/model/ClubModel.java +++ b/src/main/java/fr/titionfire/ffsaf/data/model/ClubModel.java @@ -49,7 +49,7 @@ public class ClubModel { Long SIRET; - String no_affiliation; + Long no_affiliation; boolean international; diff --git a/src/main/java/fr/titionfire/ffsaf/domain/entity/ClubEntity.java b/src/main/java/fr/titionfire/ffsaf/domain/entity/ClubEntity.java index bf4939a..cb840e9 100644 --- a/src/main/java/fr/titionfire/ffsaf/domain/entity/ClubEntity.java +++ b/src/main/java/fr/titionfire/ffsaf/domain/entity/ClubEntity.java @@ -24,7 +24,7 @@ public class ClubEntity { private String contact_intern; private String RNA; private Long SIRET; - private String no_affiliation; + private Long no_affiliation; private boolean international; public static ClubEntity fromModel (ClubModel model) { diff --git a/src/main/java/fr/titionfire/ffsaf/domain/service/AffiliationService.java b/src/main/java/fr/titionfire/ffsaf/domain/service/AffiliationService.java index 0fa74ea..2b21572 100644 --- a/src/main/java/fr/titionfire/ffsaf/domain/service/AffiliationService.java +++ b/src/main/java/fr/titionfire/ffsaf/domain/service/AffiliationService.java @@ -7,6 +7,7 @@ import fr.titionfire.ffsaf.data.repository.AffiliationRequestRepository; import fr.titionfire.ffsaf.data.repository.ClubRepository; import fr.titionfire.ffsaf.data.repository.CombRepository; import fr.titionfire.ffsaf.rest.data.SimpleAffiliation; +import fr.titionfire.ffsaf.rest.data.SimpleReqAffiliation; import fr.titionfire.ffsaf.rest.from.AffiliationRequestForm; import fr.titionfire.ffsaf.utils.Utils; import io.quarkus.hibernate.reactive.panache.Panache; @@ -75,12 +76,24 @@ public class AffiliationService { .map(__ -> "Ok"); } + public Uni getRequest(long id) { + return repositoryRequest.findById(id).map(SimpleReqAffiliation::fromModel) + .call(out -> clubRepository.find("SIRET = ?1", out.getSiret()).firstResult().invoke(c -> { + if (c != null){ + out.setClub(c.getId()); + out.setClub_name(c.getName()); + out.setClub_no_aff(c.getNo_affiliation()); + } + }) + ); + } + public Uni> getCurrentSaisonAffiliation() { return repository.list("saison = ?1", Utils.getSaison()) .map(models -> models.stream().map(SimpleAffiliation::fromModel).toList()) .chain(aff -> repositoryRequest.list("saison = ?1", Utils.getSaison()) .chain(models -> Uni.join().all(models.stream().map(model -> - clubRepository.find("siret = ?1", model.getSiret()).firstResult() + clubRepository.find("SIRET = ?1", model.getSiret()).firstResult() .map(c -> new SimpleAffiliation(model.getId() * -1, c.getId(), model.getSaison(), false))) .toList()).andFailFast() diff --git a/src/main/java/fr/titionfire/ffsaf/net2/data/SimpleClubModel.java b/src/main/java/fr/titionfire/ffsaf/net2/data/SimpleClubModel.java index 815a464..748c9ec 100644 --- a/src/main/java/fr/titionfire/ffsaf/net2/data/SimpleClubModel.java +++ b/src/main/java/fr/titionfire/ffsaf/net2/data/SimpleClubModel.java @@ -17,7 +17,7 @@ public class SimpleClubModel { String name; String country; String shieldURL; - String no_affiliation; + Long no_affiliation; public static SimpleClubModel fromModel(ClubModel model) { if (model == null) diff --git a/src/main/java/fr/titionfire/ffsaf/rest/AffiliationEndpoints.java b/src/main/java/fr/titionfire/ffsaf/rest/AffiliationEndpoints.java index 8634197..2ac5007 100644 --- a/src/main/java/fr/titionfire/ffsaf/rest/AffiliationEndpoints.java +++ b/src/main/java/fr/titionfire/ffsaf/rest/AffiliationEndpoints.java @@ -2,6 +2,7 @@ package fr.titionfire.ffsaf.rest; import fr.titionfire.ffsaf.domain.service.AffiliationService; import fr.titionfire.ffsaf.rest.data.SimpleAffiliation; +import fr.titionfire.ffsaf.rest.data.SimpleReqAffiliation; import fr.titionfire.ffsaf.rest.from.AffiliationRequestForm; import fr.titionfire.ffsaf.utils.GroupeUtils; import io.quarkus.oidc.IdToken; @@ -35,7 +36,16 @@ public class AffiliationEndpoints { throw new ForbiddenException(); }); + @GET + @Path("/request/{id}") + @RolesAllowed({"federation_admin"}) + @Produces(MediaType.APPLICATION_JSON) + public Uni getAffRequest(@PathParam("id") long id) { + return service.getRequest(id); + } + @POST + @Path("/request") @Produces(MediaType.TEXT_PLAIN) @Consumes(MediaType.MULTIPART_FORM_DATA) public Uni saveAffRequest(AffiliationRequestForm form) { diff --git a/src/main/java/fr/titionfire/ffsaf/rest/CombEndpoints.java b/src/main/java/fr/titionfire/ffsaf/rest/CombEndpoints.java index b7c60f7..0882952 100644 --- a/src/main/java/fr/titionfire/ffsaf/rest/CombEndpoints.java +++ b/src/main/java/fr/titionfire/ffsaf/rest/CombEndpoints.java @@ -26,6 +26,7 @@ import java.io.*; import java.net.URISyntaxException; import java.net.URLConnection; import java.nio.file.Files; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; import java.util.function.Consumer; @@ -68,6 +69,14 @@ public class CombEndpoints { return membreService.searchAdmin(limit, page - 1, search, club); } + @GET + @Path("/find/similar") + @RolesAllowed({"federation_admin"}) + @Produces(MediaType.APPLICATION_JSON) + public Uni> getSimilar(@QueryParam("fname") String fname, @QueryParam("lname") String lname) { + return membreService.getSimilar(fname, lname); + } + @GET @Path("/find/club") @RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"}) @@ -90,6 +99,14 @@ public class CombEndpoints { return membreService.getById(id).onItem().invoke(checkPerm).map(SimpleMembre::fromModel); } + @GET + @Path("/find/licence") + @RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"}) + @Produces(MediaType.APPLICATION_JSON) + public Uni getByLicence(@QueryParam("id") long id) { + return membreService.getByLicence(id).onItem().invoke(checkPerm).map(SimpleMembre::fromModel); + } + @PUT @Path("{id}") @RolesAllowed({"federation_admin"}) diff --git a/src/main/java/fr/titionfire/ffsaf/rest/data/SimpleClub.java b/src/main/java/fr/titionfire/ffsaf/rest/data/SimpleClub.java index 8972e07..44ba58f 100644 --- a/src/main/java/fr/titionfire/ffsaf/rest/data/SimpleClub.java +++ b/src/main/java/fr/titionfire/ffsaf/rest/data/SimpleClub.java @@ -27,7 +27,7 @@ public class SimpleClub { private String contact_intern; private String RNA; private Long SIRET; - private String no_affiliation; + private Long no_affiliation; private boolean international; private HashMap contactMap = null; diff --git a/src/main/java/fr/titionfire/ffsaf/rest/data/SimpleReqAffiliation.java b/src/main/java/fr/titionfire/ffsaf/rest/data/SimpleReqAffiliation.java new file mode 100644 index 0000000..9b0a594 --- /dev/null +++ b/src/main/java/fr/titionfire/ffsaf/rest/data/SimpleReqAffiliation.java @@ -0,0 +1,60 @@ +package fr.titionfire.ffsaf.rest.data; + +import fr.titionfire.ffsaf.data.model.AffiliationRequestModel; +import fr.titionfire.ffsaf.utils.RoleAsso; +import io.quarkus.runtime.annotations.RegisterForReflection; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; + +import java.util.List; + +@Data +@Builder +@AllArgsConstructor +@RegisterForReflection +public class SimpleReqAffiliation { + Long id; + Long club; + String club_name; + Long club_no_aff; + String name; + long siret; + String RNA; + String address; + List members; + int saison; + + public static SimpleReqAffiliation fromModel(AffiliationRequestModel model) { + if (model == null) + return null; + + return new SimpleReqAffiliation.SimpleReqAffiliationBuilder() + .id(model.getId()) + .name(model.getName()) + .siret(model.getSiret()) + .RNA(model.getRNA()) + .address(model.getAddress()) + .saison(model.getSaison()) + .members(List.of( + new AffiliationMember(model.getM1_lname(), model.getM1_fname(), model.getM1_email(), + model.getM1_lincence(), model.getM1_role()), + new AffiliationMember(model.getM2_lname(), model.getM2_fname(), model.getM2_email(), + model.getM2_lincence(), model.getM2_role()), + new AffiliationMember(model.getM3_lname(), model.getM3_fname(), model.getM3_email(), + model.getM3_lincence(), model.getM3_role()) + )) + .build(); + } + + @Data + @AllArgsConstructor + @RegisterForReflection + public static class AffiliationMember { + String lname; + String fname; + String email; + int licence; + RoleAsso role; + } +} diff --git a/src/main/java/fr/titionfire/ffsaf/rest/from/AffiliationRequestForm.java b/src/main/java/fr/titionfire/ffsaf/rest/from/AffiliationRequestForm.java index d89b26b..4b61818 100644 --- a/src/main/java/fr/titionfire/ffsaf/rest/from/AffiliationRequestForm.java +++ b/src/main/java/fr/titionfire/ffsaf/rest/from/AffiliationRequestForm.java @@ -75,21 +75,21 @@ public class AffiliationRequestForm { model.setM1_fname(this.getM1_fname()); model.setM1_email(this.getM1_email()); model.setM1_lincence((this.getM1_lincence() == null || this.getM1_lincence().isBlank()) - ? 0 : Integer.parseInt(this.getM1_lincence())); + ? -1 : Integer.parseInt(this.getM1_lincence())); model.setM1_role(this.getM1_role()); model.setM2_lname(this.getM2_lname()); model.setM2_fname(this.getM2_fname()); model.setM2_email(this.getM2_email()); model.setM2_lincence((this.getM1_lincence() == null || this.getM1_lincence().isBlank()) - ? 0 : Integer.parseInt(this.getM2_lincence())); + ? -1 : Integer.parseInt(this.getM2_lincence())); model.setM2_role(this.getM2_role()); model.setM3_lname(this.getM3_lname()); model.setM3_fname(this.getM3_fname()); model.setM3_email(this.getM3_email()); model.setM3_lincence((this.getM1_lincence() == null || this.getM1_lincence().isBlank()) - ? 0 : Integer.parseInt(this.getM3_lincence())); + ? -1 : Integer.parseInt(this.getM3_lincence())); model.setM3_role(this.getM3_role()); return model; diff --git a/src/main/webapp/src/components/Club/LocationEditor.jsx b/src/main/webapp/src/components/Club/LocationEditor.jsx index e984cb4..086e82f 100644 --- a/src/main/webapp/src/components/Club/LocationEditor.jsx +++ b/src/main/webapp/src/components/Club/LocationEditor.jsx @@ -83,7 +83,7 @@ export function LocationEditorModal({modal, sendData}) { const [location, setLocation] = useState("") const [locationObj, setLocationObj] = useState({text: "", lng: undefined, lat: undefined}) const [mapPosition, setMapPosition] = useState([46.652195, 2.430226]) - const {data, error, refresh} = useFetch(``) + const {data, error, refresh} = useFetch(null) const map = useRef(null) useEffect(() => { diff --git a/src/main/webapp/src/components/MemberCustomFiels.jsx b/src/main/webapp/src/components/MemberCustomFiels.jsx index d03e69f..d7f0050 100644 --- a/src/main/webapp/src/components/MemberCustomFiels.jsx +++ b/src/main/webapp/src/components/MemberCustomFiels.jsx @@ -49,6 +49,20 @@ export function OptionField({name, text, values, value, disabled = false}) { } +export function RoleList({name, text, value, disabled = false}) { + return +} + export function CountryList({name, text, value, values = undefined, disabled = false}) { if (values === undefined){ values = {NA: 'Sélectionner...', fr: 'FR', es: 'ES', be: 'BE'} diff --git a/src/main/webapp/src/hooks/useFetch.js b/src/main/webapp/src/hooks/useFetch.js index 99379fc..947894b 100644 --- a/src/main/webapp/src/hooks/useFetch.js +++ b/src/main/webapp/src/hooks/useFetch.js @@ -24,7 +24,8 @@ export function useFetch(url, setLoading = null, loadingLevel = 1, config = {}) } useEffect(() => { - refresh(url) + if (url !== null) + refresh(url) }, []); return { diff --git a/src/main/webapp/src/pages/DemandeAff.jsx b/src/main/webapp/src/pages/DemandeAff.jsx index 8d436d7..e50c621 100644 --- a/src/main/webapp/src/pages/DemandeAff.jsx +++ b/src/main/webapp/src/pages/DemandeAff.jsx @@ -32,7 +32,7 @@ export function DemandeAff() { const formData = new FormData(event.target) formData.append("m1_role", event.target.m1_role?.value) toast.promise( - apiAxios.post(`/affiliation`, formData, {headers: {'Accept': '*/*'}}), + 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 🎉", diff --git a/src/main/webapp/src/pages/admin/AdminRoot.jsx b/src/main/webapp/src/pages/admin/AdminRoot.jsx index 063c17e..83af37d 100644 --- a/src/main/webapp/src/pages/admin/AdminRoot.jsx +++ b/src/main/webapp/src/pages/admin/AdminRoot.jsx @@ -41,7 +41,7 @@ export function getAdminChildren() { element: }, { - path: 'affiliation/request', + path: 'affiliation/request/:id', element: }, { diff --git a/src/main/webapp/src/pages/admin/affiliation/AffiliationReqPage.jsx b/src/main/webapp/src/pages/admin/affiliation/AffiliationReqPage.jsx index 443e68e..2665aa5 100644 --- a/src/main/webapp/src/pages/admin/affiliation/AffiliationReqPage.jsx +++ b/src/main/webapp/src/pages/admin/affiliation/AffiliationReqPage.jsx @@ -1,16 +1,191 @@ -import {useNavigate} from "react-router-dom"; +import {useNavigate, useParams} from "react-router-dom"; +import {LoadingProvider, useLoadingSwitcher} from "../../../hooks/useLoading.jsx"; +import {useFetch} from "../../../hooks/useFetch.js"; +import {AxiosError} from "../../../components/AxiosError.jsx"; +import {toast} from "react-toastify"; +import {apiAxios} from "../../../utils/Tools.js"; +import {RoleList, TextField} from "../../../components/MemberCustomFiels.jsx"; +import {useEffect, useRef, useState} from "react"; export function AffiliationReqPage() { + const {id} = useParams() const navigate = useNavigate(); + const setLoading = useLoadingSwitcher() + const {data, error} = useFetch(`/affiliation/request/${id}`, setLoading, 1) + return <> -

Page affiliation

+

Demande d'affiliation

-
-
+ {data + ?
+ +
+ : error && + }
+} + +function Content({data}) { + 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 <> +
+
+ +
Demande d'affiliation
+
+ {data.club &&
Ce club a déjà ete affilier (affiliation n°{data.club_no_aff})
} +

Saison {data.saison}-{data.saison + 1}

+ +
+
+ Nom du club + +
+ {data.club &&
Ancien nom: {data.club_name}
} +
+ + + + + + {data.members.map((member, index) => { + return
+ +
+ })} + +
+
+
+ +} + +function MemberPart({index, member}) { + const [mode, setMode] = useState(member.licence >= 0 ? 0 : 2) + const [current, setCurrent] = useState(-1) + + useEffect(() => { + if (mode !== 1) + setCurrent(-1) + }, [mode]); + + return
+
+
Membre n°{index + 1}
+
+ + +
+
+
+
+ setMode(0)}/> + +
+ +
+ + + +
+
+
+ +
+
+
+ setMode(1)}/> + +
+
+ + + +
+
+
+ +
+
+
+ setMode(2)}/> + +
+
+ + + +
+
+
+
+
+
+
+} + +function MemberLicence({member, mode, index}) { + const setLoading = useLoadingSwitcher() + const [licence, setLicence] = useState(member.licence) + const {data, refresh} = useFetch(null, setLoading, 1) + const ref = useRef(-1) + + useEffect(() => { + if (licence === -1 || licence.length < 1 || licence === ref.current) + return + refresh(`/member/find/licence?id=${licence}`) + ref.current = licence + }, [licence]); + + const name = "m" + (index + 1) + "licence"; + return <> +
+
+ Licence + = 0 ? String(licence) : ""} disabled={mode !== 0} required={mode === 0} + onChange={event => setLicence(event.target.value)}/> +
+
+ {data && Nom: {data.lname} {data.fname}, Club: {data.club.name}} + +} + +function MemberSimilar({member, current, setCurrent, mode}) { + const setLoading = useLoadingSwitcher() + const {data} = useFetch(`/member/find/similar?fname=${encodeURI(member.fname)}&lname=${encodeURI(member.lname)}`, setLoading, 1) + + return
+ {data && data.map((m, index) => { + return + })} +
} \ 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 index 84570c1..ef4cfd8 100644 --- a/src/main/webapp/src/pages/admin/club/AffiliationCard.jsx +++ b/src/main/webapp/src/pages/admin/club/AffiliationCard.jsx @@ -7,12 +7,13 @@ import {AxiosError} from "../../../components/AxiosError.jsx"; import {apiAxios, getSaison} from "../../../utils/Tools.js"; import {toast} from "react-toastify"; import {SimpleReducer} from "../../../utils/SimpleReducer.jsx"; +import {useNavigate} from "react-router-dom"; 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 [modalAffiliation, setModal] = useState({id: 0, club: clubData.id}) const [affiliations, dispatch] = useReducer(SimpleReducer, []) useEffect(() => { @@ -94,6 +95,7 @@ function removeAffiliation(id, dispatch) { } function ModalContent({affiliation, dispatch}) { + const navigate = useNavigate(); const [saison, setSaison] = useState(0) const setSeason = (event) => { setSaison(Number(event.target.value)) @@ -130,7 +132,9 @@ function ModalContent({affiliation, dispatch}) { {affiliation.validate ? Validée : <> En attente - // TODO + } @@ -138,7 +142,7 @@ function ModalContent({affiliation, dispatch}) { {affiliation.id === 0 && } {affiliation.id <= 0 || } + onClick={() => removeAffiliation(affiliation.id, dispatch)}>Supprimer} } \ 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 index 93b7a40..f6a8ac0 100644 --- a/src/main/webapp/src/pages/admin/club/ClubPage.jsx +++ b/src/main/webapp/src/pages/admin/club/ClubPage.jsx @@ -114,13 +114,14 @@ function InformationForm({data}) {
setSwitchOn(!switchOn)}/> +
- {!switchOn && <> - +
diff --git a/src/main/webapp/src/pages/admin/member/InformationForm.jsx b/src/main/webapp/src/pages/admin/member/InformationForm.jsx index 3c62e9c..c6ea3fe 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, CountryList, OptionField, TextField} from "../../../components/MemberCustomFiels.jsx"; +import {BirthDayField, CountryList, OptionField, RoleList, TextField} from "../../../components/MemberCustomFiels.jsx"; import {ClubSelect} from "../../../components/ClubSelect.jsx"; export function addPhoto(event, formData, send) { @@ -80,17 +80,7 @@ export function InformationForm({data}) {
- +
diff --git a/src/main/webapp/src/pages/admin/member/NewMemberPage.jsx b/src/main/webapp/src/pages/admin/member/NewMemberPage.jsx index ab4ca01..1106d99 100644 --- a/src/main/webapp/src/pages/admin/member/NewMemberPage.jsx +++ b/src/main/webapp/src/pages/admin/member/NewMemberPage.jsx @@ -2,7 +2,7 @@ import {useNavigate} from "react-router-dom"; 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, OptionField, RoleList, TextField} from "../../../components/MemberCustomFiels.jsx"; import {ClubSelect} from "../../../components/ClubSelect.jsx"; import {addPhoto} from "./InformationForm.jsx"; @@ -79,13 +79,7 @@ function Form() {
- +
diff --git a/src/main/webapp/src/pages/club/member/InformationForm.jsx b/src/main/webapp/src/pages/club/member/InformationForm.jsx index 7d9f96f..648adde 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, CountryList, OptionField, TextField} from "../../../components/MemberCustomFiels.jsx"; +import {BirthDayField, CountryList, OptionField, RoleList, TextField} from "../../../components/MemberCustomFiels.jsx"; import {addPhoto} from "../../admin/member/InformationForm.jsx"; export function InformationForm({data}) { @@ -55,17 +55,7 @@ export function InformationForm({data}) { - +