diff --git a/redux/PlayersSlice.ts b/redux/PlayersSlice.ts index 27db67e2..9080194b 100644 --- a/redux/PlayersSlice.ts +++ b/redux/PlayersSlice.ts @@ -1,6 +1,7 @@ import crashlytics from '@react-native-firebase/crashlytics'; import { PayloadAction, createEntityAdapter, createSelector, createSlice } from '@reduxjs/toolkit'; +import { grandTotalScore, totalScoreBeforeRound } from './scoreUtils'; import { RootState } from './store'; type RoundIndex = number; @@ -14,7 +15,8 @@ export interface ScoreState { const playersAdapter = createEntityAdapter({ sortComparer: (a: ScoreState, b: ScoreState) => ( - a.scores.reduce((a, b) => a + b, 0)) < b.scores.reduce((a, b) => a + b, 0) ? 1 : -1, + grandTotalScore(a.scores) < grandTotalScore(b.scores) ? 1 : -1 + ), }); const initialState = playersAdapter.getInitialState({ @@ -127,7 +129,7 @@ export const selectPlayerScoreByRound = createSelector( export const selectPlayerGrandTotalScore = createSelector( [(state: RootState, playerId: string) => state.players.entities[playerId]], - (player) => player?.scores?.reduce((sum, s) => sum + (s || 0), 0) ?? 0 + (player) => grandTotalScore(player?.scores) ); export const selectPlayerRoundStats = createSelector( @@ -138,11 +140,9 @@ export const selectPlayerRoundStats = createSelector( (player, currentRoundIndex) => { const scores = player?.scores ?? []; const currentRoundScore = scores[currentRoundIndex] ?? 0; - const previousTotal = scores.reduce( - (sum, s, i) => (i < currentRoundIndex ? sum + (s || 0) : sum), 0 - ); + const previousTotal = totalScoreBeforeRound(scores, currentRoundIndex); const currentRoundTotalScore = previousTotal + currentRoundScore; - const grandTotalScore = scores.reduce((sum, s) => sum + (s || 0), 0); - return { currentRoundScore, previousTotal, currentRoundTotalScore, grandTotalScore }; + const grandTotal = grandTotalScore(scores); + return { currentRoundScore, previousTotal, currentRoundTotalScore, grandTotalScore: grandTotal }; } ); diff --git a/redux/scoreUtils.test.ts b/redux/scoreUtils.test.ts new file mode 100644 index 00000000..ea837a08 --- /dev/null +++ b/redux/scoreUtils.test.ts @@ -0,0 +1,24 @@ +import { grandTotalScore, totalScoreBeforeRound } from './scoreUtils'; + +describe('scoreUtils', () => { + describe('grandTotalScore', () => { + it('should add all scores', () => { + expect(grandTotalScore([2, -1, 4])).toBe(5); + }); + + it('should handle empty or missing scores', () => { + expect(grandTotalScore()).toBe(0); + expect(grandTotalScore([])).toBe(0); + }); + }); + + describe('totalScoreBeforeRound', () => { + it('should add scores before the requested round', () => { + expect(totalScoreBeforeRound([3, 4, 5], 2)).toBe(7); + }); + + it('should return zero for the first round', () => { + expect(totalScoreBeforeRound([3, 4, 5], 0)).toBe(0); + }); + }); +}); diff --git a/redux/scoreUtils.ts b/redux/scoreUtils.ts new file mode 100644 index 00000000..e51ee33f --- /dev/null +++ b/redux/scoreUtils.ts @@ -0,0 +1,10 @@ +export function grandTotalScore(scores: number[] = []): number { + return scores.reduce((total, score) => total + (score || 0), 0); +} + +export function totalScoreBeforeRound(scores: number[] = [], roundIndex: number): number { + return scores.reduce( + (total, score, index) => (index < roundIndex ? total + (score || 0) : total), + 0 + ); +} diff --git a/src/components/ScoreLog/SortHelper.ts b/src/components/ScoreLog/SortHelper.ts index bed4a3f9..191e3912 100644 --- a/src/components/ScoreLog/SortHelper.ts +++ b/src/components/ScoreLog/SortHelper.ts @@ -2,6 +2,7 @@ import { createSelector } from '@reduxjs/toolkit'; import { GameState } from '../../../redux/GamesSlice'; import { ScoreState, selectAllPlayers } from '../../../redux/PlayersSlice'; +import { grandTotalScore } from '../../../redux/scoreUtils'; import { RootState } from '../../../redux/store'; export const selectSortedPlayerIdsByIndex = createSelector( @@ -39,9 +40,7 @@ export const selectSortedPlayerIdsByScore: SortSelector = createSelector( const playerIds = [...players] .filter(player => currentGame.playerIds?.includes(player.id)) .sort((a, b) => { - const totalScoreA = a.scores.reduce((acc, score) => acc + score, 0); - const totalScoreB = b.scores.reduce((acc, score) => acc + score, 0); - const scoreDifference = totalScoreB - totalScoreA; + const scoreDifference = grandTotalScore(b.scores) - grandTotalScore(a.scores); if (scoreDifference === 0) { // If the total scores are equal, sort by player index @@ -50,7 +49,7 @@ export const selectSortedPlayerIdsByScore: SortSelector = createSelector( return indexA - indexB; } - return totalScoreB - totalScoreA; + return scoreDifference; }) .map(player => player.id);