Skip to content

Commit 46b463b

Browse files
committed
refactor: separate plan loading from tree building
1 parent c34a6c1 commit 46b463b

17 files changed

Lines changed: 329 additions & 250 deletions

File tree

src/modules/sharing/server/load-share-link.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import { getTranslations } from 'next-intl/server'
44
import { getPayload } from 'payload'
55

66
import config from '@/payload.config'
7-
import type { Plan } from '@/modules/training/plans'
8-
import { loadPlanItems } from '@/modules/training/plans/server'
7+
import type { PlanTree } from '@/modules/training/plans'
8+
import { loadPlanTree } from '@/modules/training/plans/server'
99
import type { LoadShareLinkOutput } from '@/modules/sharing'
1010

1111
export async function loadShareLink(token: string): Promise<LoadShareLinkOutput> {
@@ -32,10 +32,10 @@ export async function loadShareLink(token: string): Promise<LoadShareLinkOutput>
3232

3333
const t = await getTranslations('share')
3434

35-
let planData: Plan[] | undefined
35+
let planData: PlanTree[] | undefined
3636

3737
if (permissions.includes('plan')) {
38-
planData = await loadPlanItems(
38+
planData = await loadPlanTree(
3939
payload,
4040
[planId],
4141
{

src/modules/sharing/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import type { Plan } from '@/modules/training/plans'
1+
import type { PlanTree } from '@/modules/training/plans'
22

33
export type LoadShareLinkOutput = {
44
meta: {
55
planTitle: string
66
permissions: ('plan' | 'results')[]
77
expiresAt: string
88
}
9-
plan?: Plan[]
9+
plan?: PlanTree[]
1010
} | null

src/modules/training/components/exercise-card/exercise-card.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import React, { useState } from 'react'
44
import { SeriesForm } from '@/modules/training/components/series-form'
55
import { getTrackingFields, type MetricField } from '@/modules/training/exercises'
6-
import { getExerciseName, type Exercise } from '@/modules/training/plans'
6+
import { getExerciseName, type WorkoutExerciseTree } from '@/modules/training/plans'
77
import type { SetLog } from '@/payload-types'
88
import {
99
toMetricFormValues,
@@ -25,13 +25,17 @@ export function ExerciseCard({
2525
onSaveNote,
2626
readOnly,
2727
}: {
28-
exercise: Exercise
28+
exercise: WorkoutExerciseTree
2929
sets: SetLog[]
3030
clientNote?: string
31-
onAdd?: (exercise: Exercise, fields: MetricField[], values: MetricFormValues) => Promise<void>
31+
onAdd?: (
32+
exercise: WorkoutExerciseTree,
33+
fields: MetricField[],
34+
values: MetricFormValues,
35+
) => Promise<void>
3236
onUpdate?: (id: number, fields: MetricField[], values: MetricFormValues) => Promise<void>
3337
onDelete?: (id: number) => Promise<void>
34-
onSaveNote?: (exercise: Exercise, note: string) => Promise<void>
38+
onSaveNote?: (exercise: WorkoutExerciseTree, note: string) => Promise<void>
3539
readOnly?: boolean
3640
}) {
3741
const [open, setOpen] = useState(false)

src/modules/training/components/workout-plans/components/workout-pickers/workout-pickers.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import React from 'react'
44
import { Button } from '@/components/ui/button'
5-
import type { Microcycle, Workout } from '@/modules/training/plans'
5+
import type { MicrocycleTree, WorkoutTree } from '@/modules/training/plans'
66

77
type Id = number | string | null | undefined
88

@@ -11,9 +11,9 @@ export function MicrocyclePicker({
1111
activeMicrocycleId,
1212
onSelect,
1313
}: {
14-
microcycles: Microcycle[]
14+
microcycles: MicrocycleTree[]
1515
activeMicrocycleId: Id
16-
onSelect: (microcycleId: Microcycle['id']) => void
16+
onSelect: (microcycleId: MicrocycleTree['id']) => void
1717
}) {
1818
return (
1919
<div className="flex gap-1.5">
@@ -37,9 +37,9 @@ export function WorkoutPicker({
3737
activeWorkoutId,
3838
onSelect,
3939
}: {
40-
workouts: Workout[]
40+
workouts: WorkoutTree[]
4141
activeWorkoutId: Id
42-
onSelect: (workoutId: Workout['id']) => void
42+
onSelect: (workoutId: WorkoutTree['id']) => void
4343
}) {
4444
return (
4545
<div className="flex flex-wrap gap-1">

src/modules/training/components/workout-plans/hooks/use-workout-selection.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use client'
22

33
import { useEffect, useMemo, useState, useSyncExternalStore } from 'react'
4-
import type { Microcycle, Plan, Workout } from '@/modules/training/plans'
4+
import type { MicrocycleTree, PlanTree, WorkoutTree } from '@/modules/training/plans'
55

66
const STORAGE_KEY = 'training-app:active-workout-selection'
77
const SSR_SNAPSHOT = '__SSR_SELECTION__'
@@ -17,7 +17,7 @@ const subscribeToSelection = (onStoreChange: () => void) => {
1717
return () => window.removeEventListener('storage', onStoreChange)
1818
}
1919

20-
const firstAvailableSelection = (plans: Plan[]): WorkoutSelection => {
20+
const firstAvailableSelection = (plans: PlanTree[]): WorkoutSelection => {
2121
const plan = plans[0]
2222
const microcycle = plan?.microcycles[0]
2323
const workout = microcycle?.workouts[0]
@@ -29,7 +29,7 @@ const firstAvailableSelection = (plans: Plan[]): WorkoutSelection => {
2929
}
3030
}
3131

32-
const isValidSelection = (plans: Plan[], selection: WorkoutSelection) => {
32+
const isValidSelection = (plans: PlanTree[], selection: WorkoutSelection) => {
3333
const plan = plans.find((item) => item.id === selection.planId)
3434
if (!plan) return false
3535

@@ -40,15 +40,15 @@ const isValidSelection = (plans: Plan[], selection: WorkoutSelection) => {
4040
}
4141

4242
export function useWorkoutSelection(
43-
plans: Plan[],
43+
plans: PlanTree[],
4444
options: { readOnly?: boolean },
4545
): {
4646
resolvedSelection: WorkoutSelection
47-
activePlan: Plan | null
48-
activeMicrocycle: Microcycle | null
49-
activeWorkout: Workout | null
50-
selectPlan: (plan: Plan) => void
51-
selectMicrocycle: (plan: Plan, microcycleId: number | string) => void
47+
activePlan: PlanTree | null
48+
activeMicrocycle: MicrocycleTree | null
49+
activeWorkout: WorkoutTree | null
50+
selectPlan: (plan: PlanTree) => void
51+
selectMicrocycle: (plan: PlanTree, microcycleId: number | string) => void
5252
selectWorkout: (workoutId: number | string) => void
5353
} {
5454
const { readOnly } = options
@@ -82,7 +82,7 @@ export function useWorkoutSelection(
8282
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(resolvedSelection))
8383
}, [plans, readOnly, resolvedSelection, storedSelectionRaw])
8484

85-
const selectPlan = (plan: Plan) => {
85+
const selectPlan = (plan: PlanTree) => {
8686
const nextMicrocycle = plan.microcycles[0] ?? null
8787
const nextWorkout = nextMicrocycle?.workouts[0] ?? null
8888
setSelection({
@@ -92,7 +92,7 @@ export function useWorkoutSelection(
9292
})
9393
}
9494

95-
const selectMicrocycle = (plan: Plan, microcycleId: number | string) => {
95+
const selectMicrocycle = (plan: PlanTree, microcycleId: number | string) => {
9696
const microcycle = plan.microcycles.find((item) => item.id === microcycleId) ?? null
9797
const nextWorkout = microcycle?.workouts[0] ?? null
9898
setSelection({

src/modules/training/components/workout-plans/workout-plans.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Button } from '@/components/ui/button'
66
import { StatusBadge } from '@/components/ui/status-badge'
77
import { Surface } from '@/components/ui/surface'
88
import { mutedTextClass } from '@/lib/class-names'
9-
import type { Plan } from '@/modules/training/plans'
9+
import type { PlanTree } from '@/modules/training/plans'
1010
import { ActiveContextBanner } from './components/active-context-banner'
1111
import { MicrocyclePicker, WorkoutPicker } from './components/workout-pickers'
1212
import { useWorkoutSelection } from './hooks/use-workout-selection'
@@ -16,7 +16,7 @@ export function WorkoutPlans({
1616
readOnly,
1717
showResults,
1818
}: {
19-
plans: Plan[]
19+
plans: PlanTree[]
2020
readOnly?: boolean
2121
showResults?: boolean
2222
}) {

src/modules/training/components/workout-tracker/hooks/use-workout-session.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
import { useEffect, useRef, useState } from 'react'
44
import { sdk } from '@/lib/sdk'
55
import type { MetricField } from '@/modules/training/exercises'
6-
import { getExerciseName, type Exercise, type Workout } from '@/modules/training/plans'
6+
import {
7+
getExerciseName,
8+
type WorkoutExerciseTree,
9+
type WorkoutTree,
10+
} from '@/modules/training/plans'
711
import { toSetLogMetricData, type MetricFormValues } from '@/modules/training/logs'
812
import type { ExerciseLog, SetLog, WorkoutLog } from '@/payload-types'
913

@@ -13,7 +17,7 @@ const relationshipId = (
1317
relationship && typeof relationship === 'object' ? relationship.id : (relationship ?? null)
1418

1519
export function useWorkoutSession(
16-
workout: Workout,
20+
workout: WorkoutTree,
1721
options: { readOnly?: boolean; showResults?: boolean },
1822
) {
1923
const { readOnly, showResults } = options
@@ -132,19 +136,23 @@ export function useWorkoutSession(
132136
setSession(doc)
133137
}, 'Błąd zapisu czasu')
134138

135-
const addSet = (ex: Exercise, fields: MetricField[], values: MetricFormValues) =>
139+
const addSet = (
140+
exercise: WorkoutExerciseTree,
141+
fields: MetricField[],
142+
values: MetricFormValues,
143+
) =>
136144
runMutation(async () => {
137145
const s = await ensureSession()
138-
const setNumber = setsForRow(ex.id).length + 1
139-
const exerciseName = getExerciseName(ex)
146+
const setNumber = setsForRow(exercise.id).length + 1
147+
const exerciseName = getExerciseName(exercise)
140148
const doc = await sdk.create({
141149
collection: 'set-logs',
142150
depth: 0,
143151
data: {
144152
session: s.id,
145-
exercise: ex.exercise?.id ?? undefined,
153+
exercise: exercise.exercise?.id ?? undefined,
146154
exerciseName,
147-
exerciseRow: ex.id,
155+
exerciseRow: exercise.id,
148156
setNumber,
149157
...toSetLogMetricData(fields, values),
150158
},
@@ -183,11 +191,11 @@ export function useWorkoutSession(
183191
setSession(doc)
184192
}, 'Błąd zapisu notatki')
185193

186-
const saveExerciseNote = (ex: Exercise, note: string) =>
194+
const saveExerciseNote = (exercise: WorkoutExerciseTree, note: string) =>
187195
runMutation(async () => {
188196
const s = await ensureSession()
189-
const rowId = ex.id
190-
const exerciseName = getExerciseName(ex)
197+
const rowId = exercise.id
198+
const exerciseName = getExerciseName(exercise)
191199
const existing = exerciseNotes.find(
192200
(entry) => relationshipId(entry.exerciseRow) === rowId,
193201
)
@@ -205,7 +213,7 @@ export function useWorkoutSession(
205213
depth: 0,
206214
data: {
207215
session: s.id,
208-
exercise: ex.exercise?.id ?? undefined,
216+
exercise: exercise.exercise?.id ?? undefined,
209217
exerciseName,
210218
exerciseRow: rowId,
211219
note: trimmed,

src/modules/training/components/workout-tracker/workout-tracker.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ import { Alert } from '@/components/ui/alert'
77
import { ExerciseCard } from '@/modules/training/components/exercise-card'
88
import { NoteField } from '@/modules/training/components/note-field'
99
import { SessionTimesBadge, SessionTimesForm } from '@/modules/training/components/session-times'
10-
import type { Workout } from '@/modules/training/plans'
10+
import type { WorkoutTree } from '@/modules/training/plans'
1111
import { useWorkoutSession } from './hooks/use-workout-session'
1212

1313
export function WorkoutTracker({
1414
workout,
1515
readOnly,
1616
showResults,
1717
}: {
18-
workout: Workout
18+
workout: WorkoutTree
1919
readOnly?: boolean
2020
showResults?: boolean
2121
}) {

0 commit comments

Comments
 (0)