diff --git a/asc/package-lock.json b/asc/package-lock.json index 582319d..0be8485 100644 --- a/asc/package-lock.json +++ b/asc/package-lock.json @@ -17,6 +17,7 @@ "@testing-library/user-event": "^13.5.0", "react": "^19.0.0", "react-dom": "^19.0.0", + "react-router-dom": "^7.1.5", "react-scripts": "^5.0.1", "web-vitals": "^2.1.4" } @@ -4552,6 +4553,12 @@ "@types/node": "*" } }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "license": "MIT" + }, "node_modules/@types/eslint": { "version": "8.56.12", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz", @@ -16101,6 +16108,55 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.5.tgz", + "integrity": "sha512-8BUF+hZEU4/z/JD201yK6S+UYhsf58bzYIDq2NS1iGpwxSXDu7F+DeGSkIXMFBuHZB21FSiCzEcUb18cQNdRkA==", + "license": "MIT", + "dependencies": { + "@types/cookie": "^0.6.0", + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0", + "turbo-stream": "2.4.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.1.5.tgz", + "integrity": "sha512-/4f9+up0Qv92D3bB8iN5P1s3oHAepSGa9h5k6tpTFlixTTskJZwKGhJ6vRJ277tLD1zuaZTt95hyGWV1Z37csQ==", + "license": "MIT", + "dependencies": { + "react-router": "7.1.5" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-router/node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -17035,6 +17091,12 @@ "node": ">= 0.8.0" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -18432,6 +18494,12 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "license": "0BSD" }, + "node_modules/turbo-stream": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz", + "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==", + "license": "ISC" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/asc/package.json b/asc/package.json index 986de28..7e0ac48 100644 --- a/asc/package.json +++ b/asc/package.json @@ -12,6 +12,7 @@ "@testing-library/user-event": "^13.5.0", "react": "^19.0.0", "react-dom": "^19.0.0", + "react-router-dom": "^7.1.5", "react-scripts": "^5.0.1", "web-vitals": "^2.1.4" }, diff --git a/asc/src/App.js b/asc/src/App.js index 04bf3da..498b2aa 100644 --- a/asc/src/App.js +++ b/asc/src/App.js @@ -1,10 +1,13 @@ // src/App.js import React, { useState, useMemo, useEffect } from 'react'; -import { CssBaseline, Container, ThemeProvider, createTheme, IconButton } from '@mui/material'; -import { Brightness4, Brightness7 } from '@mui/icons-material'; +import { CssBaseline, Container, IconButton } from '@mui/material'; +import { ThemeProvider, createTheme } from '@mui/material/styles'; +import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; import { ScoreProvider } from './context/ScoreContext'; import GameSetup from './components/GameSetup'; import ScoreTracker from './components/ScoreTracker'; +import GameSummary from './components/GameSummary'; +import { Brightness7, Brightness4 } from '@mui/icons-material'; function App() { // Initialize theme from localStorage or default to 'light' @@ -12,7 +15,7 @@ function App() { try { const savedMode = localStorage.getItem('themeMode'); return savedMode || 'light'; - } catch { + } catch (e) { return 'light'; } }); @@ -69,11 +72,15 @@ function App() { > {mode === 'dark' ? : } - {!gameStarted ? ( - setGameStarted(true)} /> - ) : ( - - )} + + + setGameStarted(true)} /> : } + /> + } /> + + @@ -81,3 +88,4 @@ function App() { } export default App; + diff --git a/asc/src/components/GameSummary.js b/asc/src/components/GameSummary.js new file mode 100644 index 0000000..c5ab3a4 --- /dev/null +++ b/asc/src/components/GameSummary.js @@ -0,0 +1,58 @@ +import React from 'react'; +import { useScore } from '../context/ScoreContext'; +import { Button, Grid, Typography, Box } from '@mui/material'; +import { useNavigate } from 'react-router-dom'; + +const GameSummary = () => { + const { state } = useScore(); + const navigate = useNavigate(); + + const handleNewGame = () => { + navigate('/'); + }; + + return ( + <> + {/* Main Menu Button */} + + + + + + + + Game Summary + + + + {/* Total score */} + + + Total Score: {state.currentGame.totalScore} + + + Total Bullseyes: {state.currentGame.totalBullseyes} + + + + {/* New game button */} + + + + + + ); +}; + +export default GameSummary; + diff --git a/asc/src/components/ScoreTracker.js b/asc/src/components/ScoreTracker.js index b633f0e..bbe62f8 100644 --- a/asc/src/components/ScoreTracker.js +++ b/asc/src/components/ScoreTracker.js @@ -2,21 +2,43 @@ import React, { useState } from 'react'; import { useScore, ACTIONS } from '../context/ScoreContext'; import { Button, Grid, Typography, TextField, Box } from '@mui/material'; +import { useNavigate } from 'react-router-dom'; // <-- Add this import const ScoreTracker = () => { const { state, dispatch } = useScore(); - const [arrowScores, setArrowScores] = useState(['', '', '', '', '']); + const navigate = useNavigate(); // <-- Define the navigate hook const gameType = state.currentGame.gameType; const maxArrowsPerRound = gameType === '450' ? 3 : 5; const maxScore = gameType === '450' ? 10 : 5; + const maxRounds = gameType === '450' ? 16 : 12; + + const [arrowScores, setArrowScores] = useState(Array(maxArrowsPerRound).fill('')); const handleScoreChange = (index, value) => { - const updatedScores = [...arrowScores]; + const updatedScores = [...arrowScores]; updatedScores[index] = value; setArrowScores(updatedScores); }; + // Handle Add Round, Game Completion, etc. + + const handleGameEnd = () => { + // Navigate to the summary page after the game ends + navigate('/summary'); + }; + + // Rest of your component code (Rendering, Button handlers, etc.) +}; + + // Handle adding a round const handleAddRound = () => { + // Check if the max number of rounds is reached + if (state.currentGame.rounds.length >= maxRounds) { + navigate('/summary'); // Navigate to summary page when max rounds are reached + return; + } + + // Validate Scores const valid = arrowScores.slice(0, maxArrowsPerRound).every(score => (score >= 0 && score <= maxScore) || score.toUpperCase() === 'X' ); @@ -25,17 +47,23 @@ const ScoreTracker = () => { return; } - arrowScores.slice(0, maxArrowsPerRound).forEach((score) => { + // Add arrows to the current round + const roundArrows = arrowScores.slice(0, maxArrowsPerRound).map((score) => { const arrowScore = score.toUpperCase() === 'X' ? maxScore : parseInt(score, 10); - dispatch({ - type: ACTIONS.ADD_ARROW, - payload: { - roundIndex: state.currentGame.rounds.length, - score: arrowScore, - isBullseye: score.toUpperCase() === 'X', - }, - }); + return { + score: arrowScore, + isBullseye: score.toUpperCase() === 'X', + }; }); + + dispatch({ + type: ACTIONS.ADD_ROUND, + payload: { + roundIndex: state.currentGame.rounds.length, + arrows: roundArrows, + }, + }); + setArrowScores(['', '', '', '', '']); }; @@ -120,6 +148,13 @@ const ScoreTracker = () => { > X + + @@ -150,19 +185,24 @@ const ScoreTracker = () => { Bullseyes: {state.currentGame.totalBullseyes} - - {/* Round history */} - - - {state.currentGame.rounds.map((round, roundIndex) => ( - - Round {roundIndex + 1}: {round.arrows.join(', ')} - (Total: {round.total}, Bullseyes: {round.bullseyes}) - - ))} - - - +{/* Round history */} + + + {state.currentGame && state.currentGame.rounds && state.currentGame.rounds.length > 0 ? ( + state.currentGame.rounds.map((round, roundIndex) => ( + + Round {roundIndex + 1}: {round.arrows ? round.arrows.join(', ') : 'No arrows'} + (Total: {round.total || 0}, Bullseyes: {round.bullseyes || 0}) + + )) + ) : ( + + No rounds played yet. + + )} + + + ); };