feat: add public screen
This commit is contained in:
parent
8e01fb46f8
commit
0ac92fcda3
@ -17,7 +17,7 @@ public class CombEntity {
|
|||||||
private String lname;
|
private String lname;
|
||||||
private String fname;
|
private String fname;
|
||||||
Categorie categorie;
|
Categorie categorie;
|
||||||
Long club;
|
String club_uuid;
|
||||||
String club_str;
|
String club_str;
|
||||||
Genre genre;
|
Genre genre;
|
||||||
String country;
|
String country;
|
||||||
@ -29,7 +29,7 @@ public class CombEntity {
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
return new CombEntity(model.getId(), model.getLname(), model.getFname(), model.getCategorie(),
|
return new CombEntity(model.getId(), model.getLname(), model.getFname(), model.getCategorie(),
|
||||||
model.getClub() == null ? null : model.getClub().getId(),
|
model.getClub() == null ? null : model.getClub().getClubId(),
|
||||||
model.getClub() == null ? "Sans club" : model.getClub().getName(), model.getGenre(), model.getCountry(),
|
model.getClub() == null ? "Sans club" : model.getClub().getName(), model.getGenre(), model.getCountry(),
|
||||||
0, null);
|
0, null);
|
||||||
}
|
}
|
||||||
@ -49,7 +49,7 @@ public class CombEntity {
|
|||||||
MembreModel model = registerModel.getMembre();
|
MembreModel model = registerModel.getMembre();
|
||||||
|
|
||||||
return new CombEntity(model.getId(), model.getLname(), model.getFname(), registerModel.getCategorie(),
|
return new CombEntity(model.getId(), model.getLname(), model.getFname(), registerModel.getCategorie(),
|
||||||
registerModel.getClub2() == null ? null : registerModel.getClub2().getId(),
|
registerModel.getClub2() == null ? null : registerModel.getClub2().getClubId(),
|
||||||
registerModel.getClub2() == null ? "Sans club" : registerModel.getClub2().getName(), model.getGenre(),
|
registerModel.getClub2() == null ? "Sans club" : registerModel.getClub2().getName(), model.getGenre(),
|
||||||
model.getCountry(), registerModel.getOverCategory(), registerModel.getWeight());
|
model.getCountry(), registerModel.getOverCategory(), registerModel.getWeight());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -186,6 +186,6 @@ public class AffiliationRequestEndpoints {
|
|||||||
public Uni<Response> getStatus(
|
public Uni<Response> getStatus(
|
||||||
@Parameter(description = "L'identifiant de la demande d'affiliation") @PathParam("id") long id) throws URISyntaxException {
|
@Parameter(description = "L'identifiant de la demande d'affiliation") @PathParam("id") long id) throws URISyntaxException {
|
||||||
return Utils.getMediaFile(id, media, "aff_request/status", "affiliation_request_" + id,
|
return Utils.getMediaFile(id, media, "aff_request/status", "affiliation_request_" + id,
|
||||||
Uni.createFrom().nullItem());
|
Uni.createFrom().nullItem(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -335,7 +335,7 @@ public class ClubEndpoints {
|
|||||||
@Parameter(description = "Identifiant long (clubId) de club") @PathParam("clubId") String clubId) {
|
@Parameter(description = "Identifiant long (clubId) de club") @PathParam("clubId") String clubId) {
|
||||||
return clubService.getByClubId(clubId).chain(Unchecked.function(clubModel -> {
|
return clubService.getByClubId(clubId).chain(Unchecked.function(clubModel -> {
|
||||||
try {
|
try {
|
||||||
return Utils.getMediaFile((clubModel != null) ? clubModel.getId() : -1, media, "ppClub",
|
return Utils.getMediaFileNoDefault((clubModel != null) ? clubModel.getId() : -1, media, "ppClub",
|
||||||
Uni.createFrom().nullItem());
|
Uni.createFrom().nullItem());
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException e) {
|
||||||
throw new InternalError();
|
throw new InternalError();
|
||||||
@ -358,7 +358,7 @@ public class ClubEndpoints {
|
|||||||
return clubService.getById(id).onItem().invoke(checkPerm).chain(Unchecked.function(clubModel -> {
|
return clubService.getById(id).onItem().invoke(checkPerm).chain(Unchecked.function(clubModel -> {
|
||||||
try {
|
try {
|
||||||
return Utils.getMediaFile(clubModel.getId(), media, "clubStatus",
|
return Utils.getMediaFile(clubModel.getId(), media, "clubStatus",
|
||||||
"statue-" + clubModel.getName(), Uni.createFrom().nullItem());
|
"statue-" + clubModel.getName(), Uni.createFrom().nullItem(), false);
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException e) {
|
||||||
throw new InternalError();
|
throw new InternalError();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -150,11 +150,16 @@ public class Utils {
|
|||||||
|
|
||||||
public static Uni<Response> getMediaFile(long id, String media, String dirname,
|
public static Uni<Response> getMediaFile(long id, String media, String dirname,
|
||||||
Uni<?> uniBase) throws URISyntaxException {
|
Uni<?> uniBase) throws URISyntaxException {
|
||||||
return getMediaFile(id, media, dirname, null, uniBase);
|
return getMediaFile(id, media, dirname, null, uniBase, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Uni<Response> getMediaFileNoDefault(long id, String media, String dirname,
|
||||||
|
Uni<?> uniBase) throws URISyntaxException {
|
||||||
|
return getMediaFile(id, media, dirname, null, uniBase, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Uni<Response> getMediaFile(long id, String media, String dirname, String out_filename,
|
public static Uni<Response> getMediaFile(long id, String media, String dirname, String out_filename,
|
||||||
Uni<?> uniBase) throws URISyntaxException {
|
Uni<?> uniBase, boolean default_) throws URISyntaxException {
|
||||||
Future<Pair<File, byte[]>> future = CompletableFuture.supplyAsync(() -> {
|
Future<Pair<File, byte[]>> future = CompletableFuture.supplyAsync(() -> {
|
||||||
FilenameFilter filter = (directory, filename) -> filename.startsWith(id + ".");
|
FilenameFilter filter = (directory, filename) -> filename.startsWith(id + ".");
|
||||||
File[] files = new File(media, dirname).listFiles(filter);
|
File[] files = new File(media, dirname).listFiles(filter);
|
||||||
@ -182,19 +187,25 @@ public class Utils {
|
|||||||
return uniBase.chain(__ -> Uni.createFrom().future(future)
|
return uniBase.chain(__ -> Uni.createFrom().future(future)
|
||||||
.chain(filePair -> {
|
.chain(filePair -> {
|
||||||
if (filePair == null) {
|
if (filePair == null) {
|
||||||
return Uni.createFrom().future(future2).map(data -> {
|
if (default_) {
|
||||||
if (data == null)
|
return Uni.createFrom().future(future2).map(data -> {
|
||||||
return Response.noContent().build();
|
if (data == null)
|
||||||
|
return Response.noContent().build();
|
||||||
|
|
||||||
String mimeType = "image/apng";
|
String mimeType = "image/apng";
|
||||||
Response.ResponseBuilder resp = Response.ok(data);
|
Response.ResponseBuilder resp = Response.ok(data);
|
||||||
resp.type(MediaType.APPLICATION_OCTET_STREAM);
|
resp.type(MediaType.APPLICATION_OCTET_STREAM);
|
||||||
resp.header(HttpHeaders.CONTENT_LENGTH, data.length);
|
resp.header(HttpHeaders.CONTENT_LENGTH, data.length);
|
||||||
resp.header(HttpHeaders.CONTENT_TYPE, mimeType);
|
resp.header(HttpHeaders.CONTENT_TYPE, mimeType);
|
||||||
resp.header(HttpHeaders.CONTENT_DISPOSITION,
|
resp.header(HttpHeaders.CONTENT_DISPOSITION,
|
||||||
"inline; " + ((out_filename == null) ? "" : "filename=\"" + out_filename + "\""));
|
"inline; " + ((out_filename == null) ? "" : "filename=\"" + out_filename + "\""));
|
||||||
return resp.build();
|
return resp.build();
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
Response.ResponseBuilder resp = Response.status(404);
|
||||||
|
resp.header(HttpHeaders.CACHE_CONTROL, "max-age=600");
|
||||||
|
return Uni.createFrom().item(resp.build());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return Uni.createFrom().item(() -> {
|
return Uni.createFrom().item(() -> {
|
||||||
String mimeType = URLConnection.guessContentTypeFromName(filePair.getKey().getName());
|
String mimeType = URLConnection.guessContentTypeFromName(filePair.getKey().getName());
|
||||||
|
|||||||
@ -22,7 +22,7 @@ public class RRegister {
|
|||||||
@Inject
|
@Inject
|
||||||
CompetitionRepository competitionRepository;
|
CompetitionRepository competitionRepository;
|
||||||
|
|
||||||
@WSReceiver(code = "getRegister", permission = PermLevel.ADMIN)
|
@WSReceiver(code = "getRegister", permission = PermLevel.TABLE)
|
||||||
public Uni<List<CombEntity>> getRegister(WebSocketConnection connection, Object o) {
|
public Uni<List<CombEntity>> getRegister(WebSocketConnection connection, Object o) {
|
||||||
return competitionRepository.find("uuid", connection.pathParam("uuid")).firstResult()
|
return competitionRepository.find("uuid", connection.pathParam("uuid")).firstResult()
|
||||||
.call(cm -> Mutiny.fetch(cm.getInsc()))
|
.call(cm -> Mutiny.fetch(cm.getInsc()))
|
||||||
|
|||||||
@ -40,7 +40,7 @@ public class SRegister {
|
|||||||
public Uni<Void> send(String uuid, String code, Object data) {
|
public Uni<Void> send(String uuid, String code, Object data) {
|
||||||
List<Uni<Void>> queue = connections.findByEndpointId(CompetitionWS.class.getCanonicalName()).stream()
|
List<Uni<Void>> queue = connections.findByEndpointId(CompetitionWS.class.getCanonicalName()).stream()
|
||||||
.filter(c -> c.pathParam("uuid").equals(uuid) && PermLevel.valueOf(
|
.filter(c -> c.pathParam("uuid").equals(uuid) && PermLevel.valueOf(
|
||||||
c.userData().get(UserData.TypedKey.forString("prem"))).ordinal() >= PermLevel.ADMIN.ordinal())
|
c.userData().get(UserData.TypedKey.forString("prem"))).ordinal() >= PermLevel.TABLE.ordinal())
|
||||||
.map(c -> c.sendText(
|
.map(c -> c.sendText(
|
||||||
new MessageOut(UUID.randomUUID(), code, MessageType.NOTIFY, data)))
|
new MessageOut(UUID.randomUUID(), code, MessageType.NOTIFY, data)))
|
||||||
.toList();
|
.toList();
|
||||||
|
|||||||
26
src/main/webapp/src/assets/SimpleIconsScore.ts
Normal file
26
src/main/webapp/src/assets/SimpleIconsScore.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import {
|
||||||
|
IconDefinition,
|
||||||
|
IconName,
|
||||||
|
IconPrefix
|
||||||
|
} from "@fortawesome/fontawesome-svg-core";
|
||||||
|
|
||||||
|
export const SimpleIconsScore: IconDefinition = {
|
||||||
|
icon: [
|
||||||
|
// SVG viewbox width (in pixels)
|
||||||
|
122.88,
|
||||||
|
|
||||||
|
// SVG viewbox height (in pixels)
|
||||||
|
100.08,
|
||||||
|
|
||||||
|
// Aliases (not needed)
|
||||||
|
[],
|
||||||
|
|
||||||
|
// Unicode as hex value (not needed)
|
||||||
|
"",
|
||||||
|
|
||||||
|
// SVG path data
|
||||||
|
"M5.49,0h55.95h55.95c1.51,0,2.89,0.62,3.88,1.61c0.99,0.99,1.61,2.37,1.61,3.88v75.79c0,1.51-0.62,2.89-1.61,3.88 c-0.99,0.99-2.37,1.61-3.88,1.61h-25v12.15c0,0.64-0.52,1.16-1.16,1.16H31.66c-0.65,0-1.17-0.53-1.17-1.17V86.77h-25 c-1.51,0-2.89-0.62-3.88-1.61C0.62,84.17,0,82.8,0,81.28V5.49C0,3.98,0.62,2.6,1.61,1.61C2.6,0.62,3.98,0,5.49,0L5.49,0z M45.45,37.11v13.88c0,3.16-0.18,5.45-0.52,6.89c-0.34,1.45-1.05,2.79-2.13,4.05c-1.08,1.25-2.38,2.15-3.9,2.69 c-1.52,0.55-3.22,0.82-5.11,0.82c-2.48,0-4.54-0.29-6.19-0.86c-1.64-0.58-2.95-1.47-3.93-2.68c-0.97-1.22-1.67-2.5-2.08-3.84 c-0.41-1.35-0.61-3.49-0.61-6.42V37.11c0-3.83,0.33-6.69,0.99-8.59c0.66-1.9,1.97-3.43,3.93-4.58c1.96-1.15,4.33-1.72,7.12-1.72 c2.28,0,4.32,0.39,6.12,1.19c1.8,0.8,3.14,1.77,4.03,2.92c0.89,1.15,1.5,2.44,1.82,3.88C45.29,31.66,45.45,33.95,45.45,37.11 L45.45,37.11z M35.08,33.63c0-2.21-0.11-3.59-0.32-4.15c-0.21-0.55-0.71-0.83-1.51-0.83c-0.77,0-1.28,0.3-1.53,0.89 c-0.25,0.59-0.38,1.96-0.38,4.1v20.29c0,2.41,0.11,3.87,0.35,4.36c0.23,0.5,0.73,0.75,1.51,0.75c0.77,0,1.27-0.29,1.52-0.88 c0.24-0.58,0.36-1.89,0.36-3.92V33.63L35.08,33.63z M98.87,23.01v41.64H88.49V42.3c0-3.23-0.07-5.18-0.23-5.83 c-0.15-0.65-0.58-1.15-1.27-1.48c-0.69-0.33-2.24-0.5-4.63-0.5h-1.03v-4.83c5.02-1.07,8.83-3.29,11.42-6.64H98.87L98.87,23.01z M64.96,7.05v72.68h50.87V7.05H64.96L64.96,7.05z M57.92,79.73V7.05H7.05v72.68H57.92L57.92,79.73z"
|
||||||
|
],
|
||||||
|
iconName: "simple-icons-score" as IconName,
|
||||||
|
prefix: "simple-icons" as IconPrefix
|
||||||
|
};
|
||||||
@ -15,12 +15,15 @@ export function SmartLogoBackground({
|
|||||||
}) {
|
}) {
|
||||||
const canvasRef = useRef(null);
|
const canvasRef = useRef(null);
|
||||||
const [background, setBackground] = useState(defaultBackground);
|
const [background, setBackground] = useState(defaultBackground);
|
||||||
|
const [load, setLoad] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (cache[src]) {
|
if (cache[src]) {
|
||||||
setBackground(cache[src]);
|
setBackground(cache[src]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!load)
|
||||||
|
return;
|
||||||
|
|
||||||
const canvas = canvasRef.current;
|
const canvas = canvasRef.current;
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
@ -29,6 +32,11 @@ export function SmartLogoBackground({
|
|||||||
img.crossOrigin = 'Anonymous';
|
img.crossOrigin = 'Anonymous';
|
||||||
img.src = src;
|
img.src = src;
|
||||||
|
|
||||||
|
// Prevent error logging
|
||||||
|
img.onerror = function () {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
canvas.width = img.width;
|
canvas.width = img.width;
|
||||||
canvas.height = img.height;
|
canvas.height = img.height;
|
||||||
@ -92,22 +100,18 @@ export function SmartLogoBackground({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}, [src, darkBackground, lightBackground, defaultBackground, tolerance, minPixels, load]);
|
||||||
// Prevent error logging
|
|
||||||
img.onerror = e => {
|
|
||||||
//e.stopPropagation()
|
|
||||||
//e.stopImmediatePropagation()
|
|
||||||
//e.preventDefault()
|
|
||||||
}
|
|
||||||
}, [src, darkBackground, lightBackground, defaultBackground, tolerance, minPixels]);
|
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<img className={imgClassName} src={src} alt={alt} style={{...style, filter: `drop-shadow(0 0 1rem ${background})`}}
|
<img className={imgClassName} src={src} alt={alt} style={{...style, filter: `drop-shadow(0 0 1rem ${background})`}}
|
||||||
onError={e => {
|
onError={e => {
|
||||||
e.preventDefault()
|
|
||||||
e.target.style.opacity = "0"
|
e.target.style.opacity = "0"
|
||||||
}
|
setLoad(false)
|
||||||
} onLoad={e => e.target.style.opacity = "1"}/>
|
}}
|
||||||
|
onLoad={e => {
|
||||||
|
e.target.style.opacity = "1"
|
||||||
|
setLoad(true)
|
||||||
|
}}/>
|
||||||
<canvas ref={canvasRef} style={{display: 'none'}}/>
|
<canvas ref={canvasRef} style={{display: 'none'}}/>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import {createContext, useContext, useReducer} from "react";
|
import {createContext, useContext, useEffect, useReducer} from "react";
|
||||||
|
import {useWS} from "./useWS.jsx";
|
||||||
|
|
||||||
const CombsContext = createContext({});
|
const CombsContext = createContext({});
|
||||||
const CombsDispatchContext = createContext(() => {
|
const CombsDispatchContext = createContext(() => {
|
||||||
@ -16,11 +17,18 @@ function compareCombs(a, b) {
|
|||||||
function reducer(state, action) {
|
function reducer(state, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'SET_COMB':
|
case 'SET_COMB':
|
||||||
if (state[action.payload.id] === undefined || !compareCombs(state[action.payload.id], action.payload)) {
|
const comb = (action.payload.source === "register") ? action.payload.data : ({
|
||||||
console.debug("Updating comb", action.payload);
|
id: action.payload.data.id,
|
||||||
|
fname: action.payload.data.fname,
|
||||||
|
lname: action.payload.data.lname,
|
||||||
|
genre: action.payload.data.genre,
|
||||||
|
country: action.payload.data.country,
|
||||||
|
})
|
||||||
|
if (state[comb.id] === undefined || !compareCombs(comb, state[comb.id])) {
|
||||||
|
console.debug("Updating comb", comb);
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
[action.payload.id]: action.payload.value
|
[comb.id]: comb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return state
|
return state
|
||||||
@ -58,12 +66,30 @@ function reducer(state, action) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function WSListener({dispatch}) {
|
||||||
|
const {dispatch: dispatchWS} = useWS()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const sendRegister = ({data}) => {
|
||||||
|
dispatch({type: 'SET_ALL', payload: {source: "register", data: data}});
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatchWS({type: 'addListener', payload: {callback: sendRegister, code: 'sendRegister'}})
|
||||||
|
return () => {
|
||||||
|
dispatchWS({type: 'removeListener', payload: {callback: sendRegister, code: 'sendRegister'}})
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return <></>
|
||||||
|
}
|
||||||
|
|
||||||
export function CombsProvider({children}) {
|
export function CombsProvider({children}) {
|
||||||
const [combs, dispatch] = useReducer(reducer, {})
|
const [combs, dispatch] = useReducer(reducer, {})
|
||||||
|
|
||||||
return <CombsContext.Provider value={combs}>
|
return <CombsContext.Provider value={combs}>
|
||||||
<CombsDispatchContext.Provider value={dispatch}>
|
<CombsDispatchContext.Provider value={dispatch}>
|
||||||
{children}
|
{children}
|
||||||
|
<WSListener dispatch={dispatch}/>
|
||||||
</CombsDispatchContext.Provider>
|
</CombsDispatchContext.Provider>
|
||||||
</CombsContext.Provider>
|
</CombsContext.Provider>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import {createContext, useContext, useReducer} from "react";
|
import {createContext, useContext, useReducer} from "react";
|
||||||
|
|
||||||
const PubAffContext = createContext({next: [], c1: undefined, c2: undefined});
|
const PubAffContext = createContext({next: [], c1: undefined, c2: undefined, showScore: true});
|
||||||
const PubAffDispatchContext = createContext(() => {
|
const PubAffDispatchContext = createContext(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -11,9 +11,10 @@ import {scorePrint, win} from "../../../utils/Tools.js";
|
|||||||
import {toast} from "react-toastify";
|
import {toast} from "react-toastify";
|
||||||
import {createPortal} from "react-dom";
|
import {createPortal} from "react-dom";
|
||||||
import {copyStyles} from "../../../utils/copyStyles.js";
|
import {copyStyles} from "../../../utils/copyStyles.js";
|
||||||
import {PubAffProvider, usePubAffDispatch, usePubAffState} from "../../../hooks/useExternalWindow.jsx";
|
import {PubAffProvider, usePubAffDispatch} from "../../../hooks/useExternalWindow.jsx";
|
||||||
import {faDisplay} from "@fortawesome/free-solid-svg-icons";
|
import {faDisplay} from "@fortawesome/free-solid-svg-icons";
|
||||||
import {PubAffWindow} from "./PubAffWindow.jsx";
|
import {PubAffWindow} from "./PubAffWindow.jsx";
|
||||||
|
import {SimpleIconsScore} from "../../../assets/SimpleIconsScore.ts";
|
||||||
|
|
||||||
function CupImg() {
|
function CupImg() {
|
||||||
return <img decoding="async" loading="lazy" width={"16"} height={"16"} className="wp-image-1635"
|
return <img decoding="async" loading="lazy" width={"16"} height={"16"} className="wp-image-1635"
|
||||||
@ -22,8 +23,15 @@ function CupImg() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function CMTable() {
|
export function CMTable() {
|
||||||
|
const combDispatch = useCombsDispatch()
|
||||||
const [catId, setCatId] = useState(-1);
|
const [catId, setCatId] = useState(-1);
|
||||||
const menuAction = useRef({});
|
const {data} = useRequestWS("getRegister", null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (data === null)
|
||||||
|
return;
|
||||||
|
combDispatch({type: 'SET_ALL', payload: {source: "register", data: data}});
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
return <PubAffProvider>
|
return <PubAffProvider>
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
@ -40,7 +48,7 @@ export function CMTable() {
|
|||||||
<div className="card">
|
<div className="card">
|
||||||
<div className="card-header">Matches</div>
|
<div className="card-header">Matches</div>
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<CategorieSelect catId={catId} setCatId={setCatId} menuAction={menuAction}/>
|
<CategorieSelect catId={catId} setCatId={setCatId}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{backgroundColor: "#c70000"}}>
|
<div style={{backgroundColor: "#c70000"}}>
|
||||||
@ -48,16 +56,18 @@ export function CMTable() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Menu menuAction={menuAction}/>
|
<Menu/>
|
||||||
</div>
|
</div>
|
||||||
</PubAffProvider>
|
</PubAffProvider>
|
||||||
}
|
}
|
||||||
|
|
||||||
const windowName = "FFSAFScorePublicWindow";
|
const windowName = "FFSAFScorePublicWindow";
|
||||||
|
|
||||||
function Menu({menuAction}) {
|
function Menu() {
|
||||||
const e = document.getElementById("actionMenu")
|
const e = document.getElementById("actionMenu")
|
||||||
|
const publicAffDispatch = usePubAffDispatch()
|
||||||
const [showPubAff, setShowPubAff] = useState(false)
|
const [showPubAff, setShowPubAff] = useState(false)
|
||||||
|
const [showScore, setShowScore] = useState(true)
|
||||||
|
|
||||||
const externalWindow = useRef(null)
|
const externalWindow = useRef(null)
|
||||||
const containerEl = useRef(document.createElement("div"))
|
const containerEl = useRef(document.createElement("div"))
|
||||||
@ -93,20 +103,28 @@ function Menu({menuAction}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleScore = __ => {
|
||||||
|
setShowScore(!showScore);
|
||||||
|
publicAffDispatch({type: 'SET_DATA', payload: {showScore: !showScore}});
|
||||||
|
}
|
||||||
|
|
||||||
if (!e)
|
if (!e)
|
||||||
return <></>;
|
return <></>;
|
||||||
return <>
|
return <>
|
||||||
{createPortal(
|
{createPortal(
|
||||||
<>
|
<>
|
||||||
<div className="vr" style={{margin: "0 0.5em", height: "100%"}}></div>
|
<div className="vr" style={{margin: "0 0.5em", height: "100%"}}></div>
|
||||||
<FontAwesomeIcon icon={faDisplay} size="xl" style={{color: showPubAff ? "#00c700" : "#6c757d", cursor: "pointer"}}
|
<FontAwesomeIcon icon={faDisplay} size="xl"
|
||||||
|
style={{color: showPubAff ? "#00c700" : "#6c757d", cursor: "pointer", marginRight: "0.25em"}}
|
||||||
onClick={handlePubAff}/>
|
onClick={handlePubAff}/>
|
||||||
|
<FontAwesomeIcon icon={SimpleIconsScore} size="xl" style={{color: showScore ? "#00c700" : "#6c757d", cursor: "pointer"}}
|
||||||
|
onClick={handleScore}/>
|
||||||
</>, document.getElementById("actionMenu"))}
|
</>, document.getElementById("actionMenu"))}
|
||||||
{externalWindow.current && createPortal(<PubAffWindow document={externalWindow.current.document}/>, containerEl.current)}
|
{externalWindow.current && createPortal(<PubAffWindow document={externalWindow.current.document}/>, containerEl.current)}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
||||||
function CategorieSelect({catId, setCatId, menuAction}) {
|
function CategorieSelect({catId, setCatId}) {
|
||||||
const setLoading = useLoadingSwitcher()
|
const setLoading = useLoadingSwitcher()
|
||||||
const {data: cats, setData: setCats} = useRequestWS('getAllCategory', {}, setLoading);
|
const {data: cats, setData: setCats} = useRequestWS('getAllCategory', {}, setLoading);
|
||||||
const {dispatch} = useWS();
|
const {dispatch} = useWS();
|
||||||
@ -130,11 +148,11 @@ function CategorieSelect({catId, setCatId, menuAction}) {
|
|||||||
<option key={c.id} value={c.id}>{c.name}</option>))}
|
<option key={c.id} value={c.id}>{c.name}</option>))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
{catId !== -1 && <MatchPanel catId={catId} cat={cat} menuAction={menuAction}/>}
|
{catId !== -1 && <MatchPanel catId={catId} cat={cat}/>}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
||||||
function MatchPanel({catId, cat, menuAction}) {
|
function MatchPanel({catId, cat}) {
|
||||||
const setLoading = useLoadingSwitcher()
|
const setLoading = useLoadingSwitcher()
|
||||||
const {sendRequest, dispatch} = useWS();
|
const {sendRequest, dispatch} = useWS();
|
||||||
const [trees, setTrees] = useState([]);
|
const [trees, setTrees] = useState([]);
|
||||||
@ -206,10 +224,10 @@ function MatchPanel({catId, cat, menuAction}) {
|
|||||||
}
|
}
|
||||||
}, [catId]);
|
}, [catId]);
|
||||||
|
|
||||||
return <ListMatch cat={cat} matches={matches} trees={trees} menuAction={menuAction}/>
|
return <ListMatch cat={cat} matches={matches} trees={trees}/>
|
||||||
}
|
}
|
||||||
|
|
||||||
function ListMatch({cat, matches, trees, menuAction}) {
|
function ListMatch({cat, matches, trees}) {
|
||||||
const [type, setType] = useState(1);
|
const [type, setType] = useState(1);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -246,6 +264,7 @@ function ListMatch({cat, matches, trees, menuAction}) {
|
|||||||
|
|
||||||
function MatchList({matches, cat}) {
|
function MatchList({matches, cat}) {
|
||||||
const [activeMatch, setActiveMatch] = useState(null)
|
const [activeMatch, setActiveMatch] = useState(null)
|
||||||
|
const [lice, setLice] = useState(localStorage.getItem("cm_lice") || "A")
|
||||||
const publicAffDispatch = usePubAffDispatch();
|
const publicAffDispatch = usePubAffDispatch();
|
||||||
|
|
||||||
const liceName = (cat.liceName || "N/A").split(";");
|
const liceName = (cat.liceName || "N/A").split(";");
|
||||||
@ -260,7 +279,7 @@ function MatchList({matches, cat}) {
|
|||||||
} else {
|
} else {
|
||||||
publicAffDispatch({
|
publicAffDispatch({
|
||||||
type: 'SET_DATA',
|
type: 'SET_DATA',
|
||||||
payload: {c1: match.c1, c2: match.c2, next: marches2.filter(m => !m.end && m.id !== activeMatch).map(m => ({c1: m.c1, c2: m.c2}))}
|
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]);
|
}, [match]);
|
||||||
@ -269,17 +288,36 @@ function MatchList({matches, cat}) {
|
|||||||
// setActiveMatch(null);
|
// setActiveMatch(null);
|
||||||
//}, [cat])
|
//}, [cat])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (match && match.poule !== lice)
|
||||||
|
setActiveMatch(marches2.find(m => !m.end && m.poule === lice)?.id)
|
||||||
|
}, [lice]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (marches2.length === 0)
|
if (marches2.length === 0)
|
||||||
return;
|
return;
|
||||||
if (marches2.some(m => m.id === activeMatch))
|
if (marches2.some(m => m.id === activeMatch))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
setActiveMatch(marches2.find(m => !m.end)?.id);
|
setActiveMatch(marches2.find(m => !m.end && m.poule === lice)?.id);
|
||||||
}, [matches])
|
}, [matches])
|
||||||
|
|
||||||
const firstIndex = marches2.findLastIndex(m => m.poule === '-') + 1;
|
const firstIndex = marches2.findLastIndex(m => m.poule === '-') + 1;
|
||||||
return <>
|
return <>
|
||||||
|
{liceName.length > 1 &&
|
||||||
|
<div className="input-group" style={{maxWidth: "10em", marginTop: "0.5em"}}>
|
||||||
|
<label className="input-group-text" htmlFor="selectLice">Lice</label>
|
||||||
|
<select className="form-select" id="selectLice" value={lice} onChange={e => {
|
||||||
|
setLice(e.target.value);
|
||||||
|
localStorage.setItem("cm_lice", e.target.value);
|
||||||
|
}}>
|
||||||
|
{liceName.map((l, index) => (
|
||||||
|
<option key={index} value={l}>{l}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<div className="table-responsive-xxl">
|
<div className="table-responsive-xxl">
|
||||||
<table className="table table-striped table-hover">
|
<table className="table table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
@ -295,7 +333,7 @@ function MatchList({matches, cat}) {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody className="table-group-divider">
|
<tbody className="table-group-divider">
|
||||||
{marches2.map((m, index) => (
|
{marches2.map((m, index) => (
|
||||||
<tr key={m.id} className={m.id === activeMatch ? "table-info" : ""} onClick={() => setActiveMatch(m.id)}>
|
<tr key={m.id} className={m.id === activeMatch ? "table-info" : (m.poule === lice ? "" : "table-warning")} onClick={() => setActiveMatch(m.id)}>
|
||||||
<td style={{textAlign: "center", paddingLeft: "0.2em", paddingRight: "0.2em"}}>
|
<td style={{textAlign: "center", paddingLeft: "0.2em", paddingRight: "0.2em"}}>
|
||||||
{liceName[(index - firstIndex) % liceName.length]}</td>
|
{liceName[(index - firstIndex) % liceName.length]}</td>
|
||||||
<td style={{textAlign: "center", paddingLeft: "0.2em", paddingRight: "0.2em"}}>{m.poule}</td>
|
<td style={{textAlign: "center", paddingLeft: "0.2em", paddingRight: "0.2em"}}>{m.poule}</td>
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
import {useCombs} from "../../../hooks/useComb.jsx";
|
import {useCombs} from "../../../hooks/useComb.jsx";
|
||||||
import {usePubAffState} from "../../../hooks/useExternalWindow.jsx";
|
import {usePubAffState} from "../../../hooks/useExternalWindow.jsx";
|
||||||
|
import {SmartLogoBackgroundMemo} from "../../../components/SmartLogoBackground.jsx";
|
||||||
|
import {useMemo} from 'react';
|
||||||
|
|
||||||
|
const vite_url = import.meta.env.VITE_URL;
|
||||||
|
|
||||||
const noMP = {margin: 0, padding: 0};
|
const noMP = {margin: 0, padding: 0};
|
||||||
const redBackground = "radial-gradient(circle, #C80000FF 0%, #000000FF 100%)"
|
const redBackground = "radial-gradient(circle, #C80000FF 0%, #000000FF 100%)"
|
||||||
@ -14,7 +18,7 @@ export function PubAffWindow({document}) {
|
|||||||
document.title = "A React portal window"
|
document.title = "A React portal window"
|
||||||
document.body.className = "bg-dark text-white overflow-hidden";
|
document.body.className = "bg-dark text-white overflow-hidden";
|
||||||
|
|
||||||
const showScore = false;
|
const showScore = state.showScore ?? true;
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<div className="row text-center"
|
<div className="row text-center"
|
||||||
@ -73,8 +77,6 @@ function MatchDisplay({state}) {
|
|||||||
const {getComb} = useCombs();
|
const {getComb} = useCombs();
|
||||||
const combs = state?.next?.slice(1, 6) || [];
|
const combs = state?.next?.slice(1, 6) || [];
|
||||||
|
|
||||||
console.log("Rendering MatchDisplay for", combs);
|
|
||||||
|
|
||||||
return <div className="col-12 position-relative" style={{height: `calc(${combHeight} * 2)`}}>
|
return <div className="col-12 position-relative" style={{height: `calc(${combHeight} * 2)`}}>
|
||||||
<div className="position-absolute bottom-0 start-0" style={{height: "100%", background: redBackground, width: "50vw"}}/>
|
<div className="position-absolute bottom-0 start-0" style={{height: "100%", background: redBackground, width: "50vw"}}/>
|
||||||
<div className="position-absolute bottom-0 start-50" style={{height: "100%", background: blueBackground, width: "50vw"}}/>
|
<div className="position-absolute bottom-0 start-50" style={{height: "100%", background: blueBackground, width: "50vw"}}/>
|
||||||
@ -99,7 +101,8 @@ function MatchDisplay({state}) {
|
|||||||
<div className="col" style={{fontSize: `3vh`}}>
|
<div className="col" style={{fontSize: `3vh`}}>
|
||||||
{c2.fname} {c2.lname}
|
{c2.fname} {c2.lname}
|
||||||
</div>
|
</div>
|
||||||
{index !== combs.length - 1 && <div className="w-75" style={{...noMP, height: "0.2vh", margin: "0 12.5vw", backgroundColor: "#646464AA"}}/>}
|
{index !== combs.length - 1 &&
|
||||||
|
<div className="w-75" style={{...noMP, height: "0.2vh", margin: "0 12.5vw", backgroundColor: "#646464AA"}}/>}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
})}
|
})}
|
||||||
@ -107,11 +110,18 @@ function MatchDisplay({state}) {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const logoStyle = {width: "6vw", height: "min(11vh, 6vw)", objectFit: "contain", margin: "0 .5vw"};
|
||||||
|
|
||||||
function CombDisplay({combId, background, children}) {
|
function CombDisplay({combId, background, children}) {
|
||||||
const {getComb} = useCombs();
|
const {getComb} = useCombs();
|
||||||
const comb = getComb(combId, "");
|
const comb = getComb(combId, "");
|
||||||
|
|
||||||
//console.log("Rendering CombDisplay for", combId, comb);
|
const logoAlt = useMemo(() => {
|
||||||
|
return comb?.club_str
|
||||||
|
}, [comb]);
|
||||||
|
const logoSrc = useMemo(() => {
|
||||||
|
return `${vite_url}/api/club/${comb?.club_uuid}/logo`
|
||||||
|
}, [comb]);
|
||||||
|
|
||||||
return <div className="col position-relative"
|
return <div className="col position-relative"
|
||||||
style={{
|
style={{
|
||||||
@ -123,8 +133,8 @@ function CombDisplay({combId, background, children}) {
|
|||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
}}>
|
}}>
|
||||||
{comb !== "" && <>
|
{comb !== "" && <>
|
||||||
<img src={`/flags/svg/ad.svg`} alt={"fr"} style={{width: "6vw", height: "min(9vh, 6vw)", objectFit: "contain", margin: "0 .5vw"}}/>
|
<SmartLogoBackgroundMemo src={logoSrc} alt={logoAlt} style={logoStyle}/>
|
||||||
<div style={{fontSize: "min(3.5vw, 10vh)"}}>{comb.fname} {comb.lname}</div>
|
<div style={{fontSize: "min(3.5vw, 6.5vh)"}}>{comb.fname} {comb.lname}</div>
|
||||||
<img src={`/flags/svg/${comb.country.toLowerCase()}.svg`} alt={comb.country}
|
<img src={`/flags/svg/${comb.country.toLowerCase()}.svg`} alt={comb.country}
|
||||||
style={{width: "4vw", height: "8vh", objectFit: "contain", margin: "0 1.25vw"}}/>
|
style={{width: "4vw", height: "8vh", objectFit: "contain", margin: "0 1.25vw"}}/>
|
||||||
</>}
|
</>}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user