diff --git a/TESTING.md b/TESTING.md new file mode 100644 index 0000000..5d61c6e --- /dev/null +++ b/TESTING.md @@ -0,0 +1,211 @@ +# Testing Guide - Unbroken Tactical Barbell Tracker + +This guide explains how to test different workouts and training blocks without manually progressing through the entire program. + +## Testing Different Workouts via IndexedDB + +The app stores workout progress in IndexedDB, which can be modified directly in the browser to test different workout types (HIIT, LISS, strength, etc.) without completing entire blocks. + +### Method 1: Browser DevTools (Recommended) + +1. **Start the development server:** + ```bash + npm run dev + ``` + +2. **Open the app in your browser:** + - Navigate to http://localhost:5173 + +3. **Open Browser DevTools:** + - Press F12 or right-click → Inspect + - Go to the "Application" tab (Chrome) or "Storage" tab (Firefox) + +4. **Navigate to IndexedDB:** + - Expand "IndexedDB" in the left sidebar + - Find "UnbrokenTracker" database + - Expand it to see object stores: + - `workoutState` - Contains current progress (week, day, completed workouts) + - `trainingPlanState` - Contains the custom training plan + - `exerciseState` - Contains maxes and rep maxes + - `preferencesState` - Contains user preferences + +5. **Modify workout progress:** + - Click on `workoutState` object store + - Find the record with key "data" + - Double-click the value to edit the JSON + - Modify these fields: + ```json + { + "currentWeek": 1, // Week number (1-based) + "currentDay": 1, // Day number (1-based, 1-7 for each week) + "completedWorkouts": [], // Array of completed workouts + "completedSets": {} // Object tracking completed sets + } + ``` + +6. **Examples of useful test values:** + + **Test HIIT workouts (Powerbuilding Block 3):** + ```json + { + "currentWeek": 1, + "currentDay": 3, + "completedWorkouts": [], + "completedSets": {} + } + ``` + + **Test different HIIT variations:** + ```json + { + "currentWeek": 2, + "currentDay": 3, + "completedWorkouts": [], + "completedSets": {} + } + ``` + + **Test LISS workouts (Endurance Block):** + ```json + { + "currentWeek": 1, + "currentDay": 2, + "completedWorkouts": [], + "completedSets": {} + } + ``` + +7. **Refresh the page:** + - After modifying IndexedDB values, refresh the browser page + - Navigate to the "Workout" tab + - Click "Start Today's Workout" to see the modified workout + +### Method 2: Console Commands + +You can also modify the workout state programmatically using the browser console: + +1. **Open Browser Console:** + - Press F12 → Console tab + +2. **Get current state:** + ```javascript + // Open IndexedDB and read current state + const request = indexedDB.open('UnbrokenTracker', 1); + request.onsuccess = function(event) { + const db = event.target.result; + const transaction = db.transaction(['workoutState'], 'readonly'); + const store = transaction.objectStore('workoutState'); + const getRequest = store.get('data'); + getRequest.onsuccess = function() { + console.log('Current workout state:', getRequest.result); + }; + }; + ``` + +3. **Set new state:** + ```javascript + // Modify workout state to test different workouts + const request = indexedDB.open('UnbrokenTracker', 1); + request.onsuccess = function(event) { + const db = event.target.result; + const transaction = db.transaction(['workoutState'], 'readwrite'); + const store = transaction.objectStore('workoutState'); + + const newState = { + currentWeek: 1, // Change this + currentDay: 3, // Change this (day 3 often has HIIT in powerbuilding blocks) + completedWorkouts: [], + completedSets: {} + }; + + store.put(newState, 'data'); + console.log('Updated workout state:', newState); + // Refresh the page after this + }; + ``` + +## Available Workout Types by Block and Day + +### Get Ready Block (Week 1) +- Day 1: Rest day + +### Endurance Block 1 (Weeks 1-8) +- Days 1, 3, 5: Strength workouts (Overhead Press, Front Squat, Weighted Pull-up) +- Days 2, 4, 6: LISS cardio (running, various durations) +- Day 7: Rest + +### Powerbuilding Block 3 (Weeks 1-3) - Contains HIIT +- Days 1, 4: Strength + Hypertrophy workouts +- **Day 3: HIIT workout** - "Reset-20" activity + - Week 1: 20 seconds, 5 rounds + - Week 2: 15 seconds, 4 rounds + - Week 3: 15 seconds, 4 rounds +- Days 2, 5: Hypertrophy workouts +- Days 6, 7: Rest + +### Bodybuilding Block (Weeks 1-3) +- Days 1, 3, 4: Hypertrophy workouts +- Day 2, 5: Hypertrophy workouts +- **Day 3: HIIT workout** - "Hill Sprints" + - Week 1: 3 rounds + - Week 2: 5 rounds + - Week 3: 7 rounds +- Days 6, 7: Rest + +### Strength Block (Weeks 1-6) +- Days 1, 2, 4, 5: Strength workouts +- **Days 3, 6: HIIT workouts** - Various activities (Tempo Run, 600m Resets, GC 9) +- Day 7: Rest + +## Quick Testing Scenarios + +### Test HIIT Timer Functionality +1. Set `currentWeek: 1, currentDay: 3` (Powerbuilding Block 3) +2. Refresh page and start workout +3. Test round progression, pause/resume, reset functionality + +### Test LISS Timer Functionality +1. Set `currentWeek: 1, currentDay: 2` (Endurance Block 1) +2. Refresh page and start workout +3. Test timer countdown, pause/resume functionality + +### Test Different HIIT Variations +1. **Short rounds:** Set to Powerbuilding Block 3, Week 2/3 (15s rounds) +2. **Longer rounds:** Set to Powerbuilding Block 3, Week 1 (20s rounds) +3. **Different activities:** Set to Strength Block for "Tempo Run" or "600m Resets" + +## Reset Progress for Clean Testing + +To start fresh testing: + +1. **Via Settings Page:** + - Navigate to Settings tab + - Click "Reset All Progress" + - Confirm the reset + +2. **Via Console:** + ```javascript + // Clear all IndexedDB data + const request = indexedDB.open('UnbrokenTracker', 1); + request.onsuccess = function(event) { + const db = event.target.result; + const storeNames = ['workoutState', 'trainingPlanState', 'exerciseState', 'preferencesState']; + + storeNames.forEach(storeName => { + const transaction = db.transaction([storeName], 'readwrite'); + const store = transaction.objectStore(storeName); + store.clear(); + }); + + console.log('All data cleared'); + // Refresh the page after this + }; + ``` + +## Notes + +- Always refresh the page after modifying IndexedDB data +- The app will automatically load the new state on page refresh +- Component-level timer state (HIIT/LISS timers) resets automatically when components re-render +- Workout state persistence only applies to training progression, not UI timer state +- Test on development server (`npm run dev`) for best debugging experience \ No newline at end of file diff --git a/src/lib/blockTemplates.ts b/src/lib/blockTemplates.ts index 3afb514..22a84d1 100644 --- a/src/lib/blockTemplates.ts +++ b/src/lib/blockTemplates.ts @@ -2,6 +2,15 @@ // Contains workout configuration templates for different training blocks export const blockTemplates = { + getready: { + weeks: [ + { + days: [ + { type: "rest" } + ] + } + ] + }, endurance1: { weeks: [ { diff --git a/src/lib/stores.ts b/src/lib/stores.ts index eec27f8..844f960 100644 --- a/src/lib/stores.ts +++ b/src/lib/stores.ts @@ -3,27 +3,6 @@ import { writable } from 'svelte/store' import type { CompletedWorkout, CustomPlanBlock } from '$lib/types' // Store interfaces -interface UIState { - activeTab: string - showResetConfirm: boolean - restTimer: { - isActive: boolean - timeLeft: number - totalTime: number - workoutType: 'strength' | 'hypertrophy' | null - phase: 'initial' | 'extended' - startTime: number - } - lissTimer: { - isActive: boolean - isPaused: boolean - timeLeft: number - totalTime: number - startTime: number - pausedTime: number - } -} - interface WorkoutState { currentWeek: number currentDay: number @@ -180,32 +159,8 @@ const createPersistedStore = ( } } -// UI Store (not persisted - transient state) -const defaultUIState: UIState = { - activeTab: 'overview', - showResetConfirm: false, - restTimer: { - isActive: false, - timeLeft: 0, - totalTime: 0, - workoutType: null, - phase: 'initial', - startTime: 0 - }, - lissTimer: { - isActive: false, - isPaused: false, - timeLeft: 0, - totalTime: 0, - startTime: 0, - pausedTime: 0 - } -} - -export const uiStore = writable(defaultUIState) - // Workout Store (persisted) -const defaultWorkoutState: WorkoutState = { +export const defaultWorkoutState: WorkoutState = { currentWeek: 1, currentDay: 1, completedWorkouts: [], @@ -215,8 +170,9 @@ const defaultWorkoutState: WorkoutState = { export const workoutStore = createPersistedStore('workoutState', defaultWorkoutState) // Training Plan Store (persisted) -const defaultTrainingPlanState: TrainingPlanState = { +export const defaultTrainingPlanState: TrainingPlanState = { customPlan: [ + { name: "Get Ready", weeks: 1, type: "getready" }, { name: "Endurance Block 1", weeks: 8, type: "endurance1" }, { name: "Powerbuilding Block 1", weeks: 3, type: "powerbuilding1" }, { name: "Powerbuilding Block 2", weeks: 3, type: "powerbuilding2" }, @@ -233,7 +189,7 @@ const defaultTrainingPlanState: TrainingPlanState = { export const trainingPlanStore = createPersistedStore('trainingPlanState', defaultTrainingPlanState) // Exercise Store (persisted) -const defaultExerciseState: ExerciseState = { +export const defaultExerciseState: ExerciseState = { maxes: { benchpress: 100, squat: 120, @@ -251,7 +207,7 @@ const defaultExerciseState: ExerciseState = { export const exerciseStore = createPersistedStore('exerciseState', defaultExerciseState) // Preferences Store (persisted) -const defaultPreferencesState: PreferencesState = { +export const defaultPreferencesState: PreferencesState = { weightUnit: 'kg' } diff --git a/src/lib/types.ts b/src/lib/types.ts index 6c4ab3f..a99731c 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -58,35 +58,6 @@ export interface CompletedWorkout { details: Workout; } -export interface AppState { - activeTab: string; - currentWeek: number; - currentDay: number; - completedWorkouts: CompletedWorkout[]; - customPlan: CustomPlanBlock[]; - maxes: Record; - tenRMs: Record; - weightUnit: string; - completedSets: Record; - showResetConfirm: boolean; - restTimer: { - isActive: boolean; - timeLeft: number; - totalTime: number; - workoutType: 'strength' | 'hypertrophy' | null; - phase: 'initial' | 'extended'; - startTime: number; - }; - lissTimer: { - isActive: boolean; - isPaused: boolean; - timeLeft: number; - totalTime: number; - startTime: number; - pausedTime: number; - }; -} - export interface WarmupSet { weight: number; reps: number; diff --git a/src/routes/api/workout/complete/+server.ts b/src/routes/api/workout/complete/+server.ts index 7c79093..074e48b 100644 --- a/src/routes/api/workout/complete/+server.ts +++ b/src/routes/api/workout/complete/+server.ts @@ -34,7 +34,11 @@ export async function POST({ request }) { const blockTemplate = blockTemplates[blockType as keyof typeof blockTemplates] const maxWeeks = blockTemplate?.weeks?.length || 8 - if (newDay > 7) { + // Check if the next day exists in the current week + const currentWeekTemplate = blockTemplate?.weeks?.[currentWeek - 1] + const maxDaysInCurrentWeek = currentWeekTemplate?.days?.length || 7 + + if (newDay > maxDaysInCurrentWeek) { newDay = 1 newWeek++ if (newWeek > maxWeeks) { diff --git a/src/routes/settings/ResetProgress.svelte b/src/routes/settings/ResetProgress.svelte index 9a3ceb7..6a822c1 100644 --- a/src/routes/settings/ResetProgress.svelte +++ b/src/routes/settings/ResetProgress.svelte @@ -1,22 +1,25 @@ - -{#if workout.type === 'liss' || workout.type === 'hiit'} -
-
-

- {cardioWorkout().activity} -

- {#if cardioWorkout().duration !== undefined} -
{displayDuration()}
-
- {#if workout.type === 'liss'} - minutes - {:else} - seconds - {/if} -
- {/if} - {#if cardioWorkout().distance !== undefined} -
{cardioWorkout().distance}
-
- {#if workout.type === 'liss'} - km - {:else} - m - {/if} -
- {/if} - {#if cardioWorkout().rounds !== undefined} -
- {cardioWorkout().rounds} rounds -
- {/if} -
- - {#if showTimerControls()} - -
- - - -
- {/if} - - -
-{/if} \ No newline at end of file diff --git a/src/routes/workout/HIITWorkout.svelte b/src/routes/workout/HIITWorkout.svelte new file mode 100644 index 0000000..df05870 --- /dev/null +++ b/src/routes/workout/HIITWorkout.svelte @@ -0,0 +1,280 @@ + + +
+
+

{workoutData().activity}

+ + {#if displayTime() !== undefined} +
{displayTime()}
+
seconds
+ {/if} + + {#if workoutData().distance !== undefined} +
{workoutData().distance}
+
meters
+ {/if} + + {#if hasRounds()} +
{roundDisplay()}
+ {/if} + + {#if workoutComplete()} +
+ + All Rounds Complete! +
+ {/if} +
+ + {#if hasRounds()} + {@const states = buttonStates()} + + +
+ + {#if workoutData().duration !== undefined && states.pause} + + {/if} + +
+ {/if} + + +
+ + \ No newline at end of file diff --git a/src/routes/workout/LISSWorkout.svelte b/src/routes/workout/LISSWorkout.svelte new file mode 100644 index 0000000..830feb6 --- /dev/null +++ b/src/routes/workout/LISSWorkout.svelte @@ -0,0 +1,222 @@ + + +
+
+

+ {cardioWorkout().activity} +

+ {#if cardioWorkout().duration !== undefined} +
+ {displayDuration()} +
+
minutes
+ {/if} + {#if cardioWorkout().distance !== undefined} +
{cardioWorkout().distance}
+
km
+ {/if} + {#if cardioWorkout().rounds !== undefined} +
+ {cardioWorkout().rounds} rounds +
+ {/if} +
+ + {#if showTimerControls()} + +
+ + + +
+ {/if} + + +
+ + \ No newline at end of file diff --git a/src/routes/workout/RestTimer.svelte b/src/routes/workout/RestTimer.svelte index 9eceb56..83d6eed 100644 --- a/src/routes/workout/RestTimer.svelte +++ b/src/routes/workout/RestTimer.svelte @@ -1,45 +1,57 @@