Updated practice view and added score distribution

This commit is contained in:
corey@blaishome.online
2025-03-19 23:05:48 -04:00
parent ef8c218b2a
commit 8ec08910af

View File

@@ -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>
{/* 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}
{/* 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>