feat: card for team

This commit is contained in:
2026-01-29 22:35:54 +01:00
parent d749dea6f4
commit 9018ecef12
17 changed files with 679 additions and 64 deletions

View File

@@ -16,10 +16,13 @@
"blue": "Blue",
"cardAdded": "Card added",
"cardRemoved": "Card removed",
"carton": "Card",
"cartonDéquipe": "Team's card",
"cartonJaune": "Yellow card",
"cartonNoir": "Black card",
"cartonRouge": "Red card",
"catégorie": "Category",
"ceCartonEstIssuDunCartonDéquipe": "This card comes from a team card, do you really want to delete it?",
"chrono.+/-...S": "+/- ... s",
"chrono.+10S": "+10 s",
"chrono.+1S": "+1 s",
@@ -48,9 +51,12 @@
"confirm3.title": "Change category type",
"confirm4.msg": "Do you really want to delete the category {{name}}. This will delete all associated matches!",
"confirm4.title": "Delete category",
"confirmer": "Confirm",
"conserverUniquementLesMatchsTerminés": "Keep only finished matches",
"contre": "vs",
"couleur": "Color",
"créerLesMatchs": "Create matches",
"date": "Date",
"demi-finalesEtFinales": "Semi-finals and finals",
"duréePause": "Pause duration",
"duréeRound": "Round duration",
@@ -72,7 +78,9 @@
"genre.f": "F",
"genre.h": "M",
"genre.na": "NA",
"individuelle": "Individual",
"inscrit": "Registered",
"listeDesCartons": "List of cards",
"manche": "Round",
"matchPourLesPerdantsDuTournoi": "Match for tournament losers:",
"matches": "Matches",
@@ -117,6 +125,9 @@
"team": "Team",
"terminé": "Finished",
"texteCopiéDansLePresse": "Text copied to clipboard! Paste it into an HTML tag on your WordPress.",
"toast.card.team.error": "Error while editing team card",
"toast.card.team.pending": "Editing team card...",
"toast.card.team.success": "Team card edited!",
"toast.createCategory.error": "Error while creating the category",
"toast.createCategory.pending": "Creating category...",
"toast.createCategory.success": "Category created!",

View File

@@ -16,10 +16,13 @@
"blue": "Blue",
"cardAdded": "Carton ajouté",
"cardRemoved": "Carton retiré",
"carton": "Carton",
"cartonDéquipe": "Carton d'équipe",
"cartonJaune": "Carton jaune",
"cartonNoir": "Carton noir",
"cartonRouge": "Carton rouge",
"catégorie": "Catégorie",
"ceCartonEstIssuDunCartonDéquipe": "Ce carton est issu d'un carton d'équipe, voulez-vous vraiment le supprimer ?",
"chrono.+/-...S": "+/- ... s",
"chrono.+10S": "+10 s",
"chrono.+1S": "+1 s",
@@ -48,9 +51,12 @@
"confirm3.title": "Changement de type de catégorie",
"confirm4.msg": "Voulez-vous vraiment supprimer la catégorie {{name}}. Cela va supprimer tous les matchs associés !",
"confirm4.title": "Suppression de la catégorie",
"confirmer": "Confirmer",
"conserverUniquementLesMatchsTerminés": "Conserver uniquement les matchs terminés",
"contre": "contre",
"couleur": "Couleur",
"créerLesMatchs": "Créer les matchs",
"date": "Date",
"demi-finalesEtFinales": "Demi-finales et finales",
"duréePause": "Durée pause",
"duréeRound": "Durée round",
@@ -72,7 +78,9 @@
"genre.f": "F",
"genre.h": "H",
"genre.na": "NA",
"individuelle": "Individuelle",
"inscrit": "Inscrit",
"listeDesCartons": "Liste des cartons",
"manche": "Manche",
"matchPourLesPerdantsDuTournoi": "Match pour les perdants du tournoi:",
"matches": "Matches",
@@ -117,6 +125,9 @@
"team": "Équipe",
"terminé": "Terminé",
"texteCopiéDansLePresse": "Texte copié dans le presse-papier ! Collez-le dans une balise HTML sur votre WordPress.",
"toast.card.team.error": "Erreur lors de la modification du carton d'équipe",
"toast.card.team.pending": "Modification du carton d'équipe...",
"toast.card.team.success": "Carton d'équipe modifié !",
"toast.createCategory.error": "Erreur lors de la création de la catégorie",
"toast.createCategory.pending": "Création de la catégorie...",
"toast.createCategory.success": "Catégorie créée !",

View File

@@ -1,7 +1,7 @@
import {createContext, useContext, useEffect, useReducer} from "react";
import {useWS} from "./useWS.jsx";
const CardContext = createContext({});
const CardContext = createContext({comb: {}, team: []});
const CardDispatchContext = createContext(() => {
});
@@ -29,34 +29,49 @@ export function compareCardOrder(a, b) {
function reducer(state, action) {
switch (action.type) {
case 'SET_CARD':
if (state[action.payload.id] === undefined || !compareCards(action.payload, state[action.payload.id])) {
if (state.comb[action.payload.id] === undefined || !compareCards(action.payload, state.comb[action.payload.id])) {
return {
...state,
[action.payload.id]: action.payload
comb: {
...state.comb,
[action.payload.id]: action.payload
},
team: state.team
}
}
return state
case 'SET_ALL':
if (action.payload.some(e => state[e.id] === undefined || !compareCards(e, state[e.id]))) {
if (action.payload.some(e => state.comb[e.id] === undefined || !compareCards(e, state.comb[e.id]))) {
const newCombs = {};
for (const o of action.payload) {
newCombs[o.id] = o;
}
return {
...state,
...newCombs
comb: {
...state.comb,
...newCombs
},
team: state.team
}
}
return state
case 'REMOVE_CARD':
console.log("Removing card", action.payload, state[action.payload]);
if (state[action.payload] !== undefined) {
const newState = {...state}
delete newState[action.payload]
return newState
case 'REMOVE_CARDS':
const newState = {...state}
for (const id of action.payload)
delete newState.comb[id]
return newState
case 'SET_TEAM_CARD':
return {
comb: state.comb,
team: [...state.team.filter(e => e.teamName !== action.payload.teamName || e.teamUuid !== action.payload.teamUuid || e.type !== action.payload.type),
action.payload]
}
return state
case 'REMOVE_TEAM_CARD':
return {
comb: state.comb,
team: [...state.team.filter(e => e.teamName !== action.payload.teamName || e.teamUuid !== action.payload.teamUuid || e.type !== action.payload.type)]
}
default:
return state
}
@@ -66,18 +81,35 @@ function WSListener({dispatch}) {
const {dispatch: dispatchWS} = useWS()
useEffect(() => {
const sendCard = ({data}) => {
dispatch({type: 'SET_CARD', payload: data});
const sendCards = ({data}) => {
dispatch({type: 'SET_ALL', payload: data});
}
const rmCard = ({data}) => {
dispatch({type: 'REMOVE_CARD', payload: data});
const rmCards = ({data}) => {
dispatch({type: 'REMOVE_CARDS', payload: data});
}
const sendTeamCard = ({data}) => {
dispatch({type: 'SET_ALL', payload: data.cards});
dispatch({
type: 'SET_TEAM_CARD',
payload: {teamName: data.teamName, teamUuid: data.teamUuid, type: data.type, reason: data.reason, date: data.date}
});
}
const rmTeamCard = ({data}) => {
dispatch({
type: 'REMOVE_TEAM_CARD',
payload: {teamName: data.teamName, teamUuid: data.teamUuid, type: data.type, reason: data.reason, date: data.date}
});
}
dispatchWS({type: 'addListener', payload: {callback: sendCard, code: 'sendCard'}})
dispatchWS({type: 'addListener', payload: {callback: rmCard, code: 'rmCard'}})
dispatchWS({type: 'addListener', payload: {callback: sendCards, code: 'sendCards'}})
dispatchWS({type: 'addListener', payload: {callback: rmCards, code: 'rmCards'}})
dispatchWS({type: 'addListener', payload: {callback: sendTeamCard, code: 'sendTeamCard'}})
dispatchWS({type: 'addListener', payload: {callback: rmTeamCard, code: 'rmTeamCard'}})
return () => {
dispatchWS({type: 'removeListener', payload: sendCard})
dispatchWS({type: 'removeListener', payload: rmCard})
dispatchWS({type: 'removeListener', payload: sendCards})
dispatchWS({type: 'removeListener', payload: rmCards})
dispatchWS({type: 'removeListener', payload: sendTeamCard})
dispatchWS({type: 'removeListener', payload: rmTeamCard})
}
}, []);
@@ -85,7 +117,7 @@ function WSListener({dispatch}) {
}
export function CardsProvider({children}) {
const [cards, dispatch] = useReducer(reducer, {})
const [cards, dispatch] = useReducer(reducer, {comb: {}, team: []})
return <CardContext.Provider value={cards}>
<CardDispatchContext.Provider value={dispatch}>
@@ -98,9 +130,9 @@ export function CardsProvider({children}) {
export function useCards() {
const cards = useContext(CardContext);
return {
cards,
cards_v: Object.values(cards),
...useCardsStatic(Object.values(cards))
cards_t: cards.team,
cards_v: Object.values(cards.comb),
...useCardsStatic(Object.values(cards.comb))
}
}

View File

@@ -29,7 +29,7 @@ function reducer(state, action) {
//console.debug("Updating comb", comb);
return {
...state,
[comb.id]: comb
[comb.id]: {...state[comb.id], ...comb}
}
}
return state
@@ -49,7 +49,10 @@ function reducer(state, action) {
if (combs.some(e => state[e.id] === undefined || !compareCombs(e, state[e.id]))) {
const newCombs = {};
for (const o of combs) {
newCombs[o.id] = o;
newCombs[o.id] = {
...state[o.id],
...o
};
}
//console.debug("Updating combs", newCombs);

View File

@@ -88,7 +88,7 @@ export function CompetitionRegisterAdmin({source}) {
<div className="col-lg-9">
{data ? <div className="">
<MakeCentralPanel
data={state.filter(s => (clubFilter.length === 0 || s.data.club.name === clubFilter)
data={state.filter(s => (clubFilter.length === 0 || s.data.club?.name === clubFilter)
&& (catAgeFilter.length === 0 || s.data.categorie === catAgeFilter)
&& (catFilter === -1 || s.data.categoriesInscrites.includes(catFilter))
&& (!filterNotWeight || (data3?.requiredWeight.includes(s.data.categorie) && (

View File

@@ -11,12 +11,14 @@ import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {SimpleIconsOBS} from "../../../assets/SimpleIconsOBS.ts";
import JSZip from "jszip";
import {detectOptimalBackground} from "../../../components/SmartLogoBackground.jsx";
import {faGlobe, faTableCellsLarge} from "@fortawesome/free-solid-svg-icons";
import {faFile, faGlobe, faTableCellsLarge, faTrash} from "@fortawesome/free-solid-svg-icons";
import {Trans, useTranslation} from "react-i18next";
import i18n from "i18next";
import {getToastMessage} from "../../../utils/Tools.js";
import {copyStyles} from "../../../utils/copyStyles.js";
import {StateWindow} from "./StateWindow.jsx";
import {CombName, useCombs} from "../../../hooks/useComb.jsx";
import {hasEffectCard, useCards, useCardsDispatch} from "../../../hooks/useCard.jsx";
const vite_url = import.meta.env.VITE_URL;
@@ -169,6 +171,7 @@ function Menu({menuActions, compUuid}) {
const e = document.getElementById("actionMenu")
const longPress = useRef({time: null, timer: null, button: null});
const obsModal = useRef(null);
const teamCardModal = useRef(null);
const {t} = useTranslation("cm");
const [showStateWin, setShowStateWin] = useState(false)
@@ -235,6 +238,8 @@ function Menu({menuActions, compUuid}) {
if (button === "obs") {
downloadResourcesAsZip(menuActions.current.resourceList || [])
.then(__ => console.log("Ressources téléchargées"));
} else if (button === "cards") {
teamCardModal.current.click();
}
}
}
@@ -274,8 +279,14 @@ function Menu({menuActions, compUuid}) {
{createPortal(
<>
<div className="vr" style={{margin: "0 0.5em", height: "100%"}}></div>
<FontAwesomeIcon icon={faFile} size="xl"
style={{color: "#6c757d", cursor: "pointer"}}
onMouseDown={() => longPressDown("cards")}
onMouseUp={() => longPressUp("cards")}
data-bs-toggle="tooltip2" data-bs-placement="top"
data-bs-title={t("carton")}/>
<FontAwesomeIcon icon={SimpleIconsOBS} size="xl"
style={{color: "#6c757d", cursor: "pointer", marginRight: "0.25em"}}
style={{color: "#6c757d", cursor: "pointer"}}
onMouseDown={() => longPressDown("obs")}
onMouseUp={() => longPressUp("obs")}
data-bs-toggle="tooltip2" data-bs-placement="top"
@@ -347,10 +358,147 @@ function Menu({menuActions, compUuid}) {
</div>
</div>
</div>
<button ref={teamCardModal} type="button" className="btn btn-link" data-bs-toggle="modal" data-bs-target="#TeamCardModal"
style={{display: 'none'}}>
Launch OBS Modal
</button>
<div className="modal modal-xl fade" id="TeamCardModal" tabIndex="-1" aria-labelledby="TeamCardModalLabel" aria-hidden="true">
<div className="modal-dialog">
<div className="modal-content">
<TeamCardModal/>
</div>
</div>
</div>
</>
}
function CategoryHeader({cat, setCatId}) {
function TeamCardModal() {
const [club, setClub] = useState("")
const {t} = useTranslation("cm");
const {combs} = useCombs()
const {sendRequest} = useWS()
const {cards_t, cards_v} = useCards()
const cardDispatch = useCardsDispatch();
const {data} = useRequestWS("getAllForTeamNoDetail", {}, null);
useEffect(() => {
if (!data)
return;
for (const card of data) {
cardDispatch({type: 'SET_TEAM_CARD', payload: card});
}
}, [data]);
let clubList = [];
if (combs != null) {
clubList = Object.values(combs).map(d => d.club_str).filter((v, i, a) => v !== "" && v !== undefined && a.indexOf(v) === i);
}
const handleAdd = (e) => {
e.preventDefault();
toast.promise(sendRequest("applyTeamCards", {
teamUuid: Object.values(combs).find(d => d.club_str === club)?.club_uuid,
teamName: club,
type: "YELLOW"
}),
getToastMessage("toast.card.team", "cm"))
.then(() => {
})
}
const GetCard = ({type}) => {
if (!type)
return <></>
let bg = "";
switch (type) {
case "YELLOW":
bg = " bg-warning";
break;
case "RED":
bg = " bg-danger";
break;
case "BLACK":
bg = " bg-dark text-white";
break;
case "BLUE":
bg = " bg-primary text-white";
break;
}
return <span className={"badge border border-light p-2" + bg}><span className="visually-hidden">card</span></span>
}
let cards = [...cards_t, ...cards_v].sort((a, b) => new Date(b.date) - new Date(a.date))
return <>
<div className="modal-header">
<h5 className="modal-title">{t('carton')}</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body">
<h5>{t('cartonDéquipe')}</h5>
<div className="input-group mb-3">
<label htmlFor="inputGroupSelect09" className="input-group-text">{t('club')}</label>
<select id="inputGroupSelect09" className="form-select" value={club} onChange={(e) => setClub(e.target.value)}>
{clubList.sort((a, b) => a.localeCompare(b)).map((club, index) => (
<option key={index} value={club}>{club}</option>))}
</select>
<button className="btn btn-outline-primary" type="button" onClick={handleAdd}>{t("ajouter")}</button>
</div>
<h5>{t('listeDesCartons')}</h5>
<table className="table">
<thead>
<tr>
<th scope="col">{t('date')}</th>
<th scope="col">{t('type')}</th>
<th scope="col">{t('couleur')}</th>
<th scope="col">{t('nom')}</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{cards.map((card, index) => <tr key={index}>
<td scope="row">{new Date(card.date).toLocaleString()}</td>
{card.teamName ? <>
<td>{t('team')}</td>
<td><GetCard type={card.type}/></td>
<td>{card.teamName}</td>
</> : <>
<td>{card.teamCard ? "|-> " + t('team'): t('individuelle')} </td>
<td><GetCard type={card.type}/></td>
<td><CombName combId={card.comb}/></td>
</>}
<td style={{textAlign: "center", cursor: "pointer", color: "#ff1313"}} onClick={_ => {
if (confirm("Êtes-vous sûr de vouloir supprimer ce carton ?")) {
if (card.teamName) {
toast.promise(sendRequest("removeTeamCards", {
teamUuid: card.teamUuid, teamName: card.teamName, type: card.type
}),
getToastMessage("toast.card.team", "cm"))
.then(() => {
})
} else {
sendRequest('sendCardRm', {matchId: card.match, combId: card.comb, type: card.type})
.then(() => toast.success(t('cardRemoved')))
.catch(err => toast.error(err))
}
}
}}><FontAwesomeIcon icon={faTrash}/></td>
</tr>)}
</tbody>
</table>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" data-bs-dismiss="modal">{t('fermer')}</button>
</div>
</>
}
function CategoryHeader({
cat, setCatId
}) {
const setLoading = useLoadingSwitcher()
const bthRef = useRef();
const confirmRef = useRef();
@@ -428,7 +576,7 @@ function CategoryHeader({cat, setCatId}) {
<button className="btn btn-primary float-end" onClick={() => {
setModal(cat);
bthRef.current.click();
}} disabled={cat === null}>Modifier
}} disabled={cat === null}>{t('modifier')}
</button>
</div>

View File

@@ -197,7 +197,7 @@ function MatchList({matches, cat, menuActions}) {
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_end(m, cards_v), end: m.end}))
.map(m => ({...m, ...win_end(m, cards_v)}))
const firstIndex = marches2.findLastIndex(m => m.poule === '-') + 1;
const isActiveMatch = (index) => {

View File

@@ -1,11 +1,11 @@
import React, {useEffect, useRef, useState} from "react";
import {useRequestWS, useWS} from "../../../hooks/useWS.jsx";
import {useCombs, useCombsDispatch} from "../../../hooks/useComb.jsx";
import {CombName, 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} from "@fortawesome/free-solid-svg-icons";
import {faArrowRightArrowLeft, faDisplay, faFile, faTrash} from "@fortawesome/free-solid-svg-icons";
import {PubAffWindow} from "./PubAffWindow.jsx";
import {SimpleIconsScore} from "../../../assets/SimpleIconsScore.ts";
import {ChronoPanel} from "./CMTChronoPanel.jsx";
@@ -13,8 +13,10 @@ import {CategorieSelect} from "./CMTMatchPanel.jsx";
import {PointPanel} from "./CMTPoint.jsx";
import {importOBSConfiguration, OBSProvider, useOBS} from "../../../hooks/useOBS.jsx";
import {SimpleIconsOBS} from "../../../assets/SimpleIconsOBS.ts";
import {toast} from "react-toastify";
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() {
const combDispatch = useCombsDispatch()
@@ -78,6 +80,7 @@ function Menu({menuActions}) {
const {connected, connect, disconnect} = useOBS();
const longPress = useRef({time: null, timer: null, button: null});
const obsModal = useRef(null);
const teamCardModal = useRef(null);
const {t} = useTranslation("cm");
const externalWindow = useRef(null)
@@ -194,6 +197,9 @@ function Menu({menuActions}) {
<div className="vr" style={{margin: "0 0.5em", height: "100%"}}></div>
<span onClick={() => obsModal.current.click()} style={{cursor: "pointer"}}>Zone {zone}</span>
<div className="vr" style={{margin: "0 0.5em", height: "100%"}}></div>
<FontAwesomeIcon icon={faFile} size="xl" style={{color: "#6c757d", cursor: "pointer", marginRight: "0.25em"}}
onClick={() => teamCardModal.current.click()} data-bs-toggle="tooltip2" data-bs-placement="top"
data-bs-title={t('cartonDéquipe')}/>
<FontAwesomeIcon icon={faArrowRightArrowLeft} size="xl" style={{color: "#6c757d", cursor: "pointer", marginRight: "0.25em"}}
onClick={handleSwitchScore} data-bs-toggle="tooltip2" data-bs-placement="top"
data-bs-title={t('ttm.table.inverserLaPosition')}/>
@@ -241,10 +247,67 @@ function Menu({menuActions}) {
</div>
</div>
</div>
<button ref={teamCardModal} type="button" className="btn btn-link" data-bs-toggle="modal" data-bs-target="#TeamCardModal"
style={{display: 'none'}}>
Launch OBS Modal
</button>s
<div className="modal fade" id="TeamCardModal" tabIndex="-1" aria-labelledby="TeamCardModalLabel" aria-hidden="true">
<div className="modal-dialog">
<div className="modal-content">
<TeamCardModal/>
</div>
</div>
</div>
<SendLiceName name={zone}/>
</>
}
function TeamCardModal() {
const [club, setClub] = useState("")
const {t} = useTranslation("cm");
const {combs} = useCombs()
const {sendRequest} = useWS()
let clubList = [];
if (combs != null) {
clubList = Object.values(combs).map(d => d.club_str).filter((v, i, a) => v !== "" && v !== undefined && a.indexOf(v) === i);
}
const handleAdd = (e) => {
e.preventDefault();
toast.promise(sendRequest("applyTeamCards", {
teamUuid: Object.values(combs).find(d => d.club_str === club)?.club_uuid,
teamName: club,
type: "YELLOW"
}),
getToastMessage("toast.card.team", "cm"))
.then(() => {
})
}
return <>
<div className="modal-header">
<h5 className="modal-title">{t('cartonDéquipe')}</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body">
<div className="input-group mb-3">
<label htmlFor="inputGroupSelect09" className="input-group-text">{t('club')}</label>
<select id="inputGroupSelect09" className="form-select" value={club} onChange={(e) => setClub(e.target.value)}>
{clubList.sort((a, b) => a.localeCompare(b)).map((club, index) => (
<option key={index} value={club}>{club}</option>))}
</select>
<button className="btn btn-outline-primary" type="button" onClick={handleAdd}>{t("ajouter")}</button>
</div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" data-bs-dismiss="modal">{t('fermer')}</button>
</div>
</>
}
function SendLiceName({name}) {
const {sendNotify, setState} = useWS();
@@ -258,15 +321,94 @@ function SendLiceName({name}) {
}
function SendCatId({catId}) {
const notifState = useRef(undefined);
const {sendNotify, setState, dispatch, tableState} = useWS();
const {t} = useTranslation("cm");
useEffect(() => {
const welcomeInfo = () => {
sendNotify("sendState", tableState.current)
}
const sendTeamCards = ({data}) => {
function content({closeToast, data}) {
const sendState = (s) => {
sendNotify("sendTeamCardReturnState", {
state: s,
teamUuid: data.teamUuid,
teamName: data.teamName,
type: data.type,
selectedCategory: tableState.current.selectedCategory,
selectedMatch: tableState.current.selectedMatch
});
}
return (
<div className="flex items-center w-full">
<span>{`Un carton jaune d'équipe a été émis à l'encontre du club ${data.teamName}. Dans votre zone de combat :`}</span><br/>
<div className="form-check">
<input className="form-check-input" type="radio" name="radioState" id="radioState1"
onChange={e => e.target.checked ? notifState.current = 0 : null}/>
<label className="form-check-label" htmlFor="radioState1">
Rien n'est en cours
</label>
</div>
<div className="form-check">
<input className="form-check-input" type="radio" name="radioState" id="radioState2"
onChange={e => e.target.checked ? notifState.current = 1 : null}/>
<label className="form-check-label" htmlFor="radioState2">
La categorie est en cours
</label>
</div>
<div className="form-check">
<input className="form-check-input" type="radio" name="radioState" id="radioState3"
onChange={e => e.target.checked ? notifState.current = 2 : null}/>
<label className="form-check-label" htmlFor="radioState3">
Le match est en cours
</label>
</div>
<button className="btn btn-sm btn-outline-primary ml-2" onClick={() => {
if (notifState.current === undefined) {
return;
}
sendState(notifState.current)
closeToast(true);
}}>
{t('confirmer')}
</button>
</div>
);
}
toast.warn(content, {
position: "top-center",
autoClose: false,
closeButton: false,
hideProgressBar: false,
closeOnClick: false,
pauseOnHover: true,
draggable: false,
progress: undefined,
theme: "colored",
transition: Flip,
data: {
teamUuid: data.teamUuid,
teamName: data.teamName,
type: data.type,
}
});
}
welcomeInfo();
dispatch({type: 'addListener', payload: {callback: welcomeInfo, code: 'welcomeInfo'}})
return () => dispatch({type: 'removeListener', payload: welcomeInfo});
dispatch({type: 'addListener', payload: {callback: sendTeamCards, code: 'sendTeamCards'}})
return () => {
dispatch({type: 'removeListener', payload: welcomeInfo});
dispatch({type: 'removeListener', payload: sendTeamCards});
setState({selectedCategory: -1});
sendNotify("sendSelectCategory", -1);
}
}, []);
useEffect(() => {

View File

@@ -694,6 +694,7 @@ function MatchList({matches, cat, groups, reducer}) {
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>

View File

@@ -267,7 +267,27 @@ function CardPanel({matchId, match, vEnd, admin}) {
})
}
const handleCardRm = (combId, type) => {
const confirmRm = (combId, type) => {
function content({closeToast}) {
return (
<div className="flex items-center w-full">
<span>{t('ceCartonEstIssuDunCartonDéquipe')}</span>{' '}
<button
className="btn btn-sm btn-warning ml-2"
onClick={() => {
closeToast(true);
handleCardRm_(combId, type)
}}>
{t('confirmer')}
</button>
</div>
);
}
toast.warn(content);
}
const handleCardRm_ = (combId, type) => {
setLoading(1)
sendRequest('sendCardRm', {matchId, combId, type})
.then(() => {
@@ -282,6 +302,15 @@ function CardPanel({matchId, match, vEnd, admin}) {
}
const cards = getCardInMatch(match)
const handleCardRm = (combId, type) => {
if (cards.find(c => c.comb === combId && c.type === type)?.teamCard) {
confirmRm(combId, type)
} else {
handleCardRm_(combId, type)
}
}
const MakeList = ({comb}) => {
const card = getHeightCardForCombInMatch(comb, match);