fix: persist and display Volume PRs in workout history

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:
2026-03-24 20:31:17 +01:00
parent 17b7e1b29a
commit 03f9194903
4 changed files with 22 additions and 1 deletions
@@ -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;