From 62b084e478828b60bd43927ba832bfd3795ae5b1 Mon Sep 17 00:00:00 2001 From: Ethan James Date: Wed, 8 Nov 2023 17:43:01 -0700 Subject: [PATCH] Added functionality to get initiaal board data --- package-lock.json | 89 +++++++++++++++++++++++++++-- package.json | 2 + pages/scoreboard/index.tsx | 114 +++++++++++++++++++++++++++++++++++-- yarn.lock | 41 ++++++++++++- 4 files changed, 236 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index d505e58..d1a4491 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,12 +35,14 @@ "@vercel/otel": "^0.3.0", "class-variance-authority": "^0.7.0", "firebase": "^10.5.0", + "konva": "^9.2.3", "lodash": "^4.17.21", "next": "^13.5.5", "next-compose-plugins": "^2.2.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-icons": "^4.11.0", + "react-konva": "^18.2.10", "tailwind-merge": "^1.14.0", "ws": "^8.14.2", "zod": "^3.22.4" @@ -10929,7 +10931,6 @@ "version": "15.7.8", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.8.tgz", "integrity": "sha512-kMpQpfZKSCBqltAJwskgePRaYRFukDkm1oItcAbC3gNELR20XIBcN9VRgg4+m8DKsTfkWeA4m4Imp4DDuWy7FQ==", - "devOptional": true, "license": "MIT" }, "node_modules/@types/qs": { @@ -10950,7 +10951,6 @@ "version": "18.2.28", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.28.tgz", "integrity": "sha512-ad4aa/RaaJS3hyGz0BGegdnSRXQBkd1CCYDCdNjBPg90UUpLgo+WlJqb9fMYUxtehmzF3PJaTWqRZjko6BRzBg==", - "devOptional": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -10968,11 +10968,18 @@ "@types/react": "*" } }, + "node_modules/@types/react-reconciler": { + "version": "0.28.8", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.8.tgz", + "integrity": "sha512-SN9c4kxXZonFhbX4hJrZy37yw9e7EIxcpHCxQv5JUS18wDE5ovkQKlqQEkufdJCCMfuI9BnjUJvhYeJ9x5Ra7g==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/scheduler": { "version": "0.16.4", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.4.tgz", "integrity": "sha512-2L9ifAGl7wmXwP4v3pN4p2FLhD0O1qsJpvKmNin5VA8+UvNVb447UDaAEV6UdrkA+m/Xs58U1RFps44x6TFsVQ==", - "devOptional": true, "license": "MIT" }, "node_modules/@types/semver": { @@ -14961,7 +14968,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "devOptional": true, "license": "MIT" }, "node_modules/cwd": { @@ -20120,6 +20126,17 @@ "set-function-name": "^2.0.1" } }, + "node_modules/its-fine": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/its-fine/-/its-fine-1.1.1.tgz", + "integrity": "sha512-v1Ia1xl20KbuSGlwoaGsW0oxsw8Be+TrXweidxD9oT/1lAh6O3K3/GIM95Tt6WCiv6W+h2M7RB1TwdoAjQyyKw==", + "dependencies": { + "@types/react-reconciler": "^0.28.0" + }, + "peerDependencies": { + "react": ">=18.0" + } + }, "node_modules/jackspeak": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", @@ -24363,6 +24380,25 @@ "node": ">= 8" } }, + "node_modules/konva": { + "version": "9.2.3", + "resolved": "https://registry.npmjs.org/konva/-/konva-9.2.3.tgz", + "integrity": "sha512-oQ6VQ6kUL9IlhOGuEKKhxqnv6g/t8jZpVuWahQQ6hCqAsO8Ydi1zFGv7ef4EOq5GoPNq/d6Fyj/3i5Y/a5NooA==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/lavrton" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/konva" + }, + { + "type": "github", + "url": "https://github.com/sponsors/lavrton" + } + ] + }, "node_modules/language-subtag-registry": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", @@ -31349,6 +31385,51 @@ "dev": true, "license": "MIT" }, + "node_modules/react-konva": { + "version": "18.2.10", + "resolved": "https://registry.npmjs.org/react-konva/-/react-konva-18.2.10.tgz", + "integrity": "sha512-ohcX1BJINL43m4ynjZ24MxFI1syjBdrXhqVxYVDw2rKgr3yuS0x/6m1Y2Z4sl4T/gKhfreBx8KHisd0XC6OT1g==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/lavrton" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/konva" + }, + { + "type": "github", + "url": "https://github.com/sponsors/lavrton" + } + ], + "dependencies": { + "@types/react-reconciler": "^0.28.2", + "its-fine": "^1.1.1", + "react-reconciler": "~0.29.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "konva": "^8.0.1 || ^7.2.5 || ^9.0.0", + "react": ">=18.0.0", + "react-dom": ">=18.0.0" + } + }, + "node_modules/react-reconciler": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.0.tgz", + "integrity": "sha512-wa0fGj7Zht1EYMRhKWwoo1H9GApxYLBuhoAuXN0TlltESAjDssB+Apf0T/DngVqaMyPypDmabL37vw/2aRM98Q==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, "node_modules/react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", diff --git a/package.json b/package.json index 2cd0482..50e4c62 100644 --- a/package.json +++ b/package.json @@ -49,12 +49,14 @@ "@vercel/otel": "^0.3.0", "class-variance-authority": "^0.7.0", "firebase": "^10.5.0", + "konva": "^9.2.3", "lodash": "^4.17.21", "next": "^13.5.5", "next-compose-plugins": "^2.2.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-icons": "^4.11.0", + "react-konva": "^18.2.10", "tailwind-merge": "^1.14.0", "ws": "^8.14.2", "zod": "^3.22.4" diff --git a/pages/scoreboard/index.tsx b/pages/scoreboard/index.tsx index 5a0d8ad..b44a699 100644 --- a/pages/scoreboard/index.tsx +++ b/pages/scoreboard/index.tsx @@ -1,12 +1,14 @@ import { onAuthStateChanged } from "firebase/auth" import Head from "next/head" import { useRouter } from "next/navigation" -import React, { useEffect, useState } from "react" +import React, { useEffect, useRef, useState } from "react" import { BsPencilSquare } from "react-icons/bs" import Navbar from "components/Navbar/Navbar" +import { useWebSocket } from "../../context/WebSocketContext" import { auth } from "../../firebase" export default function Scoreboard() { + const { messages, sendMessage, connectionStatus } = useWebSocket() const [teamAScore, setTeamAScore] = useState(0) const [teamBScore, setTeamBScore] = useState(0) @@ -19,14 +21,56 @@ export default function Scoreboard() { const [showTeamAPopup, setShowTeamAPopup] = useState(false) const [showTeamBPopup, setShowTeamBPopup] = useState(false) + const canvasRef = useRef(null) + const canvasWidth = 640 + const canvasHeight = 360 + + const hasInitialized = useRef(false); + + const router = useRouter() + useEffect(() => { + const getInitalData = async () => { + console.log("Getting initial data") + try { + const token = await auth.currentUser?.getIdToken() // Fetch the token asynchronously + const testMessageJson = { + id: Math.floor(Math.random() * 100000), + type: 8, + text: "getInitialData", + token: token, + } + + sendMessage(JSON.stringify(testMessageJson)) + } catch (error) { + // Handle any errors that may occur while fetching the token + console.error("Error fetching token:", error) + }} + + if (!hasInitialized.current) { + getInitalData(); + hasInitialized.current = true; + } + + + messages.forEach((message) => { + const messageJson = JSON.parse(message) as { type: number, text: string }; + if (messageJson.type === 18) { + const data = JSON.parse(messageJson.text) + setTeamAName((data as { teamAName: string }).teamAName) + setTeamBName((data as { teamBName: string }).teamBName) + setTeamAScore(parseInt((data as { teamAScore: string }).teamAScore)) + setTeamBScore(parseInt((data as { teamBScore: string }).teamBScore)) + } + }) + onAuthStateChanged(auth, (user) => { if (!user) { router.push("/login") } }) - }, [router]) + }, [router, sendMessage, messages]) const incrementTeamAScore = () => { setTeamAScore(teamAScore + 1) // You can change this value to the appropriate increment @@ -47,6 +91,27 @@ export default function Scoreboard() { setShowTeamBPopup(false) } + useEffect(() => { + const canvas = canvasRef.current + const ctx = canvas?.getContext("2d") + + if (ctx) { + ctx.fillStyle = "#000000" + ctx.fillRect(0, 0, canvasWidth, canvasHeight) + + ctx.fillStyle = "#FFFFFF" + ctx.font = "bold 48px Arial" + ctx.textAlign = "center" + ctx.textBaseline = "middle" + ctx.fillText(teamAName, canvasWidth / 4, canvasHeight / 2) + ctx.fillText(teamBName, (canvasWidth / 4) * 3, canvasHeight / 2) + + ctx.font = "bold 72px Arial" + ctx.fillText(teamAScore.toString(), canvasWidth / 4, (canvasHeight / 4) * 3) + ctx.fillText(teamBScore.toString(), (canvasWidth / 4) * 3, (canvasHeight / 4) * 3) + } + }, [teamAScore, teamBScore, teamAName, teamBName]) + return ( <> @@ -70,6 +135,45 @@ export default function Scoreboard() {

Settings

+ +
+

+ WS Server: + + {connectionStatus === "Connected" ? "Connected" : "Disconnected"} + +

+

+ Scoreboard: + + Disconnected + +

+

+ Audio: + + Disconnected + +

+ + + +
+
@@ -219,12 +323,14 @@ export default function Scoreboard() {
)} -
+
+

Preview

- + +
) diff --git a/yarn.lock b/yarn.lock index 6b6446a..571e336 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4962,6 +4962,13 @@ dependencies: "@types/react" "*" +"@types/react-reconciler@^0.28.0", "@types/react-reconciler@^0.28.2": + version "0.28.8" + resolved "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.8.tgz" + integrity sha512-SN9c4kxXZonFhbX4hJrZy37yw9e7EIxcpHCxQv5JUS18wDE5ovkQKlqQEkufdJCCMfuI9BnjUJvhYeJ9x5Ra7g== + dependencies: + "@types/react" "*" + "@types/react@*", "@types/react@^16.8.0 || ^17.0.0 || ^18.0.0", "@types/react@^16.9.0 || ^17.0.0 || ^18.0.0", "@types/react@^18.2.28", "@types/react@>=16": version "18.2.28" resolved "https://registry.npmjs.org/@types/react/-/react-18.2.28.tgz" @@ -10262,6 +10269,13 @@ iterator.prototype@^1.1.2: reflect.getprototypeof "^1.0.4" set-function-name "^2.0.1" +its-fine@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/its-fine/-/its-fine-1.1.1.tgz" + integrity sha512-v1Ia1xl20KbuSGlwoaGsW0oxsw8Be+TrXweidxD9oT/1lAh6O3K3/GIM95Tt6WCiv6W+h2M7RB1TwdoAjQyyKw== + dependencies: + "@types/react-reconciler" "^0.28.0" + jackspeak@^2.0.3, jackspeak@^2.3.5: version "2.3.6" resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz" @@ -11364,6 +11378,11 @@ klona@^2.0.4: resolved "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz" integrity sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA== +"konva@^8.0.1 || ^7.2.5 || ^9.0.0", konva@^9.2.3: + version "9.2.3" + resolved "https://registry.npmjs.org/konva/-/konva-9.2.3.tgz" + integrity sha512-oQ6VQ6kUL9IlhOGuEKKhxqnv6g/t8jZpVuWahQQ6hCqAsO8Ydi1zFGv7ef4EOq5GoPNq/d6Fyj/3i5Y/a5NooA== + language-subtag-registry@~0.3.2: version "0.3.22" resolved "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz" @@ -13745,7 +13764,7 @@ react-docgen@^5.0.0: node-dir "^0.1.10" strip-indent "^3.0.0" -"react-dom@^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0", "react-dom@^16.8 || ^17.0 || ^18.0", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", react-dom@^18.0.0, react-dom@^18.2.0, react-dom@>=16.8.0, "react-dom@16.8.0 - 18": +"react-dom@^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0", "react-dom@^16.8 || ^17.0 || ^18.0", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", react-dom@^18.0.0, react-dom@^18.2.0, react-dom@>=16.8.0, react-dom@>=18.0.0, "react-dom@16.8.0 - 18": version "18.2.0" resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz" integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== @@ -13792,6 +13811,24 @@ react-is@18.1.0: resolved "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz" integrity sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg== +react-konva@^18.2.10: + version "18.2.10" + resolved "https://registry.npmjs.org/react-konva/-/react-konva-18.2.10.tgz" + integrity sha512-ohcX1BJINL43m4ynjZ24MxFI1syjBdrXhqVxYVDw2rKgr3yuS0x/6m1Y2Z4sl4T/gKhfreBx8KHisd0XC6OT1g== + dependencies: + "@types/react-reconciler" "^0.28.2" + its-fine "^1.1.1" + react-reconciler "~0.29.0" + scheduler "^0.23.0" + +react-reconciler@~0.29.0: + version "0.29.0" + resolved "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.0.tgz" + integrity sha512-wa0fGj7Zht1EYMRhKWwoo1H9GApxYLBuhoAuXN0TlltESAjDssB+Apf0T/DngVqaMyPypDmabL37vw/2aRM98Q== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.0" + react-refresh@^0.11.0, "react-refresh@>=0.10.0 <1.0.0": version "0.11.0" resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz" @@ -13825,7 +13862,7 @@ react-style-singleton@^2.2.1: invariant "^2.2.4" tslib "^2.0.0" -react@*, "react@^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0", "react@^16.8 || ^17.0 || ^18.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.8.4 || ^17.0.0 || ^18.0.0", react@^18.0.0, react@^18.2.0, "react@>= 0.14.0", "react@>= 16.8.0 || 17.x.x || ^18.0.0-0", react@>=16, react@>=16.8.0, "react@16.8.0 - 18": +react@*, "react@^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0", "react@^16.8 || ^17.0 || ^18.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.8.4 || ^17.0.0 || ^18.0.0", react@^18.0.0, react@^18.2.0, "react@>= 0.14.0", "react@>= 16.8.0 || 17.x.x || ^18.0.0-0", react@>=16, react@>=16.8.0, react@>=18.0, react@>=18.0.0, "react@16.8.0 - 18": version "18.2.0" resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz" integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==