diff --git a/src/lib/storage/workoutStorage.ts b/src/lib/storage/workoutStorage.ts new file mode 100644 index 0000000..a1d69d8 --- /dev/null +++ b/src/lib/storage/workoutStorage.ts @@ -0,0 +1,185 @@ +// Workout and metrics persistence layer + +interface WorkoutSession { + id: string; + type: 'cardio' | 'training' | 'nutrition'; + date: string; + data: Record; + createdAt: number; +} + +interface UserMetrics { + totalWorkouts: number; + totalDistance: number; + totalCalories: number; + totalWeight: number; + consistency: number; // days in a row + lastUpdated: number; +} + +const STORAGE_KEYS = { + WORKOUTS: 'fitflow_workouts', + METRICS: 'fitflow_metrics', + USER_PROFILE: 'fitflow_user_profile', +} as const; + +export class WorkoutStorageService { + // Workout Session Management + static saveWorkoutSession(session: Omit): WorkoutSession { + try { + const sessions = this.getWorkoutSessions(); + const newSession: WorkoutSession = { + id: `workout_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, + ...session, + createdAt: Date.now(), + }; + sessions.push(newSession); + localStorage.setItem(STORAGE_KEYS.WORKOUTS, JSON.stringify(sessions)); + return newSession; + } catch (error) { + console.error('Error saving workout session:', error); + throw error; + } + } + + static getWorkoutSessions(): WorkoutSession[] { + try { + const data = localStorage.getItem(STORAGE_KEYS.WORKOUTS); + return data ? JSON.parse(data) : []; + } catch (error) { + console.error('Error retrieving workout sessions:', error); + return []; + } + } + + static getWorkoutSessionsByType(type: WorkoutSession['type']): WorkoutSession[] { + const sessions = this.getWorkoutSessions(); + return sessions.filter(session => session.type === type); + } + + static getWorkoutSessionsByDate(date: string): WorkoutSession[] { + const sessions = this.getWorkoutSessions(); + return sessions.filter(session => session.date === date); + } + + static updateWorkoutSession(id: string, updates: Partial): WorkoutSession | null { + try { + const sessions = this.getWorkoutSessions(); + const index = sessions.findIndex(s => s.id === id); + if (index === -1) return null; + + const updated = { ...sessions[index], ...updates, id: sessions[index].id, createdAt: sessions[index].createdAt }; + sessions[index] = updated; + localStorage.setItem(STORAGE_KEYS.WORKOUTS, JSON.stringify(sessions)); + return updated; + } catch (error) { + console.error('Error updating workout session:', error); + return null; + } + } + + static deleteWorkoutSession(id: string): boolean { + try { + const sessions = this.getWorkoutSessions(); + const filtered = sessions.filter(s => s.id !== id); + localStorage.setItem(STORAGE_KEYS.WORKOUTS, JSON.stringify(filtered)); + return filtered.length < sessions.length; + } catch (error) { + console.error('Error deleting workout session:', error); + return false; + } + } + + // Metrics Management + static saveMetrics(metrics: UserMetrics): void { + try { + localStorage.setItem(STORAGE_KEYS.METRICS, JSON.stringify(metrics)); + } catch (error) { + console.error('Error saving metrics:', error); + } + } + + static getMetrics(): UserMetrics { + try { + const data = localStorage.getItem(STORAGE_KEYS.METRICS); + if (!data) { + return { + totalWorkouts: 0, + totalDistance: 0, + totalCalories: 0, + totalWeight: 0, + consistency: 0, + lastUpdated: Date.now(), + }; + } + return JSON.parse(data); + } catch (error) { + console.error('Error retrieving metrics:', error); + return { + totalWorkouts: 0, + totalDistance: 0, + totalCalories: 0, + totalWeight: 0, + consistency: 0, + lastUpdated: Date.now(), + }; + } + } + + static updateMetrics(updates: Partial): UserMetrics { + const current = this.getMetrics(); + const updated: UserMetrics = { ...current, ...updates, lastUpdated: Date.now() }; + this.saveMetrics(updated); + return updated; + } + + // Calculated Metrics + static calculateMetricsFromSessions(): UserMetrics { + const sessions = this.getWorkoutSessions(); + let totalDistance = 0; + let totalCalories = 0; + let totalWeight = 0; + + sessions.forEach(session => { + if (session.data.distance) totalDistance += Number(session.data.distance) || 0; + if (session.data.calories) totalCalories += Number(session.data.calories) || 0; + if (session.data.weight) totalWeight += Number(session.data.weight) || 0; + }); + + return this.updateMetrics({ + totalWorkouts: sessions.length, + totalDistance, + totalCalories, + totalWeight, + }); + } + + // Batch Operations + static clearAllData(): void { + try { + localStorage.removeItem(STORAGE_KEYS.WORKOUTS); + localStorage.removeItem(STORAGE_KEYS.METRICS); + localStorage.removeItem(STORAGE_KEYS.USER_PROFILE); + } catch (error) { + console.error('Error clearing data:', error); + } + } + + static exportData(): { workouts: WorkoutSession[]; metrics: UserMetrics } { + return { + workouts: this.getWorkoutSessions(), + metrics: this.getMetrics(), + }; + } + + static importData(data: { workouts: WorkoutSession[]; metrics: UserMetrics }): void { + try { + localStorage.setItem(STORAGE_KEYS.WORKOUTS, JSON.stringify(data.workouts)); + this.saveMetrics(data.metrics); + } catch (error) { + console.error('Error importing data:', error); + } + } +} + +export type { WorkoutSession, UserMetrics }; \ No newline at end of file