dev #65
@ -13,6 +13,7 @@ import fr.titionfire.ffsaf.rest.data.SimpleMembre;
|
|||||||
import fr.titionfire.ffsaf.rest.data.SimpleMembreInOutData;
|
import fr.titionfire.ffsaf.rest.data.SimpleMembreInOutData;
|
||||||
import fr.titionfire.ffsaf.rest.exception.DBadRequestException;
|
import fr.titionfire.ffsaf.rest.exception.DBadRequestException;
|
||||||
import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
|
import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
|
||||||
|
import fr.titionfire.ffsaf.rest.exception.DInternalError;
|
||||||
import fr.titionfire.ffsaf.rest.from.FullMemberForm;
|
import fr.titionfire.ffsaf.rest.from.FullMemberForm;
|
||||||
import fr.titionfire.ffsaf.utils.*;
|
import fr.titionfire.ffsaf.utils.*;
|
||||||
import io.quarkus.hibernate.reactive.panache.Panache;
|
import io.quarkus.hibernate.reactive.panache.Panache;
|
||||||
@ -102,15 +103,47 @@ public class MembreService {
|
|||||||
return baseUni;
|
return baseUni;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Sort getSort(String order) {
|
||||||
|
|
||||||
|
Sort sort;
|
||||||
|
if (order == null || order.isBlank()) {
|
||||||
|
sort = Sort.ascending("fname", "lname");
|
||||||
|
} else {
|
||||||
|
sort = Sort.empty();
|
||||||
|
|
||||||
|
for (String e : order.split(",")) {
|
||||||
|
String[] split = e.split(" ");
|
||||||
|
if (split.length == 2) {
|
||||||
|
sort = sort.and(split[0],
|
||||||
|
split[1].equals("n") ? Sort.Direction.Ascending : Sort.Direction.Descending);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sort;
|
||||||
|
}
|
||||||
|
|
||||||
public Uni<PageResult<SimpleMembre>> searchAdmin(int limit, int page, String search, String club,
|
public Uni<PageResult<SimpleMembre>> searchAdmin(int limit, int page, String search, String club,
|
||||||
int licenceRequest, int payState) {
|
int licenceRequest, int payState, String order, String categorie) {
|
||||||
if (search == null)
|
if (search == null)
|
||||||
search = "";
|
search = "";
|
||||||
search = "%" + search.replaceAll(" ", "% %") + "%";
|
search = "%" + search.replaceAll(" ", "% %") + "%";
|
||||||
|
|
||||||
|
String categorieFilter;
|
||||||
|
if (categorie == null || categorie.isBlank())
|
||||||
|
categorieFilter = " True";
|
||||||
|
else
|
||||||
|
categorieFilter = "categorie = " + Categorie.valueOf(categorie).ordinal();
|
||||||
|
|
||||||
String finalSearch = search;
|
String finalSearch = search;
|
||||||
Uni<List<LicenceModel>> baseUni = getLicenceListe(licenceRequest, payState);
|
Uni<List<LicenceModel>> baseUni = getLicenceListe(licenceRequest, payState);
|
||||||
|
|
||||||
|
Sort sort = getSort(order);
|
||||||
|
if (sort == null)
|
||||||
|
return Uni.createFrom().failure(new DInternalError("Erreur lors calcul du trie"));
|
||||||
|
|
||||||
return baseUni
|
return baseUni
|
||||||
.map(l -> l.stream().map(l2 -> l2.getMembre().getId()).toList())
|
.map(l -> l.stream().map(l2 -> l2.getMembre().getId()).toList())
|
||||||
.chain(ids -> {
|
.chain(ids -> {
|
||||||
@ -120,18 +153,18 @@ public class MembreService {
|
|||||||
|
|
||||||
if (club == null || club.isBlank()) {
|
if (club == null || club.isBlank()) {
|
||||||
query = repository.find(
|
query = repository.find(
|
||||||
"id " + idf + " ?2 AND (" + FIND_NAME_REQUEST + ")",
|
"id " + idf + " ?2 AND (" + FIND_NAME_REQUEST + ") AND " + categorieFilter,
|
||||||
Sort.ascending("fname", "lname"), finalSearch, ids)
|
sort, finalSearch, ids)
|
||||||
.page(Page.ofSize(limit));
|
.page(Page.ofSize(limit));
|
||||||
} else {
|
} else {
|
||||||
if (club.equals("null")) {
|
if (club.equals("null")) {
|
||||||
query = repository.find(
|
query = repository.find(
|
||||||
"id " + idf + " ?2 AND club IS NULL AND (" + FIND_NAME_REQUEST + ")",
|
"id " + idf + " ?2 AND club IS NULL AND (" + FIND_NAME_REQUEST + ") AND " + categorieFilter,
|
||||||
Sort.ascending("fname", "lname"), finalSearch, ids).page(Page.ofSize(limit));
|
sort, finalSearch, ids).page(Page.ofSize(limit));
|
||||||
} else {
|
} else {
|
||||||
query = repository.find(
|
query = repository.find(
|
||||||
"id " + idf + " ?3 AND LOWER(club.name) LIKE LOWER(?2) AND (" + FIND_NAME_REQUEST + ")",
|
"id " + idf + " ?3 AND LOWER(club.name) LIKE LOWER(?2) AND (" + FIND_NAME_REQUEST + ") AND " + categorieFilter,
|
||||||
Sort.ascending("fname", "lname"), finalSearch, club + "%", ids)
|
sort, finalSearch, club, ids)
|
||||||
.page(Page.ofSize(limit));
|
.page(Page.ofSize(limit));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,7 +173,7 @@ public class MembreService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Uni<PageResult<SimpleMembre>> search(int limit, int page, String search, int licenceRequest, int payState,
|
public Uni<PageResult<SimpleMembre>> search(int limit, int page, String search, int licenceRequest, int payState,
|
||||||
String subject) {
|
String order, String categorie, String subject) {
|
||||||
if (search == null)
|
if (search == null)
|
||||||
search = "";
|
search = "";
|
||||||
search = "%" + search.replaceAll(" ", "% %") + "%";
|
search = "%" + search.replaceAll(" ", "% %") + "%";
|
||||||
@ -149,6 +182,16 @@ public class MembreService {
|
|||||||
|
|
||||||
Uni<List<LicenceModel>> baseUni = getLicenceListe(licenceRequest, payState);
|
Uni<List<LicenceModel>> baseUni = getLicenceListe(licenceRequest, payState);
|
||||||
|
|
||||||
|
String categorieFilter;
|
||||||
|
if (categorie == null || categorie.isBlank())
|
||||||
|
categorieFilter = " True";
|
||||||
|
else
|
||||||
|
categorieFilter = "categorie = " + Categorie.valueOf(categorie).ordinal();
|
||||||
|
|
||||||
|
Sort sort = getSort(order);
|
||||||
|
if (sort == null)
|
||||||
|
return Uni.createFrom().failure(new DInternalError("Erreur lors calcul du trie"));
|
||||||
|
|
||||||
return baseUni
|
return baseUni
|
||||||
.map(l -> l.stream().map(l2 -> l2.getMembre().getId()).toList())
|
.map(l -> l.stream().map(l2 -> l2.getMembre().getId()).toList())
|
||||||
.chain(ids -> {
|
.chain(ids -> {
|
||||||
@ -157,8 +200,8 @@ public class MembreService {
|
|||||||
return repository.find("userId = ?1", subject).firstResult()
|
return repository.find("userId = ?1", subject).firstResult()
|
||||||
.chain(membreModel -> {
|
.chain(membreModel -> {
|
||||||
PanacheQuery<MembreModel> query = repository.find(
|
PanacheQuery<MembreModel> query = repository.find(
|
||||||
"id " + idf + " ?3 AND club = ?2 AND (" + FIND_NAME_REQUEST + ")",
|
"id " + idf + " ?3 AND club = ?2 AND (" + FIND_NAME_REQUEST + ") AND " + categorieFilter,
|
||||||
Sort.ascending("fname", "lname"), finalSearch, membreModel.getClub(), ids)
|
sort, finalSearch, membreModel.getClub(), ids)
|
||||||
.page(Page.ofSize(limit));
|
.page(Page.ofSize(limit));
|
||||||
return getPageResult(query, limit, page);
|
return getPageResult(query, limit, page);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -58,13 +58,15 @@ public class MembreAdminEndpoints {
|
|||||||
@Parameter(description = "Page à consulter") @QueryParam("page") Integer page,
|
@Parameter(description = "Page à consulter") @QueryParam("page") Integer page,
|
||||||
@Parameter(description = "Text à rechercher") @QueryParam("search") String search,
|
@Parameter(description = "Text à rechercher") @QueryParam("search") String search,
|
||||||
@Parameter(description = "Club à filter") @QueryParam("club") String club,
|
@Parameter(description = "Club à filter") @QueryParam("club") String club,
|
||||||
@Parameter(description = "Etat de la demande de licence: 0 -> sans demande, 1 -> avec demande ou validée, 2 -> toute les demande non validée, 3 -> validée, 4 -> tout, 5 -> demande complete, 6 -> demande incomplete") @QueryParam("licenceRequest") int licenceRequest,
|
@Parameter(description = "Catégorie à filter") @QueryParam("categorie") String categorie,
|
||||||
@Parameter(description = "Etat du payment: 0 -> non payer, 1 -> payer, 2 -> tout") @QueryParam("payment") int payment) {
|
@Parameter(description = "État de la demande de licence: 0 -> sans demande, 1 -> avec demande ou validée, 2 -> toute les demande non validée, 3 -> validée, 4 -> tout, 5 -> demande complete, 6 -> demande incomplete") @QueryParam("licenceRequest") int licenceRequest,
|
||||||
|
@Parameter(description = "État du payment: 0 -> non payer, 1 -> payer, 2 -> tout") @QueryParam("payment") int payment,
|
||||||
|
@Parameter(description = "Ordre") @QueryParam("order") String order) {
|
||||||
if (limit == null)
|
if (limit == null)
|
||||||
limit = 50;
|
limit = 50;
|
||||||
if (page == null || page < 1)
|
if (page == null || page < 1)
|
||||||
page = 1;
|
page = 1;
|
||||||
return membreService.searchAdmin(limit, page - 1, search, club, licenceRequest, payment);
|
return membreService.searchAdmin(limit, page - 1, search, club, licenceRequest, payment, order, categorie);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
|
|||||||
@ -50,13 +50,15 @@ public class MembreClubEndpoints {
|
|||||||
@Parameter(description = "Nombre max de résulta (max 50)") @QueryParam("limit") Integer limit,
|
@Parameter(description = "Nombre max de résulta (max 50)") @QueryParam("limit") Integer limit,
|
||||||
@Parameter(description = "Page à consulter") @QueryParam("page") Integer page,
|
@Parameter(description = "Page à consulter") @QueryParam("page") Integer page,
|
||||||
@Parameter(description = "Text à rechercher") @QueryParam("search") String search,
|
@Parameter(description = "Text à rechercher") @QueryParam("search") String search,
|
||||||
|
@Parameter(description = "Catégorie à filter") @QueryParam("categorie") String categorie,
|
||||||
@Parameter(description = "Etat de la demande de licence: 0 -> sans demande, 1 -> avec demande ou validée, 2 -> toute les demande non validée, 3 -> validée, 4 -> tout, 5 -> demande complete, 6 -> demande incomplete") @QueryParam("licenceRequest") int licenceRequest,
|
@Parameter(description = "Etat de la demande de licence: 0 -> sans demande, 1 -> avec demande ou validée, 2 -> toute les demande non validée, 3 -> validée, 4 -> tout, 5 -> demande complete, 6 -> demande incomplete") @QueryParam("licenceRequest") int licenceRequest,
|
||||||
@Parameter(description = "Etat du payment: 0 -> non payer, 1 -> payer, 2 -> tout") @QueryParam("payment") int payment) {
|
@Parameter(description = "Etat du payment: 0 -> non payer, 1 -> payer, 2 -> tout") @QueryParam("payment") int payment,
|
||||||
|
@Parameter(description = "Ordre") @QueryParam("order") String order) {
|
||||||
if (limit == null)
|
if (limit == null)
|
||||||
limit = 50;
|
limit = 50;
|
||||||
if (page == null || page < 1)
|
if (page == null || page < 1)
|
||||||
page = 1;
|
page = 1;
|
||||||
return membreService.search(limit, page - 1, search, licenceRequest, payment, securityCtx.getSubject());
|
return membreService.search(limit, page - 1, search, licenceRequest, payment, order, categorie, securityCtx.getSubject());
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import {useEffect, useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
import {getCategoryFormBirthDate} from "../utils/Tools.js";
|
import {getCategoryFormBirthDate, getCatName} from "../utils/Tools.js";
|
||||||
import {useCountries} from "../hooks/useCountries.jsx";
|
import {useCountries} from "../hooks/useCountries.jsx";
|
||||||
|
|
||||||
export function BirthDayField({inti_date, inti_category, required = true}) {
|
export function BirthDayField({inti_date, inti_category, required = true}) {
|
||||||
@ -27,7 +27,7 @@ export function BirthDayField({inti_date, inti_category, required = true}) {
|
|||||||
<div className="input-group mb-3">
|
<div className="input-group mb-3">
|
||||||
<span className="input-group-text" id="category">Catégorie</span>
|
<span className="input-group-text" id="category">Catégorie</span>
|
||||||
<input type="text" className="form-control" placeholder="" name="category"
|
<input type="text" className="form-control" placeholder="" name="category"
|
||||||
aria-label="category" value={category ? category : ""} aria-describedby="category"
|
aria-label="category" value={category ? getCatName(category) : ""} aria-describedby="category"
|
||||||
disabled/>
|
disabled/>
|
||||||
{canUpdate && <button className="btn btn-outline-secondary" type="button" id="button-addon1"
|
{canUpdate && <button className="btn btn-outline-secondary" type="button" id="button-addon1"
|
||||||
onClick={updateCat}>Mettre à jours</button>}
|
onClick={updateCat}>Mettre à jours</button>}
|
||||||
|
|||||||
@ -7,8 +7,8 @@ const removeDiacritics = str => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function SearchBar({search}) {
|
export function SearchBar({search, defaultValue = ""}) {
|
||||||
const [searchInput, setSearchInput] = useState("");
|
const [searchInput, setSearchInput] = useState(defaultValue);
|
||||||
|
|
||||||
const handelChange = (e) => {
|
const handelChange = (e) => {
|
||||||
setSearchInput(e.target.value);
|
setSearchInput(e.target.value);
|
||||||
|
|||||||
@ -6,38 +6,60 @@ import {useEffect, useState} from "react";
|
|||||||
import {useLocation, useNavigate} from "react-router-dom";
|
import {useLocation, useNavigate} from "react-router-dom";
|
||||||
import {Checkbox} from "../components/MemberCustomFiels.jsx";
|
import {Checkbox} from "../components/MemberCustomFiels.jsx";
|
||||||
import * as Tools from "../utils/Tools.js";
|
import * as Tools from "../utils/Tools.js";
|
||||||
import {apiAxios, errFormater} from "../utils/Tools.js";
|
import {apiAxios, errFormater, getCatName} from "../utils/Tools.js";
|
||||||
import {toast} from "react-toastify";
|
import {toast} from "react-toastify";
|
||||||
import {SearchBar} from "../components/SearchBar.jsx";
|
import {SearchBar} from "../components/SearchBar.jsx";
|
||||||
import * as XLSX from "xlsx-js-style";
|
import * as XLSX from "xlsx-js-style";
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
||||||
import {faEuroSign} from "@fortawesome/free-solid-svg-icons";
|
import {faEuroSign} from "@fortawesome/free-solid-svg-icons";
|
||||||
|
|
||||||
|
|
||||||
|
let lastRefresh = "";
|
||||||
|
|
||||||
export function MemberList({source}) {
|
export function MemberList({source}) {
|
||||||
const {hash} = useLocation();
|
const {hash} = useLocation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
let page = Number(hash.substring(1));
|
|
||||||
page = (page > 0) ? page : 1;
|
|
||||||
|
|
||||||
const [memberData, setMemberData] = useState([]);
|
const [memberData, setMemberData] = useState([]);
|
||||||
const [licenceData, setLicenceData] = useState([]);
|
const [licenceData, setLicenceData] = useState([]);
|
||||||
const [showLicenceState, setShowLicenceState] = useState(false);
|
const [showLicenceState, setShowLicenceState] = useState(false);
|
||||||
const [clubFilter, setClubFilter] = useState("");
|
|
||||||
const [stateFilter, setStateFilter] = useState(4)
|
const setFilter = (filter) => {
|
||||||
const [lastSearch, setLastSearch] = useState("");
|
navigate("#" + encodeURI(JSON.stringify(filter)))
|
||||||
const [paymentFilter, setPaymentFilter] = useState(2);
|
}
|
||||||
|
const filter = {
|
||||||
|
page: 1,
|
||||||
|
search: "",
|
||||||
|
club: "",
|
||||||
|
licenceRequest: 4,
|
||||||
|
payment: 2,
|
||||||
|
order: "",
|
||||||
|
categorie: "",
|
||||||
|
...JSON.parse(decodeURI(hash.substring(1)) || "{}"),
|
||||||
|
}
|
||||||
|
|
||||||
const setLoading = useLoadingSwitcher()
|
const setLoading = useLoadingSwitcher()
|
||||||
const {data, error, refresh} = useFetch(`/member/find/${source}?page=${page}&licenceRequest=${stateFilter}&payment=${paymentFilter}`, setLoading, 1)
|
const {
|
||||||
|
data,
|
||||||
|
error,
|
||||||
|
refresh
|
||||||
|
} = useFetch(`/member/find/${source}?page=${filter.page}&search=${filter.search}&club=${filter.club}&licenceRequest=${filter.licenceRequest}&payment=${filter.payment}&order=${filter.order}&categorie=${filter.categorie}`, setLoading, 1)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
refresh(`/member/find/${source}?page=${page}&search=${lastSearch}&club=${clubFilter}&licenceRequest=${stateFilter}&payment=${paymentFilter}`);
|
const tmp = `/member/find/${source}?page=${filter.page}&search=${filter.search}&club=${filter.club}&licenceRequest=${filter.licenceRequest}&payment=${filter.payment}&order=${filter.order}&categorie=${filter.categorie}`;
|
||||||
}, [hash, clubFilter, stateFilter, lastSearch, paymentFilter]);
|
if (tmp === lastRefresh)
|
||||||
|
return;
|
||||||
|
lastRefresh = tmp
|
||||||
|
refresh(lastRefresh);
|
||||||
|
}, [hash]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!data)
|
if (!data)
|
||||||
return;
|
return;
|
||||||
|
if (data.page_count < filter.page) {
|
||||||
|
setFilter({...filter, page: 1});
|
||||||
|
}
|
||||||
|
|
||||||
const data2 = [];
|
const data2 = [];
|
||||||
for (const e of data.result) {
|
for (const e of data.result) {
|
||||||
data2.push({
|
data2.push({
|
||||||
@ -74,19 +96,19 @@ export function MemberList({source}) {
|
|||||||
}, [showLicenceState]);
|
}, [showLicenceState]);
|
||||||
|
|
||||||
const search = (search) => {
|
const search = (search) => {
|
||||||
if (search === lastSearch)
|
if (search === filter.search)
|
||||||
return;
|
return;
|
||||||
setLastSearch(search);
|
setFilter({...filter, search: search});
|
||||||
}
|
}
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<div>
|
<div>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-lg-9">
|
<div className="col-lg-9">
|
||||||
<SearchBar search={search}/>
|
<SearchBar search={search} defaultValue={filter.search}/>
|
||||||
{data
|
{data
|
||||||
? <MakeCentralPanel data={data} visibleMember={memberData} navigate={navigate} showLicenceState={showLicenceState}
|
? <MakeCentralPanel data={data} visibleMember={memberData} navigate={navigate} showLicenceState={showLicenceState}
|
||||||
page={page} source={source}/>
|
page={filter.page} setPage={e => setFilter({...filter, page: e})} source={source}/>
|
||||||
: error
|
: error
|
||||||
? <AxiosError error={error}/>
|
? <AxiosError error={error}/>
|
||||||
: <Def/>
|
: <Def/>
|
||||||
@ -102,13 +124,28 @@ export function MemberList({source}) {
|
|||||||
<button className="btn btn-primary" onClick={() => navigate("pay")} style={{marginTop: "0.5rem"}}>Paiement des
|
<button className="btn btn-primary" onClick={() => navigate("pay")} style={{marginTop: "0.5rem"}}>Paiement des
|
||||||
licences</button>}
|
licences</button>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="card mb-4">
|
||||||
|
<div className="card-header">Trie</div>
|
||||||
|
<div className="card-body">
|
||||||
|
<OrderBar onOrderChange={e => setFilter({...filter, order: e.join(",")})} defaultValues={filter.order} source={source}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="card mb-4">
|
<div className="card mb-4">
|
||||||
<div className="card-header">Filtre</div>
|
<div className="card-header">Filtre</div>
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<FiltreBar showLicenceState={showLicenceState} setShowLicenceState={setShowLicenceState} data={data}
|
<FiltreBar showLicenceState={showLicenceState}
|
||||||
clubFilter={clubFilter} setClubFilter={setClubFilter} source={source}
|
setShowLicenceState={setShowLicenceState}
|
||||||
stateFilter={stateFilter} setStateFilter={setStateFilter} paymentFilter={paymentFilter}
|
clubFilter={filter.club}
|
||||||
setPaymentFilter={setPaymentFilter}/>
|
setClubFilter={e => setFilter({...filter, club: e})}
|
||||||
|
source={source}
|
||||||
|
stateFilter={filter.licenceRequest}
|
||||||
|
setStateFilter={e => setFilter({...filter, licenceRequest: e})}
|
||||||
|
paymentFilter={filter.payment}
|
||||||
|
setPaymentFilter={e => setFilter({...filter, payment: e})}
|
||||||
|
catFilter={filter.categorie}
|
||||||
|
setCatFilter={e => setFilter({...filter, categorie: e})}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -336,11 +373,11 @@ function FileInput() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function MakeCentralPanel({data, visibleMember, navigate, showLicenceState, page, source}) {
|
function MakeCentralPanel({data, visibleMember, navigate, showLicenceState, page, setPage, source}) {
|
||||||
const pages = []
|
const pages = []
|
||||||
for (let i = 1; i <= data.page_count; i++) {
|
for (let i = 1; i <= data.page_count; i++) {
|
||||||
pages.push(<li key={i} className={"page-item " + ((page === i) ? "active" : "")}>
|
pages.push(<li key={i} className={"page-item " + ((page === i) ? "active" : "")}>
|
||||||
<span className="page-link" onClick={() => navigate("#" + i)}>{i}</span>
|
<span className="page-link" onClick={() => setPage(i)}>{i}</span>
|
||||||
</li>);
|
</li>);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,10 +394,10 @@ function MakeCentralPanel({data, visibleMember, navigate, showLicenceState, page
|
|||||||
<nav aria-label="Page navigation">
|
<nav aria-label="Page navigation">
|
||||||
<ul className="pagination justify-content-center">
|
<ul className="pagination justify-content-center">
|
||||||
<li className={"page-item" + ((page <= 1) ? " disabled" : "")}>
|
<li className={"page-item" + ((page <= 1) ? " disabled" : "")}>
|
||||||
<span className="page-link" onClick={() => navigate("#" + (page - 1))}>«</span></li>
|
<span className="page-link" onClick={() => setPage(page - 1)}>«</span></li>
|
||||||
{pages}
|
{pages}
|
||||||
<li className={"page-item" + ((page >= data.page_count) ? " disabled" : "")}>
|
<li className={"page-item" + ((page >= data.page_count) ? " disabled" : "")}>
|
||||||
<span className="page-link" onClick={() => navigate("#" + (page + 1))}>»</span></li>
|
<span className="page-link" onClick={() => setPage(page + 1)}>»</span></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
@ -369,45 +406,146 @@ function MakeCentralPanel({data, visibleMember, navigate, showLicenceState, page
|
|||||||
|
|
||||||
function MakeRow({member, showLicenceState, navigate, source}) {
|
function MakeRow({member, showLicenceState, navigate, source}) {
|
||||||
const rowContent = <>
|
const rowContent = <>
|
||||||
<div className="row">
|
<div className="row" style={{padding: "0.6em 0"}}>
|
||||||
<span className="col-auto">{(member.licence_number ? String(member.licence_number).padStart(5, '0') : "-------") + " "}
|
<span className="col-auto">{(member.licence_number ? String(member.licence_number).padStart(5, '0') : "-------") + " "}
|
||||||
{(showLicenceState && member.licence != null && member.licence.pay) ? <FontAwesomeIcon icon={faEuroSign}/> : <> </>}</span>
|
{(showLicenceState && member.licence != null && member.licence.pay) ? <FontAwesomeIcon icon={faEuroSign}/> : <> </>}</span>
|
||||||
<div className="ms-2 col-auto">
|
<div className="ms-2 col-auto">
|
||||||
<div className="fw-bold">{member.fname} {member.lname}</div>
|
<div className="fw-bold">{member.fname} {member.lname}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div style={{verticalAlign: "center", margin: "auto 0"}}>
|
||||||
{source === "club" ?
|
{source === "club" ?
|
||||||
<small>{member.categorie}</small>
|
<small>{getCatName(member.categorie)}</small>
|
||||||
: <small>{member.club?.name || "Sans club"}</small>}
|
: <div style={{
|
||||||
|
textAlign: "right",
|
||||||
|
fontSize: "small"
|
||||||
|
}}>{member.club?.name || "Sans club"}<br/><small>{getCatName(member.categorie)}</small></div>}
|
||||||
|
</div>
|
||||||
|
|
||||||
</>
|
</>
|
||||||
|
|
||||||
if (showLicenceState && member.licence != null) {
|
if (showLicenceState && member.licence != null) {
|
||||||
return <div
|
return <a className={"list-group-item d-flex justify-content-between align-items-start list-group-item-action list-group-item-"
|
||||||
className={"list-group-item d-flex justify-content-between align-items-start list-group-item-action list-group-item-"
|
|
||||||
+ (member.licence.validate ? "success" : (member.licence.certificate.length > 1 ? "warning" : "danger"))}
|
+ (member.licence.validate ? "success" : (member.licence.certificate.length > 1 ? "warning" : "danger"))}
|
||||||
onClick={() => navigate("" + member.id)}>{rowContent}</div>
|
style={{padding: "0 1em"}}
|
||||||
} else {
|
onClick={e => {
|
||||||
return <div className="list-group-item d-flex justify-content-between align-items-start list-group-item-action"
|
e.preventDefault();
|
||||||
onClick={() => navigate("" + member.id)}>
|
navigate("" + member.id)
|
||||||
|
}}
|
||||||
|
href={"member/" + member.id}>
|
||||||
{rowContent}
|
{rowContent}
|
||||||
|
</a>
|
||||||
|
} else {
|
||||||
|
return <a className="list-group-item d-flex justify-content-between align-items-start list-group-item-action"
|
||||||
|
style={{padding: "0 1em"}}
|
||||||
|
onClick={e => {
|
||||||
|
e.preventDefault();
|
||||||
|
navigate("" + member.id)
|
||||||
|
}}
|
||||||
|
href={"member/" + member.id}>
|
||||||
|
{rowContent}
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function OrderBar({onOrderChange, defaultValues = "", source}) {
|
||||||
|
const [orderCriteria, setOrderCriteria] = useState([...defaultValues.split(",").filter(c => c !== ''), '']);
|
||||||
|
|
||||||
|
const handleChange = (index, value) => {
|
||||||
|
const newCriteria = [...orderCriteria];
|
||||||
|
newCriteria[index] = value;
|
||||||
|
|
||||||
|
// Si le dernier critère est rempli, on en ajoute un nouveau
|
||||||
|
if (index === orderCriteria.length - 1 && value !== '') {
|
||||||
|
newCriteria.push('');
|
||||||
|
}
|
||||||
|
// Si un critère (sauf le premier) est réinitialisé, on le supprime
|
||||||
|
else if (value === '' && (index !== 0 || orderCriteria.length > 1)) {
|
||||||
|
newCriteria.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
setOrderCriteria(newCriteria);
|
||||||
|
onOrderChange(newCriteria.filter(c => c !== ''));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Liste de toutes les options possibles
|
||||||
|
const allOptions = [
|
||||||
|
{value: 'lname n', label: 'Nom ↓', base: 'lname'},
|
||||||
|
{value: 'lname i', label: 'Nom ↑', base: 'lname'},
|
||||||
|
{value: 'fname n', label: 'Prénom ↓', base: 'fname'},
|
||||||
|
{value: 'fname i', label: 'Prénom ↑', base: 'fname'},
|
||||||
|
{value: 'categorie n', label: 'Catégorie ↓', base: 'categorie'},
|
||||||
|
{value: 'categorie i', label: 'Catégorie ↑', base: 'categorie'},
|
||||||
|
{value: 'licence n', label: 'Licence ↓', base: 'licence'},
|
||||||
|
{value: 'licence i', label: 'Licence ↑', base: 'licence'},
|
||||||
|
];
|
||||||
|
|
||||||
|
if (source === "admin") {
|
||||||
|
allOptions.push(
|
||||||
|
{value: 'club.name n', label: 'Club ↓', base: 'club.name'},
|
||||||
|
{value: 'club.name i', label: 'Club ↑', base: 'club.name'},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mb-3">
|
||||||
|
{orderCriteria.map((criteria, index) => {
|
||||||
|
// Récupère les bases des critères déjà sélectionnés (sauf le courant)
|
||||||
|
const usedBases = orderCriteria
|
||||||
|
.filter((c, i) => c !== '' && i !== index)
|
||||||
|
.map(c => allOptions.find(o => o.value === c)?.base);
|
||||||
|
|
||||||
|
// Filtre les options disponibles
|
||||||
|
const availableOptions = allOptions.filter(option =>
|
||||||
|
!usedBases.includes(option.base) || option.value === criteria
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<select
|
||||||
|
key={index}
|
||||||
|
className="form-select mb-2"
|
||||||
|
value={criteria}
|
||||||
|
onChange={(e) => handleChange(index, e.target.value)}
|
||||||
|
>
|
||||||
|
<option value="">----</option>
|
||||||
|
{availableOptions.map((option) => (
|
||||||
|
<option key={option.value} value={option.value}>
|
||||||
|
{option.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let allClub = []
|
function FiltreBar({
|
||||||
|
showLicenceState,
|
||||||
function FiltreBar({showLicenceState, setShowLicenceState, data, clubFilter, setClubFilter, source, stateFilter, setStateFilter, paymentFilter, setPaymentFilter}) {
|
setShowLicenceState,
|
||||||
useEffect(() => {
|
clubFilter,
|
||||||
if (!data)
|
setClubFilter,
|
||||||
return;
|
source,
|
||||||
allClub.push(...data.result.map((e) => e.club?.name))
|
stateFilter,
|
||||||
allClub = allClub.filter((value, index, self) => self.indexOf(value) === index).filter(value => value != null).sort()
|
setStateFilter,
|
||||||
}, [data]);
|
paymentFilter,
|
||||||
|
setPaymentFilter,
|
||||||
|
catFilter,
|
||||||
|
setCatFilter,
|
||||||
|
}) {
|
||||||
|
|
||||||
return <div>
|
return <div>
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<Checkbox value={showLicenceState} onChange={setShowLicenceState} label="Afficher l'état des licences"/>
|
<Checkbox value={showLicenceState} onChange={setShowLicenceState} label="Afficher l'état des licences"/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<select className="form-select" value={catFilter} onChange={event => setCatFilter(event.target.value)}>
|
||||||
|
<option value="">--- toute les catégories ---</option>
|
||||||
|
{Tools.CatList.map(cat => (
|
||||||
|
<option key={cat} value={cat}>{getCatName(cat)}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
{source !== "club" && <ClubSelectFilter clubFilter={clubFilter} setClubFilter={setClubFilter}/>}
|
{source !== "club" && <ClubSelectFilter clubFilter={clubFilter} setClubFilter={setClubFilter}/>}
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<select className="form-select" value={stateFilter} onChange={event => setStateFilter(Number(event.target.value))}>
|
<select className="form-select" value={stateFilter} onChange={event => setStateFilter(Number(event.target.value))}>
|
||||||
|
|||||||
@ -34,13 +34,13 @@ export function MemberPage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
).then(_ => {
|
).then(_ => {
|
||||||
navigate("/admin/member")
|
navigate(-1)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<h2>Page membre</h2>
|
<h2>Page membre</h2>
|
||||||
<button type="button" className="btn btn-link" onClick={() => navigate("/admin/member")}>
|
<button type="button" className="btn btn-link" onClick={() => navigate(-1)}>
|
||||||
« retour
|
« retour
|
||||||
</button>
|
</button>
|
||||||
{data
|
{data
|
||||||
|
|||||||
@ -33,13 +33,13 @@ export function MemberPage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
).then(_ => {
|
).then(_ => {
|
||||||
navigate("/club/member")
|
navigate(-1)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<h2>Page membre</h2>
|
<h2>Page membre</h2>
|
||||||
<button type="button" className="btn btn-link" onClick={() => navigate("/club/member")}>
|
<button type="button" className="btn btn-link" onClick={() => navigate(-1)}>
|
||||||
« retour
|
« retour
|
||||||
</button>
|
</button>
|
||||||
{data
|
{data
|
||||||
|
|||||||
@ -23,6 +23,20 @@ export const errFormater = (data, msg) => {
|
|||||||
return `${msg} (${data.response.statusText}: ${JSON.stringify(data.response.data)}) 😕`
|
return `${msg} (${data.response.statusText}: ${JSON.stringify(data.response.data)}) 😕`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const CatList = [
|
||||||
|
"SUPER_MINI",
|
||||||
|
"MINI_POUSSIN",
|
||||||
|
"POUSSIN",
|
||||||
|
"BENJAMIN",
|
||||||
|
"MINIME",
|
||||||
|
"CADET",
|
||||||
|
"JUNIOR",
|
||||||
|
"SENIOR1",
|
||||||
|
"SENIOR2",
|
||||||
|
"VETERAN1",
|
||||||
|
"VETERAN2"
|
||||||
|
];
|
||||||
|
|
||||||
export function getCategoryFormBirthDate(birth_date, currentDate = new Date()) {
|
export function getCategoryFormBirthDate(birth_date, currentDate = new Date()) {
|
||||||
const currentSaison = getSaison(currentDate)
|
const currentSaison = getSaison(currentDate)
|
||||||
const birthYear = birth_date.getFullYear()
|
const birthYear = birth_date.getFullYear()
|
||||||
@ -60,3 +74,32 @@ export function getSaison(currentDate = new Date()) {
|
|||||||
return currentDate.getFullYear() - 1
|
return currentDate.getFullYear() - 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getCatName(cat) {
|
||||||
|
switch (cat) {
|
||||||
|
case "SUPER_MINI":
|
||||||
|
return "Super Mini";
|
||||||
|
case "MINI_POUSSIN":
|
||||||
|
return "Mini Poussin";
|
||||||
|
case "POUSSIN":
|
||||||
|
return "Poussin";
|
||||||
|
case "BENJAMIN":
|
||||||
|
return "Benjamin";
|
||||||
|
case "MINIME":
|
||||||
|
return "Minime";
|
||||||
|
case "CADET":
|
||||||
|
return "Cadet";
|
||||||
|
case "JUNIOR":
|
||||||
|
return "Junior";
|
||||||
|
case "SENIOR1":
|
||||||
|
return "Senior 1";
|
||||||
|
case "SENIOR2":
|
||||||
|
return "Senior 2";
|
||||||
|
case "VETERAN1":
|
||||||
|
return "Vétéran 1";
|
||||||
|
case "VETERAN2":
|
||||||
|
return "Vétéran 2";
|
||||||
|
default:
|
||||||
|
return cat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user