Update src/lib/storage/workoutStorage.ts
This commit is contained in:
@@ -1,285 +1,64 @@
|
||||
// User data persistence layer for workouts and metrics
|
||||
'use client';
|
||||
|
||||
export interface ExerciseLog {
|
||||
id: string;
|
||||
name: string;
|
||||
sets: number;
|
||||
reps: number;
|
||||
weight?: number;
|
||||
}
|
||||
|
||||
export interface WorkoutSession {
|
||||
id: string;
|
||||
date: string;
|
||||
type: 'cardio' | 'training' | 'nutrition';
|
||||
duration?: number;
|
||||
distance?: number;
|
||||
calories?: number;
|
||||
duration: number;
|
||||
pace?: string;
|
||||
calories?: number;
|
||||
steps?: number;
|
||||
exercises?: ExerciseLog[];
|
||||
meals?: MealLog[];
|
||||
meals?: Array<{
|
||||
id: string;
|
||||
name: string;
|
||||
calories: number;
|
||||
protein: number;
|
||||
carbs: number;
|
||||
fats: number;
|
||||
timestamp: string;
|
||||
}>;
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
export interface ExerciseLog {
|
||||
id: string;
|
||||
name: string;
|
||||
muscleGroup: string;
|
||||
sets: SetLog[];
|
||||
totalVolume?: number;
|
||||
}
|
||||
const STORAGE_KEY = 'workout_sessions';
|
||||
|
||||
export interface SetLog {
|
||||
reps: number;
|
||||
weight: number;
|
||||
restTime?: number;
|
||||
}
|
||||
export const workoutStorage = {
|
||||
getSessions: (): WorkoutSession[] => {
|
||||
if (typeof window === 'undefined') return [];
|
||||
const stored = localStorage.getItem(STORAGE_KEY);
|
||||
return stored ? JSON.parse(stored) : [];
|
||||
},
|
||||
|
||||
export interface MealLog {
|
||||
id: string;
|
||||
name: string;
|
||||
calories: number;
|
||||
protein: number;
|
||||
carbs: number;
|
||||
fats: number;
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
export interface UserMetrics {
|
||||
totalSteps: number;
|
||||
totalDistance: number;
|
||||
totalCalories: number;
|
||||
totalVolume: number;
|
||||
workoutStreak: number;
|
||||
lastWorkoutDate?: string;
|
||||
personalRecords: Record<string, number>;
|
||||
}
|
||||
|
||||
const STORAGE_KEY = 'fitflow_workouts';
|
||||
const METRICS_KEY = 'fitflow_metrics';
|
||||
|
||||
// Workout Session Management
|
||||
export const saveWorkoutSession = (session: WorkoutSession): boolean => {
|
||||
try {
|
||||
const existing = getWorkoutSessions();
|
||||
const updated = [...existing, { ...session, id: session.id || Date.now().toString() }];
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(updated));
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error saving workout session:', error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const getWorkoutSessions = (): WorkoutSession[] => {
|
||||
try {
|
||||
const data = localStorage.getItem(STORAGE_KEY);
|
||||
return data ? JSON.parse(data) : [];
|
||||
} catch (error) {
|
||||
console.error('Error retrieving workout sessions:', error);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
export const getWorkoutById = (id: string): WorkoutSession | null => {
|
||||
try {
|
||||
const sessions = getWorkoutSessions();
|
||||
return sessions.find(s => s.id === id) || null;
|
||||
} catch (error) {
|
||||
console.error('Error retrieving workout by id:', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const updateWorkoutSession = (id: string, updates: Partial<WorkoutSession>): boolean => {
|
||||
try {
|
||||
const sessions = getWorkoutSessions();
|
||||
const index = sessions.findIndex(s => s.id === id);
|
||||
if (index === -1) return false;
|
||||
sessions[index] = { ...sessions[index], ...updates, id };
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(sessions));
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error updating workout session:', error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteWorkoutSession = (id: string): boolean => {
|
||||
try {
|
||||
const sessions = getWorkoutSessions();
|
||||
const filtered = sessions.filter(s => s.id !== id);
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(filtered));
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error deleting workout session:', error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const getWorkoutsByType = (type: 'cardio' | 'training' | 'nutrition'): WorkoutSession[] => {
|
||||
try {
|
||||
const sessions = getWorkoutSessions();
|
||||
return sessions.filter(s => s.type === type);
|
||||
} catch (error) {
|
||||
console.error('Error filtering workouts by type:', error);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
export const getWorkoutsByDateRange = (startDate: string, endDate: string): WorkoutSession[] => {
|
||||
try {
|
||||
const sessions = getWorkoutSessions();
|
||||
return sessions.filter(s => {
|
||||
const sessionDate = new Date(s.date);
|
||||
return sessionDate >= new Date(startDate) && sessionDate <= new Date(endDate);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error filtering workouts by date range:', error);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
// Metrics Management
|
||||
export const saveUserMetrics = (metrics: UserMetrics): boolean => {
|
||||
try {
|
||||
localStorage.setItem(METRICS_KEY, JSON.stringify(metrics));
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error saving user metrics:', error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const getUserMetrics = (): UserMetrics => {
|
||||
try {
|
||||
const data = localStorage.getItem(METRICS_KEY);
|
||||
return data ? JSON.parse(data) : getDefaultMetrics();
|
||||
} catch (error) {
|
||||
console.error('Error retrieving user metrics:', error);
|
||||
return getDefaultMetrics();
|
||||
}
|
||||
};
|
||||
|
||||
export const updateUserMetrics = (updates: Partial<UserMetrics>): boolean => {
|
||||
try {
|
||||
const current = getUserMetrics();
|
||||
const updated = { ...current, ...updates };
|
||||
return saveUserMetrics(updated);
|
||||
} catch (error) {
|
||||
console.error('Error updating user metrics:', error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const calculateMetricsFromSessions = (): UserMetrics => {
|
||||
try {
|
||||
const sessions = getWorkoutSessions();
|
||||
let totalSteps = 0;
|
||||
let totalDistance = 0;
|
||||
let totalCalories = 0;
|
||||
let totalVolume = 0;
|
||||
const personalRecords: Record<string, number> = {};
|
||||
|
||||
sessions.forEach(session => {
|
||||
if (session.steps) totalSteps += session.steps;
|
||||
if (session.distance) totalDistance += session.distance;
|
||||
if (session.calories) totalCalories += session.calories;
|
||||
if (session.exercises) {
|
||||
session.exercises.forEach(ex => {
|
||||
ex.sets.forEach(set => {
|
||||
totalVolume += set.weight * set.reps;
|
||||
const key = ex.name;
|
||||
if (!personalRecords[key] || set.weight > personalRecords[key]) {
|
||||
personalRecords[key] = set.weight;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const metrics: UserMetrics = {
|
||||
totalSteps,
|
||||
totalDistance,
|
||||
totalCalories,
|
||||
totalVolume,
|
||||
workoutStreak: calculateWorkoutStreak(sessions),
|
||||
lastWorkoutDate: sessions.length > 0 ? sessions[sessions.length - 1].date : undefined,
|
||||
personalRecords
|
||||
addSession: (session: Omit<WorkoutSession, 'id'>): WorkoutSession => {
|
||||
const sessions = workoutStorage.getSessions();
|
||||
const newSession: WorkoutSession = {
|
||||
...session,
|
||||
id: `session-${Date.now()}`,
|
||||
};
|
||||
|
||||
return metrics;
|
||||
} catch (error) {
|
||||
console.error('Error calculating metrics:', error);
|
||||
return getDefaultMetrics();
|
||||
}
|
||||
};
|
||||
|
||||
export const calculateWorkoutStreak = (sessions: WorkoutSession[]): number => {
|
||||
if (sessions.length === 0) return 0;
|
||||
|
||||
const sortedSessions = [...sessions].sort((a, b) =>
|
||||
new Date(b.date).getTime() - new Date(a.date).getTime()
|
||||
);
|
||||
|
||||
let streak = 0;
|
||||
let currentDate = new Date();
|
||||
currentDate.setHours(0, 0, 0, 0);
|
||||
|
||||
for (const session of sortedSessions) {
|
||||
const sessionDate = new Date(session.date);
|
||||
sessionDate.setHours(0, 0, 0, 0);
|
||||
|
||||
const dayDiff = Math.floor((currentDate.getTime() - sessionDate.getTime()) / (1000 * 60 * 60 * 24));
|
||||
|
||||
if (dayDiff === streak) {
|
||||
streak++;
|
||||
} else {
|
||||
break;
|
||||
sessions.push(newSession);
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(sessions));
|
||||
}
|
||||
}
|
||||
return newSession;
|
||||
},
|
||||
|
||||
return streak;
|
||||
};
|
||||
|
||||
const getDefaultMetrics = (): UserMetrics => ({
|
||||
totalSteps: 0,
|
||||
totalDistance: 0,
|
||||
totalCalories: 0,
|
||||
totalVolume: 0,
|
||||
workoutStreak: 0,
|
||||
personalRecords: {}
|
||||
});
|
||||
|
||||
// Bulk operations
|
||||
export const exportWorkoutData = (): string => {
|
||||
try {
|
||||
const sessions = getWorkoutSessions();
|
||||
const metrics = getUserMetrics();
|
||||
const data = { sessions, metrics, exportDate: new Date().toISOString() };
|
||||
return JSON.stringify(data, null, 2);
|
||||
} catch (error) {
|
||||
console.error('Error exporting data:', error);
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
export const importWorkoutData = (jsonData: string): boolean => {
|
||||
try {
|
||||
const data = JSON.parse(jsonData);
|
||||
if (data.sessions) {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(data.sessions));
|
||||
}
|
||||
if (data.metrics) {
|
||||
localStorage.setItem(METRICS_KEY, JSON.stringify(data.metrics));
|
||||
}
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error importing data:', error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const clearAllData = (): boolean => {
|
||||
try {
|
||||
localStorage.removeItem(STORAGE_KEY);
|
||||
localStorage.removeItem(METRICS_KEY);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error clearing data:', error);
|
||||
return false;
|
||||
}
|
||||
getSessionsByDate: (date: string): WorkoutSession[] => {
|
||||
const sessions = workoutStorage.getSessions();
|
||||
return sessions.filter((s) => s.date.startsWith(date));
|
||||
},
|
||||
|
||||
getTodaysSessions: (): WorkoutSession[] => {
|
||||
const currentDate = new Date().toISOString().split('T')[0];
|
||||
return workoutStorage.getSessionsByDate(currentDate);
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user