fix: persist and display Volume PRs in workout history
All checks were successful
CI / update (push) Successful in 2m13s
All checks were successful
CI / update (push) Successful in 2m13s
Volume PRs were calculated client-side in the workout summary but never saved to the database, so they didn't appear in history detail pages. Add bestSetVolume PR detection to both session save and recalculate endpoints, and render the new type in the history detail view.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -771,6 +771,7 @@
|
||||
<span class="pr-type">
|
||||
{#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}
|
||||
</span>
|
||||
|
||||
Reference in New Issue
Block a user