Additional work on Main menu, and history components
This commit is contained in:
@@ -1,72 +1,44 @@
|
||||
// src/context/ScoreContext.js
|
||||
import React, { createContext, useContext, useReducer, useEffect } from 'react';
|
||||
|
||||
// Define action types
|
||||
export const ACTIONS = {
|
||||
ADD_ARROW: 'ADD_ARROW',
|
||||
START_NEW_ROUND: 'START_NEW_ROUND',
|
||||
RESET_GAME: 'RESET_GAME',
|
||||
LOAD_SAVED_GAME: 'LOAD_SAVED_GAME',
|
||||
START_NEW_GAME: 'START_NEW_GAME',
|
||||
SAVE_GAME: 'SAVE_GAME',
|
||||
UPDATE_HANDICAP: 'UPDATE_HANDICAP'
|
||||
START_GAME: 'start_game',
|
||||
ADD_ROUND: 'add_round',
|
||||
RESET_GAME: 'reset_game',
|
||||
SAVE_GAME: 'save_game',
|
||||
LOAD_HISTORY: 'load_history'
|
||||
};
|
||||
|
||||
// Initial state structure
|
||||
const initialState = {
|
||||
currentGame: {
|
||||
id: null,
|
||||
gameType: null, // '450' or '300'
|
||||
category: null, // 'league' or 'practice'
|
||||
gameType: '',
|
||||
isLeague: false,
|
||||
rounds: [],
|
||||
totalScore: 0,
|
||||
totalBullseyes: 0,
|
||||
dateStarted: null,
|
||||
dateCompleted: null,
|
||||
handicap: null,
|
||||
},
|
||||
games: {
|
||||
league: [],
|
||||
practice: [],
|
||||
},
|
||||
statistics: {
|
||||
handicapHistory: [],
|
||||
averageScores: {
|
||||
league: { '450': 0, '300': 0 },
|
||||
practice: { '450': 0, '300': 0 },
|
||||
},
|
||||
date: null
|
||||
},
|
||||
history: []
|
||||
};
|
||||
|
||||
// Handicap calculation function
|
||||
const calculateHandicap = (scores) => {
|
||||
if (scores.length < 3) return null;
|
||||
|
||||
const lastThree = scores.slice(-3);
|
||||
const average = lastThree.reduce((sum, game) => sum + game.totalScore, 0) / 3;
|
||||
|
||||
const maxPossibleScore = scores[0].gameType === '450' ? 450 : 300;
|
||||
const handicap = Math.round((maxPossibleScore - average) * 0.8);
|
||||
|
||||
return Math.max(0, Math.min(100, handicap));
|
||||
};
|
||||
|
||||
// Reducer function
|
||||
const scoreReducer = (state, action) => {
|
||||
switch (action.type) {
|
||||
case ACTIONS.ADD_ARROW: {
|
||||
const { roundIndex, score, isBullseye } = action.payload;
|
||||
case ACTIONS.START_GAME:
|
||||
return {
|
||||
...state,
|
||||
currentGame: {
|
||||
...initialState.currentGame,
|
||||
gameType: action.payload.gameType,
|
||||
isLeague: action.payload.isLeague,
|
||||
date: new Date().toISOString()
|
||||
}
|
||||
};
|
||||
|
||||
case ACTIONS.ADD_ROUND:
|
||||
const updatedRounds = [...state.currentGame.rounds];
|
||||
|
||||
if (!updatedRounds[roundIndex]) {
|
||||
updatedRounds[roundIndex] = { arrows: [], total: 0, bullseyes: 0 };
|
||||
}
|
||||
|
||||
updatedRounds[roundIndex] = {
|
||||
...updatedRounds[roundIndex],
|
||||
arrows: [...updatedRounds[roundIndex].arrows, score],
|
||||
total: updatedRounds[roundIndex].total + score,
|
||||
bullseyes: updatedRounds[roundIndex].bullseyes + (isBullseye ? 1 : 0),
|
||||
updatedRounds[action.payload.roundIndex] = {
|
||||
arrows: action.payload.arrows,
|
||||
total: action.payload.arrows.reduce((sum, arrow) => sum + arrow.score, 0),
|
||||
bullseyes: action.payload.arrows.filter(arrow => arrow.isBullseye).length
|
||||
};
|
||||
|
||||
const totalScore = updatedRounds.reduce((sum, round) => sum + round.total, 0);
|
||||
@@ -78,130 +50,58 @@ const scoreReducer = (state, action) => {
|
||||
...state.currentGame,
|
||||
rounds: updatedRounds,
|
||||
totalScore,
|
||||
totalBullseyes,
|
||||
},
|
||||
totalBullseyes
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
case ACTIONS.START_NEW_ROUND: {
|
||||
const gamesHistory = state.currentGame.gameType ?
|
||||
[...state.games, state.currentGame] :
|
||||
state.games;
|
||||
case ACTIONS.SAVE_GAME:
|
||||
if (!state.currentGame.isLeague) return state; // Only save league games
|
||||
|
||||
const updatedHistory = [
|
||||
...state.history,
|
||||
{ ...state.currentGame }
|
||||
];
|
||||
|
||||
// Save to localStorage
|
||||
localStorage.setItem('archeryHistory', JSON.stringify(updatedHistory));
|
||||
|
||||
return {
|
||||
...state,
|
||||
games: gamesHistory,
|
||||
currentGame: {
|
||||
...state.currentGame,
|
||||
gameType: action.payload.gameType,
|
||||
rounds: [],
|
||||
totalScore: 0,
|
||||
totalBullseyes: 0,
|
||||
dateStarted: new Date().toISOString(),
|
||||
},
|
||||
history: updatedHistory
|
||||
};
|
||||
}
|
||||
|
||||
case ACTIONS.START_NEW_GAME: {
|
||||
const { gameType, category } = action.payload;
|
||||
case ACTIONS.LOAD_HISTORY:
|
||||
return {
|
||||
...state,
|
||||
currentGame: {
|
||||
...initialState.currentGame,
|
||||
id: Date.now(),
|
||||
gameType,
|
||||
category,
|
||||
dateStarted: new Date().toISOString(),
|
||||
},
|
||||
history: action.payload
|
||||
};
|
||||
}
|
||||
|
||||
case ACTIONS.SAVE_GAME: {
|
||||
const completedGame = {
|
||||
...state.currentGame,
|
||||
dateCompleted: new Date().toISOString(),
|
||||
};
|
||||
|
||||
if (completedGame.category === 'league') {
|
||||
const relevantGames = [...state.games.league, completedGame]
|
||||
.filter(game => game.gameType === completedGame.gameType)
|
||||
.sort((a, b) => new Date(b.dateCompleted) - new Date(a.dateCompleted));
|
||||
|
||||
completedGame.handicap = calculateHandicap(relevantGames);
|
||||
}
|
||||
|
||||
const newGames = {
|
||||
...state.games,
|
||||
[completedGame.category]: [
|
||||
...state.games[completedGame.category],
|
||||
completedGame,
|
||||
],
|
||||
};
|
||||
|
||||
const updateAverages = (games, type, category) => {
|
||||
const relevantGames = games.filter(game => game.gameType === type);
|
||||
return relevantGames.length > 0
|
||||
? relevantGames.reduce((sum, game) => sum + game.totalScore, 0) / relevantGames.length
|
||||
: 0;
|
||||
};
|
||||
|
||||
const newStatistics = {
|
||||
...state.statistics,
|
||||
averageScores: {
|
||||
league: {
|
||||
'450': updateAverages(newGames.league, '450', 'league'),
|
||||
'300': updateAverages(newGames.league, '300', 'league'),
|
||||
},
|
||||
practice: {
|
||||
'450': updateAverages(newGames.practice, '450', 'practice'),
|
||||
'300': updateAverages(newGames.practice, '300', 'practice'),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
...state,
|
||||
currentGame: initialState.currentGame,
|
||||
games: newGames,
|
||||
statistics: newStatistics,
|
||||
};
|
||||
}
|
||||
|
||||
case ACTIONS.RESET_GAME:
|
||||
return initialState;
|
||||
|
||||
case ACTIONS.LOAD_SAVED_GAME:
|
||||
return action.payload;
|
||||
return {
|
||||
...state,
|
||||
currentGame: initialState.currentGame
|
||||
};
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
// Create context
|
||||
const ScoreContext = createContext();
|
||||
|
||||
// Context provider component
|
||||
export const ScoreProvider = ({ children }) => {
|
||||
const [state, dispatch] = useReducer(scoreReducer, initialState, () => {
|
||||
try {
|
||||
const localData = localStorage.getItem('archeryScores');
|
||||
if (localData) {
|
||||
const parsedData = JSON.parse(localData);
|
||||
if (parsedData.currentGame && parsedData.games) {
|
||||
return parsedData;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading saved game:', error);
|
||||
}
|
||||
return initialState;
|
||||
});
|
||||
const [state, dispatch] = useReducer(scoreReducer, initialState);
|
||||
|
||||
// Save to localStorage after every state change
|
||||
// Load history from localStorage on initial mount
|
||||
useEffect(() => {
|
||||
localStorage.setItem('archeryScores', JSON.stringify(state));
|
||||
}, [state]);
|
||||
const savedHistory = localStorage.getItem('archeryHistory');
|
||||
if (savedHistory) {
|
||||
dispatch({
|
||||
type: ACTIONS.LOAD_HISTORY,
|
||||
payload: JSON.parse(savedHistory)
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ScoreContext.Provider value={{ state, dispatch }}>
|
||||
@@ -210,7 +110,6 @@ export const ScoreProvider = ({ children }) => {
|
||||
);
|
||||
};
|
||||
|
||||
// Custom hook for using the score context
|
||||
export const useScore = () => {
|
||||
const context = useContext(ScoreContext);
|
||||
if (!context) {
|
||||
@@ -218,5 +117,3 @@ export const useScore = () => {
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
export default ScoreContext;
|
||||
|
||||
Reference in New Issue
Block a user