fixed navigation and updated buttons
This commit is contained in:
@@ -1,16 +1,14 @@
|
||||
import React, { useState, useMemo, useEffect } from 'react';
|
||||
import { CssBaseline, Container, IconButton } from '@mui/material';
|
||||
import { ThemeProvider, createTheme } from '@mui/material/styles'; // <-- Import createTheme
|
||||
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
|
||||
import { ScoreProvider } from './context/ScoreContext'; // <-- Import ScoreProvider
|
||||
|
||||
import MainMenu from './components/MainMenu';
|
||||
import { ThemeProvider, createTheme } from '@mui/material/styles';
|
||||
import { Brightness7, Brightness4 } from '@mui/icons-material';
|
||||
import { BrowserRouter, Routes, Route } 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() {
|
||||
const App = () => {
|
||||
// Theme state
|
||||
const [mode, setMode] = useState(() => {
|
||||
try {
|
||||
const savedMode = localStorage.getItem('themeMode');
|
||||
@@ -42,36 +40,36 @@ function App() {
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<ScoreProvider>
|
||||
<CssBaseline />
|
||||
<Container
|
||||
maxWidth="lg"
|
||||
sx={{
|
||||
minHeight: '100vh',
|
||||
bgcolor: 'background.default',
|
||||
color: 'text.primary',
|
||||
pb: 4
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
onClick={toggleTheme}
|
||||
color="inherit"
|
||||
sx={{ position: 'absolute', top: 16, right: 16 }}
|
||||
<BrowserRouter>
|
||||
<CssBaseline />
|
||||
<Container
|
||||
maxWidth="lg"
|
||||
sx={{
|
||||
minHeight: '100vh',
|
||||
bgcolor: 'background.default',
|
||||
color: 'text.primary',
|
||||
pb: 4
|
||||
}}
|
||||
>
|
||||
{mode === 'dark' ? <Brightness7 /> : <Brightness4 />}
|
||||
</IconButton>
|
||||
<Router>
|
||||
{/* Theme Toggle Button */}
|
||||
<IconButton
|
||||
onClick={toggleTheme}
|
||||
color="inherit"
|
||||
sx={{ position: 'absolute', top: 16, right: 16 }}
|
||||
>
|
||||
{mode === 'dark' ? <Brightness7 /> : <Brightness4 />}
|
||||
</IconButton>
|
||||
|
||||
{/* Routes for navigation */}
|
||||
<Routes>
|
||||
<Route path="/" element={<MainMenu />} /> {/* MainMenu as the default page */}
|
||||
<Route path="/setup" element={<GameSetup />} />
|
||||
<Route path="/score-tracker" element={<ScoreTracker />} />
|
||||
<Route path="/summary" element={<GameSummary />} />
|
||||
<Route path="/" element={<GameSetup />} />
|
||||
<Route path="/score" element={<ScoreTracker />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
</Container>
|
||||
</Container>
|
||||
</BrowserRouter>
|
||||
</ScoreProvider>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default App;
|
||||
|
||||
|
||||
@@ -1,60 +1,75 @@
|
||||
// File: src/AppRouter.js
|
||||
import React, { useState } from 'react';
|
||||
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
|
||||
import React from 'react';
|
||||
import { BrowserRouter as Router, Route, Routes, Navigate } from 'react-router-dom';
|
||||
import { Container, IconButton } from '@mui/material';
|
||||
import { Brightness7, Brightness4 } from '@mui/icons-material';
|
||||
import GameSetup from './components/GameSetup';
|
||||
import ScoreTracker from './components/ScoreTracker';
|
||||
import GameSummary from './components/GameSummary';
|
||||
import { useTheme } from './context/ThemeContext';
|
||||
import { useScore } from './context/ScoreContext';
|
||||
|
||||
// The main router component
|
||||
function AppRouter() {
|
||||
const { mode, toggleTheme } = useTheme();
|
||||
const { state } = useScore();
|
||||
|
||||
const [gameStarted, setGameStarted] = useState(() => {
|
||||
try {
|
||||
const savedGame = localStorage.getItem('archeryScores');
|
||||
if (savedGame) {
|
||||
const parsedGame = JSON.parse(savedGame);
|
||||
return parsedGame.currentGame && parsedGame.currentGame.gameType !== null;
|
||||
}
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
// Check if a game is currently in progress
|
||||
const isGameActive = () => {
|
||||
return state.currentGame && state.currentGame.gameType !== null;
|
||||
};
|
||||
|
||||
return (
|
||||
<Container
|
||||
maxWidth="lg"
|
||||
sx={{
|
||||
minHeight: '100vh',
|
||||
bgcolor: 'background.default',
|
||||
color: 'text.primary',
|
||||
pb: 4
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
onClick={toggleTheme}
|
||||
color="inherit"
|
||||
sx={{ position: 'absolute', top: 16, right: 16 }}
|
||||
<Router>
|
||||
<Container
|
||||
maxWidth="lg"
|
||||
sx={{
|
||||
minHeight: '100vh',
|
||||
bgcolor: 'background.default',
|
||||
color: 'text.primary',
|
||||
pb: 4
|
||||
}}
|
||||
>
|
||||
{mode === 'dark' ? <Brightness7 /> : <Brightness4 />}
|
||||
</IconButton>
|
||||
<Router>
|
||||
<IconButton
|
||||
onClick={toggleTheme}
|
||||
color="inherit"
|
||||
sx={{ position: 'absolute', top: 16, right: 16 }}
|
||||
>
|
||||
{mode === 'dark' ? <Brightness7 /> : <Brightness4 />}
|
||||
</IconButton>
|
||||
|
||||
<Routes>
|
||||
{/* Home route - redirects to score if a game is active */}
|
||||
<Route
|
||||
path="/"
|
||||
element={
|
||||
!gameStarted
|
||||
? <GameSetup onGameStart={() => setGameStarted(true)} />
|
||||
: <ScoreTracker />
|
||||
isGameActive() ?
|
||||
<Navigate to="/score" replace /> :
|
||||
<GameSetup />
|
||||
}
|
||||
/>
|
||||
<Route path="/summary" element={<GameSummary />} />
|
||||
|
||||
{/* Explicit score tracker route */}
|
||||
<Route
|
||||
path="/score"
|
||||
element={
|
||||
isGameActive() ?
|
||||
<ScoreTracker /> :
|
||||
<Navigate to="/" replace />
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Summary route */}
|
||||
<Route
|
||||
path="/summary"
|
||||
element={<GameSummary />}
|
||||
/>
|
||||
|
||||
{/* Catch-all route for any invalid URLs */}
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
</Container>
|
||||
</Container>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
61
asc/src/AppRouter.old
Normal file
61
asc/src/AppRouter.old
Normal file
@@ -0,0 +1,61 @@
|
||||
// File: src/AppRouter.js
|
||||
import React, { useState } from 'react';
|
||||
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
|
||||
import { Container, IconButton } from '@mui/material';
|
||||
import { Brightness7, Brightness4 } from '@mui/icons-material';
|
||||
import GameSetup from './components/GameSetup';
|
||||
import ScoreTracker from './components/ScoreTracker';
|
||||
import GameSummary from './components/GameSummary';
|
||||
import { useTheme } from './context/ThemeContext';
|
||||
|
||||
function AppRouter() {
|
||||
const { mode, toggleTheme } = useTheme();
|
||||
|
||||
const [gameStarted, setGameStarted] = useState(() => {
|
||||
try {
|
||||
const savedGame = localStorage.getItem('archeryScores');
|
||||
if (savedGame) {
|
||||
const parsedGame = JSON.parse(savedGame);
|
||||
return parsedGame.currentGame && parsedGame.currentGame.gameType !== null;
|
||||
}
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
return (
|
||||
<Container
|
||||
maxWidth="lg"
|
||||
sx={{
|
||||
minHeight: '100vh',
|
||||
bgcolor: 'background.default',
|
||||
color: 'text.primary',
|
||||
pb: 4
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
onClick={toggleTheme}
|
||||
color="inherit"
|
||||
sx={{ position: 'absolute', top: 16, right: 16 }}
|
||||
>
|
||||
{mode === 'dark' ? <Brightness7 /> : <Brightness4 />}
|
||||
</IconButton>
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route
|
||||
path="/"
|
||||
element={
|
||||
!gameStarted
|
||||
? <GameSetup onGameStart={() => setGameStarted(true)} />
|
||||
: <ScoreTracker />
|
||||
}
|
||||
/>
|
||||
<Route path="/summary" element={<GameSummary />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
export default AppRouter;
|
||||
118
asc/src/ScoreContext.js
Normal file
118
asc/src/ScoreContext.js
Normal file
@@ -0,0 +1,118 @@
|
||||
// File: src/context/ScoreContext.js
|
||||
import React, { createContext, useContext, useReducer, useEffect } from 'react';
|
||||
|
||||
// Action types
|
||||
export const ACTIONS = {
|
||||
START_GAME: 'start_game',
|
||||
END_GAME: 'end_game',
|
||||
SAVE_GAME: 'save_game',
|
||||
ADD_END: 'add_end', // Changed from UPDATE_SCORE to ADD_END to match ScoreTracker
|
||||
// Add other actions as needed
|
||||
};
|
||||
|
||||
// Initial state
|
||||
const initialState = {
|
||||
currentGame: null,
|
||||
gameHistory: [],
|
||||
// Add other state properties as needed
|
||||
};
|
||||
|
||||
// Get saved state from localStorage if available
|
||||
const getSavedState = () => {
|
||||
try {
|
||||
const savedState = localStorage.getItem('archeryScores');
|
||||
if (savedState) {
|
||||
return JSON.parse(savedState);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading saved game state:', error);
|
||||
}
|
||||
return initialState;
|
||||
};
|
||||
|
||||
// Reducer function
|
||||
const scoreReducer = (state, action) => {
|
||||
switch (action.type) {
|
||||
case ACTIONS.START_GAME:
|
||||
const newGame = {
|
||||
gameType: action.payload.gameType,
|
||||
isLeague: action.payload.isLeague,
|
||||
targetFace: action.payload.targetFace,
|
||||
dateStarted: new Date().toISOString(),
|
||||
ends: [], // Changed from scores to ends to match ScoreTracker expectations
|
||||
// Add other game properties as needed
|
||||
};
|
||||
|
||||
return {
|
||||
...state,
|
||||
currentGame: newGame,
|
||||
};
|
||||
|
||||
case ACTIONS.END_GAME:
|
||||
return {
|
||||
...state,
|
||||
currentGame: null,
|
||||
};
|
||||
|
||||
case ACTIONS.SAVE_GAME:
|
||||
// Only save if there's a current game
|
||||
if (!state.currentGame) return state;
|
||||
|
||||
const completedGame = {
|
||||
...state.currentGame,
|
||||
dateCompleted: new Date().toISOString(),
|
||||
};
|
||||
|
||||
return {
|
||||
...state,
|
||||
gameHistory: [...state.gameHistory, completedGame],
|
||||
};
|
||||
|
||||
case ACTIONS.ADD_END: // Changed from UPDATE_SCORE to ADD_END
|
||||
// Handle adding a new end
|
||||
if (!state.currentGame) return state;
|
||||
|
||||
return {
|
||||
...state,
|
||||
currentGame: {
|
||||
...state.currentGame,
|
||||
ends: [...(state.currentGame.ends || []), action.payload], // Updated to use ends instead of scores
|
||||
}
|
||||
};
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
// Create context
|
||||
const ScoreContext = createContext();
|
||||
|
||||
// Provider component
|
||||
export const ScoreProvider = ({ children }) => {
|
||||
const [state, dispatch] = useReducer(scoreReducer, getSavedState());
|
||||
|
||||
// Save state to localStorage whenever it changes
|
||||
useEffect(() => {
|
||||
try {
|
||||
localStorage.setItem('archeryScores', JSON.stringify(state));
|
||||
} catch (error) {
|
||||
console.error('Error saving game state:', error);
|
||||
}
|
||||
}, [state]);
|
||||
|
||||
return (
|
||||
<ScoreContext.Provider value={{ state, dispatch }}>
|
||||
{children}
|
||||
</ScoreContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
// Custom hook for using the score context
|
||||
export const useScore = () => {
|
||||
const context = useContext(ScoreContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('useScore must be used within a ScoreProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -1,216 +1,215 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useScore, ACTIONS } from '../context/ScoreContext';
|
||||
import { Button, Grid, Typography, TextField, Box } from '@mui/material';
|
||||
// File: src/components/GameSetup.js
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardContent,
|
||||
CardHeader,
|
||||
Grid,
|
||||
Typography,
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
FormLabel,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Divider
|
||||
} from '@mui/material';
|
||||
import { useScore, ACTIONS } from '../context/ScoreContext';
|
||||
|
||||
const ScoreTracker = () => {
|
||||
const { state, dispatch } = useScore();
|
||||
const GameSetup = () => {
|
||||
const { dispatch } = useScore();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const gameType = state.currentGame.gameType;
|
||||
const [selectedGameType, setSelectedGameType] = useState('');
|
||||
const [selectedTargetFace, setSelectedTargetFace] = useState('standard');
|
||||
const [isLeague, setIsLeague] = useState(false);
|
||||
|
||||
// Determine the number of arrows per round based on game type
|
||||
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];
|
||||
updatedScores[index] = value;
|
||||
setArrowScores(updatedScores);
|
||||
// For debugging - will show in browser console
|
||||
useEffect(() => {
|
||||
console.log("GameSetup.js: League mode state:", isLeague);
|
||||
}, [isLeague]);
|
||||
|
||||
const handleGameTypeSelect = (gameType) => {
|
||||
console.log("GameSetup.js: Setting game type to:", gameType);
|
||||
setSelectedGameType(gameType);
|
||||
setSelectedTargetFace('standard'); // Reset to standard when game type changes
|
||||
};
|
||||
|
||||
const handleAddRound = () => {
|
||||
const valid = arrowScores.slice(0, maxArrowsPerRound).every(score =>
|
||||
(score >= 0 && score <= maxScore) || score.toUpperCase() === 'X'
|
||||
);
|
||||
const handleGameModeChange = (event) => {
|
||||
// Direct conversion to boolean using === comparison
|
||||
const leagueMode = event.target.value === "league";
|
||||
console.log("GameSetup.js: Setting isLeague to:", leagueMode);
|
||||
setIsLeague(leagueMode);
|
||||
};
|
||||
|
||||
const startGame = () => {
|
||||
console.log("GameSetup.js: Start Game button clicked");
|
||||
console.log("GameSetup.js: Current state:", {
|
||||
selectedGameType,
|
||||
isLeague,
|
||||
selectedTargetFace
|
||||
});
|
||||
|
||||
if (!valid) {
|
||||
alert(`Please enter valid scores between 0-${maxScore} or X for bullseyes.`);
|
||||
if (!selectedGameType) {
|
||||
console.log("GameSetup.js: No game type selected, returning early");
|
||||
return;
|
||||
}
|
||||
|
||||
const roundArrows = arrowScores.slice(0, maxArrowsPerRound).map((score) => {
|
||||
const arrowScore = score.toUpperCase() === 'X' ? maxScore : parseInt(score, 10);
|
||||
return {
|
||||
score: arrowScore,
|
||||
isBullseye: score.toUpperCase() === 'X',
|
||||
};
|
||||
});
|
||||
|
||||
const roundTotal = roundArrows.reduce((sum, arrow) => sum + arrow.score, 0);
|
||||
|
||||
dispatch({
|
||||
type: ACTIONS.ADD_ROUND,
|
||||
payload: {
|
||||
roundIndex: state.currentGame.rounds.length,
|
||||
arrows: roundArrows,
|
||||
total: roundTotal
|
||||
},
|
||||
});
|
||||
|
||||
setArrowScores(Array(maxArrowsPerRound).fill(''));
|
||||
|
||||
if (state.currentGame.rounds.length >= maxRounds - 1) {
|
||||
navigate('/summary');
|
||||
|
||||
try {
|
||||
console.log("GameSetup.js: Dispatching START_GAME action");
|
||||
dispatch({
|
||||
type: ACTIONS.START_GAME,
|
||||
payload: {
|
||||
gameType: selectedGameType,
|
||||
isLeague: isLeague,
|
||||
targetFace: selectedTargetFace
|
||||
}
|
||||
});
|
||||
console.log("GameSetup.js: Dispatch completed successfully");
|
||||
|
||||
// Use React Router navigation
|
||||
navigate('/score');
|
||||
|
||||
} catch (error) {
|
||||
console.error("GameSetup.js: Error in startGame function:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleMainMenu = () => {
|
||||
dispatch({ type: ACTIONS.RESET_GAME });
|
||||
navigate('/');
|
||||
};
|
||||
// Determine if we should show target face options
|
||||
const showTargetFaceOptions = selectedGameType !== '';
|
||||
|
||||
return (
|
||||
<Grid container spacing={2} justifyContent="center">
|
||||
{/* Main Menu Button */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: 16,
|
||||
left: 16,
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={handleMainMenu}
|
||||
>
|
||||
Main Menu
|
||||
</Button>
|
||||
</Box>
|
||||
<Grid container spacing={3} justifyContent="center" alignItems="center" style={{ minHeight: '80vh' }}>
|
||||
<Grid item xs={12} sm={8} md={6}>
|
||||
<Card>
|
||||
<CardHeader
|
||||
title="Start New Game"
|
||||
titleTypographyProps={{ align: 'center' }}
|
||||
/>
|
||||
<CardContent>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" align="center" gutterBottom>
|
||||
Select your game type:
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="primary"
|
||||
size={selectedGameType === '450' ? "large" : "medium"}
|
||||
onClick={() => handleGameTypeSelect('450')}
|
||||
style={{
|
||||
backgroundColor: selectedGameType === '450' ? undefined : '#1976d2',
|
||||
boxShadow: selectedGameType === '450' ? '0 0 10px #1976d2' : undefined
|
||||
}}
|
||||
>
|
||||
450 Round
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
size={selectedGameType === '300' ? "large" : "medium"}
|
||||
onClick={() => handleGameTypeSelect('300')}
|
||||
style={{
|
||||
backgroundColor: selectedGameType === '300' ? undefined : '#9c27b0',
|
||||
boxShadow: selectedGameType === '300' ? '0 0 10px #9c27b0' : undefined
|
||||
}}
|
||||
>
|
||||
300 Round
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h5" align="center" gutterBottom>
|
||||
{gameType} Round - Round {state.currentGame.rounds.length + 1}
|
||||
</Typography>
|
||||
</Grid>
|
||||
{showTargetFaceOptions && (
|
||||
<>
|
||||
<Grid item xs={12}>
|
||||
<Divider style={{ margin: '16px 0' }} />
|
||||
<Typography variant="body1" align="center" gutterBottom>
|
||||
Game Settings:
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
{/* Game Mode Selection */}
|
||||
<Grid item xs={12}>
|
||||
<FormControl component="fieldset" style={{ marginBottom: '16px', width: '100%' }}>
|
||||
<FormLabel component="legend">Game Mode</FormLabel>
|
||||
<RadioGroup
|
||||
row
|
||||
name="gameMode"
|
||||
value={isLeague ? "league" : "practice"}
|
||||
onChange={handleGameModeChange}
|
||||
>
|
||||
<FormControlLabel
|
||||
value="practice"
|
||||
control={<Radio />}
|
||||
label="Practice"
|
||||
/>
|
||||
<FormControlLabel
|
||||
value="league"
|
||||
control={<Radio />}
|
||||
label="League"
|
||||
/>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
|
||||
{/* Target Face Selection */}
|
||||
<Grid item xs={12}>
|
||||
<FormControl component="fieldset" style={{ width: '100%' }}>
|
||||
<FormLabel component="legend">Target Face</FormLabel>
|
||||
<RadioGroup
|
||||
row
|
||||
name="targetFace"
|
||||
value={selectedTargetFace}
|
||||
onChange={(e) => setSelectedTargetFace(e.target.value)}
|
||||
>
|
||||
<FormControlLabel
|
||||
value="standard"
|
||||
control={<Radio />}
|
||||
label="Standard"
|
||||
/>
|
||||
{selectedGameType === '300' && (
|
||||
<FormControlLabel
|
||||
value="5-spot"
|
||||
control={<Radio />}
|
||||
label="5-Spot"
|
||||
/>
|
||||
)}
|
||||
{selectedGameType === '450' && (
|
||||
<FormControlLabel
|
||||
value="3-spot"
|
||||
control={<Radio />}
|
||||
label="3-Spot"
|
||||
/>
|
||||
)}
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
|
||||
{/* Score input section */}
|
||||
<Grid item xs={12}>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
gap: 1,
|
||||
mb: 2
|
||||
}}
|
||||
>
|
||||
{Array.from({ length: maxArrowsPerRound }).map((_, index) => (
|
||||
<TextField
|
||||
key={index}
|
||||
value={arrowScores[index]}
|
||||
onChange={(e) => handleScoreChange(index, e.target.value)}
|
||||
placeholder="0"
|
||||
size="small"
|
||||
sx={{
|
||||
width: '60px',
|
||||
'& .MuiInputBase-input': {
|
||||
padding: '8px',
|
||||
textAlign: 'center'
|
||||
}
|
||||
}}
|
||||
inputProps={{
|
||||
maxLength: 1,
|
||||
style: { textAlign: 'center' }
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
</Grid>
|
||||
|
||||
{/* Score buttons */}
|
||||
<Grid item xs={12}>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'center',
|
||||
gap: 1,
|
||||
mb: 2
|
||||
}}
|
||||
>
|
||||
{Array.from({ length: maxScore + 1 }).map((_, i) => (
|
||||
<Button
|
||||
key={i}
|
||||
variant="outlined"
|
||||
size="small"
|
||||
sx={{ minWidth: '40px', height: '40px' }}
|
||||
onClick={() => {
|
||||
const emptyIndex = arrowScores.findIndex(score => score === '');
|
||||
if (emptyIndex >= 0 && emptyIndex < maxArrowsPerRound) {
|
||||
handleScoreChange(emptyIndex, i.toString());
|
||||
}
|
||||
}}
|
||||
>
|
||||
{i}
|
||||
</Button>
|
||||
))}
|
||||
<Button
|
||||
variant="outlined"
|
||||
size="small"
|
||||
sx={{ minWidth: '40px', height: '40px' }}
|
||||
onClick={() => {
|
||||
const emptyIndex = arrowScores.findIndex(score => score === '');
|
||||
if (emptyIndex >= 0 && emptyIndex < maxArrowsPerRound) {
|
||||
handleScoreChange(emptyIndex, 'X');
|
||||
}
|
||||
}}
|
||||
>
|
||||
X
|
||||
</Button>
|
||||
</Box>
|
||||
</Grid>
|
||||
|
||||
{/* Control buttons */}
|
||||
<Grid item xs={12}>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'center', gap: 2 }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleAddRound}
|
||||
disabled={!arrowScores.slice(0, maxArrowsPerRound).every(score => score !== '')}
|
||||
>
|
||||
Add Round
|
||||
</Button>
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={() => setArrowScores(Array(maxArrowsPerRound).fill(''))}
|
||||
>
|
||||
Clear
|
||||
</Button>
|
||||
</Box>
|
||||
</Grid>
|
||||
|
||||
{/* Scores display */}
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h6" align="center">
|
||||
Total Score: {state.currentGame.totalScore} |
|
||||
Bullseyes: {state.currentGame.totalBullseyes}
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
{/* Round history */}
|
||||
<Grid item xs={12}>
|
||||
<Box sx={{ maxHeight: '200px', overflow: 'auto' }}>
|
||||
{state.currentGame.rounds.length > 0 ? (
|
||||
state.currentGame.rounds.map((round, roundIndex) => (
|
||||
<Typography key={roundIndex} variant="body2" align="center">
|
||||
Round {roundIndex + 1}: {round.arrows.map(arrow => arrow.score).join(', ')}
|
||||
(Total: {round.total}, Bullseyes: {round.bullseyes})
|
||||
</Typography>
|
||||
))
|
||||
) : (
|
||||
<Typography variant="body2" align="center">
|
||||
No rounds played yet.
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
<Grid item xs={12} style={{ marginTop: '16px' }}>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="success"
|
||||
size="large"
|
||||
onClick={startGame}
|
||||
id="start-game-button"
|
||||
>
|
||||
Start Game
|
||||
</Button>
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default ScoreTracker;
|
||||
|
||||
export default GameSetup;
|
||||
|
||||
219
asc/src/components/GameSetup.old
Normal file
219
asc/src/components/GameSetup.old
Normal file
@@ -0,0 +1,219 @@
|
||||
// filename: GameSetup.js
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardContent,
|
||||
CardHeader,
|
||||
Grid,
|
||||
Typography,
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
FormLabel,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Divider
|
||||
} from '@mui/material';
|
||||
import { useScore, ACTIONS } from '../context/ScoreContext';
|
||||
|
||||
|
||||
|
||||
|
||||
const GameSetup = ({ onGameStart }) => {
|
||||
const { dispatch } = useScore();
|
||||
const [selectedGameType, setSelectedGameType] = useState('');
|
||||
const [selectedTargetFace, setSelectedTargetFace] = useState('standard');
|
||||
const [isLeague, setIsLeague] = useState(false);
|
||||
|
||||
// For debugging - will show in browser console
|
||||
useEffect(() => {
|
||||
console.log("GameSetup.js: League mode state:", isLeague);
|
||||
}, [isLeague]);
|
||||
|
||||
const handleGameTypeSelect = (gameType) => {
|
||||
console.log("GameSetup.js: Setting game type to:", gameType);
|
||||
setSelectedGameType(gameType);
|
||||
setSelectedTargetFace('standard'); // Reset to standard when game type changes
|
||||
};
|
||||
|
||||
const handleGameModeChange = (event) => {
|
||||
// Direct conversion to boolean using === comparison
|
||||
const leagueMode = event.target.value === "league";
|
||||
console.log("GameSetup.js: Setting isLeague to:", leagueMode);
|
||||
setIsLeague(leagueMode);
|
||||
};
|
||||
|
||||
const startGame = () => {
|
||||
console.log("GameSetup.js: Start Game button clicked");
|
||||
console.log("GameSetup.js: Current state:", {
|
||||
selectedGameType,
|
||||
isLeague,
|
||||
selectedTargetFace
|
||||
});
|
||||
|
||||
if (!selectedGameType) {
|
||||
console.log("GameSetup.js: No game type selected, returning early");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("GameSetup.js: Dispatching START_GAME action");
|
||||
dispatch({
|
||||
type: ACTIONS.START_GAME,
|
||||
payload: {
|
||||
gameType: selectedGameType,
|
||||
isLeague: isLeague,
|
||||
targetFace: selectedTargetFace
|
||||
}
|
||||
});
|
||||
console.log("GameSetup.js: Dispatch completed successfully");
|
||||
|
||||
if (typeof onGameStart === 'function') {
|
||||
console.log("GameSetup.js: Calling onGameStart function");
|
||||
onGameStart();
|
||||
} else {
|
||||
console.log("GameSetup.js: onGameStart is not a function or is undefined:", onGameStart);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("GameSetup.js: Error in startGame function:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// Determine if we should show target face options
|
||||
const showTargetFaceOptions = selectedGameType !== '';
|
||||
|
||||
return (
|
||||
<Grid container spacing={3} justifyContent="center" alignItems="center" style={{ minHeight: '80vh' }}>
|
||||
<Grid item xs={12} sm={8} md={6}>
|
||||
<Card>
|
||||
<CardHeader
|
||||
title="Start New Game"
|
||||
titleTypographyProps={{ align: 'center' }}
|
||||
/>
|
||||
<CardContent>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" align="center" gutterBottom>
|
||||
Select your game type:
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="primary"
|
||||
size={selectedGameType === '450' ? "large" : "medium"}
|
||||
onClick={() => handleGameTypeSelect('450')}
|
||||
style={{
|
||||
backgroundColor: selectedGameType === '450' ? undefined : '#1976d2',
|
||||
boxShadow: selectedGameType === '450' ? '0 0 10px #1976d2' : undefined
|
||||
}}
|
||||
>
|
||||
450 Round
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
size={selectedGameType === '300' ? "large" : "medium"}
|
||||
onClick={() => handleGameTypeSelect('300')}
|
||||
style={{
|
||||
backgroundColor: selectedGameType === '300' ? undefined : '#9c27b0',
|
||||
boxShadow: selectedGameType === '300' ? '0 0 10px #9c27b0' : undefined
|
||||
}}
|
||||
>
|
||||
300 Round
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
{showTargetFaceOptions && (
|
||||
<>
|
||||
<Grid item xs={12}>
|
||||
<Divider style={{ margin: '16px 0' }} />
|
||||
<Typography variant="body1" align="center" gutterBottom>
|
||||
Game Settings:
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
{/* Game Mode Selection */}
|
||||
<Grid item xs={12}>
|
||||
<FormControl component="fieldset" style={{ marginBottom: '16px', width: '100%' }}>
|
||||
<FormLabel component="legend">Game Mode</FormLabel>
|
||||
<RadioGroup
|
||||
row
|
||||
name="gameMode"
|
||||
value={isLeague ? "league" : "practice"}
|
||||
onChange={handleGameModeChange}
|
||||
>
|
||||
<FormControlLabel
|
||||
value="practice"
|
||||
control={<Radio />}
|
||||
label="Practice"
|
||||
/>
|
||||
<FormControlLabel
|
||||
value="league"
|
||||
control={<Radio />}
|
||||
label="League"
|
||||
/>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
|
||||
{/* Target Face Selection */}
|
||||
<Grid item xs={12}>
|
||||
<FormControl component="fieldset" style={{ width: '100%' }}>
|
||||
<FormLabel component="legend">Target Face</FormLabel>
|
||||
<RadioGroup
|
||||
row
|
||||
name="targetFace"
|
||||
value={selectedTargetFace}
|
||||
onChange={(e) => setSelectedTargetFace(e.target.value)}
|
||||
>
|
||||
<FormControlLabel
|
||||
value="standard"
|
||||
control={<Radio />}
|
||||
label="Standard"
|
||||
/>
|
||||
{selectedGameType === '300' && (
|
||||
<FormControlLabel
|
||||
value="5-spot"
|
||||
control={<Radio />}
|
||||
label="5-Spot"
|
||||
/>
|
||||
)}
|
||||
{selectedGameType === '450' && (
|
||||
<FormControlLabel
|
||||
value="3-spot"
|
||||
control={<Radio />}
|
||||
label="3-Spot"
|
||||
/>
|
||||
)}
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} style={{ marginTop: '16px' }}>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="success"
|
||||
size="large"
|
||||
onClick={startGame}
|
||||
id="start-game-button" // Adding an ID for easier debugging
|
||||
>
|
||||
Start Game
|
||||
</Button>
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default GameSetup;
|
||||
@@ -1,156 +1,319 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardContent,
|
||||
CardHeader,
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
RadioGroup,
|
||||
Radio,
|
||||
Grid,
|
||||
Typography,
|
||||
Select,
|
||||
MenuItem
|
||||
Box,
|
||||
Paper,
|
||||
IconButton,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
Divider,
|
||||
ButtonGroup
|
||||
} from '@mui/material';
|
||||
import { Remove } from '@mui/icons-material';
|
||||
import { useScore, ACTIONS } from '../context/ScoreContext';
|
||||
|
||||
const GameSetup = ({ onGameStart }) => {
|
||||
const { dispatch } = useScore();
|
||||
|
||||
const [selectedGameType, setSelectedGameType] = useState('');
|
||||
const [isLeague, setIsLeague] = useState(false); // This tracks if it's a league game
|
||||
const [selectedTargetFace, setSelectedTargetFace] = useState('single'); // Assuming single as default target face
|
||||
|
||||
// Log isLeague to verify if it changes correctly
|
||||
const ScoreTracker = () => {
|
||||
const { state, dispatch } = useScore();
|
||||
const navigate = useNavigate();
|
||||
|
||||
// Local state for the current end
|
||||
const [currentEnd, setCurrentEnd] = useState([]);
|
||||
|
||||
// Check if we have an active game, if not redirect to setup
|
||||
useEffect(() => {
|
||||
console.log("Game mode isLeague:", isLeague); // Check this in the console
|
||||
}, [isLeague]);
|
||||
|
||||
const handleGameModeChange = (event) => {
|
||||
const leagueMode = event.target.value === "league";
|
||||
setIsLeague(leagueMode); // Update isLeague based on user selection
|
||||
if (!state.currentGame || !state.currentGame.gameType) {
|
||||
navigate('/');
|
||||
}
|
||||
}, [state.currentGame, navigate]);
|
||||
|
||||
// Handle adding an arrow score
|
||||
const handleAddArrow = (score) => {
|
||||
// Add to current end
|
||||
setCurrentEnd([...currentEnd, score]);
|
||||
};
|
||||
|
||||
const handleTargetFaceChange = (event) => {
|
||||
setSelectedTargetFace(event.target.value);
|
||||
|
||||
// Handle removing the last arrow
|
||||
const handleRemoveArrow = () => {
|
||||
if (currentEnd.length > 0) {
|
||||
const newEnd = [...currentEnd];
|
||||
newEnd.pop();
|
||||
setCurrentEnd(newEnd);
|
||||
}
|
||||
};
|
||||
|
||||
const startGame = () => {
|
||||
if (!selectedGameType) return;
|
||||
|
||||
// Log the values to ensure they're correct
|
||||
console.log("Starting game with settings:", {
|
||||
gameType: selectedGameType,
|
||||
isLeague: isLeague,
|
||||
targetFace: selectedTargetFace
|
||||
});
|
||||
|
||||
|
||||
// Calculate total for current end
|
||||
const calculateEndTotal = (arrows) => {
|
||||
return arrows.reduce((total, arrow) => {
|
||||
if (arrow.toUpperCase() === 'X') {
|
||||
return total + 10;
|
||||
} else if (arrow.toUpperCase() === 'M') {
|
||||
return total;
|
||||
} else {
|
||||
return total + parseInt(arrow);
|
||||
}
|
||||
}, 0);
|
||||
};
|
||||
|
||||
// Get button color based on score
|
||||
const getButtonColor = (score) => {
|
||||
switch(score) {
|
||||
case 'X':
|
||||
return { bgcolor: '#FF9800', color: 'white' }; // Orange
|
||||
case '10':
|
||||
return { bgcolor: '#9C27B0', color: 'white' }; // Purple
|
||||
case '9':
|
||||
case '8':
|
||||
return { bgcolor: '#2196F3', color: 'white' }; // Blue
|
||||
case '7':
|
||||
case '6':
|
||||
case '5':
|
||||
case '4':
|
||||
case '3':
|
||||
case '2':
|
||||
case '1':
|
||||
return { bgcolor: '#4CAF50', color: 'white' }; // Green
|
||||
case 'M':
|
||||
return { bgcolor: '#9E9E9E', color: 'white' }; // Gray
|
||||
default:
|
||||
return { bgcolor: 'default' };
|
||||
}
|
||||
};
|
||||
|
||||
// Handle saving the current end
|
||||
const handleSaveEnd = () => {
|
||||
if (currentEnd.length > 0) {
|
||||
// Create the end object
|
||||
const endObject = {
|
||||
arrows: [...currentEnd],
|
||||
total: calculateEndTotal(currentEnd),
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
|
||||
// Dispatch to context
|
||||
dispatch({
|
||||
type: ACTIONS.ADD_END,
|
||||
payload: endObject
|
||||
});
|
||||
|
||||
// Clear current end
|
||||
setCurrentEnd([]);
|
||||
}
|
||||
};
|
||||
|
||||
// Handle ending the game
|
||||
const handleEndGame = () => {
|
||||
// Save final scores to history first
|
||||
dispatch({
|
||||
type: ACTIONS.START_GAME,
|
||||
payload: {
|
||||
gameType: selectedGameType,
|
||||
isLeague: isLeague, // Pass the league/practice mode correctly
|
||||
targetFace: selectedTargetFace
|
||||
}
|
||||
type: ACTIONS.SAVE_GAME,
|
||||
});
|
||||
onGameStart();
|
||||
|
||||
// Then end the current game
|
||||
dispatch({
|
||||
type: ACTIONS.END_GAME,
|
||||
});
|
||||
|
||||
// Navigate to setup page
|
||||
navigate('/');
|
||||
};
|
||||
|
||||
// Early return if no game is active
|
||||
if (!state.currentGame || !state.currentGame.gameType) {
|
||||
return null; // Will be redirected by useEffect
|
||||
}
|
||||
|
||||
// Get the number of arrows per end based on game type
|
||||
const arrowsPerEnd = state.currentGame.gameType === '450' ? 6 : 5;
|
||||
|
||||
// Score button values
|
||||
const scoreButtons = ['X', '10', '9', '8', '7', '6', '5', '4', '3', '2', '1', 'M'];
|
||||
|
||||
return (
|
||||
<Grid container spacing={3} justifyContent="center" alignItems="center" style={{ minHeight: '80vh' }}>
|
||||
<Grid item xs={12} sm={8} md={6}>
|
||||
<Grid container spacing={3} justifyContent="center">
|
||||
<Grid item xs={12} sm={10} md={8}>
|
||||
<Card>
|
||||
<CardHeader
|
||||
title="Start New Game"
|
||||
<CardHeader
|
||||
title={`${state.currentGame.gameType} Round ${state.currentGame.isLeague ? '(League)' : '(Practice)'}`}
|
||||
titleTypographyProps={{ align: 'center' }}
|
||||
/>
|
||||
<CardContent>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" align="center" gutterBottom>
|
||||
Select your game type:
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Target Face: {state.currentGame.targetFace || 'Standard'}
|
||||
</Typography>
|
||||
|
||||
{/* Current game stats */}
|
||||
<Box sx={{ mb: 3 }}>
|
||||
<Paper elevation={2} sx={{ p: 2 }}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Current Score: {state.currentGame.ends?.reduce((total, end) => total + end.total, 0) || 0}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color={selectedGameType === '450' ? 'primary' : 'default'}
|
||||
size="large"
|
||||
onClick={() => setSelectedGameType('450')}
|
||||
>
|
||||
450 Round
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color={selectedGameType === '300' ? 'secondary' : 'default'}
|
||||
size="large"
|
||||
onClick={() => setSelectedGameType('300')}
|
||||
>
|
||||
300 Round
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
{/* Select League or Practice Mode */}
|
||||
<Grid item xs={12}>
|
||||
<FormControl component="fieldset" fullWidth>
|
||||
<Typography variant="body1" align="center" gutterBottom>
|
||||
Select game mode:
|
||||
</Typography>
|
||||
<RadioGroup
|
||||
row
|
||||
name="gameMode"
|
||||
value={isLeague ? "league" : "practice"} // Display correct mode
|
||||
onChange={handleGameModeChange}
|
||||
<Typography variant="body1">
|
||||
Ends Completed: {state.currentGame.ends?.length || 0}
|
||||
</Typography>
|
||||
</Paper>
|
||||
</Box>
|
||||
|
||||
{/* Score input section */}
|
||||
<Box sx={{ mb: 3 }}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Score Current End
|
||||
</Typography>
|
||||
|
||||
{/* Score buttons */}
|
||||
<Box sx={{ mb: 2 }}>
|
||||
<Box sx={{ display: 'flex', flexWrap: 'wrap', mb: 1, gap: 0.5 }}>
|
||||
{scoreButtons.map((score) => {
|
||||
const colorStyle = getButtonColor(score);
|
||||
return (
|
||||
<Button
|
||||
key={score}
|
||||
variant="contained"
|
||||
onClick={() => handleAddArrow(score)}
|
||||
disabled={currentEnd.length >= arrowsPerEnd}
|
||||
sx={{
|
||||
minWidth: '45px',
|
||||
bgcolor: colorStyle.bgcolor,
|
||||
color: colorStyle.color,
|
||||
'&:hover': {
|
||||
bgcolor: colorStyle.bgcolor,
|
||||
opacity: 0.9
|
||||
}
|
||||
}}
|
||||
>
|
||||
{score}
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
|
||||
<IconButton
|
||||
color="secondary"
|
||||
onClick={handleRemoveArrow}
|
||||
disabled={currentEnd.length === 0}
|
||||
sx={{ ml: 1 }}
|
||||
>
|
||||
<FormControlLabel
|
||||
value="practice"
|
||||
control={<Radio />}
|
||||
label="Practice"
|
||||
/>
|
||||
<FormControlLabel
|
||||
value="league"
|
||||
control={<Radio />}
|
||||
label="League"
|
||||
/>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
|
||||
{/* Target face selection */}
|
||||
<Grid item xs={12}>
|
||||
<FormControl fullWidth>
|
||||
<Typography variant="body1" align="center" gutterBottom>
|
||||
Select target face:
|
||||
</Typography>
|
||||
<Select
|
||||
value={selectedTargetFace}
|
||||
onChange={handleTargetFaceChange}
|
||||
<Remove />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Current end display */}
|
||||
<Box sx={{ display: 'flex', flexWrap: 'wrap', mb: 2 }}>
|
||||
{currentEnd.map((arrow, index) => {
|
||||
let bgColor;
|
||||
if (arrow.toUpperCase() === 'X') bgColor = '#FF9800'; // Orange
|
||||
else if (arrow.toUpperCase() === '10') bgColor = '#9C27B0'; // Purple
|
||||
else if (['9', '8'].includes(arrow)) bgColor = '#2196F3'; // Blue
|
||||
else if (['7', '6', '5', '4', '3', '2', '1'].includes(arrow)) bgColor = '#4CAF50'; // Green
|
||||
else if (arrow.toUpperCase() === 'M') bgColor = '#9E9E9E'; // Gray
|
||||
else bgColor = 'default';
|
||||
|
||||
return (
|
||||
<Paper
|
||||
key={index}
|
||||
elevation={1}
|
||||
sx={{
|
||||
p: 1.5,
|
||||
m: 0.5,
|
||||
minWidth: '40px',
|
||||
textAlign: 'center',
|
||||
bgcolor: bgColor,
|
||||
color: 'white'
|
||||
}}
|
||||
>
|
||||
<Typography variant="h6">{arrow.toUpperCase()}</Typography>
|
||||
</Paper>
|
||||
);
|
||||
})}
|
||||
{Array(arrowsPerEnd - currentEnd.length).fill(0).map((_, index) => (
|
||||
<Paper
|
||||
key={`empty-${index}`}
|
||||
elevation={1}
|
||||
sx={{
|
||||
p: 1.5,
|
||||
m: 0.5,
|
||||
minWidth: '40px',
|
||||
textAlign: 'center',
|
||||
bgcolor: '#f5f5f5'
|
||||
}}
|
||||
>
|
||||
<MenuItem value="single">Single Spot</MenuItem>
|
||||
<MenuItem value="five">Five Spot</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
|
||||
{/* Start Game Button */}
|
||||
<Grid item xs={12}>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="primary"
|
||||
size="large"
|
||||
onClick={startGame}
|
||||
disabled={!selectedGameType} // Disable button if no game type selected
|
||||
<Typography variant="h6">-</Typography>
|
||||
</Paper>
|
||||
))}
|
||||
</Box>
|
||||
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Typography variant="body1">
|
||||
End Total: {calculateEndTotal(currentEnd)}
|
||||
</Typography>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleSaveEnd}
|
||||
disabled={currentEnd.length === 0 || currentEnd.length < arrowsPerEnd}
|
||||
>
|
||||
Start Game
|
||||
Save End
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Divider sx={{ my: 3 }} />
|
||||
|
||||
{/* Previous ends display */}
|
||||
{(state.currentGame.ends?.length > 0) && (
|
||||
<Box sx={{ mb: 3 }}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Previous Ends
|
||||
</Typography>
|
||||
<TableContainer component={Paper}>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>End</TableCell>
|
||||
<TableCell>Arrows</TableCell>
|
||||
<TableCell>Total</TableCell>
|
||||
<TableCell>Running Total</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{state.currentGame.ends.map((end, endIndex) => {
|
||||
const runningTotal = state.currentGame.ends
|
||||
.slice(0, endIndex + 1)
|
||||
.reduce((total, e) => total + e.total, 0);
|
||||
|
||||
return (
|
||||
<TableRow key={endIndex}>
|
||||
<TableCell>{endIndex + 1}</TableCell>
|
||||
<TableCell>
|
||||
{end.arrows.join(', ')}
|
||||
</TableCell>
|
||||
<TableCell>{end.total}</TableCell>
|
||||
<TableCell>{runningTotal}</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
onClick={handleEndGame}
|
||||
sx={{ mt: 3 }}
|
||||
>
|
||||
End Game
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
@@ -158,5 +321,4 @@ const GameSetup = ({ onGameStart }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default GameSetup;
|
||||
|
||||
export default ScoreTracker;
|
||||
|
||||
Reference in New Issue
Block a user