Updated practice view and added score distribution
This commit is contained in:
@@ -17,7 +17,8 @@ import {
|
||||
TableHead,
|
||||
TableRow,
|
||||
Divider,
|
||||
ButtonGroup
|
||||
ButtonGroup,
|
||||
LinearProgress
|
||||
} from '@mui/material';
|
||||
import { Remove } from '@mui/icons-material';
|
||||
import { useScore, ACTIONS } from '../context/ScoreContext';
|
||||
@@ -28,6 +29,10 @@ const ScoreTracker = () => {
|
||||
|
||||
// Local state for the current end
|
||||
const [currentEnd, setCurrentEnd] = useState([]);
|
||||
// Local state to track score distribution
|
||||
const [scoreDistribution, setScoreDistribution] = useState({});
|
||||
// Local state to track total arrows
|
||||
const [totalArrows, setTotalArrows] = useState(0);
|
||||
|
||||
// Check if we have an active game, if not redirect to setup
|
||||
useEffect(() => {
|
||||
@@ -36,6 +41,15 @@ const ScoreTracker = () => {
|
||||
}
|
||||
}, [state.currentGame, navigate]);
|
||||
|
||||
// Update score distribution whenever the current game changes
|
||||
useEffect(() => {
|
||||
if (state.currentGame) {
|
||||
const distribution = calculateScoreDistribution();
|
||||
setScoreDistribution(distribution);
|
||||
setTotalArrows(calculateTotalArrows(distribution));
|
||||
}
|
||||
}, [state.currentGame]);
|
||||
|
||||
// Handle adding an arrow score
|
||||
const handleAddArrow = (score) => {
|
||||
// Add to current end
|
||||
@@ -64,6 +78,42 @@ const ScoreTracker = () => {
|
||||
}, 0);
|
||||
};
|
||||
|
||||
// Calculate score distribution for all completed ends
|
||||
const calculateScoreDistribution = () => {
|
||||
// Initialize distribution object based on game type
|
||||
let distribution = {};
|
||||
|
||||
if (state.currentGame.gameType === '300' && state.currentGame.targetFace === '5-spot') {
|
||||
distribution = { 'X': 0, '5': 0, '4': 0, 'M': 0 };
|
||||
} else if (state.currentGame.gameType === '300' && state.currentGame.targetFace !== '5-spot') {
|
||||
distribution = { 'X': 0, '5': 0, '4': 0, '3': 0, '2': 0, '1': 0, 'M': 0 };
|
||||
} else if (state.currentGame.gameType === '450' && state.currentGame.targetFace === '3-spot') {
|
||||
distribution = { 'X': 0, '10': 0, '9': 0, '8': 0, 'M': 0 };
|
||||
} else {
|
||||
distribution = { 'X': 0, '10': 0, '9': 0, '8': 0, '7': 0, '6': 0, '5': 0, '4': 0, '3': 0, '2': 0, '1': 0, 'M': 0 };
|
||||
}
|
||||
|
||||
// Count arrows from all completed ends
|
||||
if (state.currentGame.ends && state.currentGame.ends.length > 0) {
|
||||
state.currentGame.ends.forEach(end => {
|
||||
end.arrows.forEach(arrow => {
|
||||
// Make sure to handle uppercase X and M
|
||||
const normalizedArrow = arrow.toUpperCase();
|
||||
if (distribution.hasOwnProperty(normalizedArrow)) {
|
||||
distribution[normalizedArrow]++;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return distribution;
|
||||
};
|
||||
|
||||
// Calculate total arrows shot
|
||||
const calculateTotalArrows = (distribution) => {
|
||||
return Object.values(distribution).reduce((sum, count) => sum + count, 0);
|
||||
};
|
||||
|
||||
// Get button color based on score
|
||||
const getButtonColor = (score) => {
|
||||
// For 450 game with single spot, use a specific color scheme
|
||||
@@ -150,6 +200,29 @@ const ScoreTracker = () => {
|
||||
payload: endObject
|
||||
});
|
||||
|
||||
// Update score distribution immediately
|
||||
// Create a new temporary game state that includes the new end
|
||||
const updatedEnds = [...(state.currentGame.ends || []), endObject];
|
||||
const tempGameState = {
|
||||
...state.currentGame,
|
||||
ends: updatedEnds
|
||||
};
|
||||
|
||||
// Calculate distribution based on this updated state
|
||||
let updatedDistribution = { ...scoreDistribution };
|
||||
|
||||
// Add the new arrows to the distribution
|
||||
currentEnd.forEach(arrow => {
|
||||
const normalizedArrow = arrow.toUpperCase();
|
||||
if (updatedDistribution.hasOwnProperty(normalizedArrow)) {
|
||||
updatedDistribution[normalizedArrow]++;
|
||||
}
|
||||
});
|
||||
|
||||
// Update the state
|
||||
setScoreDistribution(updatedDistribution);
|
||||
setTotalArrows(calculateTotalArrows(updatedDistribution));
|
||||
|
||||
// Clear current end
|
||||
setCurrentEnd([]);
|
||||
}
|
||||
@@ -198,6 +271,12 @@ const ScoreTracker = () => {
|
||||
// Use the function to get the appropriate buttons
|
||||
const scoreButtons = getScoreButtons();
|
||||
|
||||
// Calculate current game total score
|
||||
const currentGameTotal = state.currentGame.ends?.reduce((total, end) => total + end.total, 0) || 0;
|
||||
|
||||
// Check if this is a practice game (not league)
|
||||
const isPracticeGame = !state.currentGame.isLeague;
|
||||
|
||||
return (
|
||||
<Grid container spacing={3} justifyContent="center">
|
||||
<Grid item xs={12} sm={10} md={8}>
|
||||
@@ -207,19 +286,123 @@ const ScoreTracker = () => {
|
||||
titleTypographyProps={{ align: 'center' }}
|
||||
/>
|
||||
<CardContent>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Target Face: {state.currentGame.targetFace || 'Standard'}
|
||||
</Typography>
|
||||
{/* Only show target face for league games */}
|
||||
{!isPracticeGame && (
|
||||
<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>
|
||||
<Typography variant="body1">
|
||||
Ends Completed: {state.currentGame.ends?.length || 0}
|
||||
</Typography>
|
||||
{/* Score Distribution Section - moved to the top and enhanced */}
|
||||
<Box sx={{ mb: 4 }}>
|
||||
<Paper
|
||||
elevation={3}
|
||||
sx={{
|
||||
p: 3,
|
||||
borderRadius: 2,
|
||||
border: '1px solid #e0e0e0'
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 2 }}>
|
||||
<Typography variant="h5" component="h2" fontWeight="bold">
|
||||
Score Distribution
|
||||
</Typography>
|
||||
{/* Only show Total Score for league games */}
|
||||
{!isPracticeGame && (
|
||||
<Typography variant="h6">
|
||||
Total Score: {currentGameTotal}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<Grid container spacing={2} sx={{ mb: 2 }}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1">
|
||||
Arrows Shot: {totalArrows}
|
||||
</Typography>
|
||||
</Grid>
|
||||
{/* Only show Ends Completed for league games */}
|
||||
{!isPracticeGame && (
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="body1">
|
||||
Ends Completed: {state.currentGame.ends?.length || 0}
|
||||
</Typography>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
<Divider sx={{ mb: 3 }} />
|
||||
|
||||
{totalArrows > 0 ? (
|
||||
<Box>
|
||||
{Object.entries(scoreDistribution)
|
||||
// Only display scores that have valid values in the target face
|
||||
.filter(([score, _]) => {
|
||||
const validScores = getScoreButtons();
|
||||
return validScores.includes(score);
|
||||
})
|
||||
// Sort by score value (X first, then 10, 9, etc.)
|
||||
.sort(([scoreA], [scoreB]) => {
|
||||
if (scoreA === 'X') return -1;
|
||||
if (scoreB === 'X') return 1;
|
||||
if (scoreA === 'M') return 1;
|
||||
if (scoreB === 'M') return -1;
|
||||
return parseInt(scoreB) - parseInt(scoreA);
|
||||
})
|
||||
// Only show scores that have at least one arrow
|
||||
.filter(([_, count]) => count > 0)
|
||||
.map(([score, count]) => {
|
||||
const percentage = totalArrows > 0 ? (count / totalArrows) * 100 : 0;
|
||||
const colorStyle = getButtonColor(score);
|
||||
|
||||
return (
|
||||
<Box key={score} sx={{ mb: 2 }}>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 0.5, alignItems: 'center' }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Paper
|
||||
elevation={1}
|
||||
sx={{
|
||||
display: 'inline-block',
|
||||
p: 1,
|
||||
minWidth: '36px',
|
||||
textAlign: 'center',
|
||||
mr: 2,
|
||||
bgcolor: colorStyle.bgcolor,
|
||||
color: colorStyle.color
|
||||
}}
|
||||
>
|
||||
<Typography variant="body1" fontWeight="bold">{score}</Typography>
|
||||
</Paper>
|
||||
<Typography variant="body1" fontWeight="medium">
|
||||
{count} arrows
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography variant="body1" fontWeight="medium">
|
||||
{percentage.toFixed(1)}%
|
||||
</Typography>
|
||||
</Box>
|
||||
<LinearProgress
|
||||
variant="determinate"
|
||||
value={percentage}
|
||||
sx={{
|
||||
height: 12,
|
||||
borderRadius: 1,
|
||||
bgcolor: '#f5f5f5',
|
||||
'& .MuiLinearProgress-bar': {
|
||||
bgcolor: colorStyle.bgcolor
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
})
|
||||
}
|
||||
</Box>
|
||||
) : (
|
||||
<Typography variant="body1" sx={{ textAlign: 'center', py: 4, color: 'text.secondary' }}>
|
||||
No arrows recorded yet. Start scoring to see your distribution.
|
||||
</Typography>
|
||||
)}
|
||||
</Paper>
|
||||
</Box>
|
||||
|
||||
@@ -393,7 +576,7 @@ const ScoreTracker = () => {
|
||||
onClick={handleEndGame}
|
||||
sx={{ mt: 3 }}
|
||||
>
|
||||
End Game
|
||||
{isPracticeGame ? "End Practice" : "End Game"}
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user