diff --git a/src/main/webapp/public/locales/en/cm.json b/src/main/webapp/public/locales/en/cm.json index c929839..37a904c 100644 --- a/src/main/webapp/public/locales/en/cm.json +++ b/src/main/webapp/public/locales/en/cm.json @@ -82,12 +82,14 @@ "genre.h": "M", "genre.na": "NA", "individuelle": "Individual", + "informationCatégorie": "Category information", "inscrit": "Registered", "leTournoiServiraDePhaseFinaleAuxPoules": "The tournament will serve as the final phase for the group stage.", "lesCombattantsEnDehors": "Fighters not participating in the tournament will have a ranking match.", "listeDesCartons": "List of cards", "manche": "Round", "matchPourLesPerdantsDuTournoi": "Match for tournament losers:", + "matchTerminé": "Match over", "matches": "Matches", "modifier": "Edit", "msg1": "There are already matches in this pool; what do you want to do with them?", @@ -97,6 +99,7 @@ "nomDeLaZone": "Area name", "nomDeLéquipe": "team name", "nomDesZonesDeCombat": "Combat zone names <1>(separated by ';')", + "nombreDeCombattants": "Number of fighters", "nouvelle...": "New...", "obs.préfixDesSources": "Source prefix", "pays": "Country", @@ -127,6 +130,7 @@ "supprimerUn": "Delete one", "sélectionneLesModesDaffichage": "Select display modes", "sélectionner": "Select", + "taille": "Size", "team": "Team", "terminé": "Finished", "texteCopiéDansLePresse": "Text copied to clipboard! Paste it into an HTML tag on your WordPress.", diff --git a/src/main/webapp/public/locales/en/common.json b/src/main/webapp/public/locales/en/common.json index 33372fe..178174a 100644 --- a/src/main/webapp/public/locales/en/common.json +++ b/src/main/webapp/public/locales/en/common.json @@ -619,9 +619,9 @@ "supprimerLeCompte": "Delete account", "supprimerLeCompte.msg": "Are you sure you want to delete this account?", "sword.none": "$t(sans) / $t(nonDéfinie)", - "sword.oneHand": "One hand", + "sword.oneHand": "One hand sword", "sword.saber": "Saber", - "sword.twoHand": "Two hands", + "sword.twoHand": "Two hands sword", "sélectionEnéquipeDeFrance": "Selection in the French team", "sélectionner...": "Select...", "toast.edit.error": "Failed to save changes", diff --git a/src/main/webapp/public/locales/en/result.json b/src/main/webapp/public/locales/en/result.json index 5448a44..4de482a 100644 --- a/src/main/webapp/public/locales/en/result.json +++ b/src/main/webapp/public/locales/en/result.json @@ -11,6 +11,7 @@ "catégorie": "Category", "chargement": "Loading", "classement": "Ranking", + "classementFinal": "Final standings", "club": "Club", "combattant": "Fighter", "combattants": "Fighters", @@ -65,6 +66,5 @@ "tournois": "Tournaments", "tousLesCombattants": "All fighters", "victoire": "Win", - "victoires": "Wins", - "classementFinal": "Final standings" + "victoires": "Wins" } diff --git a/src/main/webapp/public/locales/fr/cm.json b/src/main/webapp/public/locales/fr/cm.json index a23bd18..5bcf129 100644 --- a/src/main/webapp/public/locales/fr/cm.json +++ b/src/main/webapp/public/locales/fr/cm.json @@ -82,12 +82,14 @@ "genre.h": "H", "genre.na": "NA", "individuelle": "Individuelle", + "informationCatégorie": "Information catégorie", "inscrit": "Inscrit", "leTournoiServiraDePhaseFinaleAuxPoules": "Le tournoi servira de phase finale aux poules", "lesCombattantsEnDehors": "Les combattants en dehors du tournoi auront un match de classement", "listeDesCartons": "Liste des cartons", "manche": "Manche", "matchPourLesPerdantsDuTournoi": "Match pour les perdants du tournoi:", + "matchTerminé": "Match terminé", "matches": "Matches", "modifier": "Modifier", "msg1": "Il y a déjà des matchs dans cette poule, que voulez-vous faire avec ?", @@ -97,6 +99,7 @@ "nomDeLaZone": "Nom de la zone", "nomDeLéquipe": "Nom de l'équipe", "nomDesZonesDeCombat": "Nom des zones de combat <1>(séparée par des ';')", + "nombreDeCombattants": "Nombre de combattants", "nouvelle...": "Nouvelle...", "obs.préfixDesSources": "Préfix des sources", "pays": "Pays", @@ -127,6 +130,7 @@ "supprimerUn": "Supprimer un", "sélectionneLesModesDaffichage": "Sélectionne les modes d'affichage", "sélectionner": "Sélectionner", + "taille": "Taille", "team": "Équipe", "terminé": "Terminé", "texteCopiéDansLePresse": "Texte copié dans le presse-papier ! Collez-le dans une balise HTML sur votre WordPress.", diff --git a/src/main/webapp/public/locales/fr/common.json b/src/main/webapp/public/locales/fr/common.json index 790d076..7a41aa2 100644 --- a/src/main/webapp/public/locales/fr/common.json +++ b/src/main/webapp/public/locales/fr/common.json @@ -623,9 +623,9 @@ "supprimerLeCompte": "Supprimer le compte", "supprimerLeCompte.msg": "Êtes-vous sûr de vouloir supprimer ce compte ?", "sword.none": "$t(sans) / $t(nonDéfinie)", - "sword.oneHand": "Une main", + "sword.oneHand": "Épée une main", "sword.saber": "Sabre", - "sword.twoHand": "Deux mains", + "sword.twoHand": "Épée deux mains", "sélectionEnéquipeDeFrance": "Sélection en équipe de France", "sélectionner...": "Sélectionner...", "toast.edit.error": "Échec de l'enregistrement des modifications", diff --git a/src/main/webapp/public/locales/fr/result.json b/src/main/webapp/public/locales/fr/result.json index 958a9ab..115350d 100644 --- a/src/main/webapp/public/locales/fr/result.json +++ b/src/main/webapp/public/locales/fr/result.json @@ -11,6 +11,7 @@ "catégorie": "Catégorie", "chargement": "Chargement", "classement": "Classement", + "classementFinal": "Classement final", "club": "Club", "combattant": "Combattant", "combattants": "Combattants", @@ -65,6 +66,5 @@ "tournois": "Tournois", "tousLesCombattants": "Tous les combattants", "victoire": "Victoire", - "victoires": "Victoires", - "classementFinal": "Classement final" + "victoires": "Victoires" } diff --git a/src/main/webapp/src/pages/competition/editor/CMTChronoPanel.jsx b/src/main/webapp/src/pages/competition/editor/CMTChronoPanel.jsx index 887d707..4dba14f 100644 --- a/src/main/webapp/src/pages/competition/editor/CMTChronoPanel.jsx +++ b/src/main/webapp/src/pages/competition/editor/CMTChronoPanel.jsx @@ -4,7 +4,7 @@ import {timePrint} from "../../../utils/Tools.js"; import {useTranslation} from "react-i18next"; import {useWS} from "../../../hooks/useWS.jsx"; -export function ChronoPanel() { +export function ChronoPanel({menuActions}) { const [config, setConfig] = useState({ time: Number(sessionStorage.getItem("chronoTime") || "90999"), pause: Number(sessionStorage.getItem("chronoPause") || "60999") @@ -25,6 +25,10 @@ export function ChronoPanel() { return chrono.time + Date.now() - chrono.startTime } + menuActions.current.setTimerConfig = (time, pause) => { + setConfig({time: time + 999, pause: pause + 999}) + } + useEffect(() => { publicAffDispatch({type: 'CALL_TIME', payload: {timeStr: state.current.lastTimeStr, timeColor: state.current.color}}) }, []) diff --git a/src/main/webapp/src/pages/competition/editor/CMTMatchPanel.jsx b/src/main/webapp/src/pages/competition/editor/CMTMatchPanel.jsx index d879ece..293ba7c 100644 --- a/src/main/webapp/src/pages/competition/editor/CMTMatchPanel.jsx +++ b/src/main/webapp/src/pages/competition/editor/CMTMatchPanel.jsx @@ -6,13 +6,24 @@ import {DrawGraph} from "../../result/DrawGraph.jsx"; import {LoadingProvider, useLoadingSwitcher} from "../../../hooks/useLoading.jsx"; import {useRequestWS, useWS} from "../../../hooks/useWS.jsx"; import {MarchReducer} from "../../../utils/MatchReducer.jsx"; -import {getToastMessage, virtualScore, win_end} from "../../../utils/Tools.js"; +import { + CatList, + getCatName, getShieldSize, + getShieldTypeName, getSwordSize, + getSwordTypeName, + getToastMessage, timePrint, + virtual_end, + virtualScore, + win_end +} from "../../../utils/Tools.js"; import "./CMTMatchPanel.css" import {useOBS} from "../../../hooks/useOBS.jsx"; import {useTranslation} from "react-i18next"; import {hasEffectCard, useCards, useCardsDispatch} from "../../../hooks/useCard.jsx"; import {ScorePanel} from "./ScoreAndCardPanel.jsx"; import {toast} from "react-toastify"; +import {createPortal} from "react-dom"; +import ProtectionSelector from "../../../components/ProtectionSelector.jsx"; function CupImg() { return + return <> + + + +} + +function SetTimeToChrono({cat, matches, menuActions}) { + const [catAverage, setCatAverage] = useState("---"); + const [genreAverage, setGenreAverage] = useState("H"); + const [nbComb, setNbComb] = useState(0); + const [preset, setPreset] = useState(undefined); + const [time, setTime] = useState({round: 0, pause: 0}); + const {cards_v} = useCards(); + + const {t} = useTranslation("cm"); + const {getComb} = useCombs(); + + useEffect(() => { + if (!cat || matches.filter(m => m.categorie === cat.id).length === 0) { + setCatAverage("---"); + setNbComb(0); + return; + } + setPreset(cat.preset); + + const genres = []; + const cats = []; + const combs = []; + for (const m of matches.filter(m => m.categorie === cat.id)) { + if (m.c1 && !combs.includes(m.c1)) + combs.push(m.c1); + if (m.c2 && !combs.includes(m.c2)) + combs.push(m.c2); + } + setNbComb(combs.length); + + combs.map(cId => getComb(cId, null)).filter(c => c && c.categorie) + .forEach(c => { + cats.push(Math.min(CatList.length, CatList.indexOf(c.categorie) + c.overCategory)) + genres.push(c.genre) + }); + + const catAvg = Math.round(cats.reduce((a, b) => a + b, 0) / cats.length); + setCatAverage(CatList.at(catAvg) || "---"); + + const genreAvg = Math.round(genres.reduce((a, b) => a + (b === "F" ? 1 : 0), 0) / genres.length); + setGenreAverage(genreAvg > 0.5 ? "F" : "H"); + + if (!cat.preset || !cat.preset.categories) + return; + + const catAvailable = cat.preset.categories.map(c => CatList.indexOf(c.categorie)); + + let p; + if (catAvailable.includes(catAvg)) { + p = cat.preset.categories.find(c => CatList.indexOf(c.categorie) === catAvg); + } else { + const closest = catAvailable.reduce((a, b) => Math.abs(b - catAvg) < Math.abs(a - catAvg) ? b : a); + p = cat.preset.categories.find(c => CatList.indexOf(c.categorie) === closest); + } + menuActions.current.setTimerConfig(p.roundDuration, p.pauseDuration) + setTime({round: p.roundDuration, pause: p.pauseDuration}) + + }, [cat, matches]); + + const marches2 = matches.filter(m => m.categorie === cat.id) + .map(m => ({...m, end: m.end || virtual_end(m, cards_v)})) + + return createPortal(
+
{t('informationCatégorie')}
+
+
+
+
{t('catégorie')} : {getCatName(catAverage)}
+
{t('arme', {ns: 'common'})} : {getSwordTypeName(preset?.sword)} - {t('taille')} {getSwordSize(preset?.sword, catAverage, genreAverage)}
+
{t('bouclier', {ns: 'common'})} : {getShieldTypeName(preset?.shield)} - {t('taille')} {getShieldSize(preset?.shield, catAverage)}
+
{t('duréeRound')} : {timePrint(time.round)}
+
{t('duréePause')} : {timePrint(time.pause)}
+
{t('matchTerminé')}: {marches2.filter(m => m.end).length} sur {marches2.length}
+
{t('nombreDeCombattants')} : {nbComb}
+
+
+
{t('protectionObligatoire', {ns: 'common'})} :
+ { + }}/> +
+
+
+
, document.getElementById("infoCategory")) } function ListMatch({cat, matches, trees, menuActions}) { diff --git a/src/main/webapp/src/pages/competition/editor/CMTable.jsx b/src/main/webapp/src/pages/competition/editor/CMTable.jsx index dcfd6ab..f32af02 100644 --- a/src/main/webapp/src/pages/competition/editor/CMTable.jsx +++ b/src/main/webapp/src/pages/competition/editor/CMTable.jsx @@ -1,11 +1,11 @@ import React, {useEffect, useRef, useState} from "react"; import {useRequestWS, useWS} from "../../../hooks/useWS.jsx"; -import {CombName, useCombs, useCombsDispatch} from "../../../hooks/useComb.jsx"; +import {useCombs, useCombsDispatch} from "../../../hooks/useComb.jsx"; import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; import {createPortal} from "react-dom"; import {copyStyles} from "../../../utils/copyStyles.js"; import {PubAffProvider, usePubAffDispatch, usePubAffState} from "../../../hooks/useExternalWindow.jsx"; -import {faArrowRightArrowLeft, faDisplay, faFile, faTrash} from "@fortawesome/free-solid-svg-icons"; +import {faArrowRightArrowLeft, faDisplay, faFile} from "@fortawesome/free-solid-svg-icons"; import {PubAffWindow} from "./PubAffWindow.jsx"; import {SimpleIconsScore} from "../../../assets/SimpleIconsScore.ts"; import {ChronoPanel} from "./CMTChronoPanel.jsx"; @@ -15,7 +15,6 @@ import {importOBSConfiguration, OBSProvider, useOBS} from "../../../hooks/useOBS import {SimpleIconsOBS} from "../../../assets/SimpleIconsOBS.ts"; import {Flip, toast} from "react-toastify"; import {useTranslation} from "react-i18next"; -import {useCards, useCardsDispatch} from "../../../hooks/useCard.jsx"; import {getToastMessage} from "../../../utils/Tools.js"; export function CMTable() { @@ -39,7 +38,7 @@ export function CMTable() {
{t('chronomètre')}
- +
@@ -49,9 +48,11 @@ export function CMTable() { + +
-
+
{t('matches')}
diff --git a/src/main/webapp/src/utils/Tools.js b/src/main/webapp/src/utils/Tools.js index 9b1f55e..7f4f78e 100644 --- a/src/main/webapp/src/utils/Tools.js +++ b/src/main/webapp/src/utils/Tools.js @@ -199,6 +199,38 @@ export function getSwordTypeName(type) { } } +export function getSwordSize(type, cat, gender) { + const catIndex = CatList.indexOf(cat) + if (type === "ONE_HAND") { + if (catIndex <= 1) { + return "XS" + } else if (catIndex <= 3) { + return "S" + } else if (catIndex <= 6 || gender === "F") { + return "M" + } else { + return "L" + } + } else if (type === "TWO_HAND") { + if (catIndex <= 5) { + return "--" + } else if (catIndex <= 6 || gender === "F") { + return "XL" + } else { + return "XXL" + } + } else if (type === "SABER") { + if (catIndex <= 3) { + return "--" + } else if (catIndex <= 6) { + return "S" + } else { + return "L" + } + } + return "--" +} + export const ShieldList = [ "NONE", "STANDARD", @@ -224,6 +256,18 @@ export function getShieldTypeName(type) { } } +export function getShieldSize(type, cat) { + if (type === "STANDARD") { + const catIndex = CatList.indexOf(cat) + if (catIndex <= 1) { + return "S" + } else { + return "L" + } + } + return "--" +} + export function getToastMessage(msgKey, ns = 'common') { return { pending: i18n.t(msgKey + '.pending', {ns}),