feat: translation result

This commit is contained in:
Thibaut Valentin 2026-01-14 15:51:15 +01:00
parent 9170157dbb
commit d8b6f1ad25
8 changed files with 370 additions and 175 deletions

View File

@ -1,12 +1,14 @@
import i18next from 'https://cdn.jsdelivr.net/npm/i18next@25.7.4/+esm';
import i18nextHttpBackend from 'https://cdn.jsdelivr.net/npm/i18next-http-backend@3.0.2/+esm'
import i18nextBrowserLanguagedetector from 'https://cdn.jsdelivr.net/npm/i18next-browser-languagedetector@8.2.0/+esm'
let apiUrlRoot = ""; let apiUrlRoot = "";
const rootDiv = document.getElementById("safca_api_data"); const rootDiv = document.getElementById("safca_api_data");
const header = `<h4>Résultat de la compétition :</h4>`
const backButton = `<a onclick="setSubPage('home')" href="javascript:void(0);">Retour</a>`
const cupImg = `<img decoding="async" loading="lazy" width="16" height="16" class="wp-image-1635" const cupImg = `<img decoding="async" loading="lazy" width="16" height="16" class="wp-image-1635"
style="width: 16px;" src="https://intra.ffsaf.fr/img/171891.png" style="width: 16px;" src="https://intra.ffsaf.fr/img/171891.png"
alt="">` alt="">`
const voidFunction = () => { const voidFunction = () => {
} }
let lastRf = 0; let lastRf = 0;
@ -41,18 +43,23 @@ function setSubPage(name) {
} }
function homePage() { function homePage() {
rootDiv.innerHTML = header; rootDiv.innerHTML = `<h4>${i18next.t('résultatDeLaCompétition')} :</h4>`;
let content = document.createElement('div'); let content = document.createElement('div');
content.innerHTML = ` content.innerHTML = `
<ul> <ul>
<li><a onclick="setSubPage('poule')" href="javascript:void(0);">Par catégorie</a></li> <li><a id="pouleLink" href="javascript:void(0);">${i18next.t('parCatégorie')}</a></li>
<li><a onclick="setSubPage('comb')" href="javascript:void(0);">Par combattant</a></li> <li><a id="combLink" href="javascript:void(0);">${i18next.t('parCombattant')}</a></li>
<li><a onclick="setSubPage('club')" href="javascript:void(0);">Par club</a></li> <li><a id="clubLink" href="javascript:void(0);">${i18next.t('parClub')}</a></li>
<li><a onclick="setSubPage('all')" href="javascript:void(0);">Tous les combattants</a></li> <li><a id="allLink" href="javascript:void(0);">${i18next.t('tousLesCombattants')}</a></li>
</ul> </ul>
` `
rootDiv.append(content) rootDiv.append(content)
document.getElementById('pouleLink').addEventListener('click', () => setSubPage('poule'));
document.getElementById('combLink').addEventListener('click', () => setSubPage('comb'));
document.getElementById('clubLink').addEventListener('click', () => setSubPage('club'));
document.getElementById('allLink').addEventListener('click', () => setSubPage('all'));
} }
let loadingAnimationStep = 0; let loadingAnimationStep = 0;
@ -63,7 +70,7 @@ function startLoading(root) {
element.id = id; element.id = id;
const anim = setInterval(() => { const anim = setInterval(() => {
let str = "Chargement"; let str = i18next.t('chargement');
for (let i = 0; i < loadingAnimationStep; i++) { for (let i = 0; i < loadingAnimationStep; i++) {
str += "."; str += ".";
} }
@ -84,11 +91,11 @@ function scoreToString(score) {
const scorePrint = (s1) => { const scorePrint = (s1) => {
switch (s1) { switch (s1) {
case -997: case -997:
return "disc."; return i18next.t('disc.');
case -998: case -998:
return "abs."; return i18next.t('abs.');
case -999: case -999:
return "for."; return i18next.t('for.');
case -1000: case -1000:
return ""; return "";
default: default:
@ -111,11 +118,11 @@ function dateToString(date) {
let d = Math.floor((current - date_2) / (1000 * 60 * 60 * 24)); let d = Math.floor((current - date_2) / (1000 * 60 * 60 * 24));
if (d === 0) if (d === 0)
return "Aujourd'hui à " + date_.toLocaleTimeString([], {hour: "2-digit", minute: "2-digit"}); return i18next.t('aujourdhuià', {time: date_.toLocaleTimeString([], {hour: "2-digit", minute: "2-digit"})});
else if (d === 1) else if (d === 1)
return "Hier à " + date_.toLocaleTimeString([], {hour: "2-digit", minute: "2-digit"}); return i18next.t('hierà', {time: date_.toLocaleTimeString([], {hour: "2-digit", minute: "2-digit"})});
else if (d === 2) else if (d === 2)
return "Avant-hier à " + date_.toLocaleTimeString([], {hour: "2-digit", minute: "2-digit"}); return i18next.t('avanthierà', {time: date_.toLocaleTimeString([], {hour: "2-digit", minute: "2-digit"})});
else else
return date_.toLocaleDateString(); return date_.toLocaleDateString();
} }
@ -175,11 +182,11 @@ function buildPouleMenu(isPoule, change_view) {
return li; return li;
} }
const li1 = createTab('Poule', isPoule, function () { const li1 = createTab(i18next.t('poule'), isPoule, function () {
change_view(true); change_view(true);
}); });
ul.appendChild(li1); ul.appendChild(li1);
const li2 = createTab('Tournois', !isPoule, function () { const li2 = createTab(i18next.t('tournois'), !isPoule, function () {
change_view(false); change_view(false);
}); });
ul.appendChild(li2); ul.appendChild(li2);
@ -195,12 +202,12 @@ function buildMatchArray(matchs) {
<figure class="wp-block-table is-style-stripes" style="font-size: 16px"> <figure class="wp-block-table is-style-stripes" style="font-size: 16px">
<table style="width: 800px;overflow: auto"><thead> <table style="width: 800px;overflow: auto"><thead>
<tr> <tr>
<th class="has-text-align-center" data-align="center">Rouge</th> <th class="has-text-align-center" data-align="center">${i18next.t('rouge')}</th>
<th class="has-text-align-center" data-align="center"></th> <th class="has-text-align-center" data-align="center"></th>
<th class="has-text-align-center" data-align="center">Scores</th> <th class="has-text-align-center" data-align="center">${i18next.t('scores')}</th>
<th class="has-text-align-center" data-align="center"></th> <th class="has-text-align-center" data-align="center"></th>
<th class="has-text-align-center" data-align="center">Bleu</th> <th class="has-text-align-center" data-align="center">${i18next.t('bleu')}</th>
<th class="has-text-align-center" data-align="center">Date</th> <th class="has-text-align-center" data-align="center">${i18next.t('date')}</th>
</tr> </tr>
</thead><tbody>` </thead><tbody>`
for (const match of matchs) { for (const match of matchs) {
@ -225,12 +232,12 @@ function buildRankArray(rankArray) {
<table style="width: 600px;overflow: auto"> <table style="width: 600px;overflow: auto">
<thead> <thead>
<tr> <tr>
<th class="has-text-align-center" data-align="center">Place</th> <th class="has-text-align-center" data-align="center">${i18next.t('place')}</th>
<th class="has-text-align-center" data-align="center">Nom</th> <th class="has-text-align-center" data-align="center">${i18next.t('nom')}</th>
<th class="has-text-align-center" data-align="center">Victoire</th> <th class="has-text-align-center" data-align="center">${i18next.t('victoire')}</th>
<th class="has-text-align-center" data-align="center">Ratio</th> <th class="has-text-align-center" data-align="center">${i18next.t('ratio')}</th>
<th class="has-text-align-center" data-align="center">Points marqués</th> <th class="has-text-align-center" data-align="center">${i18next.t('pointsMarqués')}</th>
<th class="has-text-align-center" data-align="center">Points reçus</th> <th class="has-text-align-center" data-align="center">${i18next.t('pointsReçus')}</th>
</tr> </tr>
</thead><tbody>` </thead><tbody>`
for (const row of rankArray) { for (const row of rankArray) {
@ -255,10 +262,12 @@ function buildTree(treeData) {
} }
function poulePage(location) { function poulePage(location) {
rootDiv.innerHTML = header + backButton; rootDiv.innerHTML = `<h4>${i18next.t('résultatDeLaCompétition')} :</h4><a id="homeLink" href="javascript:void(0);">${i18next.t('back')}</a>`;
document.getElementById('homeLink').addEventListener('click', () => setSubPage('home'));
const content = document.createElement('div'); const content = document.createElement('div');
content.style.marginTop = '1em'; content.style.marginTop = '1em';
content.innerHTML = '<h4>Recherche par catégorie</h4>'; content.innerHTML = `<h4>${i18next.t('rechercheParCatégorie')}</h4>`;
const dataContainer = document.createElement('div'); const dataContainer = document.createElement('div');
dataContainer.id = 'data-container'; dataContainer.id = 'data-container';
@ -286,7 +295,7 @@ function poulePage(location) {
for (const g in poule.matchs) { for (const g in poule.matchs) {
if (Object.keys(poule.matchs).length > 1) { if (Object.keys(poule.matchs).length > 1) {
const text = document.createElement('h4'); const text = document.createElement('h4');
text.textContent = `Groupe ${g}`; text.textContent = `${i18next.t('poule')} ${g}`;
text.style.marginTop = '2em'; text.style.marginTop = '2em';
dataContainer.append(text); dataContainer.append(text);
} }
@ -303,7 +312,7 @@ function poulePage(location) {
for (const g in poule.matchs) { for (const g in poule.matchs) {
if (Object.keys(poule.matchs).length > 1) { if (Object.keys(poule.matchs).length > 1) {
const text = document.createElement('h4'); const text = document.createElement('h4');
text.textContent = `Groupe ${g}`; text.textContent = `${i18next.t('poule')} ${g}`;
text.style.marginTop = '2em'; text.style.marginTop = '2em';
dataContainer.append(text); dataContainer.append(text);
} }
@ -323,7 +332,7 @@ function poulePage(location) {
}) })
.catch(e => { .catch(e => {
console.error(e); console.error(e);
dataContainer.replaceChildren(new Text("Erreur de chargement de la poule")); dataContainer.replaceChildren(new Text(i18next.t('erreurDeChargementDeLaPoule')));
}) })
.finally(() => stopLoading(loading)); .finally(() => stopLoading(loading));
} }
@ -334,7 +343,7 @@ function poulePage(location) {
.then(poule => { .then(poule => {
const select = document.createElement('select'); const select = document.createElement('select');
select.setAttribute('id', poule.id); select.setAttribute('id', poule.id);
select.innerHTML = `<option value="0">--Sélectionner une catégorie--</option>`; select.innerHTML = `<option value="0">${i18next.t('--sélectionnerUneCatégorie--')}</option>`;
for (const pouleKey of Object.keys(poule).sort((a, b) => a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase()))) { for (const pouleKey of Object.keys(poule).sort((a, b) => a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase()))) {
select.innerHTML += `<option value="${poule[pouleKey]}">${pouleKey}</option>`; select.innerHTML += `<option value="${poule[pouleKey]}">${pouleKey}</option>`;
} }
@ -356,7 +365,7 @@ function poulePage(location) {
loadPoule(); loadPoule();
} }
}) })
.catch(() => rootDiv.append(new Text("Erreur de chargement des catégories"))) .catch(() => rootDiv.append(new Text(i18next.t('erreurDeChargementDesCatégories'))))
.finally(() => stopLoading(loading)); .finally(() => stopLoading(loading));
rfFonction = () => { rfFonction = () => {
@ -372,28 +381,33 @@ function buildCombView(comb) {
let arrayContent = ` let arrayContent = `
<h3>Info :</h3> <h3>Info :</h3>
<ul> <ul>
<li>Nom Pr&eacute;nom : ${comb.name}</li> <li>${i18next.t('nomPrénom')} : ${comb.name}</li>
<li>Club : ${comb.club}</li> <li>${i18next.t('club')} : ${comb.club}</li>
<li>Cat&eacute;gorie : ${comb.cat}</li> <li>${i18next.t('catégorie')} : ${comb.cat}</li>
</ul> </ul>
<h3>Statistique :</h3> <h3>${i18next.t('statistique')} :</h3>
<ul> <ul>
<li>Taux de victoire : ${comb.matchs.length === 0 ? "---" : (comb.totalWin / comb.matchs.length * 100).toFixed(0)}% (${comb.totalWin} sur ${comb.matchs.length})</li> <li>${i18next.t('tauxDeVictoire2', {
<li>Points marqués : ${comb.pointMake}</li> nb: comb.matchs.length === 0 ? "---" : (comb.totalWin / comb.matchs.length * 100).toFixed(0),
<li>Points reçus : ${comb.pointTake}</li> victoires: comb.totalWin,
<li>Ratio du score (point marqu&eacute; / point re&ccedil;u): ${comb.pointRatio.toFixed(3)}</li> matchs: comb.matchs.length
})}
</li>
<li>${i18next.t('pointsMarqués2', {nb: comb.pointMake})}</li>
<li>${i18next.t('pointsReçus2', {nb: comb.pointTake})}</li>
<li>${i18next.t('ratioDuScore2', {nb: comb.pointRatio.toFixed(3)})}</li>
</ul> </ul>
<h3>Liste des matchs:</h3> <h3>${i18next.t('listeDesMatchs')}:</h3>
<figure class="wp-block-table is-style-stripes" style="font-size: 16px"> <figure class="wp-block-table is-style-stripes" style="font-size: 16px">
<table style="width: 700px;overflow: auto"><thead> <table style="width: 700px;overflow: auto"><thead>
<tr> <tr>
<th class="has-text-align-center" data-align="center">Date</th> <th class="has-text-align-center" data-align="center">${i18next.t('date')}</th>
<th class="has-text-align-center" data-align="center">Poule</th> <th class="has-text-align-center" data-align="center">${i18next.t('poule')}</th>
<th class="has-text-align-center" data-align="center">Adversaire</th> <th class="has-text-align-center" data-align="center">${i18next.t('adversaire')}</th>
<th class="has-text-align-center" data-align="center">Scores</th> <th class="has-text-align-center" data-align="center">${i18next.t('scores')}</th>
<th class="has-text-align-center" data-align="center">Ratio</th> <th class="has-text-align-center" data-align="center">${i18next.t('ratio')}</th>
<th class="has-text-align-center" data-align="center"></th> <th class="has-text-align-center" data-align="center"></th>
</tr> </tr>
</thead><tbody>` </thead><tbody>`
@ -414,10 +428,12 @@ function buildCombView(comb) {
} }
function combPage(location) { function combPage(location) {
rootDiv.innerHTML = header + backButton; rootDiv.innerHTML = `<h4>${i18next.t('résultatDeLaCompétition')} :</h4><a id="homeLink" href="javascript:void(0);">${i18next.t('back')}</a>`;
document.getElementById('homeLink').addEventListener('click', () => setSubPage('home'));
const content = document.createElement('div'); const content = document.createElement('div');
content.style.marginTop = '1em'; content.style.marginTop = '1em';
content.innerHTML = '<h4>Recherche par combattant</h4>'; content.innerHTML = `<h4>${i18next.t('rechercheParCombattant')}</h4>`;
const dataContainer = document.createElement('div'); const dataContainer = document.createElement('div');
dataContainer.id = 'data-container'; dataContainer.id = 'data-container';
@ -430,7 +446,7 @@ function combPage(location) {
console.log(comb); console.log(comb);
dataContainer.replaceChildren(buildCombView(comb)); dataContainer.replaceChildren(buildCombView(comb));
}) })
.catch(() => dataContainer.replaceChildren(new Text("Erreur de chargement du combattant"))) .catch(() => dataContainer.replaceChildren(new Text(i18next.t('erreurDeChargementDuCombattant'))))
.finally(() => stopLoading(loading)); .finally(() => stopLoading(loading));
} }
@ -439,7 +455,7 @@ function combPage(location) {
.then(response => response.json()) .then(response => response.json())
.then(combs => { .then(combs => {
const select = document.createElement('select'); const select = document.createElement('select');
select.innerHTML = `<option value="0">--Sélectionner un combattant--</option>`; select.innerHTML = `<option value="0">${i18next.t('--sélectionnerUnCombattant--')}</option>`;
for (const comb of Object.keys(combs).sort()) { for (const comb of Object.keys(combs).sort()) {
select.innerHTML += `<option value="${combs[comb]}">${comb}</option>`; select.innerHTML += `<option value="${combs[comb]}">${comb}</option>`;
} }
@ -458,7 +474,7 @@ function combPage(location) {
loadComb(tmp); loadComb(tmp);
} }
}) })
.catch(() => rootDiv.append(new Text("Erreur de chargement des combattants"))) .catch(() => rootDiv.append(new Text(i18next.t('erreurDeChargementDesCombattants'))))
.finally(() => stopLoading(loading)); .finally(() => stopLoading(loading));
rootDiv.append(content) rootDiv.append(content)
@ -467,34 +483,34 @@ function combPage(location) {
function buildClubView(club) { function buildClubView(club) {
const pouleDiv = document.createElement('div'); const pouleDiv = document.createElement('div');
let arrayContent = ` let arrayContent = `
<h3>Info :</h3> <h3>${i18next.t('info')} :</h3>
<ul> <ul>
<li>Nom : ${club.name}</li> <li>${i18next.t('nom')} : ${club.name}</li>
<li>Nombre d'inscris : ${club.nb_insc}</li> <li>${i18next.t('nombreDinscris')} : ${club.nb_insc}</li>
</ul> </ul>
<h3>Statistique :</h3> <h3>${i18next.t('statistique')} :</h3>
<ul> <ul>
<li>Nombre de match disput&eacute; : ${club.nb_match}</li> <li>${i18next.t('nombreDeMatchDisputé2', {nb: club.nb_match})}</li>
<li>Nombre de victoires : ${club.match_w}</li> <li>${i18next.t('nombreDeVictoires2', {nb: club.match_w})}</li>
<li>Ratio de victoires moyen : ${club.ratioVictoire.toFixed(3)}</li> <li>${i18next.t('ratioDeVictoiresMoyen2', {nb: club.ratioVictoire.toFixed(3)})}</li>
<li>Points marqués : ${club.pointMake}</li> <li>${i18next.t('pointsMarqués2', {nb: club.pointMake})}</li>
<li>Points reçus : ${club.pointTake}</li> <li>${i18next.t('pointsReçus2', {nb: club.pointTake})}</li>
<li>Ratio de points moyen : ${club.ratioPoint.toFixed(3)}</li> <li>${i18next.t('ratioDePointsMoyen2', {nb: club.ratioPoint.toFixed(3)})}</li>
</ul> </ul>
<h3>Liste des menbres :</h3> <h3>${i18next.t('listeDesMenbres')} :</h3>
<figure class="wp-block-table is-style-stripes" style="font-size: 16px"> <figure class="wp-block-table is-style-stripes" style="font-size: 16px">
<table style="width: 800px;overflow: auto"><thead> <table style="width: 800px;overflow: auto"><thead>
<tr> <tr>
<th class="has-text-align-center" data-align="center">Cat&eacute;gorie</th> <th class="has-text-align-center" data-align="center">${i18next.t('catégorie')}</th>
<th class="has-text-align-center" data-align="center">Nom</th> <th class="has-text-align-center" data-align="center">${i18next.t('nom')}</th>
<th class="has-text-align-center" data-align="center">Victoires</th> <th class="has-text-align-center" data-align="center">${i18next.t('victoires')}</th>
<th class="has-text-align-center" data-align="center">D&eacute;faites</th> <th class="has-text-align-center" data-align="center">${i18next.t('défaites')}</th>
<th class="has-text-align-center" data-align="center">Ratio victoires</th> <th class="has-text-align-center" data-align="center">${i18next.t('ratioVictoires')}</th>
<th class="has-text-align-center" data-align="center">Points marqués</th> <th class="has-text-align-center" data-align="center">${i18next.t('pointsMarqués')}</th>
<th class="has-text-align-center" data-align="center">Points reçus</th> <th class="has-text-align-center" data-align="center">${i18next.t('pointsReçus')}</th>
<th class="has-text-align-center" data-align="center">Ratio points</th> <th class="has-text-align-center" data-align="center">${i18next.t('ratioPoints')}</th>
</tr> </tr>
</thead><tbody>` </thead><tbody>`
for (const comb of club.combs) { for (const comb of club.combs) {
@ -516,10 +532,12 @@ function buildClubView(club) {
} }
function clubPage(location) { function clubPage(location) {
rootDiv.innerHTML = header + backButton; rootDiv.innerHTML = `<h4>${i18next.t('résultatDeLaCompétition')} :</h4><a id="homeLink" href="javascript:void(0);">${i18next.t('back')}</a>`;
document.getElementById('homeLink').addEventListener('click', () => setSubPage('home'));
const content = document.createElement('div'); const content = document.createElement('div');
content.style.marginTop = '1em'; content.style.marginTop = '1em';
content.innerHTML = '<h4>Recherche par club</h4>'; content.innerHTML = `<h4>${i18next.t('rechercheParClub')}</h4>`;
const dataContainer = document.createElement('div'); const dataContainer = document.createElement('div');
dataContainer.id = 'data-container'; dataContainer.id = 'data-container';
@ -532,7 +550,7 @@ function clubPage(location) {
console.log(club); console.log(club);
dataContainer.replaceChildren(buildClubView(club)); dataContainer.replaceChildren(buildClubView(club));
}) })
.catch(() => dataContainer.replaceChildren(new Text("Erreur de chargement du club"))) .catch(() => dataContainer.replaceChildren(new Text(i18next.t('erreurDeChargementDuClub'))))
.finally(() => stopLoading(loading)); .finally(() => stopLoading(loading));
} }
@ -541,7 +559,7 @@ function clubPage(location) {
.then(response => response.json()) .then(response => response.json())
.then(clubs => { .then(clubs => {
const select = document.createElement('select'); const select = document.createElement('select');
select.innerHTML = `<option value="0">--Sélectionner un club--</option>`; select.innerHTML = `<option value="0">${i18next.t('--sélectionnerUnClub--')}</option>`;
for (const club of Object.keys(clubs).sort()) { for (const club of Object.keys(clubs).sort()) {
select.innerHTML += `<option value="${clubs[club]}">${club}</option>`; select.innerHTML += `<option value="${clubs[club]}">${club}</option>`;
} }
@ -562,7 +580,7 @@ function clubPage(location) {
loadComb(tmp); loadComb(tmp);
} }
}) })
.catch(() => rootDiv.append(new Text("Erreur de chargement des clubs"))) .catch(() => rootDiv.append(new Text(i18next.t('erreurDeChargementDesClubs'))))
.finally(() => stopLoading(loading)); .finally(() => stopLoading(loading));
rootDiv.append(content) rootDiv.append(content)
@ -571,27 +589,27 @@ function clubPage(location) {
function buildCombsView(combs) { function buildCombsView(combs) {
const pouleDiv = document.createElement('div'); const pouleDiv = document.createElement('div');
let arrayContent = ` let arrayContent = `
<h3>Statistique :</h3> <h3>${i18next.t('statistique')} :</h3>
<ul> <ul>
<li>Nombre d'inscris : ${combs.nb_insc}</li> <li>${i18next.t('nombreDinscris2', {nb: combs.nb_insc})}</li>
<li>Nombre de match disput&eacute; : ${combs.tt_match}</li> <li>${i18next.t('nombreDeMatchDisputé2', {nb: combs.tt_match})}</li>
<li>Points marqués : ${combs.point}</li> <li>${i18next.t('pointsMarqués2', {nb: combs.point})}</li>
</ul> </ul>
<h3>Liste des combattants :</h3> <h3>${i18next.t('listeDesCombattants')} :</h3>
<figure class="wp-block-table is-style-stripes" style="font-size: 16px"> <figure class="wp-block-table is-style-stripes" style="font-size: 16px">
<table style="width: 1200px;overflow: auto"><thead> <table style="width: 1200px;overflow: auto"><thead>
<tr> <tr>
<th class="has-text-align-center" data-align="center">Cat&eacute;gorie</th> <th class="has-text-align-center" data-align="center">${i18next.t('catégorie')}</th>
<th class="has-text-align-center" data-align="center">Club</th> <th class="has-text-align-center" data-align="center">${i18next.t('club')}</th>
<th class="has-text-align-center" data-align="center">Nom</th> <th class="has-text-align-center" data-align="center">${i18next.t('nom')}</th>
<th class="has-text-align-center" data-align="center">Victoires</th> <th class="has-text-align-center" data-align="center">${i18next.t('victoires')}</th>
<th class="has-text-align-center" data-align="center">D&eacute;faites</th> <th class="has-text-align-center" data-align="center">${i18next.t('défaites')}</th>
<th class="has-text-align-center" data-align="center">Ratio victoires</th> <th class="has-text-align-center" data-align="center">${i18next.t('ratioVictoires')}</th>
<th class="has-text-align-center" data-align="center">Points marqués</th> <th class="has-text-align-center" data-align="center">${i18next.t('pointsMarqués')}</th>
<th class="has-text-align-center" data-align="center">Points reçus</th> <th class="has-text-align-center" data-align="center">${i18next.t('pointsReçus')}</th>
<th class="has-text-align-center" data-align="center">Ratios points</th> <th class="has-text-align-center" data-align="center">${i18next.t('ratiosPoints')}</th>
</tr> </tr>
</thead><tbody>` </thead><tbody>`
for (const comb of combs.combs) { for (const comb of combs.combs) {
@ -614,7 +632,9 @@ function buildCombsView(combs) {
} }
function combsPage() { function combsPage() {
rootDiv.innerHTML = header + backButton; rootDiv.innerHTML = `<h4>${i18next.t('résultatDeLaCompétition')} :</h4><a id="homeLink" href="javascript:void(0);">${i18next.t('back')}</a>`;
document.getElementById('homeLink').addEventListener('click', () => setSubPage('home'));
const content = document.createElement('div'); const content = document.createElement('div');
content.style.marginTop = '1em'; content.style.marginTop = '1em';
@ -628,26 +648,44 @@ function combsPage() {
console.log(combs); console.log(combs);
dataContainer.replaceChildren(buildCombsView(combs)); dataContainer.replaceChildren(buildCombsView(combs));
}) })
.catch(() => dataContainer.replaceChildren(new Text("Erreur de chargement de la liste"))) .catch(() => dataContainer.replaceChildren(new Text(i18next.t('erreurDeChargementDeLaListe'))))
.finally(() => stopLoading(loading)); .finally(() => stopLoading(loading));
content.append(dataContainer); content.append(dataContainer);
rootDiv.append(content) rootDiv.append(content)
} }
window.addEventListener("load", () => { export async function initCompetitionApi(apiUrlRoot_) {
let path = document.getElementById('safca_api_script').src; apiUrlRoot = apiUrlRoot_;
const urlParams = new URLSearchParams(new URL(path).search);
apiUrlRoot = path.substring(0, path.lastIndexOf('/')) + "/api/public/result/" + urlParams.get("id"); const options = {
order: ['querystring', 'cookie', 'localStorage', 'sessionStorage', 'navigator', 'htmlTag'],
caches: [],
}
await i18next
.use(i18nextHttpBackend)
.use(i18nextBrowserLanguagedetector)
.init({
fallbackLng: 'fr',
debug: true,
interpolation: {
escapeValue: true,
},
detection: options,
ns: ['result'],
defaultNS: 'result',
})
console.log("apiUrlRoot:", apiUrlRoot) console.log("apiUrlRoot:", apiUrlRoot)
console.log("FFSAF Competition API initialized.")
let hash = window.location.hash.substring(1); let hash = window.location.hash.substring(1);
if (hash.length === 0) if (hash.length === 0)
setSubPage('home'); setSubPage('home');
else else
setSubPage(hash); setSubPage(hash);
}); }
class TreeNode { class TreeNode {
constructor(data) { constructor(data) {
@ -671,7 +709,7 @@ class TreeNode {
} }
function initTree(data_in) { function initTree(data_in) {
out = []; let out = [];
for (const din of data_in) { for (const din of data_in) {
out.push(parseTree(din)); out.push(parseTree(din));
} }
@ -818,7 +856,7 @@ function drawGraph(root = []) {
ctx.textBaseline = 'top'; ctx.textBaseline = 'top';
for (let i = 0; i < scores.length; i++) { for (let i = 0; i < scores.length; i++) {
const score = scores[i].s1+"-"+scores[i].s2; const score = scores[i].s1 + "-" + scores[i].s2;
const div = (scores.length <= 2) ? 2 : (scores.length >= 4) ? 4 : 3; const div = (scores.length <= 2) ? 2 : (scores.length >= 4) ? 4 : 3;
const text = ctx.measureText(score); const text = ctx.measureText(score);
let dx = (size * 2 - text.width) / 2; let dx = (size * 2 - text.width) / 2;

View File

@ -0,0 +1,67 @@
{
"--sélectionnerUnClub--": "--Select a club--",
"--sélectionnerUnCombattant--": "--Select a fighter--",
"--sélectionnerUneCatégorie--": "--Select a category--",
"abs.": "abs.",
"adversaire": "Opponent",
"aujourdhuià": "Today at {{time}}",
"avanthierà": "Day before yesterday at {{time}}",
"back": "« back",
"bleu": "Blue",
"catégorie": "Category",
"chargement": "Loading",
"club": "Club",
"combattant": "Fighter",
"combattants": "Fighters",
"date": "Date",
"disc.": "DQ",
"défaites": "Losses",
"erreurDeChargementDeLaListe": "Error loading the list",
"erreurDeChargementDeLaPoule": "Error loading the pool",
"erreurDeChargementDesCatégories": "Error loading categories",
"erreurDeChargementDesClubs": "Error loading clubs",
"erreurDeChargementDesCombattants": "Error loading fighters",
"erreurDeChargementDuClub": "Error loading club",
"erreurDeChargementDuCombattant": "Error loading fighter",
"for.": "forf.",
"hierà": "Yesterday at {{time}}",
"info": "Info",
"listeDesCombattants": "List of fighters",
"listeDesMatchs": "List of matches",
"listeDesMembres": "List of members",
"listeDesMenbres": "List of members",
"nom": "Last name",
"nomPrénom": "Last name First name",
"nombreDeMatchDisputé2": "Number of matches played: {{nb}}",
"nombreDeVictoires2": "Number of wins: {{nb}}",
"nombreDinscris": "Number of registered",
"nombreDinscris2": "Number of registered: {{nb}}",
"parCatégorie": "By category",
"parClub": "By club",
"parCombattant": "By fighter",
"place": "Place",
"pointsMarqués": "Points scored",
"pointsMarqués2": "Points scored: {{nb}}",
"pointsReçus": "Points received",
"pointsReçus2": "Points received: {{nb}}",
"poule": "Pool",
"ratio": "Ratio",
"ratioDePointsMoyen2": "Average points ratio: {{nb}}",
"ratioDeVictoiresMoyen2": "Average win ratio: {{nb}}",
"ratioDuScore2": "Score ratio (points scored / points received): {{nb}}",
"ratioPoints": "Points ratio",
"ratioVictoires": "Win ratio",
"ratiosPoints": "Points ratios",
"rechercheParCatégorie": "Search by category",
"rechercheParClub": "Search by club",
"rechercheParCombattant": "Search by fighter",
"rouge": "Red",
"résultatDeLaCompétition": "Competition result",
"scores": "Scores",
"statistique": "Statistics",
"tauxDeVictoire2": "Win rate: {{nb}}% ({{victoires}} out of {{matchs}})",
"tournois": "Tournaments",
"tousLesCombattants": "All fighters",
"victoire": "Win",
"victoires": "Wins"
}

View File

@ -0,0 +1,67 @@
{
"--sélectionnerUnClub--": "--Sélectionner un club--",
"--sélectionnerUnCombattant--": "--Sélectionner un combattant--",
"--sélectionnerUneCatégorie--": "--Sélectionner une catégorie--",
"abs.": "abs.",
"adversaire": "Adversaire",
"aujourdhuià": "Aujourd'hui à {{time}}",
"avanthierà": "Avant-hier à {{time}}",
"back": "« retour",
"bleu": "Bleu",
"catégorie": "Catégorie",
"chargement": "Chargement",
"club": "Club",
"combattant": "Combattant",
"combattants": "Combattants",
"date": "Date",
"disc.": "disc.",
"défaites": "Défaites",
"erreurDeChargementDeLaListe": "Erreur de chargement de la liste",
"erreurDeChargementDeLaPoule": "Erreur de chargement de la poule",
"erreurDeChargementDesCatégories": "Erreur de chargement des catégories",
"erreurDeChargementDesClubs": "Erreur de chargement des clubs",
"erreurDeChargementDesCombattants": "Erreur de chargement des combattants",
"erreurDeChargementDuClub": "Erreur de chargement du club",
"erreurDeChargementDuCombattant": "Erreur de chargement du combattant",
"for.": "for.",
"hierà": "Hier à {{time}}",
"info": "Info",
"listeDesCombattants": "Liste des combattants",
"listeDesMatchs": "Liste des matchs",
"listeDesMembres": "Liste des membres",
"listeDesMenbres": "Liste des menbres",
"nom": "Nom",
"nomPrénom": "Nom Prénom",
"nombreDeMatchDisputé2": "Nombre de match disputé : {{nb}}",
"nombreDeVictoires2": "Nombre de victoires : {{nb}} ",
"nombreDinscris": "Nombre d'inscris",
"nombreDinscris2": "Nombre d'inscris : {{nb}}",
"parCatégorie": "Par catégorie",
"parClub": "Par club",
"parCombattant": "Par combattant",
"place": "Place",
"pointsMarqués": "Points marqués",
"pointsMarqués2": "Points marqués : {{nb}}",
"pointsReçus": "Points reçus",
"pointsReçus2": "Points reçus : {{nb}}",
"poule": "Poule",
"ratio": "Ratio",
"ratioDePointsMoyen2": "Ratio de points moyen : {{nb}}",
"ratioDeVictoiresMoyen2": "Ratio de victoires moyen : {{nb}}",
"ratioDuScore2": "Ratio du score (point marqué / point reçu): {{nb}}",
"ratioPoints": "Ratio points",
"ratioVictoires": "Ratio victoires",
"ratiosPoints": "Ratios points",
"rechercheParCatégorie": "Recherche par catégorie",
"rechercheParClub": "Recherche par club",
"rechercheParCombattant": "Recherche par combattant",
"rouge": "Rouge",
"résultatDeLaCompétition": "Résultat de la compétition",
"scores": "Scores",
"statistique": "Statistique",
"tauxDeVictoire2": "Taux de victoire : {{nb}}% ({{victoires}} sur {{matchs}})",
"tournois": "Tournois",
"tousLesCombattants": "Tous les combattants",
"victoire": "Victoire",
"victoires": "Victoires"
}

View File

@ -26,7 +26,7 @@ i18n
escapeValue: false, // not needed for react as it escapes by default escapeValue: false, // not needed for react as it escapes by default
}, },
detection: options, detection: options,
ns: ['common'], ns: ['common', 'result'],
defaultNS: 'common', defaultNS: 'common',
}); });

View File

@ -217,8 +217,12 @@ function Menu({menuActions, compUuid}) {
} }
const copyScriptToClipboard = () => { const copyScriptToClipboard = () => {
navigator.clipboard.writeText(`<div id='safca_api_data'></div> navigator.clipboard.writeText(`<!--suppress ALL -->
<script id="safca_api_script" type="text/javascript" src="${vite_url}/competition.js?id=${compUuid}"></script>` <div id='safca_api_data'></div>
<script type="module">
import {initCompetitionApi} from '${vite_url}/competition.js';
initCompetitionApi("${vite_url}/api/public/result/${compUuid}")
</script>`
).then(() => { ).then(() => {
toast.success("Texte copié dans le presse-papier ! Collez-le dans une balise HTML sur votre WordPress."); toast.success("Texte copié dans le presse-papier ! Collez-le dans une balise HTML sur votre WordPress.");
}).catch(err => { }).catch(err => {

View File

@ -3,7 +3,7 @@ import {useLoadingSwitcher} from "../../hooks/useLoading.jsx";
import {useFetch} from "../../hooks/useFetch.js"; import {useFetch} from "../../hooks/useFetch.js";
import {AxiosError} from "../../components/AxiosError.jsx"; import {AxiosError} from "../../components/AxiosError.jsx";
import {ThreeDots} from "react-loader-spinner"; import {ThreeDots} from "react-loader-spinner";
import {useAuth} from "../../hooks/useAuth.jsx"; import {useTranslation} from "react-i18next";
export function ResultList() { export function ResultList() {
const navigate = useNavigate(); const navigate = useNavigate();
@ -25,14 +25,15 @@ export function ResultList() {
} }
function MakeCentralPanel({data, navigate}) { function MakeCentralPanel({data, navigate}) {
const {t} = useTranslation();
return <> return <>
<div className="mb-4"> <div className="mb-4">
<h4>Compétition:</h4> <h4>{t('competition', {count: data.length})}:</h4>
<div className="list-group"> <div className="list-group">
{data.sort((a, b) => new Date(b[2].split('T')[0]) - new Date(a[2].split('T')[0])).map((o) => ( {data.sort((a, b) => new Date(b[2].split('T')[0]) - new Date(a[2].split('T')[0])).map((o) => (
<li className="list-group-item list-group-item-action" key={o[0]} <li className="list-group-item list-group-item-action" key={o[0]}
onClick={e => navigate(`${o[0]}`)}>{o[1]}</li>))} onClick={() => navigate(`${o[0]}`)}>{o[1]}</li>))}
</div> </div>
</div> </div>
</> </>

View File

@ -2,10 +2,13 @@ import {LoadingProvider} from "../../hooks/useLoading.jsx";
import {Outlet} from "react-router-dom"; import {Outlet} from "react-router-dom";
import {ResultList} from "./ResultList.jsx"; import {ResultList} from "./ResultList.jsx";
import {ResultView} from "./ResultView.jsx"; import {ResultView} from "./ResultView.jsx";
import {useTranslation} from "react-i18next";
export function ResultRoot() { export function ResultRoot() {
const {t} = useTranslation();
return <> return <>
<h1>Résultat</h1> <h1>{t("result", {count: 1})}</h1>
<LoadingProvider> <LoadingProvider>
<Outlet/> <Outlet/>
</LoadingProvider> </LoadingProvider>

View File

@ -7,6 +7,7 @@ import React, {useEffect, useState} from "react";
import {DrawGraph} from "./DrawGraph.jsx"; import {DrawGraph} from "./DrawGraph.jsx";
import {TreeNode} from "../../utils/TreeUtils.js"; import {TreeNode} from "../../utils/TreeUtils.js";
import {scoreToString} from "../../utils/CompetitionTools.js"; import {scoreToString} from "../../utils/CompetitionTools.js";
import {useTranslation} from "react-i18next";
function CupImg() { function CupImg() {
return <img decoding="async" loading="lazy" width="16" height="16" className="wp-image-1635" return <img decoding="async" loading="lazy" width="16" height="16" className="wp-image-1635"
@ -18,10 +19,11 @@ export function ResultView() {
const {uuid} = useParams() const {uuid} = useParams()
const navigate = useNavigate(); const navigate = useNavigate();
const [resultShow, setResultShow] = useState("cat") const [resultShow, setResultShow] = useState("cat")
const {t} = useTranslation('result');
return <> return <>
<button type="button" className="btn btn-link" onClick={() => navigate("/result")}> <button type="button" className="btn btn-link" onClick={() => navigate("/result")}>
&laquo; retour {t('back')}
</button> </button>
<MenuBar resultShow={resultShow} setResultShow={setResultShow}/> <MenuBar resultShow={resultShow} setResultShow={setResultShow}/>
@ -40,22 +42,23 @@ export function ResultView() {
// || resultShow && resultShow === "club_all" && <ClubAllResult uuid={uuid}/> // || resultShow && resultShow === "club_all" && <ClubAllResult uuid={uuid}/>
function MenuBar({resultShow, setResultShow}) { function MenuBar({resultShow, setResultShow}) {
const {t} = useTranslation('result');
return <ul className="nav nav-tabs"> return <ul className="nav nav-tabs">
<li className="nav-item"> <li className="nav-item">
<a className={"nav-link my-1" + (resultShow === "cat" ? " active" : "")} aria-current={(resultShow === "cat" ? " page" : "false")} <a className={"nav-link my-1" + (resultShow === "cat" ? " active" : "")} aria-current={(resultShow === "cat" ? " page" : "false")}
href="#" onClick={_ => setResultShow("cat")}>Par catégorie</a> href="#" onClick={_ => setResultShow("cat")}>{t('parCatégorie')}</a>
</li> </li>
<li className="nav-item"> <li className="nav-item">
<a className={"nav-link my-1" + (resultShow === "club" ? " active" : "")} aria-current={(resultShow === "club" ? " page" : "false")} <a className={"nav-link my-1" + (resultShow === "club" ? " active" : "")} aria-current={(resultShow === "club" ? " page" : "false")}
href="#" onClick={_ => setResultShow("club")}>Par club</a> href="#" onClick={_ => setResultShow("club")}>{t('parClub')}</a>
</li> </li>
<li className="nav-item"> <li className="nav-item">
<a className={"nav-link my-1" + (resultShow === "comb" ? " active" : "")} aria-current={(resultShow === "comb" ? " page" : "false")} <a className={"nav-link my-1" + (resultShow === "comb" ? " active" : "")} aria-current={(resultShow === "comb" ? " page" : "false")}
href="#" onClick={_ => setResultShow("comb")}>Par combattant</a> href="#" onClick={_ => setResultShow("comb")}>{t('parCombattant')}</a>
</li> </li>
<li className="nav-item"> <li className="nav-item">
<a className={"nav-link my-1" + (resultShow === "combs" ? " active" : "")} aria-current={(resultShow === "combs" ? " page" : "false")} <a className={"nav-link my-1" + (resultShow === "combs" ? " active" : "")} aria-current={(resultShow === "combs" ? " page" : "false")}
href="#" onClick={_ => setResultShow("combs")}>Combattants</a> href="#" onClick={_ => setResultShow("combs")}>{t('combattants')}</a>
</li> </li>
</ul> </ul>
@ -69,15 +72,16 @@ function MenuBar({resultShow, setResultShow}) {
} }
function BuildMatchArray({matchs}) { function BuildMatchArray({matchs}) {
const {t} = useTranslation('result');
return <> return <>
<table className="table table-striped"> <table className="table table-striped">
<thead> <thead>
<tr> <tr>
<th scope="col" style={{textAlign: "center"}}>Rouge</th> <th scope="col" style={{textAlign: "center"}}>{t('rouge')}</th>
<th scope="col" style={{textAlign: "center"}}></th> <th scope="col" style={{textAlign: "center"}}></th>
<th scope="col" style={{textAlign: "center"}}>Scores</th> <th scope="col" style={{textAlign: "center"}}>{t('scores')}</th>
<th scope="col" style={{textAlign: "center"}}></th> <th scope="col" style={{textAlign: "center"}}></th>
<th scope="col" style={{textAlign: "center"}}>Bleu</th> <th scope="col" style={{textAlign: "center"}}>{t('bleu')}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -94,16 +98,17 @@ function BuildMatchArray({matchs}) {
} }
function BuildRankArray({rankArray}) { function BuildRankArray({rankArray}) {
const {t} = useTranslation('result');
return <> return <>
<table className="table table-striped"> <table className="table table-striped">
<thead> <thead>
<tr> <tr>
<th scope="col" style={{textAlign: "center"}}>Place</th> <th scope="col" style={{textAlign: "center"}}>{t('place')}</th>
<th scope="col" style={{textAlign: "center"}}>Nom</th> <th scope="col" style={{textAlign: "center"}}>{t('nom')}</th>
<th scope="col" style={{textAlign: "center"}}>Victoire</th> <th scope="col" style={{textAlign: "center"}}>{t('victoire')}</th>
<th scope="col" style={{textAlign: "center"}}>Ratio</th> <th scope="col" style={{textAlign: "center"}}>{t('ratio')}</th>
<th scope="col" style={{textAlign: "center"}}>Points marqués</th> <th scope="col" style={{textAlign: "center"}}>{t('pointsMarqués')}</th>
<th scope="col" style={{textAlign: "center"}}>Points reçus</th> <th scope="col" style={{textAlign: "center"}}>{t('pointsReçus')}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -147,6 +152,7 @@ function CategoryList({uuid}) {
const [catId, setCatId] = useState(null) const [catId, setCatId] = useState(null)
const setLoading = useLoadingSwitcher() const setLoading = useLoadingSwitcher()
const {data, error} = useFetch(`/result/${uuid}/category/list`, setLoading, 1) const {data, error} = useFetch(`/result/${uuid}/category/list`, setLoading, 1)
const {t} = useTranslation('result');
useEffect(() => { useEffect(() => {
if (data && Object.keys(data).length > 0) if (data && Object.keys(data).length > 0)
@ -155,7 +161,7 @@ function CategoryList({uuid}) {
return <> return <>
{data ? <div className="input-group" style={{marginBottom: "1em"}}> {data ? <div className="input-group" style={{marginBottom: "1em"}}>
<h6 style={{margin: "auto 0.5em auto 0"}}>Catégorie</h6> <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)}> <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())) {Object.keys(data).sort((a, b) => a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase()))
.map(key => <option key={key} value={data[key]}>{key}</option>)} .map(key => <option key={key} value={data[key]}>{key}</option>)}
@ -170,6 +176,7 @@ function CategoryList({uuid}) {
function CategoryResult({uuid, catId}) { function CategoryResult({uuid, catId}) {
const [type, setType] = useState(1) const [type, setType] = useState(1)
const {t} = useTranslation('result');
const setLoading = useLoadingSwitcher() const setLoading = useLoadingSwitcher()
const {data, refresh, error} = useFetch(`/result/${uuid}/category/${catId}`, setLoading, 1) const {data, refresh, error} = useFetch(`/result/${uuid}/category/${catId}`, setLoading, 1)
@ -194,18 +201,18 @@ function CategoryResult({uuid, catId}) {
<ul className="nav nav-tabs"> <ul className="nav nav-tabs">
<li className="nav-item"> <li className="nav-item">
<a className={"nav-link" + (type === 1 ? " active" : "")} aria-current={(type === 1 ? " page" : "false")} href="#" <a className={"nav-link" + (type === 1 ? " active" : "")} aria-current={(type === 1 ? " page" : "false")} href="#"
onClick={_ => setType(1)}>Poule</a> onClick={_ => setType(1)}>{t('poule')}</a>
</li> </li>
<li className="nav-item"> <li className="nav-item">
<a className={"nav-link" + (type === 2 ? " active" : "")} aria-current={(type === 2 ? " page" : "false")} href="#" <a className={"nav-link" + (type === 2 ? " active" : "")} aria-current={(type === 2 ? " page" : "false")} href="#"
onClick={_ => setType(2)}>Tournois</a> onClick={_ => setType(2)}>{t('tournois')}</a>
</li> </li>
</ul> </ul>
</>} </>}
{type === 1 && <> {type === 1 && <>
{Object.keys(data.matchs).map(p => <div key={p}> {Object.keys(data.matchs).map(p => <div key={p}>
{Object.keys(data.matchs).length > 1 && <h4 style={{marginTop: "2em"}}>Poule {p}</h4>} {Object.keys(data.matchs).length > 1 && <h4 style={{marginTop: "2em"}}>{t('poule')} {p}</h4>}
<BuildMatchArray matchs={data.matchs[p]}/> <BuildMatchArray matchs={data.matchs[p]}/>
<BuildRankArray rankArray={data.rankArray[p]}/> <BuildRankArray rankArray={data.rankArray[p]}/>
</div>)} </div>)}
@ -222,6 +229,7 @@ function ClubList({uuid}) {
const [clubId, setClubId] = useState(null) const [clubId, setClubId] = useState(null)
const setLoading = useLoadingSwitcher() const setLoading = useLoadingSwitcher()
const {data, error} = useFetch(`/result/${uuid}/club/list`, setLoading, 1) const {data, error} = useFetch(`/result/${uuid}/club/list`, setLoading, 1)
const {t} = useTranslation('result');
useEffect(() => { useEffect(() => {
if (data && Object.keys(data).length > 0) if (data && Object.keys(data).length > 0)
@ -230,7 +238,7 @@ function ClubList({uuid}) {
return <> return <>
{data ? <div className="input-group" style={{marginBottom: "1em"}}> {data ? <div className="input-group" style={{marginBottom: "1em"}}>
<h6 style={{margin: "auto 0.5em auto 0"}}>Club</h6> <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)}> <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())) {Object.keys(data).sort((a, b) => a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase()))
.map(key => <option key={key} value={data[key]}>{key}</option>)} .map(key => <option key={key} value={data[key]}>{key}</option>)}
@ -246,6 +254,7 @@ function ClubList({uuid}) {
function ClubResult({uuid, clubId}) { function ClubResult({uuid, clubId}) {
const setLoading = useLoadingSwitcher() const setLoading = useLoadingSwitcher()
const {data, refresh, error} = useFetch(`/result/${uuid}/club/${clubId}`, setLoading, 1) const {data, refresh, error} = useFetch(`/result/${uuid}/club/${clubId}`, setLoading, 1)
const {t} = useTranslation('result');
useEffect(() => { useEffect(() => {
refresh(`/result/${uuid}/club/${clubId}`) refresh(`/result/${uuid}/club/${clubId}`)
@ -253,34 +262,34 @@ function ClubResult({uuid, clubId}) {
return <> return <>
{data ? <> {data ? <>
<h3>Info :</h3> <h3>{t('info')} :</h3>
<ul> <ul>
<li>Nom : {data.name}</li> <li>{t('nom')} : {data.name}</li>
<li>Nombre d'inscris : {data.nb_insc}</li> <li>{t('nombreDinscris')} : {data.nb_insc}</li>
</ul> </ul>
<h3>Statistique :</h3> <h3>{t('statistique')} :</h3>
<ul> <ul>
<li>Nombre de match disput&eacute; : {data.nb_match}</li> <li>{t('nombreDeMatchDisputé2', {nb: data.nb_match})}</li>
<li>Nombre de victoires : {data.match_w}</li> <li>{t('nombreDeVictoires2', {nb: data.match_w})}</li>
<li>Ratio de victoires moyen : {data.ratioVictoire.toFixed(3)}</li> <li>{t('ratioDeVictoiresMoyen2', {nb: data.ratioVictoire.toFixed(3)})}</li>
<li>Points marqués : {data.pointMake}</li> <li>{t('pointsMarqués2', {nb: data.pointMake})}</li>
<li>Points reçus : {data.pointTake}</li> <li>{t('pointsReçus2', {nb: data.pointTake})}</li>
<li>Ratio de points moyen : {data.ratioPoint.toFixed(3)}</li> <li>{t('ratioDePointsMoyen2', {nb: data.ratioPoint.toFixed(3)})}</li>
</ul> </ul>
<h3>Liste des membres :</h3> <h3>{t('listeDesMembres')} :</h3>
<table className="table table-striped"> <table className="table table-striped">
<thead> <thead>
<tr> <tr>
<th scope="col" style={{textAlign: "center"}}>Cat&eacute;gorie</th> <th scope="col" style={{textAlign: "center"}}>{t('catégorie')}</th>
<th scope="col" style={{textAlign: "center"}}>Nom</th> <th scope="col" style={{textAlign: "center"}}>{t('nom')}</th>
<th scope="col" style={{textAlign: "center"}}>Victoires</th> <th scope="col" style={{textAlign: "center"}}>{t('victoires')}</th>
<th scope="col" style={{textAlign: "center"}}>D&eacute;faites</th> <th scope="col" style={{textAlign: "center"}}>{t('défaites')}</th>
<th scope="col" style={{textAlign: "center"}}>Ratio victoires</th> <th scope="col" style={{textAlign: "center"}}>{t('ratioVictoires')}</th>
<th scope="col" style={{textAlign: "center"}}>Points marqués</th> <th scope="col" style={{textAlign: "center"}}>{t('pointsMarqués')}</th>
<th scope="col" style={{textAlign: "center"}}>Points reçus</th> <th scope="col" style={{textAlign: "center"}}>{t('pointsReçus')}</th>
<th scope="col" style={{textAlign: "center"}}>Ratio points</th> <th scope="col" style={{textAlign: "center"}}>{t('ratioPoints')}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -309,6 +318,7 @@ function CombList({uuid}) {
const [combId, setCombId] = useState(null) const [combId, setCombId] = useState(null)
const setLoading = useLoadingSwitcher() const setLoading = useLoadingSwitcher()
const {data, error} = useFetch(`/result/${uuid}/comb/list`, setLoading, 1) const {data, error} = useFetch(`/result/${uuid}/comb/list`, setLoading, 1)
const {t} = useTranslation('result');
useEffect(() => { useEffect(() => {
if (data && Object.keys(data).length > 0) if (data && Object.keys(data).length > 0)
@ -317,7 +327,7 @@ function CombList({uuid}) {
return <> return <>
{data ? <div className="input-group" style={{marginBottom: "1em"}}> {data ? <div className="input-group" style={{marginBottom: "1em"}}>
<h6 style={{margin: "auto 0.5em auto 0"}}>Combattant</h6> <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)}> <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())) {Object.keys(data).sort((a, b) => a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase()))
.map(key => <option key={key} value={data[key]}>{key}</option>)} .map(key => <option key={key} value={data[key]}>{key}</option>)}
@ -333,6 +343,7 @@ function CombList({uuid}) {
function CombResult({uuid, combId}) { function CombResult({uuid, combId}) {
const setLoading = useLoadingSwitcher() const setLoading = useLoadingSwitcher()
const {data, refresh, error} = useFetch(`/result/${uuid}/comb/${combId}`, setLoading, 1) const {data, refresh, error} = useFetch(`/result/${uuid}/comb/${combId}`, setLoading, 1)
const {t} = useTranslation('result');
useEffect(() => { useEffect(() => {
refresh(`/result/${uuid}/comb/${combId}`) refresh(`/result/${uuid}/comb/${combId}`)
@ -346,31 +357,34 @@ function CombResult({uuid, combId}) {
} }
return <div> return <div>
<h3>Info :</h3> <h3>{t('info')} :</h3>
<ul> <ul>
<li>Nom Prénom : {data.name}</li> <li>{t('nomPrénom')} : {data.name}</li>
<li>Club : {data.club}</li> <li>{t('club')} : {data.club}</li>
<li>Catégorie : {data.cat}</li> <li>{t('catégorie')} : {data.cat}</li>
</ul> </ul>
<h3>Statistique :</h3> <h3>{t('statistique')} :</h3>
<ul> <ul>
<li>Taux de victoire : {data.matchs.length === 0 ? "---" : (data.totalWin / data.matchs.length * 100).toFixed(0)}% ({data.totalWin} sur <li>{t('tauxDeVictoire2', {
${data.matchs.length}) nb: data.matchs.length === 0 ? "---" : (data.totalWin / data.matchs.length * 100).toFixed(0),
victoires: data.totalWin,
matchs: data.matchs.length
})}
</li> </li>
<li>Points marqués : {data.pointMake}</li> <li>{t('pointsMarqués2', {nb: data.pointMake})}</li>
<li>Points reçus : {data.pointTake}</li> <li>{t('pointsReçus2', {nb: data.pointTake})}</li>
<li>Ratio du score (point marqué / point reçu): {data.pointRatio.toFixed(3)}</li> <li>{t('ratioDuScore2', {nb: data.pointRatio.toFixed(3)})}</li>
</ul> </ul>
<h3>Liste des matchs:</h3> <h3>{t('listeDesMatchs')}:</h3>
<table className="table table-striped"> <table className="table table-striped">
<thead> <thead>
<tr> <tr>
<th scope="col" style={{textAlign: "center"}}>Catégorie</th> <th scope="col" style={{textAlign: "center"}}>{t('catégorie')}</th>
<th scope="col" style={{textAlign: "center"}}>Adversaire</th> <th scope="col" style={{textAlign: "center"}}>{t('adversaire')}</th>
<th scope="col" style={{textAlign: "center"}}>Scores</th> <th scope="col" style={{textAlign: "center"}}>{t("scores")}</th>
<th scope="col" style={{textAlign: "center"}}>Ratio</th> <th scope="col" style={{textAlign: "center"}}>{t('ratio')}</th>
<th scope="col" style={{textAlign: "center"}}></th> <th scope="col" style={{textAlign: "center"}}></th>
</tr> </tr>
</thead> </thead>
@ -391,30 +405,31 @@ function CombResult({uuid, combId}) {
function CombsResult({uuid}) { function CombsResult({uuid}) {
const setLoading = useLoadingSwitcher() const setLoading = useLoadingSwitcher()
const {data, error} = useFetch(`/result/${uuid}/comb`, setLoading, 1) const {data, error} = useFetch(`/result/${uuid}/comb`, setLoading, 1)
const {t} = useTranslation('result');
return <> return <>
{data ? <> {data ? <>
<h3>Statistique :</h3> <h3>{t('statistique')} :</h3>
<ul> <ul>
<li>Nombre d'inscris : {data.nb_insc}</li> <li>{t('nombreDinscris2', {nb: data.nb_insc})}</li>
<li>Nombre de match disput&eacute; : {data.tt_match}</li> <li>{t('nombreDeMatchDisputé2', {nb: data.tt_match})}</li>
<li>Points marqués : {data.point}</li> <li>{t('pointsMarqués2', {nb: data.point})}</li>
</ul> </ul>
<h3>Liste des combattants :</h3> <h3>{t('listeDesCombattants')} :</h3>
<table className="table table-striped"> <table className="table table-striped">
<thead> <thead>
<tr> <tr>
<th scope="col" style={{textAlign: "center"}}>Cat&eacute;gorie</th> <th scope="col" style={{textAlign: "center"}}>{t('catégorie')}</th>
<th scope="col" style={{textAlign: "center"}}>Club</th> <th scope="col" style={{textAlign: "center"}}>{t('club')}</th>
<th scope="col" style={{textAlign: "center"}}>Nom</th> <th scope="col" style={{textAlign: "center"}}>{t('nom')}</th>
<th scope="col" style={{textAlign: "center"}}>Victoires</th> <th scope="col" style={{textAlign: "center"}}>{t('victoires')}</th>
<th scope="col" style={{textAlign: "center"}}>D&eacute;faites</th> <th scope="col" style={{textAlign: "center"}}>{t('défaites')}</th>
<th scope="col" style={{textAlign: "center"}}>Ratio victoires</th> <th scope="col" style={{textAlign: "center"}}>{t('ratioVictoires')}</th>
<th scope="col" style={{textAlign: "center"}}>Points marqués</th> <th scope="col" style={{textAlign: "center"}}>{t('pointsMarqués')}</th>
<th scope="col" style={{textAlign: "center"}}>Points reçus</th> <th scope="col" style={{textAlign: "center"}}>{t('pointsReçus')}</th>
<th scope="col" style={{textAlign: "center"}}>Ratios points</th> <th scope="col" style={{textAlign: "center"}}>{t('ratiosPoints')}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>