Skip to content

Commit

Permalink
Merge pull request #148 from WhyAsh5114/147-temporary-skipping
Browse files Browse the repository at this point in the history
Temporary workout skipping
  • Loading branch information
WhyAsh5114 authored Nov 29, 2024
2 parents 07ca196 + b0430ab commit d2e0d8b
Show file tree
Hide file tree
Showing 11 changed files with 900 additions and 510 deletions.
1,104 changes: 644 additions & 460 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"prettier": "^3.3.3",
"prettier-plugin-svelte": "^3.2.5",
"prettier-plugin-tailwindcss": "^0.6.5",
"prisma": "^5.16.2",
"prisma": "^5.0.0",
"svelte": "^5.0.0-next.184",
"svelte-check": "^4.0.0",
"svelte-dnd-action": "^0.9.49",
Expand All @@ -56,21 +56,21 @@
"@auth/prisma-adapter": "^2.4.1",
"@auth/sveltekit": "^1.4.1",
"@internationalized/date": "^3.5.4",
"@prisma/client": "^5.16.2",
"@prisma/client": "^5.0.0",
"@trpc/client": "^10.45.2",
"@trpc/server": "^10.45.2",
"bits-ui": "^0.21.16",
"chart.js": "^4.4.3",
"clsx": "^2.1.1",
"cmdk-sv": "^0.0.18",
"embla-carousel-svelte": "^8.3.0",
"mode-watcher": "^0.4.0",
"mode-watcher": "^0.5.0",
"paneforge": "^0.0.6",
"posthog-js": "^1.160.3",
"svelte-infinite-loading": "^1.4.0",
"svelte-sonner": "^0.3.26",
"tailwind-merge": "^2.4.0",
"tailwind-variants": "^0.2.1",
"tailwind-variants": "^0.3.0",
"trpc-sveltekit": "^3.6.2",
"trpc-transformer": "^3.2.2",
"vaul-svelte": "^0.3.2"
Expand Down
3 changes: 2 additions & 1 deletion playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ const config: PlaywrightTestConfig = {
use: {
baseURL: 'http://localhost:4173',
trace: 'on-first-retry',
video: 'retain-on-failure'
video: 'retain-on-failure',
locale: 'en-US'
},
timeout: 60000,
projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }]
Expand Down
146 changes: 140 additions & 6 deletions src/lib/trpc/routes/workouts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,9 +289,107 @@ export const workouts = t.router({
return todaysWorkoutData;
}),

getSkippedWorkoutData: t.procedure.input(z.number().int()).query(async ({ ctx, input }) => {
const splitDayIndex = input;

const data = await prisma.mesocycle.findFirst({
where: { userId: ctx.userId, startDate: { not: null }, endDate: null },
include: {
mesocycleExerciseSplitDays: {
include: {
mesocycleSplitDayExercises: {
select: { name: true, targetMuscleGroup: true, customMuscleGroup: true },
orderBy: { exerciseIndex: 'asc' }
}
},
orderBy: { dayIndex: 'asc' }
},
mesocycleCyclicSetChanges: true,
workoutsOfMesocycle: {
include: { workout: true },
orderBy: { workout: { startedAt: 'desc' } }
}
}
});
const lastBodyweight = data?.workoutsOfMesocycle.map((wm) => wm.workout.userBodyweight)[0];
const userBodyweight = lastBodyweight ?? null;

const todaysWorkoutData: TodaysWorkoutData = {
workoutExercises: [],
userBodyweight,
startedAt: new Date(),
endedAt: null
};

if (data === null) {
return todaysWorkoutData;
}

const { isRestDay, cycleNumber, todaysSplitDay } = getBasicDayInfoForSkippedWorkout(
data,
data.workoutsOfMesocycle.length,
splitDayIndex
);
const { mesocycleCyclicSetChanges, workoutsOfMesocycle, mesocycleExerciseSplitDays, ...mesocycleData } = data;

todaysWorkoutData.workoutOfMesocycle = {
mesocycle: mesocycleData,
splitDayName: todaysSplitDay.name,
workoutStatus: isRestDay ? 'RestDay' : null,
cycleNumber,
splitDayIndex
};

if (!isRestDay) {
todaysWorkoutData.workoutExercises = todaysSplitDay.mesocycleSplitDayExercises.map((exercise) => ({
name: exercise.name,
targetMuscleGroup: exercise.targetMuscleGroup,
customMuscleGroup: exercise.customMuscleGroup
}));
}

return todaysWorkoutData;
}),

getSkippedWorkoutsOfCurrentCycle: t.procedure.query(async ({ ctx }) => {
const data = await prisma.mesocycle.findFirst({
where: { userId: ctx.userId, startDate: { not: null }, endDate: null },
select: {
mesocycleExerciseSplitDays: {
select: { name: true },
orderBy: { dayIndex: 'asc' }
},
workoutsOfMesocycle: {
select: { splitDayIndex: true, workoutStatus: true },
orderBy: { workout: { startedAt: 'desc' } }
}
}
});

if (data === null) {
return [];
}

const { workoutsOfMesocycle, mesocycleExerciseSplitDays } = data;
const currentCycleWorkouts = workoutsOfMesocycle.slice(
0,
workoutsOfMesocycle.length % mesocycleExerciseSplitDays.length
);
const skippedWorkouts = currentCycleWorkouts.filter((wm) => wm.workoutStatus === 'Skipped');
const skippedWorkoutsWithNames = skippedWorkouts
.map((workout) => ({
...workout,
splitDayName: mesocycleExerciseSplitDays[workout.splitDayIndex].name
}))
.toReversed();

return skippedWorkoutsWithNames;
}),

getWorkoutExercisesWithPreviousData: t.procedure
.input(z.strictObject({ userBodyweight: z.number(), splitDayIndex: z.number().int() }))
.query(async ({ ctx, input }) => {
const { splitDayIndex } = input;
const data: ActiveMesocycleWithProgressionData | null = await prisma.mesocycle.findFirst({
where: {
userId: ctx.userId,
Expand All @@ -308,7 +406,7 @@ export const workouts = t.router({
if (!data) return workoutExercisesWithPreviousData;

const totalWorkouts = await prisma.workoutOfMesocycle.count({ where: { mesocycleId: data?.id } });
const { isRestDay, cycleNumber, splitDayIndex } = getBasicDayInfo(data, totalWorkouts);
const { isRestDay, cycleNumber } = getBasicDayInfoForSkippedWorkout(data, totalWorkouts, splitDayIndex);
if (isRestDay) return workoutExercisesWithPreviousData;

workoutExercisesWithPreviousData.todaysWorkoutExercises = progressiveOverloadMagic(
Expand Down Expand Up @@ -390,13 +488,15 @@ export const workouts = t.router({
}

// Update mesocycle data using this new workout
let mesocycleCompleted: boolean | undefined = undefined;
const mesocycleData = await prisma.mesocycle.findFirst({
where: { id: workoutOfMesocycle.mesocycle.id, userId: ctx.userId },
select: {
RIRProgression: true,
mesocycleExerciseSplitDays: { select: { id: true }, orderBy: { dayIndex: 'asc' } },
_count: { select: { workoutsOfMesocycle: true } }
workoutsOfMesocycle: {
select: { workoutId: true, splitDayIndex: true },
orderBy: { workout: { startedAt: 'desc' } }
}
}
});

Expand Down Expand Up @@ -436,12 +536,24 @@ export const workouts = t.router({
);
}

// End mesocycle if all workouts completed
// Delete skipped workout if repeating
const currentCycleWorkouts = mesocycleData.workoutsOfMesocycle.slice(
0,
mesocycleData.workoutsOfMesocycle.length % mesocycleData.mesocycleExerciseSplitDays.length
);
const repeatOfSkippedWorkout = currentCycleWorkouts.find(
(wm) => wm.splitDayIndex === input.workoutData.workoutOfMesocycle?.splitDayIndex
);

// End mesocycle if all workouts completed (shouldn't happen when repeating skipped workouts)
let mesocycleCompleted: boolean | undefined = undefined;
const totalWorkouts = arraySum(mesocycleData.RIRProgression) * mesocycleData.mesocycleExerciseSplitDays.length;
const completedWorkouts = mesocycleData._count.workoutsOfMesocycle + 1; // +1 as we assume this new workout to be completed as well
const completedWorkouts = mesocycleData.workoutsOfMesocycle.length + 1; // +1 as we assume this new workout to be completed as well
mesocycleCompleted = completedWorkouts >= totalWorkouts;

if (mesocycleCompleted) {
if (repeatOfSkippedWorkout) {
transactionQueries.push(prisma.workout.delete({ where: { id: repeatOfSkippedWorkout.workoutId } }));
} else if (mesocycleCompleted) {
transactionQueries.push(
prisma.mesocycle.update({
where: { id: workoutOfMesocycle.mesocycle.id, userId: ctx.userId },
Expand Down Expand Up @@ -580,3 +692,25 @@ function getBasicDayInfo(
const cycleNumber = 1 + Math.floor(totalWorkouts / splitLength);
return { isRestDay, splitDayIndex, cycleNumber, todaysSplitDay };
}

function getBasicDayInfoForSkippedWorkout(
mesocycleData: {
mesocycleExerciseSplitDays: (MesocycleExerciseSplitDay & {
mesocycleSplitDayExercises: {
name: string;
targetMuscleGroup: MuscleGroup;
customMuscleGroup: string | null;
}[];
})[];
workoutsOfMesocycle: WorkoutOfMesocycle[];
},
totalWorkouts: number,
skippedWorkoutIndex: number
) {
const { mesocycleExerciseSplitDays } = mesocycleData;
const splitLength = mesocycleExerciseSplitDays.length;
const todaysSplitDay = mesocycleExerciseSplitDays[skippedWorkoutIndex];
const isRestDay = todaysSplitDay.isRestDay;
const cycleNumber = 1 + Math.floor(totalWorkouts / splitLength);
return { isRestDay, cycleNumber, todaysSplitDay };
}
Loading

0 comments on commit d2e0d8b

Please sign in to comment.