diff --git a/src/models/WorkoutSession.ts b/src/models/WorkoutSession.ts index f077dfd..8565eec 100644 --- a/src/models/WorkoutSession.ts +++ b/src/models/WorkoutSession.ts @@ -31,7 +31,7 @@ export interface ICompletedExercise { export interface IPr { exerciseId: string; - type: string; // 'est1rm' | 'maxWeight' | 'repMax' + type: string; // 'est1rm' | 'maxWeight' | 'bestSetVolume' | 'repMax' value: number; reps?: number; } diff --git a/src/routes/api/fitness/sessions/+server.ts b/src/routes/api/fitness/sessions/+server.ts index 6242267..7cc62c0 100644 --- a/src/routes/api/fitness/sessions/+server.ts +++ b/src/routes/api/fitness/sessions/+server.ts @@ -100,8 +100,12 @@ export const POST: RequestHandler = async ({ request, locals }) => { 'exercises.exerciseId': ex.exerciseId, }).sort({ startTime: -1 }).limit(50).lean(); + const isBilateral = exercise?.bilateral ?? false; + const weightMul = isBilateral ? 2 : 1; + let prevBestWeight = 0; let prevBestEst1rm = 0; + let prevBestVolume = 0; for (const ps of prevSessions) { const pe = ps.exercises.find((e) => e.exerciseId === ex.exerciseId); if (!pe) continue; @@ -109,15 +113,18 @@ export const POST: RequestHandler = async ({ request, locals }) => { if (!s.completed || !s.weight || !s.reps) continue; prevBestWeight = Math.max(prevBestWeight, s.weight); prevBestEst1rm = Math.max(prevBestEst1rm, estimatedOneRepMax(s.weight, s.reps)); + prevBestVolume = Math.max(prevBestVolume, s.weight * s.reps * weightMul); } } let bestWeight = 0; let bestEst1rm = 0; + let bestVolume = 0; for (const s of completedSets) { if (!s.weight || !s.reps) continue; bestWeight = Math.max(bestWeight, s.weight); bestEst1rm = Math.max(bestEst1rm, estimatedOneRepMax(s.weight, s.reps)); + bestVolume = Math.max(bestVolume, s.weight * s.reps * weightMul); } if (bestWeight > prevBestWeight && prevBestWeight > 0) { @@ -126,6 +133,9 @@ export const POST: RequestHandler = async ({ request, locals }) => { if (bestEst1rm > prevBestEst1rm && prevBestEst1rm > 0) { prs.push({ exerciseId: ex.exerciseId, type: 'est1rm', value: bestEst1rm }); } + if (bestVolume > prevBestVolume && prevBestVolume > 0) { + prs.push({ exerciseId: ex.exerciseId, type: 'bestSetVolume', value: Math.round(bestVolume) }); + } } const workoutSession = new WorkoutSession({ diff --git a/src/routes/api/fitness/sessions/[id]/recalculate/+server.ts b/src/routes/api/fitness/sessions/[id]/recalculate/+server.ts index 3e69ce5..617b09f 100644 --- a/src/routes/api/fitness/sessions/[id]/recalculate/+server.ts +++ b/src/routes/api/fitness/sessions/[id]/recalculate/+server.ts @@ -76,8 +76,12 @@ export const POST: RequestHandler = async ({ params, locals }) => { startTime: { $lt: workoutSession.startTime } }).sort({ startTime: -1 }).limit(50).lean(); + const isBilateral = exercise?.bilateral ?? false; + const weightMul = isBilateral ? 2 : 1; + let prevBestWeight = 0; let prevBestEst1rm = 0; + let prevBestVolume = 0; for (const ps of prevSessions) { const pe = ps.exercises.find(e => e.exerciseId === ex.exerciseId); if (!pe) continue; @@ -85,15 +89,18 @@ export const POST: RequestHandler = async ({ params, locals }) => { if (!s.completed || !s.weight || !s.reps) continue; prevBestWeight = Math.max(prevBestWeight, s.weight); prevBestEst1rm = Math.max(prevBestEst1rm, estimatedOneRepMax(s.weight, s.reps)); + prevBestVolume = Math.max(prevBestVolume, s.weight * s.reps * weightMul); } } let bestWeight = 0; let bestEst1rm = 0; + let bestVolume = 0; for (const s of completedSets) { if (!s.weight || !s.reps) continue; bestWeight = Math.max(bestWeight, s.weight); bestEst1rm = Math.max(bestEst1rm, estimatedOneRepMax(s.weight, s.reps)); + bestVolume = Math.max(bestVolume, s.weight * s.reps * weightMul); } if (bestWeight > prevBestWeight && prevBestWeight > 0) { @@ -102,6 +109,9 @@ export const POST: RequestHandler = async ({ params, locals }) => { if (bestEst1rm > prevBestEst1rm && prevBestEst1rm > 0) { prs.push({ exerciseId: ex.exerciseId, type: 'est1rm', value: bestEst1rm }); } + if (bestVolume > prevBestVolume && prevBestVolume > 0) { + prs.push({ exerciseId: ex.exerciseId, type: 'bestSetVolume', value: Math.round(bestVolume) }); + } } workoutSession.totalVolume = totalVolume > 0 ? totalVolume : undefined; diff --git a/src/routes/fitness/[history=fitnessHistory]/[id]/+page.svelte b/src/routes/fitness/[history=fitnessHistory]/[id]/+page.svelte index f114103..4f28e78 100644 --- a/src/routes/fitness/[history=fitnessHistory]/[id]/+page.svelte +++ b/src/routes/fitness/[history=fitnessHistory]/[id]/+page.svelte @@ -771,6 +771,7 @@ {#if pr.type === 'est1rm'}Est. 1RM {:else if pr.type === 'maxWeight'}Max Weight + {:else if pr.type === 'bestSetVolume'}Best Set Volume {:else if pr.type === 'repMax'}{pr.reps}-rep max {:else}{pr.type}{/if}