feat: card for team
This commit is contained in:
@@ -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!",
|
||||
|
||||
@@ -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 !",
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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) && (
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -694,6 +694,7 @@ function MatchList({matches, cat, groups, reducer}) {
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user