diff --git a/src/main/webapp/src/pages/competition/editor/CMTMatchPanel.jsx b/src/main/webapp/src/pages/competition/editor/CMTMatchPanel.jsx
new file mode 100644
index 0000000..ab7f99b
--- /dev/null
+++ b/src/main/webapp/src/pages/competition/editor/CMTMatchPanel.jsx
@@ -0,0 +1,510 @@
+import React, {useEffect, useRef, useState, useReducer} from "react";
+import {CombName, useCombs, useCombsDispatch} from "../../../hooks/useComb.jsx";
+import {usePubAffDispatch} from "../../../hooks/useExternalWindow.jsx";
+import {from_sendTree, TreeNode} from "../../../utils/TreeUtils.js";
+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 {scorePrint, win} from "../../../utils/Tools.js";
+import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
+import {faCircleQuestion} from "@fortawesome/free-regular-svg-icons";
+import {toast} from "react-toastify";
+
+function CupImg() {
+ return
+}
+
+export function CategorieSelect({catId, setCatId}) {
+ const setLoading = useLoadingSwitcher()
+ const {data: cats, setData: setCats} = useRequestWS('getAllCategory', {}, setLoading);
+ const {dispatch} = useWS();
+
+ useEffect(() => {
+ const categoryListener = ({data}) => {
+ setCats([...cats.filter(c => c.id !== data.id), data])
+ }
+ dispatch({type: 'addListener', payload: {callback: categoryListener, code: 'sendCategory'}})
+ return () => dispatch({type: 'removeListener', payload: categoryListener})
+ }, [cats]);
+
+ const cat = cats?.find(c => c.id === catId);
+
+ return <>
+
+
Catégorie
+
+
+ {catId !== -1 && }
+ >
+}
+
+function CMTMatchPanel({catId, cat}) {
+ const setLoading = useLoadingSwitcher()
+ const {sendRequest, dispatch} = useWS();
+ const [trees, setTrees] = useState([]);
+ const [matches, reducer] = useReducer(MarchReducer, []);
+ const combDispatch = useCombsDispatch();
+
+ function readAndConvertMatch(matches, data, combsToAdd) {
+ matches.push({...data, c1: data.c1?.id, c2: data.c2?.id})
+ if (data.c1)
+ combsToAdd.push(data.c1)
+ if (data.c2)
+ combsToAdd.push(data.c2)
+ }
+
+ useEffect(() => {
+ if (!catId)
+ return;
+ setLoading(1);
+ sendRequest('getFullCategory', catId)
+ .then((data) => {
+ setTrees(data.trees.map(d => from_sendTree(d, true)))
+
+ let matches2 = [];
+ let combsToAdd = [];
+ data.trees.flatMap(d => from_sendTree(d, false).flat()).forEach((data_) => readAndConvertMatch(matches2, data_, combsToAdd));
+ data.matches.forEach((data_) => readAndConvertMatch(matches2, data_, combsToAdd));
+
+ reducer({type: 'REPLACE_ALL', payload: matches2});
+ combDispatch({type: 'SET_ALL', payload: {source: "match", data: combsToAdd}});
+ }).finally(() => setLoading(0))
+
+ const treeListener = ({data}) => {
+ if (data.length < 1 || data[0].categorie !== catId)
+ return
+ setTrees(data.map(d => from_sendTree(d, true)))
+
+ let matches2 = [];
+ let combsToAdd = [];
+ data.flatMap(d => from_sendTree(d, false).flat()).forEach((data_) => readAndConvertMatch(matches2, data_, combsToAdd));
+ reducer({type: 'REPLACE_TREE', payload: matches2});
+ combDispatch({type: 'SET_ALL', payload: {source: "match", data: combsToAdd}});
+ }
+
+ const matchListener = ({data: datas}) => {
+ for (const data of datas) {
+ reducer({type: 'UPDATE_OR_ADD', payload: {...data, c1: data.c1?.id, c2: data.c2?.id}})
+ combDispatch({type: 'SET_ALL', payload: {source: "match", data: [data.c1, data.c2].filter(d => d != null)}})
+ }
+ }
+
+ const matchOrder = ({data}) => {
+ reducer({type: 'REORDER', payload: data})
+ }
+
+ const deleteMatch = ({data: datas}) => {
+ for (const data of datas)
+ reducer({type: 'REMOVE', payload: data})
+ }
+
+ dispatch({type: 'addListener', payload: {callback: treeListener, code: 'sendTreeCategory'}})
+ dispatch({type: 'addListener', payload: {callback: matchListener, code: 'sendMatch'}})
+ dispatch({type: 'addListener', payload: {callback: matchOrder, code: 'sendMatchOrder'}})
+ dispatch({type: 'addListener', payload: {callback: deleteMatch, code: 'sendDeleteMatch'}})
+ return () => {
+ dispatch({type: 'removeListener', payload: treeListener})
+ dispatch({type: 'removeListener', payload: matchListener})
+ dispatch({type: 'removeListener', payload: matchOrder})
+ dispatch({type: 'removeListener', payload: deleteMatch})
+ }
+ }, [catId]);
+
+ return
+}
+
+function ListMatch({cat, matches, trees}) {
+ const [type, setType] = useState(1);
+
+ useEffect(() => {
+ if ((cat.type & type) === 0)
+ setType(cat.type);
+ }, [cat]);
+
+ return
+ {cat && cat.type === 3 && <>
+
+ -
+
setType(1)}>Poule
+
+
+ -
+
setType(2)}>Tournois
+
+
+
+ >
+ }
+
+ {type === 1 && <>
+
+ >}
+
+ {type === 2 && <>
+
+ >}
+
+}
+
+function MatchList({matches, cat}) {
+ const [activeMatch, setActiveMatch] = useState(null)
+ const [lice, setLice] = useState(localStorage.getItem("cm_lice") || "A")
+ const publicAffDispatch = usePubAffDispatch();
+
+ const liceName = (cat.liceName || "N/A").split(";");
+ const marches2 = matches.filter(m => m.categorie_ord !== -42)
+ .sort((a, b) => a.categorie_ord - b.categorie_ord)
+ .map(m => ({...m, win: win(m.scores)}))
+
+ const match = matches.find(m => m.id === activeMatch)
+ useEffect(() => {
+ if (!match) {
+ publicAffDispatch({type: 'SET_DATA', payload: {c1: undefined, c2: undefined, next: []}});
+ } else {
+ publicAffDispatch({
+ type: 'SET_DATA',
+ payload: {
+ c1: match.c1,
+ c2: match.c2,
+ next: marches2.filter(m => !m.end && m.poule === lice && m.id !== activeMatch).map(m => ({c1: m.c1, c2: m.c2}))
+ }
+ });
+ }
+ }, [match]);
+ //useEffect(() => {
+ // if (activeMatch !== null)
+ // setActiveMatch(null);
+ //}, [cat])
+
+ useEffect(() => {
+ if (match && match.poule !== lice)
+ setActiveMatch(marches2.find(m => !m.end && m.poule === lice)?.id)
+ }, [lice]);
+
+ useEffect(() => {
+ if (marches2.length === 0)
+ return;
+ if (marches2.some(m => m.id === activeMatch))
+ return;
+
+ setActiveMatch(marches2.find(m => !m.end && m.poule === lice)?.id);
+ }, [matches])
+
+ const firstIndex = marches2.findLastIndex(m => m.poule === '-') + 1;
+ return <>
+ {liceName.length > 1 &&
+
+
+
+
+ }
+
+
+
+
+
+ | L |
+ P |
+ N° |
+ |
+ Rouge |
+ Blue |
+ |
+
+
+
+ {marches2.map((m, index) => (
+ setActiveMatch(m.id)}>
+ |
+ {liceName[(index - firstIndex) % liceName.length]} |
+ {m.poule} |
+
+ {index >= firstIndex ? index + 1 - firstIndex : ""} |
+ {m.end && m.win > 0 && } |
+
+ |
+
+ |
+ {m.end && m.win < 0 && } |
+
+ ))}
+
+
+
+
+ {activeMatch && }
+ >
+}
+
+function BuildTree({treeData, matches}) {
+ const scrollRef = useRef(null)
+ const [currentMatch, setCurrentMatch] = useState(null)
+ const {getComb} = useCombs()
+ const publicAffDispatch = usePubAffDispatch();
+
+ const match = matches.find(m => m.id === currentMatch?.matchSelect)
+ useEffect(() => {
+ if (!match) {
+ publicAffDispatch({type: 'SET_DATA', payload: {c1: undefined, c2: undefined}});
+ } else {
+ publicAffDispatch({type: 'SET_DATA', payload: {c1: match.c1, c2: match.c2}});
+ }
+ }, [match]);
+ const next_match = matches.find(m => m.id === currentMatch?.matchNext)
+ useEffect(() => {
+ if (!next_match) {
+ publicAffDispatch({type: 'SET_DATA', payload: {next: []}});
+ } else {
+ publicAffDispatch({type: 'SET_DATA', payload: {next: [{c1: next_match.c1, c2: next_match.c2}]}});
+ }
+ }, [next_match]);
+
+ function parseTree(data_in) {
+ if (data_in?.data == null)
+ return null
+
+ const matchData = matches.find(m => m.id === data_in.data)
+ const c1 = getComb(matchData?.c1)
+ const c2 = getComb(matchData?.c2)
+
+
+ let node = new TreeNode({
+ ...matchData,
+ c1FullName: c1 !== null ? c1.fname + " " + c1.lname : null,
+ c2FullName: c2 !== null ? c2.fname + " " + c2.lname : null
+ })
+ 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
+ }
+
+ const trees = initTree(treeData);
+
+ const onMatchClick = (rect, matchId, __) => {
+ setCurrentMatch({matchSelect: matchId, matchNext: new TreeNode(matchId).nextMatchTree(trees.reverse())});
+ }
+
+ const onClickVoid = () => {
+ }
+
+
+ return
+
+
+
+
+ {currentMatch?.matchSelect &&
}
+
+}
+
+function ScorePanel({matchId, match}) {
+ const {sendRequest} = useWS()
+ const setLoading = useLoadingSwitcher()
+
+ const [end, setEnd] = useState(match?.end || false)
+ const [scoreIn, setScoreIn] = useState("")
+ const inputRef = useRef(null)
+ const tableRef = useRef(null)
+ const scoreRef = useRef([])
+ const lastScoreClick = useRef(null)
+
+ const handleScoreClick = (e, round, comb) => {
+ e.stopPropagation();
+ const tableRect = tableRef.current.getBoundingClientRect();
+ const rect = e.currentTarget.getBoundingClientRect();
+
+ updateScore();
+
+ const sel = inputRef.current;
+ sel.style.top = (rect.y - tableRect.y) + "px";
+ sel.style.left = (rect.x - tableRect.x) + "px";
+ sel.style.width = rect.width + "px";
+ sel.style.height = rect.height + "px";
+ sel.style.display = "block";
+
+ if (round === -1) {
+ const maxRound = (Math.max(...match.scores.map(s => s.n_round), -1) + 1) || 0;
+ setScoreIn("");
+ console.log("Setting for new round", maxRound);
+ lastScoreClick.current = {matchId: matchId, round: maxRound, comb};
+ } else {
+ const score = match.scores.find(s => s.n_round === round);
+ setScoreIn((comb === 1 ? score?.s1 : score?.s2) || "");
+ lastScoreClick.current = {matchId: matchId, round, comb};
+ setTimeout(() => inputRef.current.select(), 100);
+ }
+ }
+
+ const updateScore = () => {
+ if (lastScoreClick.current !== null) {
+ const {matchId, round, comb} = lastScoreClick.current;
+ lastScoreClick.current = null;
+
+ const scoreIn_ = String(scoreIn).trim() === "" ? -1000 : Number(scoreIn);
+
+ const score = match.scores.find(s => s.n_round === round);
+ let newScore;
+ if (score) {
+ if (comb === 1)
+ newScore = {...score, s1: scoreIn_};
+ else
+ newScore = {...score, s2: scoreIn_};
+
+ if (newScore.s1 === score?.s1 && newScore.s2 === score?.s2)
+ return
+ } else {
+ newScore = {n_round: round, s1: (comb === 1 ? scoreIn_ : -1000), s2: (comb === 2 ? scoreIn_ : -1000)};
+ if (newScore.s1 === -1000 && newScore.s2 === -1000)
+ return
+ }
+
+ console.log("Updating score", matchId, newScore);
+
+ setLoading(1)
+ sendRequest('updateMatchScore', {matchId: matchId, ...newScore})
+ .finally(() => {
+ setLoading(0)
+ })
+ }
+ }
+
+ const onClickVoid = () => {
+ updateScore();
+
+ const sel = inputRef.current;
+ sel.style.display = "none";
+ lastScoreClick.current = null;
+ }
+
+ useEffect(() => {
+ if (!match || match?.end === end)
+ return;
+
+ if (end) {
+ if (win(match?.scores) === 0 && match.categorie_ord === -42) {
+ toast.error("Impossible de terminer un match nul en tournois.");
+ setEnd(false);
+ return;
+ }
+ }
+
+ setLoading(1)
+ sendRequest('updateMatchEnd', {matchId: matchId, end})
+ .finally(() => {
+ setLoading(0)
+ })
+ }, [end]);
+
+ useEffect(() => {
+ onClickVoid()
+ }, [matchId]);
+
+ useEffect(() => {
+ if (match?.scores)
+ scoreRef.current = scoreRef.current.slice(0, match.scores.length);
+ }, [match?.scores]);
+
+ useEffect(() => {
+ if (!match)
+ return;
+ setEnd(match.end);
+ }, [match]);
+
+ const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
+ const o = [...tooltipTriggerList]
+ o.map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))
+
+ const tt = "Score speciaux :
" +
+ "-997 : disqualifié
" +
+ "-998 : absent
" +
+ "-999 : forfait"
+
+ const maxRound = (match?.scores) ? (Math.max(...match.scores.map(s => s.n_round), -1) + 1) : 0;
+ return
+
+
Scores
+
+
+
+ | Manche |
+ Rouge |
+ Bleu |
+
+
+
+ {match?.scores && match.scores.sort((a, b) => a.n_round - b.n_round).map(score => (
+
+ | {score.n_round + 1} |
+ scoreRef.current[score.n_round * 2] = e}
+ onClick={e => handleScoreClick(e, score.n_round, 1)}>{scorePrint(score.s1)} |
+ scoreRef.current[score.n_round * 2 + 1] = e}
+ onClick={e => handleScoreClick(e, score.n_round, 2)}>{scorePrint(score.s2)} |
+
+ ))}
+
+ |
+ scoreRef.current[maxRound * 2] = e} onClick={e => handleScoreClick(e, -1, 1)}>- |
+ scoreRef.current[maxRound * 2 + 1] = e} onClick={e => handleScoreClick(e, -1, 2)}>-
+ |
+
+
+
+
+
+ setEnd(e.target.checked)}/>
+
+
+
+
setScoreIn(e.target.value)}
+ onClick={e => e.stopPropagation()}
+ onKeyDown={e => {
+ if (e.key === "Tab") {
+ if (lastScoreClick.current !== null) {
+ const {round, comb} = lastScoreClick.current;
+ const nextIndex = (round * 2 + (comb - 1)) + (e.shiftKey ? -1 : 1);
+ if (nextIndex >= 0 && nextIndex < scoreRef.current.length) {
+ e.preventDefault();
+ scoreRef.current[nextIndex].click();
+ }
+ }
+ } else if (e.key === "Enter") {
+ e.preventDefault();
+ onClickVoid();
+ }
+ }}/>
+
+
+
+
+}
diff --git a/src/main/webapp/src/pages/competition/editor/CMTable.jsx b/src/main/webapp/src/pages/competition/editor/CMTable.jsx
index 9929bc2..c5e0fde 100644
--- a/src/main/webapp/src/pages/competition/editor/CMTable.jsx
+++ b/src/main/webapp/src/pages/competition/editor/CMTable.jsx
@@ -1,14 +1,7 @@
-import React, {useEffect, useReducer, useRef, useState} from "react";
-import {useRequestWS, useWS} from "../../../hooks/useWS.jsx";
-import {LoadingProvider, useLoadingSwitcher} from "../../../hooks/useLoading.jsx";
-import {from_sendTree, TreeNode} from "../../../utils/TreeUtils.js";
-import {MarchReducer} from "../../../utils/MatchReducer.jsx";
-import {CombName, useCombs, useCombsDispatch} from "../../../hooks/useComb.jsx";
+import React, {useEffect, useRef, useState} from "react";
+import {useRequestWS} from "../../../hooks/useWS.jsx";
+import {useCombsDispatch} from "../../../hooks/useComb.jsx";
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
-import {faCircleQuestion} from "@fortawesome/free-regular-svg-icons";
-import {DrawGraph} from "../../result/DrawGraph.jsx";
-import {scorePrint, win} from "../../../utils/Tools.js";
-import {toast} from "react-toastify";
import {createPortal} from "react-dom";
import {copyStyles} from "../../../utils/copyStyles.js";
import {PubAffProvider, usePubAffDispatch} from "../../../hooks/useExternalWindow.jsx";
@@ -16,12 +9,7 @@ import {faDisplay} from "@fortawesome/free-solid-svg-icons";
import {PubAffWindow} from "./PubAffWindow.jsx";
import {SimpleIconsScore} from "../../../assets/SimpleIconsScore.ts";
import {ChronoPanel} from "./CMTChronoPanel.jsx";
-
-function CupImg() {
- return
-}
+import {CategorieSelect} from "./CMTMatchPanel.jsx";
export function CMTable() {
const combDispatch = useCombsDispatch()
@@ -128,496 +116,3 @@ function Menu() {
{externalWindow.current && createPortal(, containerEl.current)}
>
}
-
-function CategorieSelect({catId, setCatId}) {
- const setLoading = useLoadingSwitcher()
- const {data: cats, setData: setCats} = useRequestWS('getAllCategory', {}, setLoading);
- const {dispatch} = useWS();
-
- useEffect(() => {
- const categoryListener = ({data}) => {
- setCats([...cats.filter(c => c.id !== data.id), data])
- }
- dispatch({type: 'addListener', payload: {callback: categoryListener, code: 'sendCategory'}})
- return () => dispatch({type: 'removeListener', payload: categoryListener})
- }, [cats]);
-
- const cat = cats?.find(c => c.id === catId);
-
- return <>
-
-
Catégorie
-
-
- {catId !== -1 && }
- >
-}
-
-function MatchPanel({catId, cat}) {
- const setLoading = useLoadingSwitcher()
- const {sendRequest, dispatch} = useWS();
- const [trees, setTrees] = useState([]);
- const [matches, reducer] = useReducer(MarchReducer, []);
- const combDispatch = useCombsDispatch();
-
- function readAndConvertMatch(matches, data, combsToAdd) {
- matches.push({...data, c1: data.c1?.id, c2: data.c2?.id})
- if (data.c1)
- combsToAdd.push(data.c1)
- if (data.c2)
- combsToAdd.push(data.c2)
- }
-
- useEffect(() => {
- if (!catId)
- return;
- setLoading(1);
- sendRequest('getFullCategory', catId)
- .then((data) => {
- setTrees(data.trees.map(d => from_sendTree(d, true)))
-
- let matches2 = [];
- let combsToAdd = [];
- data.trees.flatMap(d => from_sendTree(d, false).flat()).forEach((data_) => readAndConvertMatch(matches2, data_, combsToAdd));
- data.matches.forEach((data_) => readAndConvertMatch(matches2, data_, combsToAdd));
-
- reducer({type: 'REPLACE_ALL', payload: matches2});
- combDispatch({type: 'SET_ALL', payload: {source: "match", data: combsToAdd}});
- }).finally(() => setLoading(0))
-
- const treeListener = ({data}) => {
- if (data.length < 1 || data[0].categorie !== catId)
- return
- setTrees(data.map(d => from_sendTree(d, true)))
-
- let matches2 = [];
- let combsToAdd = [];
- data.flatMap(d => from_sendTree(d, false).flat()).forEach((data_) => readAndConvertMatch(matches2, data_, combsToAdd));
- reducer({type: 'REPLACE_TREE', payload: matches2});
- combDispatch({type: 'SET_ALL', payload: {source: "match", data: combsToAdd}});
- }
-
- const matchListener = ({data: datas}) => {
- for (const data of datas) {
- reducer({type: 'UPDATE_OR_ADD', payload: {...data, c1: data.c1?.id, c2: data.c2?.id}})
- combDispatch({type: 'SET_ALL', payload: {source: "match", data: [data.c1, data.c2].filter(d => d != null)}})
- }
- }
-
- const matchOrder = ({data}) => {
- reducer({type: 'REORDER', payload: data})
- }
-
- const deleteMatch = ({data: datas}) => {
- for (const data of datas)
- reducer({type: 'REMOVE', payload: data})
- }
-
- dispatch({type: 'addListener', payload: {callback: treeListener, code: 'sendTreeCategory'}})
- dispatch({type: 'addListener', payload: {callback: matchListener, code: 'sendMatch'}})
- dispatch({type: 'addListener', payload: {callback: matchOrder, code: 'sendMatchOrder'}})
- dispatch({type: 'addListener', payload: {callback: deleteMatch, code: 'sendDeleteMatch'}})
- return () => {
- dispatch({type: 'removeListener', payload: treeListener})
- dispatch({type: 'removeListener', payload: matchListener})
- dispatch({type: 'removeListener', payload: matchOrder})
- dispatch({type: 'removeListener', payload: deleteMatch})
- }
- }, [catId]);
-
- return
-}
-
-function ListMatch({cat, matches, trees}) {
- const [type, setType] = useState(1);
-
- useEffect(() => {
- if ((cat.type & type) === 0)
- setType(cat.type);
- }, [cat]);
-
- return
- {cat && cat.type === 3 && <>
-
- -
-
setType(1)}>Poule
-
-
- -
-
setType(2)}>Tournois
-
-
-
- >
- }
-
- {type === 1 && <>
-
- >}
-
- {type === 2 && <>
-
- >}
-
-}
-
-function MatchList({matches, cat}) {
- const [activeMatch, setActiveMatch] = useState(null)
- const [lice, setLice] = useState(localStorage.getItem("cm_lice") || "A")
- const publicAffDispatch = usePubAffDispatch();
-
- const liceName = (cat.liceName || "N/A").split(";");
- const marches2 = matches.filter(m => m.categorie_ord !== -42)
- .sort((a, b) => a.categorie_ord - b.categorie_ord)
- .map(m => ({...m, win: win(m.scores)}))
-
- const match = matches.find(m => m.id === activeMatch)
- useEffect(() => {
- if (!match) {
- publicAffDispatch({type: 'SET_DATA', payload: {c1: undefined, c2: undefined, next: []}});
- } else {
- publicAffDispatch({
- type: 'SET_DATA',
- payload: {
- c1: match.c1,
- c2: match.c2,
- next: marches2.filter(m => !m.end && m.poule === lice && m.id !== activeMatch).map(m => ({c1: m.c1, c2: m.c2}))
- }
- });
- }
- }, [match]);
- //useEffect(() => {
- // if (activeMatch !== null)
- // setActiveMatch(null);
- //}, [cat])
-
- useEffect(() => {
- if (match && match.poule !== lice)
- setActiveMatch(marches2.find(m => !m.end && m.poule === lice)?.id)
- }, [lice]);
-
- useEffect(() => {
- if (marches2.length === 0)
- return;
- if (marches2.some(m => m.id === activeMatch))
- return;
-
- setActiveMatch(marches2.find(m => !m.end && m.poule === lice)?.id);
- }, [matches])
-
- const firstIndex = marches2.findLastIndex(m => m.poule === '-') + 1;
- return <>
- {liceName.length > 1 &&
-
-
-
-
- }
-
-
-
-
-
- | L |
- P |
- N° |
- |
- Rouge |
- Blue |
- |
-
-
-
- {marches2.map((m, index) => (
- setActiveMatch(m.id)}>
- |
- {liceName[(index - firstIndex) % liceName.length]} |
- {m.poule} |
-
- {index >= firstIndex ? index + 1 - firstIndex : ""} |
- {m.end && m.win > 0 && } |
-
- |
-
- |
- {m.end && m.win < 0 && } |
-
- ))}
-
-
-
-
- {activeMatch && }
- >
-}
-
-function BuildTree({treeData, matches}) {
- const scrollRef = useRef(null)
- const [currentMatch, setCurrentMatch] = useState(null)
- const {getComb} = useCombs()
- const publicAffDispatch = usePubAffDispatch();
-
- const match = matches.find(m => m.id === currentMatch?.matchSelect)
- useEffect(() => {
- if (!match) {
- publicAffDispatch({type: 'SET_DATA', payload: {c1: undefined, c2: undefined}});
- } else {
- publicAffDispatch({type: 'SET_DATA', payload: {c1: match.c1, c2: match.c2}});
- }
- }, [match]);
- const next_match = matches.find(m => m.id === currentMatch?.matchNext)
- useEffect(() => {
- if (!next_match) {
- publicAffDispatch({type: 'SET_DATA', payload: {next: []}});
- } else {
- publicAffDispatch({type: 'SET_DATA', payload: {next: [{c1: next_match.c1, c2: next_match.c2}]}});
- }
- }, [next_match]);
-
- function parseTree(data_in) {
- if (data_in?.data == null)
- return null
-
- const matchData = matches.find(m => m.id === data_in.data)
- const c1 = getComb(matchData?.c1)
- const c2 = getComb(matchData?.c2)
-
-
- let node = new TreeNode({
- ...matchData,
- c1FullName: c1 !== null ? c1.fname + " " + c1.lname : null,
- c2FullName: c2 !== null ? c2.fname + " " + c2.lname : null
- })
- 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
- }
-
- const trees = initTree(treeData);
-
- const onMatchClick = (rect, matchId, __) => {
- setCurrentMatch({matchSelect: matchId, matchNext: new TreeNode(matchId).nextMatchTree(trees.reverse())});
- }
-
- const onClickVoid = () => {
- }
-
-
- return
-
-
-
-
- {currentMatch?.matchSelect &&
}
-
-}
-
-
-function ScorePanel({matchId, match}) {
- const {sendRequest} = useWS()
- const setLoading = useLoadingSwitcher()
-
- const [end, setEnd] = useState(match?.end || false)
- const [scoreIn, setScoreIn] = useState("")
- const inputRef = useRef(null)
- const tableRef = useRef(null)
- const scoreRef = useRef([])
- const lastScoreClick = useRef(null)
-
- const handleScoreClick = (e, round, comb) => {
- e.stopPropagation();
- const tableRect = tableRef.current.getBoundingClientRect();
- const rect = e.currentTarget.getBoundingClientRect();
-
- updateScore();
-
- const sel = inputRef.current;
- sel.style.top = (rect.y - tableRect.y) + "px";
- sel.style.left = (rect.x - tableRect.x) + "px";
- sel.style.width = rect.width + "px";
- sel.style.height = rect.height + "px";
- sel.style.display = "block";
-
- if (round === -1) {
- const maxRound = (Math.max(...match.scores.map(s => s.n_round), -1) + 1) || 0;
- setScoreIn("");
- console.log("Setting for new round", maxRound);
- lastScoreClick.current = {matchId: matchId, round: maxRound, comb};
- } else {
- const score = match.scores.find(s => s.n_round === round);
- setScoreIn((comb === 1 ? score?.s1 : score?.s2) || "");
- lastScoreClick.current = {matchId: matchId, round, comb};
- setTimeout(() => inputRef.current.select(), 100);
- }
- }
-
- const updateScore = () => {
- if (lastScoreClick.current !== null) {
- const {matchId, round, comb} = lastScoreClick.current;
- lastScoreClick.current = null;
-
- const scoreIn_ = String(scoreIn).trim() === "" ? -1000 : Number(scoreIn);
-
- const score = match.scores.find(s => s.n_round === round);
- let newScore;
- if (score) {
- if (comb === 1)
- newScore = {...score, s1: scoreIn_};
- else
- newScore = {...score, s2: scoreIn_};
-
- if (newScore.s1 === score?.s1 && newScore.s2 === score?.s2)
- return
- } else {
- newScore = {n_round: round, s1: (comb === 1 ? scoreIn_ : -1000), s2: (comb === 2 ? scoreIn_ : -1000)};
- if (newScore.s1 === -1000 && newScore.s2 === -1000)
- return
- }
-
- console.log("Updating score", matchId, newScore);
-
- setLoading(1)
- sendRequest('updateMatchScore', {matchId: matchId, ...newScore})
- .finally(() => {
- setLoading(0)
- })
- }
- }
-
- const onClickVoid = () => {
- updateScore();
-
- const sel = inputRef.current;
- sel.style.display = "none";
- lastScoreClick.current = null;
- }
-
- useEffect(() => {
- if (!match || match?.end === end)
- return;
-
- if (end) {
- if (win(match?.scores) === 0 && match.categorie_ord === -42) {
- toast.error("Impossible de terminer un match nul en tournois.");
- setEnd(false);
- return;
- }
- }
-
- setLoading(1)
- sendRequest('updateMatchEnd', {matchId: matchId, end})
- .finally(() => {
- setLoading(0)
- })
- }, [end]);
-
- useEffect(() => {
- onClickVoid()
- }, [matchId]);
-
- useEffect(() => {
- if (match?.scores)
- scoreRef.current = scoreRef.current.slice(0, match.scores.length);
- }, [match?.scores]);
-
- useEffect(() => {
- if (!match)
- return;
- setEnd(match.end);
- }, [match]);
-
- const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
- const o = [...tooltipTriggerList]
- o.map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))
-
- const tt = "Score speciaux :
" +
- "-997 : disqualifié
" +
- "-998 : absent
" +
- "-999 : forfait"
-
- const maxRound = (match?.scores) ? (Math.max(...match.scores.map(s => s.n_round), -1) + 1) : 0;
- return
-
-
Scores
-
-
-
- | Manche |
- Rouge |
- Bleu |
-
-
-
- {match?.scores && match.scores.sort((a, b) => a.n_round - b.n_round).map(score => (
-
- | {score.n_round + 1} |
- scoreRef.current[score.n_round * 2] = e}
- onClick={e => handleScoreClick(e, score.n_round, 1)}>{scorePrint(score.s1)} |
- scoreRef.current[score.n_round * 2 + 1] = e}
- onClick={e => handleScoreClick(e, score.n_round, 2)}>{scorePrint(score.s2)} |
-
- ))}
-
- |
- scoreRef.current[maxRound * 2] = e} onClick={e => handleScoreClick(e, -1, 1)}>- |
- scoreRef.current[maxRound * 2 + 1] = e} onClick={e => handleScoreClick(e, -1, 2)}>-
- |
-
-
-
-
-
- setEnd(e.target.checked)}/>
-
-
-
-
setScoreIn(e.target.value)}
- onClick={e => e.stopPropagation()}
- onKeyDown={e => {
- if (e.key === "Tab") {
- if (lastScoreClick.current !== null) {
- const {round, comb} = lastScoreClick.current;
- const nextIndex = (round * 2 + (comb - 1)) + (e.shiftKey ? -1 : 1);
- if (nextIndex >= 0 && nextIndex < scoreRef.current.length) {
- e.preventDefault();
- scoreRef.current[nextIndex].click();
- }
- }
- } else if (e.key === "Enter") {
- e.preventDefault();
- onClickVoid();
- }
- }}/>
-
-
-
-
-}