All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m42s
473 lines
20 KiB
JavaScript
473 lines
20 KiB
JavaScript
import {useNavigate, useParams} from "react-router-dom";
|
|
import {useLoadingSwitcher} from "../../hooks/useLoading.jsx";
|
|
import {useFetch} from "../../hooks/useFetch.js";
|
|
import {AxiosError} from "../../components/AxiosError.jsx";
|
|
import {ThreeDots} from "react-loader-spinner";
|
|
import React, {useEffect, useState} from "react";
|
|
import {DrawGraph} from "./DrawGraph.jsx";
|
|
import {TreeNode} from "../../utils/TreeUtils.js";
|
|
import {scoreToString} from "../../utils/CompetitionTools.js";
|
|
import {useTranslation} from "react-i18next";
|
|
|
|
function CupImg() {
|
|
return <img decoding="async" loading="lazy" width="16" height="16" className="wp-image-1635"
|
|
style={{width: "16px"}} src="/img/171891.png"
|
|
alt=""/>
|
|
}
|
|
function CupImg2() {
|
|
return <img decoding="async" loading="lazy" width="16" height="16" className="wp-image-1635"
|
|
style={{width: "16px"}} src="/img/171892.png"
|
|
alt=""/>
|
|
}
|
|
|
|
export function ResultView() {
|
|
const {uuid} = useParams()
|
|
const navigate = useNavigate();
|
|
const [resultShow, setResultShow] = useState("cat")
|
|
const {t} = useTranslation('result');
|
|
|
|
return <>
|
|
<button type="button" className="btn btn-link" onClick={() => navigate("/result")}>
|
|
{t('back')}
|
|
</button>
|
|
|
|
<MenuBar resultShow={resultShow} setResultShow={setResultShow}/>
|
|
|
|
<div className="row" style={{marginTop: "1em"}}>
|
|
<div className="col-auto">
|
|
{resultShow && resultShow === "cat" && <CategoryList uuid={uuid}/>
|
|
|| resultShow && resultShow === "club" && <ClubList uuid={uuid}/>
|
|
|| resultShow && resultShow === "comb" && <CombList uuid={uuid}/>
|
|
|| resultShow && resultShow === "combs" && <CombsResult uuid={uuid}/>}
|
|
</div>
|
|
</div>
|
|
</>
|
|
}
|
|
|
|
// || resultShow && resultShow === "club_all" && <ClubAllResult uuid={uuid}/>
|
|
|
|
function MenuBar({resultShow, setResultShow}) {
|
|
const {t} = useTranslation('result');
|
|
return <ul className="nav nav-tabs">
|
|
<li className="nav-item">
|
|
<a className={"nav-link my-1" + (resultShow === "cat" ? " active" : "")} aria-current={(resultShow === "cat" ? " page" : "false")}
|
|
href="#" onClick={_ => setResultShow("cat")}>{t('parCatégorie')}</a>
|
|
</li>
|
|
<li className="nav-item">
|
|
<a className={"nav-link my-1" + (resultShow === "club" ? " active" : "")} aria-current={(resultShow === "club" ? " page" : "false")}
|
|
href="#" onClick={_ => setResultShow("club")}>{t('parClub')}</a>
|
|
</li>
|
|
<li className="nav-item">
|
|
<a className={"nav-link my-1" + (resultShow === "comb" ? " active" : "")} aria-current={(resultShow === "comb" ? " page" : "false")}
|
|
href="#" onClick={_ => setResultShow("comb")}>{t('parCombattant')}</a>
|
|
</li>
|
|
<li className="nav-item">
|
|
<a className={"nav-link my-1" + (resultShow === "combs" ? " active" : "")} aria-current={(resultShow === "combs" ? " page" : "false")}
|
|
href="#" onClick={_ => setResultShow("combs")}>{t('combattants')}</a>
|
|
</li>
|
|
</ul>
|
|
|
|
/*
|
|
<li className="nav-item">
|
|
<a className={"nav-link my-1" + (resultShow === "club_all" ? " active" : "")}
|
|
aria-current={(resultShow === "club_all" ? " page" : "false")}
|
|
href="#" onClick={_ => setResultShow("club_all")}>Clubs</a>
|
|
</li>
|
|
*/
|
|
}
|
|
|
|
function BuildMatchArray({matchs}) {
|
|
const {t} = useTranslation('result');
|
|
return <>
|
|
<table className="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('rouge')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}></th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('scores')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}></th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('bleu')}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{matchs.map((match, idx) => <tr key={idx}>
|
|
<td style={{textAlign: "right"}}>{match.red}</td>
|
|
<td style={{textAlign: "center"}}>{match.red_w ? <CupImg/> : (match.eq ? <CupImg2/> : "")}</td>
|
|
<td style={{textAlign: "center"}}>{scoreToString(match.score)}</td>
|
|
<td style={{textAlign: "center"}}>{match.blue_w ? <CupImg/> : (match.eq ? <CupImg2/> : "")}</td>
|
|
<td style={{textAlign: "left"}}>{match.blue}</td>
|
|
</tr>)}
|
|
</tbody>
|
|
</table>
|
|
</>
|
|
}
|
|
|
|
function BuildRankArray({rankArray}) {
|
|
const {t} = useTranslation('result');
|
|
return <>
|
|
<table className="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('place')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('nom')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('score')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('victoire')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('ratio')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('pointsMarqués')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('pointsReçus')}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{rankArray.map((row, idx) => <tr key={idx}>
|
|
<td style={{textAlign: "center"}}>{row.rank}</td>
|
|
<td style={{textAlign: "left"}}>{row.name}</td>
|
|
<td style={{textAlign: "center"}}>{row.score}</td>
|
|
<td style={{textAlign: "center"}}>{row.win}</td>
|
|
<td style={{textAlign: "center"}}>{row.pointRate.toFixed(3)}</td>
|
|
<td style={{textAlign: "center"}}>{row.pointMake}</td>
|
|
<td style={{textAlign: "center"}}>{row.pointTake}</td>
|
|
</tr>)}
|
|
</tbody>
|
|
</table>
|
|
</>
|
|
}
|
|
|
|
function BuildTree({treeData}) {
|
|
function parseTree(data_in) {
|
|
if (data_in?.data == null)
|
|
return null;
|
|
|
|
let node = new TreeNode(data_in.data);
|
|
node.left = parseTree(data_in?.left);
|
|
node.right = parseTree(data_in?.right);
|
|
|
|
return node;
|
|
}
|
|
|
|
function initTree(data_in) {
|
|
let out = [];
|
|
for (const din of data_in) {
|
|
out.push(parseTree(din));
|
|
}
|
|
return out;
|
|
}
|
|
|
|
return <DrawGraph root={initTree(treeData)}/>
|
|
}
|
|
|
|
function CategoryList({uuid}) {
|
|
const [catId, setCatId] = useState(null)
|
|
const setLoading = useLoadingSwitcher()
|
|
const {data, error} = useFetch(`/result/${uuid}/category/list`, setLoading, 1)
|
|
const {t} = useTranslation('result');
|
|
|
|
useEffect(() => {
|
|
if (data && Object.keys(data).length > 0)
|
|
setCatId(data[Object.keys(data).sort((a, b) => a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase()))[0]])
|
|
}, [data]);
|
|
|
|
return <>
|
|
{data ? <div className="input-group" style={{marginBottom: "1em"}}>
|
|
<h6 style={{margin: "auto 0.5em auto 0"}}>{t('catégorie')}</h6>
|
|
<select className="form-select" aria-label="Select Result Type" onChange={e => setCatId(e.target.value)}>
|
|
{Object.keys(data).sort((a, b) => a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase()))
|
|
.map(key => <option key={key} value={data[key]}>{key}</option>)}
|
|
</select>
|
|
</div>
|
|
: error
|
|
? <AxiosError error={error}/>
|
|
: <Def/>}
|
|
{catId && <CategoryResult uuid={uuid} catId={catId}/>}
|
|
</>
|
|
}
|
|
|
|
function CategoryResult({uuid, catId}) {
|
|
const [type, setType] = useState(1)
|
|
const {t} = useTranslation('result');
|
|
|
|
const setLoading = useLoadingSwitcher()
|
|
const {data, refresh, error} = useFetch(`/result/${uuid}/category/${catId}`, setLoading, 1)
|
|
|
|
useEffect(() => {
|
|
refresh(`/result/${uuid}/category/${catId}`)
|
|
}, [catId]);
|
|
|
|
useEffect(() => {
|
|
if (data)
|
|
setType(data.type === 3 ? 1 : data.type)
|
|
}, [data]);
|
|
|
|
if (!data) {
|
|
return error
|
|
? <AxiosError error={error}/>
|
|
: <Def/>
|
|
}
|
|
|
|
return <>
|
|
{data.type === 3 && <>
|
|
<ul className="nav nav-tabs">
|
|
<li className="nav-item">
|
|
<a className={"nav-link" + (type === 1 ? " active" : "")} aria-current={(type === 1 ? " page" : "false")} href="#"
|
|
onClick={_ => setType(1)}>{t('poule')}</a>
|
|
</li>
|
|
<li className="nav-item">
|
|
<a className={"nav-link" + (type === 2 ? " active" : "")} aria-current={(type === 2 ? " page" : "false")} href="#"
|
|
onClick={_ => setType(2)}>{t('tournois')}</a>
|
|
</li>
|
|
</ul>
|
|
</>}
|
|
|
|
{type === 1 && <>
|
|
{Object.keys(data.matchs).map(p => <div key={p}>
|
|
{Object.keys(data.matchs).length > 1 && <h4 style={{marginTop: "2em"}}>{t('poule')} {p}</h4>}
|
|
<BuildMatchArray matchs={data.matchs[p]}/>
|
|
<BuildRankArray rankArray={data.rankArray[p]}/>
|
|
</div>)}
|
|
</>}
|
|
|
|
{type === 2 && <>
|
|
<BuildTree treeData={data.trees}/>
|
|
</>}
|
|
|
|
</>
|
|
}
|
|
|
|
function ClubList({uuid}) {
|
|
const [clubId, setClubId] = useState(null)
|
|
const setLoading = useLoadingSwitcher()
|
|
const {data, error} = useFetch(`/result/${uuid}/club/list`, setLoading, 1)
|
|
const {t} = useTranslation('result');
|
|
|
|
useEffect(() => {
|
|
if (data && Object.keys(data).length > 0)
|
|
setClubId(data[Object.keys(data).sort((a, b) => a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase()))[0]])
|
|
}, [data]);
|
|
|
|
return <>
|
|
{data ? <div className="input-group" style={{marginBottom: "1em"}}>
|
|
<h6 style={{margin: "auto 0.5em auto 0"}}>{t('club')}</h6>
|
|
<select className="form-select" aria-label="Select Result Type" onChange={e => setClubId(e.target.value)}>
|
|
{Object.keys(data).sort((a, b) => a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase()))
|
|
.map(key => <option key={key} value={data[key]}>{key}</option>)}
|
|
</select>
|
|
</div>
|
|
: error
|
|
? <AxiosError error={error}/>
|
|
: <Def/>}
|
|
{clubId && <ClubResult uuid={uuid} clubId={clubId}/>}
|
|
</>
|
|
}
|
|
|
|
function ClubResult({uuid, clubId}) {
|
|
const setLoading = useLoadingSwitcher()
|
|
const {data, refresh, error} = useFetch(`/result/${uuid}/club/${clubId}`, setLoading, 1)
|
|
const {t} = useTranslation('result');
|
|
|
|
useEffect(() => {
|
|
refresh(`/result/${uuid}/club/${clubId}`)
|
|
}, [clubId]);
|
|
|
|
return <>
|
|
{data ? <>
|
|
<h3>{t('info')} :</h3>
|
|
<ul>
|
|
<li>{t('nom')} : {data.name}</li>
|
|
<li>{t('nombreDinscris')} : {data.nb_insc}</li>
|
|
</ul>
|
|
<h3>{t('statistique')} :</h3>
|
|
<ul>
|
|
<li>{t('nombreDeMatchDisputé2', {nb: data.nb_match})}</li>
|
|
<li>{t('nombreDeVictoires2', {nb: data.match_w})}</li>
|
|
<li>{t('ratioDeVictoiresMoyen2', {nb: data.ratioVictoire.toFixed(3)})}</li>
|
|
<li>{t('pointsMarqués2', {nb: data.pointMake})}</li>
|
|
<li>{t('pointsReçus2', {nb: data.pointTake})}</li>
|
|
<li>{t('ratioDePointsMoyen2', {nb: data.ratioPoint.toFixed(3)})}</li>
|
|
</ul>
|
|
|
|
<h3>{t('listeDesMembres')} :</h3>
|
|
|
|
<table className="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('catégorie')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('nom')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('victoires')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('défaites')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('ratioVictoires')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('pointsMarqués')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('pointsReçus')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('ratioPoints')}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{data.combs.map((comb, idx) => <tr key={idx}>
|
|
<td style={{textAlign: "center"}}>{comb.cat}</td>
|
|
<td style={{textAlign: "center"}}>{comb.name}</td>
|
|
<td style={{textAlign: "center"}}>{comb.w}</td>
|
|
<td style={{textAlign: "center"}}>{comb.l}</td>
|
|
<td style={{textAlign: "center"}}>{comb.ratioVictoire.toFixed(3)}</td>
|
|
<td style={{textAlign: "center"}}>{comb.pointMake}</td>
|
|
<td style={{textAlign: "center"}}>{comb.pointTake}</td>
|
|
<td style={{textAlign: "center"}}>{comb.ratioPoint.toFixed(3)}</td>
|
|
</tr>)}
|
|
</tbody>
|
|
</table>
|
|
|
|
</>
|
|
: error
|
|
? <AxiosError error={error}/>
|
|
: <Def/>
|
|
}
|
|
</>
|
|
}
|
|
|
|
function CombList({uuid}) {
|
|
const [combId, setCombId] = useState(null)
|
|
const setLoading = useLoadingSwitcher()
|
|
const {data, error} = useFetch(`/result/${uuid}/comb/list`, setLoading, 1)
|
|
const {t} = useTranslation('result');
|
|
|
|
useEffect(() => {
|
|
if (data && Object.keys(data).length > 0)
|
|
setCombId(data[Object.keys(data).sort((a, b) => a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase()))[0]])
|
|
}, [data]);
|
|
|
|
return <>
|
|
{data ? <div className="input-group" style={{marginBottom: "1em"}}>
|
|
<h6 style={{margin: "auto 0.5em auto 0"}}>{t('combattant')}</h6>
|
|
<select className="form-select" aria-label="Select Result Type" onChange={e => setCombId(e.target.value)}>
|
|
{Object.keys(data).sort((a, b) => a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase()))
|
|
.map(key => <option key={key} value={data[key]}>{key}</option>)}
|
|
</select>
|
|
</div>
|
|
: error
|
|
? <AxiosError error={error}/>
|
|
: <Def/>}
|
|
{combId && <CombResult uuid={uuid} combId={combId}/>}
|
|
</>
|
|
}
|
|
|
|
function CombResult({uuid, combId}) {
|
|
const setLoading = useLoadingSwitcher()
|
|
const {data, refresh, error} = useFetch(`/result/${uuid}/comb/${combId}`, setLoading, 1)
|
|
const {t} = useTranslation('result');
|
|
|
|
useEffect(() => {
|
|
refresh(`/result/${uuid}/comb/${combId}`)
|
|
}, [combId]);
|
|
|
|
|
|
if (!data) {
|
|
return error
|
|
? <AxiosError error={error}/>
|
|
: <Def/>
|
|
}
|
|
|
|
return <div>
|
|
<h3>{t('info')} :</h3>
|
|
<ul>
|
|
<li>{t('nomPrénom')} : {data.name}</li>
|
|
<li>{t('club')} : {data.club}</li>
|
|
<li>{t('catégorie')} : {data.cat}</li>
|
|
</ul>
|
|
<h3>{t('statistique')} :</h3>
|
|
<ul>
|
|
<li>{t('tauxDeVictoire2', {
|
|
nb: data.matchs.length === 0 ? "---" : (data.totalWin / data.matchs.length * 100).toFixed(0),
|
|
victoires: data.totalWin,
|
|
matchs: data.matchs.length
|
|
})}
|
|
</li>
|
|
<li>{t('pointsMarqués2', {nb: data.pointMake})}</li>
|
|
<li>{t('pointsReçus2', {nb: data.pointTake})}</li>
|
|
<li>{t('ratioDuScore2', {nb: data.pointRatio.toFixed(3)})}</li>
|
|
</ul>
|
|
|
|
<h3>{t('listeDesMatchs')}:</h3>
|
|
|
|
<table className="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('catégorie')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('adversaire')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t("scores")}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('ratio')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
|
|
{data.matchs.map((match, idx) => <tr key={idx}>
|
|
<td style={{textAlign: "center"}}>{match.poule}</td>
|
|
<td style={{textAlign: "center"}}>{match.adv}</td>
|
|
<td style={{textAlign: "center"}}>{scoreToString(match.score)}</td>
|
|
<td style={{textAlign: "center"}}>{match.ratio.toFixed(3)}</td>
|
|
<td style={{textAlign: "left"}}>{match.win ? <CupImg/> : (match.eq ? <CupImg2/> : "")}</td>
|
|
</tr>)}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
}
|
|
|
|
function CombsResult({uuid}) {
|
|
const setLoading = useLoadingSwitcher()
|
|
const {data, error} = useFetch(`/result/${uuid}/comb`, setLoading, 1)
|
|
const {t} = useTranslation('result');
|
|
|
|
return <>
|
|
{data ? <>
|
|
<h3>{t('statistique')} :</h3>
|
|
<ul>
|
|
<li>{t('nombreDinscris2', {nb: data.nb_insc})}</li>
|
|
<li>{t('nombreDeMatchDisputé2', {nb: data.tt_match})}</li>
|
|
<li>{t('pointsMarqués2', {nb: data.point})}</li>
|
|
</ul>
|
|
|
|
<h3>{t('listeDesCombattants')} :</h3>
|
|
|
|
<table className="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('catégorie')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('club')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('nom')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('victoires')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('défaites')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('ratioVictoires')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('pointsMarqués')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('pointsReçus')}</th>
|
|
<th scope="col" style={{textAlign: "center"}}>{t('ratiosPoints')}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{data.combs.map((comb, idx) => <tr key={idx}>
|
|
<td style={{textAlign: "center"}}>{comb.cat}</td>
|
|
<td style={{textAlign: "center"}}>{comb.club}</td>
|
|
<td style={{textAlign: "center"}}>{comb.name}</td>
|
|
<td style={{textAlign: "center"}}>{comb.w}</td>
|
|
<td style={{textAlign: "center"}}>{comb.l}</td>
|
|
<td style={{textAlign: "center"}}>{comb.ratioVictoire.toFixed(3)}</td>
|
|
<td style={{textAlign: "center"}}>{comb.pointMake}</td>
|
|
<td style={{textAlign: "center"}}>{comb.pointTake}</td>
|
|
<td style={{textAlign: "center"}}>{comb.ratioPoint.toFixed(3)}</td>
|
|
</tr>)}
|
|
</tbody>
|
|
</table>
|
|
</>
|
|
: error
|
|
? <AxiosError error={error}/>
|
|
: <Def/>
|
|
}
|
|
</>
|
|
}
|
|
|
|
function Def() {
|
|
return <div className="list-group">
|
|
<li className="list-group-item"><ThreeDots/></li>
|
|
<li className="list-group-item"><ThreeDots/></li>
|
|
<li className="list-group-item"><ThreeDots/></li>
|
|
<li className="list-group-item"><ThreeDots/></li>
|
|
<li className="list-group-item"><ThreeDots/></li>
|
|
</div>
|
|
}
|