diff --git a/src/components/Admin/GameDisplay/FinalRoundButtonControls.jsx b/src/components/Admin/GameDisplay/FinalRoundButtonControls.jsx new file mode 100644 index 00000000..838b9571 --- /dev/null +++ b/src/components/Admin/GameDisplay/FinalRoundButtonControls.jsx @@ -0,0 +1,94 @@ +import { useTranslation } from "react-i18next"; + +function FinalRoundButtonControls({ game, send, setGame }) { + const { t } = useTranslation(); + const controlRound = game.is_final_second ? game.final_round_2 : game.final_round; + return controlRound?.map((x, i) => ( +
+

{x.question}

+ {game.is_final_second && ( +
+ {/* PARTNER'S ANSWER PROVIDED FINAL ROUND */} +
+ {t("Partner's Answer")}: {game.final_round[i].input || `(${t("No Answer")})`} +
+ {game.final_round[i].input && ( + + )} +
+ )} +
+ {/* ANSWER PROVIDED FINAL ROUND */} + { + x.input = e.target.value; + setGame((prv) => ({ ...prv })); + }} + /> + + +
+
+ {/* POINTS AWARDED FINAL ROUND */} + + + +
+
+ )); +} + +export default FinalRoundButtonControls; \ No newline at end of file diff --git a/src/components/Admin/GameDisplay/FinalRoundPointTotals.jsx b/src/components/Admin/GameDisplay/FinalRoundPointTotals.jsx new file mode 100644 index 00000000..e7bdfeec --- /dev/null +++ b/src/components/Admin/GameDisplay/FinalRoundPointTotals.jsx @@ -0,0 +1,53 @@ +import { useTranslation } from "react-i18next"; + +function FinalRoundPointTotalsTextFunction({ title, total, isFinalSecond, place }) { + const { t } = useTranslation(); + const backgroundColor = + (isFinalSecond && place === 1) || (!isFinalSecond && place === 0) + ? "bg-primary-200" + : "bg-secondary-300"; + return ( +
+

+ {t(title)}:{" "} +

+

+ {total} +

+
+ ); +} + +const calculateTotalPoints = (rounds) => + rounds.reduce((total, round) => total + parseInt(round.points), 0); + +function FinalRoundPointTotals({ game }) { + const roundOneTotal = calculateTotalPoints(game.final_round); + const roundTwoTotal = calculateTotalPoints(game.final_round_2); + return ( +
+ + + +
+ ); +} + +export default FinalRoundPointTotals; \ No newline at end of file diff --git a/src/components/Admin/GameDisplay/TeamControls.jsx b/src/components/Admin/GameDisplay/TeamControls.jsx new file mode 100644 index 00000000..c91af1fc --- /dev/null +++ b/src/components/Admin/GameDisplay/TeamControls.jsx @@ -0,0 +1,57 @@ +import { useTranslation } from "react-i18next"; + +function TeamControls({ game, setGame, team, send, setPointsGiven, pointsGiven }) { + const { t } = useTranslation(); + + function TeamGetsPointsButton() { + return ( + + ); + } + + function TeamMistakeButton() { + return ( + + ); + } + + return ( + <> + + + + ); +} + +export default TeamControls; \ No newline at end of file diff --git a/src/components/Admin/GameDisplay/TitleMusic.jsx b/src/components/Admin/GameDisplay/TitleMusic.jsx new file mode 100644 index 00000000..5f33e34a --- /dev/null +++ b/src/components/Admin/GameDisplay/TitleMusic.jsx @@ -0,0 +1,15 @@ +import { useTranslation } from "react-i18next"; + +function TitleMusic() { + const { t } = useTranslation(); + return ( +
+

{t("Title Music")}

+ +
+ ); +} + +export default TitleMusic; \ No newline at end of file diff --git a/src/components/Admin/GameDisplay/index.jsx b/src/components/Admin/GameDisplay/index.jsx new file mode 100644 index 00000000..b715b166 --- /dev/null +++ b/src/components/Admin/GameDisplay/index.jsx @@ -0,0 +1,509 @@ +import { useTranslation } from "react-i18next"; +import Players from "@/components/Admin/Players"; +import BuzzerTable from "@/components/BuzzerTable"; +import Image from "next/image"; +import TitleMusic from "@/components/Admin/GameDisplay/TitleMusic"; +import TeamControls from "@/components/Admin/GameDisplay/TeamControls"; +import FinalRoundButtonControls from "@/components/Admin/GameDisplay/FinalRoundButtonControls"; +import FinalRoundPointTotals from "@/components/Admin/GameDisplay/FinalRoundPointTotals"; + +function GameDisplay({ + ws, + setGame, + game, + room, + send, + setPointsGiven, + pointsGiven, + timerStarted, + timerCompleted, + setTimerStarted, + setTimerCompleted +}) { + const { t } = useTranslation(); + + if (game.rounds == null) { + {/* SHOW ERRORS TO ADMIN */} + return

[{t("Please load a game")}]

; + } + + let current_screen; + if (game.title) { + current_screen = t("title"); + } else if (!game.is_final_round) { + current_screen = `${t("round")} ${t("number", { + count: game.round + 1, + })}`; + } else if (!game.is_final_second) { + current_screen = `${t("Final Round")} ${t("number", { count: 1 })}`; + } else { + current_screen = `${t("Final Round")} ${t("number", { count: 2 })}`; + } + + // var put it into function scope + var current_round = game.rounds[game.round]; + console.debug("Current round:", current_round); + + return ( +
+
+
+
+ + {/* CURRENT SCREEN TEXT */} +

+ {" "} + {t("Current Screen")}: {current_screen} +

+
+ +
+ {/* TITLE SCREEN BUTTON */} + + + {/* FINAL ROUND BUTTON */} + {game.final_round ? ( + + ) : null} + + {/* ROUND SELECTOR */} + +
+ {/* START ROUND 1 BUTTON */} +
+ + + {/* NEXT ROUND BUTTON */} + + + +
+ + {/* GETS POINTS MISTAKE */} +
+ + +
+
+
+ + {/* IS NOT THE FINAL ROUND */} + {!game.is_final_round ? ( + // GAME BOARD CONTROLS +
+
+ {/* QUESTION */} +

+ {current_round.question} +

+ {/* POINT TRACKER */} +
+
+

+ {t("Points")}:{" "} +

+

+ {t("number", { count: game.point_tracker[game.round] })} +

+
+
+

+ {t("multiplier")}:{" "} +

+

x

+ { + let value = parseInt(e.target.value); + if (value === 0) { + value = 1; + } + current_round.multiply = value; + setGame((prv) => ({ ...prv })); + send({ action: "data", data: game }); + }} + /> +
+
+
+ + {/* GAME BOARD BUTTONS */} +
+ {current_round.answers.map((x, index) => ( +
+ +
+ ))} +
+ + {/* BUZZERS AND PLAYERS */} +
+

{t("Buzzer Order")}

+

{t("players")}

+
+
+
+ {game.buzzed.length > 0 ? ( +
+ {/* active clear buzzers button */} + +

{t("Changing rounds also clears buzzers")}

+
+ ) : ( +
+ {/* disabled clear buzzers button */} + +

{t("Changing rounds also clears buzzers")}

+
+ )} +
+
+
+ +
+
+
+ +
+
+ ) : ( + // FINAL ROUND +
+ +
+ {/* FINAL ROUND TEXT */} +

+ {t("Final Round")} {t("number", { count: game.is_final_second ? "2" : "1" })} +

+
+
+ {/* START FINAL ROUND 2 */} + {!game.is_final_second ? ( + + ) : ( +
+ {/* GO BACK TO FINAL ROUND 1 */} + + {game.is_final_second ? ( +
+ {/* REVEAL FIRST ROUND ANSWERS */} + {game.hide_first_round ? ( + + ) : ( + // HIDE FIRST ROUND ANSWERS + + )} +
+ ) : null} +
+ )} +
+ {!timerStarted ? ( + /* START TIMER */ + + ) : ( + /* STOP TIMER */ + + )} + +
+
+ + {/* FINAL ROUND QUESTIONS AND ANSWERS */} + +
+
+ )} +
+ ); +} + +export default GameDisplay; \ No newline at end of file diff --git a/src/components/Admin/RoomSettings.jsx b/src/components/Admin/RoomSettings.jsx new file mode 100644 index 00000000..659ff1d8 --- /dev/null +++ b/src/components/Admin/RoomSettings.jsx @@ -0,0 +1,66 @@ +import { useTranslation } from "react-i18next"; +import GameLoader from "@/components/Admin/GameLoader"; +import LanguageSwitcher from "@/components/LanguageSwitcher"; +import Link from "next/link"; + +function RoomSettings({ + room, + gameSelector, + send, + setError, + setCsvFileUpload, + setCsvFileUploadText, + quitGame +}) { + const { i18n, t } = useTranslation(); + return ( +
+ {/* ROOM CODE TEXT */} +

+ {room} +

+
+
+ {/* ADMIN BUTTONS */} + + + + + + + +
+
+ { + i18n.changeLanguage(e.target.value); + send({ action: "change_lang", data: e.target.value }); + }} + /> + +
+
+ ); +} + +export default RoomSettings; \ No newline at end of file diff --git a/src/components/Admin/TitleLogoUpload.jsx b/src/components/Admin/TitleLogoUpload.jsx new file mode 100644 index 00000000..f7c85b26 --- /dev/null +++ b/src/components/Admin/TitleLogoUpload.jsx @@ -0,0 +1,133 @@ +import { useTranslation } from "react-i18next"; +import { Buffer } from "buffer"; +import { FileUp } from "lucide-react"; +import { Image } from "next/image"; + +function BeforeUpload({ send, room, setGame, game, setError, setImageUploaded }) { + const { t } = useTranslation(); + return ( +
+
+ + { + var file = document.getElementById("logoUpload").files[0]; + + if (file) { + if (file.size > process.env.NEXT_PUBLIC_MAX_IMAGE_UPLOAD_SIZE_MB * 1024 * 1024) { + console.error("Logo image is too large"); + setError(t(ERROR_CODES.IMAGE_TOO_LARGE, { message: "2MB" })); + return; + } + var reader = new FileReader(); + let rawData = new ArrayBuffer(); + reader.onload = function (evt) { + rawData = evt.target.result; + var headerarr = new Uint8Array(evt.target.result).subarray(0, 4); + var header = ""; + for (var i = 0; i < headerarr.length; i++) { + header += headerarr[i].toString(16); + } + let mimetype = ""; + switch (header) { + case "89504e47": + mimetype = "png"; + break; + case "47494638": + mimetype = "gif"; + break; + case "ffd8ffe0": + case "ffd8ffe1": + case "ffd8ffe2": + case "ffd8ffe3": + case "ffd8ffe8": + mimetype = "jpeg"; + break; + default: + setError(t(ERROR_CODES.UNKNOWN_FILE_TYPE)); + return; + } + + const bufferData = Buffer.from(rawData).toString("base64"); + send({ + action: "logo_upload", + logoData: bufferData, + mimetype: mimetype, + }); + setImageUploaded(file); + game.settings.logo_url = `/api/rooms/${room}/logo`; + setGame((prv) => ({ ...prv })); + send({ action: "data", data: game }); + }; + reader.readAsArrayBuffer(file); + } + document.getElementById("logoUpload").value = null; + }} + /> +
+
+

{t("logo upload")}

+

{t("(must be smaller than 2MB)")}

+
+
+ ); +} + +function AfterUpload({ send, room, game, setGame, setImageUploaded, imageUploaded }) { + return ( +
+

logo:

+ Game Logo + +
+ ); +} + +function TitleLogoUpload({ send, room, setGame, game, setError, setImageUploaded, imageUploaded }) { + return imageUploaded === null + ? + : ; +} + +export default TitleLogoUpload; \ No newline at end of file diff --git a/src/components/Admin/TitlesAndLogoSettings.jsx b/src/components/Admin/TitlesAndLogoSettings.jsx new file mode 100644 index 00000000..b147d596 --- /dev/null +++ b/src/components/Admin/TitlesAndLogoSettings.jsx @@ -0,0 +1,114 @@ +import { useTranslation } from "react-i18next"; +import { debounce } from "@/lib/utils"; +import TitleLogoUpload from "@/components/Admin/TitleLogoUpload"; + +function TitlesAndLogoSettings({ + game, + send, + room, + setGame, + setError, + setImageUploaded, + imageUploaded, + error +}) { + const { t } = useTranslation(); + return ( +
+
+
+ {/* TITLE TEXT INPUT */} +
+

{t("Title Text")}:

+ { + game.title_text = e.target.value; + setGame((prv) => ({ ...prv })); + send({ action: "data", data: game }); + })} + placeholder={t("My Family")} + defaultValue={game.title_text} + > +
+
+ +
+ {/* TEAM 1 NAME CHANGER */} + { + game.teams[0].name = e.target.value; + setGame((prv) => ({ ...prv })); + send({ action: "data", data: game }); + })} + placeholder={t("Team Name")} + defaultValue={game.teams[0].name} + > + {/* TEAM 1 POINTS CHANGER */} + { + let number = parseInt(e.target.value); + console.debug(number); + isNaN(number) ? (number = 0) : null; + game.teams[0].points = number; + setGame((prv) => ({ ...prv })); + send({ action: "data", data: game }); + }} + value={game.teams[0].points} + > +
+
+ {/* TEAM 2 NAME CHANGER */} + { + game.teams[1].name = e.target.value; + setGame((prv) => ({ ...prv })); + send({ action: "data", data: game }); + })} + placeholder={t("Team Name")} + defaultValue={game.teams[1].name} + > + {/* TEAM 2 POINTS CHANGER */} + { + let number = parseInt(e.target.value); + isNaN(number) ? (number = 0) : null; + game.teams[1].points = number; + setGame((prv) => ({ ...prv })); + send({ action: "data", data: game }); + }} + value={game.teams[1].points} + > +
+
+

+ {error.code ? t(error.code, { message: error.message }) : t(error)} +

+
+ ); +} + +export default TitlesAndLogoSettings; \ No newline at end of file diff --git a/src/components/AdminPage.jsx b/src/components/AdminPage.jsx index f468ea63..7a6ad194 100644 --- a/src/components/AdminPage.jsx +++ b/src/components/AdminPage.jsx @@ -1,347 +1,18 @@ import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import "@/i18n/i18n"; -import { Buffer } from "buffer"; -import AdminSettings from "@/components/Admin/AdminSettings"; import CSVLoader from "@/components/Admin/CSVLoader"; -import GameLoader from "@/components/Admin/GameLoader"; -import Players from "@/components/Admin/Players"; -import BuzzerTable from "@/components/BuzzerTable"; -import LanguageSwitcher from "@/components/LanguageSwitcher"; +import AdminSettings from "@/components/Admin/AdminSettings"; import { ERROR_CODES } from "@/i18n/errorCodes"; -import { debounce } from "@/lib/utils"; -import { FileUp } from "lucide-react"; -import Image from "next/image"; -import Link from "next/link"; - -function TitleMusic() { - const { i18n, t } = useTranslation(); - return ( -
-

{t("Title Music")}

- -
- ); -} +import RoomSettings from "@/components/Admin/RoomSettings"; +import TitlesAndLogoSettings from "@/components/Admin/TitlesAndLogoSettings"; +import GameDisplay from "@/components/Admin/GameDisplay"; -function TeamControls(props) { - const { i18n, t } = useTranslation(); - return ( - <> - - - - ); -} -function FinalRoundButtonControls(props) { +export default function AdminPage({ ws, game, setGame, room, quitGame, playerId }) { const { i18n, t } = useTranslation(); - const controlRound = props.game.is_final_second ? props.game.final_round_2 : props.game.final_round; - return controlRound?.map((x, i) => ( -
-

{x.question}

- {props.game.is_final_second && ( -
- {/* PARTNER'S ANSWER PROVIDED FINAL ROUND */} -
- {t("Partner's Answer")}: {props.game.final_round[i].input || `(${t("No Answer")})`} -
- {props.game.final_round[i].input && ( - - )} -
- )} -
- {/* ANSWER PROVIDED FINAL ROUND */} - { - x.input = e.target.value; - props.setGame((prv) => ({ ...prv })); - }} - /> - - -
-
- {/* POINTS AWARDED FINAL ROUND */} - - - -
-
- )); -} -function TitleLogoUpload(props) { - const { i18n, t } = useTranslation(); - if (props.imageUploaded !== null) { - return ( -
-

logo:

- Game Logo - -
- ); - } else { - return ( -
-
- - { - var file = document.getElementById("logoUpload").files[0]; - - if (file) { - if (file.size > process.env.NEXT_PUBLIC_MAX_IMAGE_UPLOAD_SIZE_MB * 1024 * 1024) { - console.error("Logo image is too large"); - props.setError(t(ERROR_CODES.IMAGE_TOO_LARGE, { message: "2MB" })); - return; - } - var reader = new FileReader(); - let rawData = new ArrayBuffer(); - reader.onload = function (evt) { - rawData = evt.target.result; - var headerarr = new Uint8Array(evt.target.result).subarray(0, 4); - var header = ""; - for (var i = 0; i < headerarr.length; i++) { - header += headerarr[i].toString(16); - } - let mimetype = ""; - switch (header) { - case "89504e47": - mimetype = "png"; - break; - case "47494638": - mimetype = "gif"; - break; - case "ffd8ffe0": - case "ffd8ffe1": - case "ffd8ffe2": - case "ffd8ffe3": - case "ffd8ffe8": - mimetype = "jpeg"; - break; - default: - props.setError(t(ERROR_CODES.UNKNOWN_FILE_TYPE)); - return; - } - - const bufferData = Buffer.from(rawData).toString("base64"); - props.send({ - action: "logo_upload", - logoData: bufferData, - mimetype: mimetype, - }); - props.setImageUploaded(file); - props.game.settings.logo_url = `/api/rooms/${props.room}/logo`; - props.setGame((prv) => ({ ...prv })); - props.send({ action: "data", data: props.game }); - }; - reader.readAsArrayBuffer(file); - } - document.getElementById("logoUpload").value = null; - }} - /> -
-
-

{t("logo upload")}

-

{t("(must be smaller than 2MB)")}

-
-
- ); - } -} - -function FinalRoundPointTotalsTextFunction(props) { - const { i18n, t } = useTranslation(); - let backgroundColor = "bg-secondary-300"; - if (props.isFinalSecond && props.place === 1) { - backgroundColor = "bg-primary-200"; - } else if (!props.isFinalSecond && props.place === 0) { - backgroundColor = "bg-primary-200"; - } - return ( -
-

- {t(props.title)}:{" "} -

-

- {props.total} -

-
- ); -} - -function FinalRoundPointTotals(props) { - let roundOneTotal = 0; - let roundTwoTotal = 0; - let total = 0; - props.game.final_round.forEach((round) => { - console.debug("round one total: "); - roundOneTotal = roundOneTotal + parseInt(round.points); - }); - props.game.final_round_2.forEach((round) => { - console.debug("round two total", total); - roundTwoTotal = roundTwoTotal + parseInt(round.points); - }); - total = roundOneTotal + roundTwoTotal; - return ( -
- - - -
- ); -} - -export default function AdminPage(props) { - const { i18n, t } = useTranslation(); - - const [pointsGivin, setPointsGivin] = useState({ + const [pointsGiven, setPointsGiven] = useState({ state: false, color: "bg-success-500", textColor: "text-foreground", @@ -353,25 +24,42 @@ export default function AdminPage(props) { const [timerCompleted, setTimerCompleted] = useState(false); const [csvFileUpload, setCsvFileUpload] = useState(null); const [csvFileUploadText, setCsvFileUploadText] = useState(null); - let ws = props.ws; - let game = props.game; let refreshCounter = 0; function setError(e) { setErrorVal(e); console.error(e); - setTimeout(() => { - setErrorVal(""); - }, 10000); + setTimeout(() => setErrorVal(""), 10000); } function send(data) { - data.room = props.room; - data.id = props.id; - console.debug(data); - ws.current.send(JSON.stringify(data)); + console.debug("Sending", data); + ws.current.send(JSON.stringify({ ...data, room, id: playerId })); } + const handleMessage = (evt) => { + var received_msg = evt.data; + let json = JSON.parse(received_msg); + if (json.action === "data") { + setGame(json.data); + } else if (json.action === "change_lang") { + console.debug("Language Change", json.data); + if (json.games != null) { + setGameSelector(json.games); + } else { + setGameSelector([]); + } + } else if (json.action === "error") { + console.error(json.code); + setError(t(json.code, { message: json.message })); + } else if (json.action === "timer_complete") { + setTimerStarted(false); + setTimerCompleted(true); + } else { + console.debug("did not expect admin: ", json); + } + }; + useEffect(() => { const retryInterval = setInterval(() => { if (ws.current.readyState !== 1) { @@ -384,29 +72,6 @@ export default function AdminPage(props) { } }, 1000); - const handleMessage = (evt) => { - var received_msg = evt.data; - let json = JSON.parse(received_msg); - if (json.action === "data") { - props.setGame(json.data); - } else if (json.action === "change_lang") { - console.debug("Language Change", json.data); - if (json.games != null) { - setGameSelector(json.games); - } else { - setGameSelector([]); - } - } else if (json.action === "error") { - console.error(json.code); - setError(t(json.code, { message: json.message })); - } else if (json.action === "timer_complete") { - setTimerStarted(false); - setTimerCompleted(true); - } else { - console.debug("did not expect admin: ", json); - } - }; - ws.current.addEventListener("message", handleMessage); send({ action: "change_lang", data: i18n.language?.split("-")[0] }); return () => { @@ -415,658 +80,66 @@ export default function AdminPage(props) { }; }, [i18n.language]); - if (game.teams != null) { - let current_screen; - if (game.title) { - current_screen = t("title"); - } else if (game.is_final_round && !game.is_final_second) { - current_screen = `${t("Final Round")} ${t("number", { count: 1 })}`; - } else if (game.is_final_round && game.is_final_second) { - current_screen = `${t("Final Round")} ${t("number", { count: 2 })}`; - } else { - current_screen = `${t("round")} ${t("number", { - count: game.round + 1, - })}`; - } - - if (game.rounds != null) { - // var put it into function scope - var current_round = game.rounds[game.round]; - console.debug("This is current round", current_round); - } - return ( -
-
- {/* ROOM CODE TEXT */} -

- {props.room} -

-
-
- {/* ADMIN BUTTONS */} - - - - - - - -
-
- { - i18n.changeLanguage(e.target.value); - send({ action: "change_lang", data: e.target.value }); - }} - /> - -
-
- -
-
-
-
- {/* TITLE TEXT INPUT */} -
-

{t("Title Text")}:

- { - game.title_text = e.target.value; - props.setGame((prv) => ({ ...prv })); - send({ action: "data", data: game }); - })} - placeholder={t("My Family")} - defaultValue={game.title_text} - > -
-
- -
- {/* TEAM 1 NAME CHANGER */} - { - game.teams[0].name = e.target.value; - props.setGame((prv) => ({ ...prv })); - send({ action: "data", data: game }); - })} - placeholder={t("Team Name")} - defaultValue={game.teams[0].name} - > - {/* TEAM 1 POINTS CHANGER */} - { - let number = parseInt(e.target.value); - console.debug(number); - isNaN(number) ? (number = 0) : null; - game.teams[0].points = number; - props.setGame((prv) => ({ ...prv })); - send({ action: "data", data: game }); - }} - value={game.teams[0].points} - > -
-
- {/* TEAM 2 NAME CHANGER */} - { - game.teams[1].name = e.target.value; - props.setGame((prv) => ({ ...prv })); - send({ action: "data", data: game }); - })} - placeholder={t("Team Name")} - defaultValue={game.teams[1].name} - > - {/* TEAM 2 POINTS CHANGER */} - { - let number = parseInt(e.target.value); - isNaN(number) ? (number = 0) : null; - game.teams[1].points = number; - props.setGame((prv) => ({ ...prv })); - send({ action: "data", data: game }); - }} - value={game.teams[1].points} - > -
-
-
- {error.code ? t(error.code, { message: error.message }) : t(error)} -
-
-
- {/* ADMIN CONTROLS */} - - {/* SHOW ERRORS TO ADMIN */} - {game.rounds == null ? ( -

[{t("Please load a game")}]

- ) : ( -
-
-
-
- - {/* CURRENT SCREEN TEXT */} -

- {" "} - {t("Current Screen")}: {current_screen} -

-
- -
- {/* TITLE SCREEN BUTTON */} - - - {/* FINAL ROUND BUTTON */} - {game.final_round ? ( - - ) : null} - - {/* ROUND SELECTOR */} - -
- {/* START ROUND 1 BUTTON */} -
- - - {/* NEXT ROUND BUTTON */} - - - -
- - {/* GETS POINTS MISTAKE */} -
- - -
-
-
- - {/* IS NOT THE FINAL ROUND */} - {!game.is_final_round ? ( - // GAME BOARD CONTROLS -
-
- {/* QUESTION */} -

- {current_round.question} -

- {/* POINT TRACKER */} -
-
-

- {t("Points")}:{" "} -

-

- {t("number", { count: game.point_tracker[game.round] })} -

-
-
-

- {t("multiplier")}:{" "} -

-

x

- { - let value = parseInt(e.target.value); - if (value === 0) { - value = 1; - } - current_round.multiply = value; - props.setGame((prv) => ({ ...prv })); - send({ action: "data", data: game }); - }} - /> -
-
-
- - {/* GAME BOARD BUTTONS */} -
- {current_round.answers.map((x, index) => ( -
- -
- ))} -
- - {/* BUZZERS AND PLAYERS */} -
-

{t("Buzzer Order")}

-

{t("players")}

-
-
-
- {game.buzzed.length > 0 ? ( -
- {/* active clear buzzers button */} - -

{t("Changing rounds also clears buzzers")}

-
- ) : ( -
- {/* disabled clear buzzers button */} - -

{t("Changing rounds also clears buzzers")}

-
- )} -
-
-
- -
-
-
- -
-
- ) : ( - // FINAL ROUND -
- -
- {/* FINAL ROUND TEXT */} -

- {t("Final Round")} {t("number", { count: game.is_final_second ? "2" : "1" })} -

-
-
- {/* START FINAL ROUND 2 */} - {!game.is_final_second ? ( - - ) : ( -
- {/* GO BACK TO FINAL ROUND 1 */} - - {game.is_final_second ? ( -
- {/* REVEAL FIRST ROUND ANSWERS */} - {game.hide_first_round ? ( - - ) : ( - // HIDE FIRST ROUND ANSWERS - - )} -
- ) : null} -
- )} -
- {!timerStarted ? ( - /* START TIMER */ - - ) : ( - /* STOP TIMER */ - - )} - -
-
- - {/* FINAL ROUND QUESTIONS AND ANSWERS */} - -
-
- )} -
- )} - {/* Modal over whole admin page */} - {csvFileUpload ? ( - - ) : null} -
- ); - } else { + if (game.teams == null) { return (

{t("loading")}

); } + + return ( +
+ +
+ +
+ {/* ADMIN CONTROLS */} + + + {/* Modal over whole admin page */} + {csvFileUpload && + + } +
+ ); } diff --git a/src/pages/index.jsx b/src/pages/index.jsx index 3c65142b..5e01fe3c 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -195,7 +195,7 @@ export default function Home() {