11import {
2+ fromRecordedExercisePOJO ,
23 RecordedExercise ,
4+ RecordedExercisePOJO ,
35 Session ,
46 SessionPOJO ,
57} from '@/models/session-models' ;
68import {
79 NormalizedName ,
810 NormalizedNameKey ,
911 ExerciseBlueprint ,
12+ KeyedExerciseBlueprint ,
13+ fromExerciseBlueprintPOJO ,
14+ ExerciseBlueprintPOJO ,
1015} from '@/models/blueprint-models' ;
11- import { LocalDate , YearMonth , ZoneId } from '@js-joda/core' ;
16+ import { LocalDate , OffsetDateTime , YearMonth , ZoneId } from '@js-joda/core' ;
1217import {
1318 createAction ,
1419 createSelector ,
1520 createSlice ,
1621 PayloadAction ,
22+ WritableDraft ,
1723} from '@reduxjs/toolkit' ;
1824import Enumerable from 'linq' ;
1925import { WeightUnit } from '@/models/weight' ;
@@ -38,6 +44,7 @@ export interface WeightMigrateableExercise {
3844interface StoredSessionState {
3945 isHydrated : boolean ;
4046 sessions : Record < string , SessionPOJO > ;
47+ latestExercises : Record < string , RecordedExercisePOJO | undefined > ; // KeyedExerciseBlueprint -> RecordedExercise
4148 savedExercises : Record < string , ExerciseDescriptor > ;
4249 filteredExerciseIds : string [ ] ;
4350 exercisesRequiringWeightMigration : WeightMigrateableExercise [ ] ;
@@ -46,6 +53,7 @@ interface StoredSessionState {
4653const initialState : StoredSessionState = {
4754 isHydrated : false ,
4855 sessions : { } ,
56+ latestExercises : { } ,
4957 savedExercises : { } ,
5058 filteredExerciseIds : [ ] ,
5159 exercisesRequiringWeightMigration : [ ] ,
@@ -66,15 +74,43 @@ const storedSessionsSlice = createSlice({
6674 } ,
6775
6876 upsertStoredSessions ( state , action : PayloadAction < Session [ ] > ) {
69- action . payload . forEach ( ( s ) => ( state . sessions [ s . id ] = s . toPOJO ( ) ) ) ;
77+ action . payload . forEach ( ( session ) => {
78+ state . sessions [ session . id ] = session . toPOJO ( ) ;
79+ updateLatestExercises ( state , session ) ;
80+ } ) ;
7081 } ,
7182
7283 addStoredSession ( state , action : PayloadAction < Session > ) {
7384 state . sessions [ action . payload . id ] = action . payload . toPOJO ( ) ;
85+ updateLatestExercises ( state , action . payload ) ;
7486 } ,
7587
7688 deleteStoredSession ( state , action : PayloadAction < string > ) {
89+ const deletedSession = state . sessions [ action . payload ] ;
7790 delete state . sessions [ action . payload ] ;
91+
92+ if ( ! deletedSession ) return ;
93+
94+ // Collect the exercise keys that were in the deleted session
95+ const affectedKeys = new Set (
96+ deletedSession . recordedExercises . map ( ( e ) =>
97+ KeyedExerciseBlueprint . fromExerciseBlueprint (
98+ fromExerciseBlueprintPOJO ( e . blueprint as ExerciseBlueprintPOJO ) ,
99+ ) . toString ( ) ,
100+ ) ,
101+ ) ;
102+
103+ // For each affected key, clear and recalculate from remaining sessions
104+ affectedKeys . forEach ( ( key ) => {
105+ delete state . latestExercises [ key ] ;
106+ } ) ;
107+
108+ Object . values ( state . sessions ) . forEach ( ( sessionPOJO ) => {
109+ updateLatestExercises (
110+ state ,
111+ Session . fromPOJO ( sessionPOJO as SessionPOJO ) ,
112+ ) ;
113+ } ) ;
78114 } ,
79115 updateExercise (
80116 state ,
@@ -112,6 +148,16 @@ const storedSessionsSlice = createSlice({
112148 } ,
113149
114150 selectors : {
151+ selectLatestExercises : createSelector (
152+ [ ( state : StoredSessionState ) => state . latestExercises ] ,
153+ ( exercises ) =>
154+ Object . fromEntries (
155+ Object . entries ( exercises ) . map ( ( [ key , exercise ] ) => [
156+ key ,
157+ exercise ? fromRecordedExercisePOJO ( exercise ) : undefined ,
158+ ] ) ,
159+ ) ,
160+ ) ,
115161 selectSessions : createSelector (
116162 [ ( state : StoredSessionState ) => state . sessions ] ,
117163 ( sessions ) => Object . values ( sessions ) . map ( ( x ) => Session . fromPOJO ( x ) ) ,
@@ -147,6 +193,26 @@ const storedSessionsSlice = createSlice({
147193 } ,
148194} ) ;
149195
196+ function updateLatestExercises (
197+ state : WritableDraft < StoredSessionState > ,
198+ session : Session ,
199+ ) {
200+ session . recordedExercises . forEach ( ( exercise ) => {
201+ const key = KeyedExerciseBlueprint . fromExerciseBlueprint (
202+ exercise . blueprint ,
203+ ) . toString ( ) ;
204+ const latestExercise = state . latestExercises [ key ] ;
205+ if (
206+ ! latestExercise ||
207+ fromRecordedExercisePOJO (
208+ latestExercise as RecordedExercisePOJO ,
209+ ) . latestTime ?. isBefore ( exercise . latestTime ?? OffsetDateTime . MIN )
210+ ) {
211+ state . latestExercises [ key ] = exercise . toPOJO ( ) ;
212+ }
213+ } ) ;
214+ }
215+
150216export const selectSessionsBy = createSelector (
151217 [
152218 storedSessionsSlice . selectors . selectSessions ,
@@ -189,6 +255,7 @@ export const {
189255 selectCompletedDistinctSessionNames,
190256 selectSession,
191257 selectExercises,
258+ selectLatestExercises,
192259 selectExerciseById,
193260} = storedSessionsSlice . selectors ;
194261
0 commit comments