feat: add cardio PRs for longest distance and fastest pace by range
CI / update (push) Successful in 2m14s

Track longestDistance and fastestPace PRs for cardio exercises with
activity-specific distance ranges: running (0-3, 3-7, 7-21.1, 21.1-42.2,
42.2+ km), swimming (0-0.4, 0.4-1.5, 1.5-5, 5-10, 10+ km), cycling
(0-15, 15-40, 40-100, 100-200, 200+ km), hiking (0-5, 5-15, 15-30,
30-50, 50+ km), rowing (0-2, 2-5, 5-10, 10-21.1, 21.1+ km).

Shared detection logic in cardioPrRanges.ts used by both session save
and recalculate endpoints. Display support in history detail and workout
completion summary.
This commit is contained in:
2026-03-24 20:41:19 +01:00
parent 81bb3a2428
commit f3a89d2590
6 changed files with 236 additions and 16 deletions
+6 -1
View File
@@ -5,6 +5,7 @@ import { WorkoutSession } from '$models/WorkoutSession';
import type { IPr } from '$models/WorkoutSession';
import { WorkoutTemplate } from '$models/WorkoutTemplate';
import { getExerciseById, getExerciseMetrics } from '$lib/data/exercises';
import { detectCardioPrs } from '$lib/data/cardioPrRanges';
function estimatedOneRepMax(weight: number, reps: number): number {
if (reps <= 0 || weight <= 0) return 0;
@@ -89,7 +90,6 @@ export const POST: RequestHandler = async ({ request, locals }) => {
const exercise = getExerciseById(ex.exerciseId);
const metrics = getExerciseMetrics(exercise);
const isCardio = metrics.includes('distance');
if (isCardio) continue;
const completedSets = (ex.sets ?? []).filter((s: { completed: boolean }) => s.completed);
if (completedSets.length === 0) continue;
@@ -100,6 +100,11 @@ export const POST: RequestHandler = async ({ request, locals }) => {
'exercises.exerciseId': ex.exerciseId,
}).sort({ startTime: -1 }).limit(50).lean();
if (isCardio) {
prs.push(...detectCardioPrs(ex.exerciseId, completedSets, prevSessions));
continue;
}
const isBilateral = exercise?.bilateral ?? false;
const weightMul = isBilateral ? 2 : 1;
@@ -4,6 +4,7 @@ import { dbConnect } from '$utils/db';
import { WorkoutSession } from '$models/WorkoutSession';
import type { IPr } from '$models/WorkoutSession';
import { getExerciseById, getExerciseMetrics } from '$lib/data/exercises';
import { detectCardioPrs } from '$lib/data/cardioPrRanges';
import { simplifyTrack } from '$lib/server/simplifyTrack';
import mongoose from 'mongoose';
@@ -64,7 +65,7 @@ export const POST: RequestHandler = async ({ params, locals }) => {
for (const ex of workoutSession.exercises) {
const exercise = getExerciseById(ex.exerciseId);
const metrics = getExerciseMetrics(exercise);
if (metrics.includes('distance')) continue;
const isCardio = metrics.includes('distance');
const completedSets = ex.sets.filter(s => s.completed);
if (completedSets.length === 0) continue;
@@ -76,6 +77,11 @@ export const POST: RequestHandler = async ({ params, locals }) => {
startTime: { $lt: workoutSession.startTime }
}).sort({ startTime: -1 }).limit(50).lean();
if (isCardio) {
prs.push(...detectCardioPrs(ex.exerciseId, completedSets, prevSessions));
continue;
}
const isBilateral = exercise?.bilateral ?? false;
const weightMul = isBilateral ? 2 : 1;