Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,10 @@ const App = () => {
}, []);

// Unified state update function that also persists to IndexedDB
const updateState = (updates: Partial<AppState>) => {
const updateState = (updates: Partial<AppState> | ((prev: AppState) => Partial<AppState>)) => {
setState((prev: AppState) => {
const newState = { ...prev, ...updates };
const updateObject = typeof updates === 'function' ? updates(prev) : updates;
const newState = { ...prev, ...updateObject };

// Save to IndexedDB asynchronously (don't wait for it)
saveStateToStorage(newState).catch(error => {
Expand Down Expand Up @@ -160,7 +161,11 @@ const App = () => {
const workout = getCurrentWorkout();
if (workout && (workout.type === 'strength' || workout.type === 'hypertrophy')) {
// Request notification permission if not already granted
await requestNotificationPermission();
try {
await requestNotificationPermission();
} catch (error) {
console.warn('Failed to request notification permission:', error);
}

const initialTime = workout.type === 'strength' ? 180 : 90; // 3 min for strength, 1.5 min for hypertrophy
const now = Date.now();
Expand Down Expand Up @@ -318,7 +323,7 @@ const App = () => {
};

const currentBlockInfo = state.customPlan[0];
const progressPercent = ((state.currentWeek - 1) / currentBlockInfo.weeks) * 100;
const progressPercent = currentBlockInfo ? ((state.currentWeek - 1) / currentBlockInfo.weeks) * 100 : 0;
const { strengthExercises, hypertrophyExercises } = getCurrentBlockExercises();

return (
Expand All @@ -344,7 +349,7 @@ const App = () => {
</div>

<div className="p-4 sm:p-6 min-h-[500px]">
{state.activeTab === 'overview' && (
{state.activeTab === 'overview' && currentBlockInfo && (
<div>
<div className="bg-gray-100 p-4 rounded-lg mb-6">
<h3 className="text-sm text-gray-600 mb-2">Current Block</h3>
Expand Down Expand Up @@ -374,7 +379,7 @@ const App = () => {
</div>
)}

{state.activeTab === 'workout' && (
{state.activeTab === 'workout' && currentBlockInfo && (
<div>
<div className="bg-blue-600 text-white p-4 rounded-lg mb-6 text-center">
<div className="text-sm opacity-90 mb-1">Week {state.currentWeek}, Day {state.currentDay}</div>
Expand All @@ -400,7 +405,7 @@ const App = () => {
state={state}
strengthExercises={strengthExercises}
hypertrophyExercises={hypertrophyExercises}
currentBlockName={currentBlockInfo.name}
currentBlockName={currentBlockInfo?.name || 'Unknown Block'}
onUpdateState={updateState}
/>

Expand Down
19 changes: 12 additions & 7 deletions src/components/StrengthWorkouts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ interface StrengthWorkoutsProps {
state: AppState;
onCompleteWorkout: () => void;
onToggleSet: (exerciseAndSchemeIndex: string, setIndex: number) => Promise<void>;
onUpdateState: (updates: Partial<AppState>) => void;
onUpdateState: (updates: Partial<AppState> | ((prev: AppState) => Partial<AppState>)) => void;
}

const StrengthWorkouts: React.FC<StrengthWorkoutsProps> = ({
Expand All @@ -33,24 +33,29 @@ const StrengthWorkouts: React.FC<StrengthWorkoutsProps> = ({
let interval: ReturnType<typeof setInterval>;

if (state.restTimer.isActive && state.restTimer.timeLeft > 0) {
// Use the dependency values directly to avoid stale closure issues
const startTime = state.restTimer.startTime;
const totalTime = state.restTimer.totalTime;

interval = setInterval(() => {
const now = Date.now();
const elapsedSeconds = Math.floor((now - state.restTimer.startTime) / 1000);
const newTimeLeft = Math.max(0, state.restTimer.totalTime - elapsedSeconds);
const elapsedSeconds = Math.floor((now - startTime) / 1000);
const newTimeLeft = Math.max(0, totalTime - elapsedSeconds);

onUpdateState({
// Use functional update to get current state and avoid stale closure
onUpdateState((prevState: AppState) => ({
restTimer: {
...state.restTimer,
...prevState.restTimer,
timeLeft: newTimeLeft
}
});
}));
}, 100); // Check more frequently for smoother updates
}

return () => {
if (interval) clearInterval(interval);
};
}, [state.restTimer, onUpdateState]);
}, [state.restTimer.isActive, state.restTimer.startTime, state.restTimer.totalTime, state.restTimer.timeLeft, onUpdateState]);

// Separate effect to handle notification when timer reaches 0
useEffect(() => {
Expand Down