Code maintainability fixes

This commit is contained in:
AG
2025-12-06 11:32:40 +02:00
parent a13ef9f479
commit 4106f3b783
23 changed files with 1775 additions and 796 deletions

View File

@@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react';
import { Routes, Route, Navigate, useNavigate, useLocation } from 'react-router-dom';
import Navbar from './components/Navbar';
import Tracker from './components/Tracker/index';
import History from './components/History';
@@ -8,250 +8,112 @@ import AICoach from './components/AICoach';
import Plans from './components/Plans';
import Login from './components/Login';
import Profile from './components/Profile';
import { TabView, WorkoutSession, WorkoutSet, WorkoutPlan, User, Language } from './types';
import { getSessions, saveSession, deleteSession, getPlans, getActiveSession, updateActiveSession, deleteActiveSession, updateSetInActiveSession, deleteSetFromActiveSession } from './services/storage';
import { getCurrentUserProfile, getMe } from './services/auth';
import { Language, User } from './types'; // Removed unused imports
import { getSystemLanguage } from './services/i18n';
import { logWeight } from './services/weight';
import { generateId } from './utils/uuid';
import { useAuth } from './context/AuthContext';
import { useData } from './context/DataContext';
function App() {
const [currentUser, setCurrentUser] = useState<User | null>(null);
const [currentTab, setCurrentTab] = useState<TabView>('TRACK');
const { currentUser, updateUser, logout } = useAuth();
const {
sessions,
plans,
activeSession,
activePlan,
startSession,
endSession,
quitSession,
addSet,
removeSet,
updateSet,
updateSession,
deleteSessionById
} = useData();
const [language, setLanguage] = useState<Language>('en');
const [sessions, setSessions] = useState<WorkoutSession[]>([]);
const [plans, setPlans] = useState<WorkoutPlan[]>([]);
const [activeSession, setActiveSession] = useState<WorkoutSession | null>(null);
const [activePlan, setActivePlan] = useState<WorkoutPlan | null>(null);
const navigate = useNavigate();
const location = useLocation();
useEffect(() => {
// Set initial language
setLanguage(getSystemLanguage());
// Restore session
const restoreSession = async () => {
const token = localStorage.getItem('token');
if (token) {
const res = await getMe();
if (res.success && res.user) {
setCurrentUser(res.user);
// Restore active workout session from database
const activeSession = await getActiveSession(res.user.id);
if (activeSession) {
setActiveSession(activeSession);
// Restore plan if session has planId
if (activeSession.planId) {
const plans = await getPlans(res.user.id);
const plan = plans.find(p => p.id === activeSession.planId);
if (plan) {
setActivePlan(plan);
}
}
}
} else {
localStorage.removeItem('token');
}
}
};
restoreSession();
}, []);
useEffect(() => {
const loadSessions = async () => {
if (currentUser) {
const s = await getSessions(currentUser.id);
setSessions(s);
// Load plans
const p = await getPlans(currentUser.id);
setPlans(p);
} else {
setSessions([]);
setPlans([]);
}
};
loadSessions();
}, [currentUser]);
const handleLogin = (user: User) => {
setCurrentUser(user);
setCurrentTab('TRACK');
updateUser(user);
navigate('/');
};
const handleLogout = () => {
localStorage.removeItem('token');
setCurrentUser(null);
setActiveSession(null);
setActivePlan(null);
logout();
navigate('/login');
};
const handleLanguageChange = (lang: Language) => {
setLanguage(lang);
};
const handleUserUpdate = (updatedUser: User) => {
setCurrentUser(updatedUser);
};
const handleStartSession = async (plan?: WorkoutPlan, startWeight?: number) => {
if (!currentUser) return;
if (activeSession) return;
// Get latest weight from profile or default
const profile = getCurrentUserProfile(currentUser.id);
// Use provided startWeight, or profile weight, or default 70
const currentWeight = startWeight || profile?.weight || 70;
const newSession: WorkoutSession = {
id: generateId(),
startTime: Date.now(),
type: 'STANDARD',
userBodyWeight: currentWeight,
sets: [],
planId: plan?.id,
planName: plan?.name
};
setActivePlan(plan || null);
setActiveSession(newSession);
setCurrentTab('TRACK');
// Save to database immediately
await saveSession(currentUser.id, newSession);
// If startWeight was provided (meaning user explicitly entered it), log it to weight history
if (startWeight) {
await logWeight(startWeight);
}
};
const handleEndSession = async () => {
if (activeSession && currentUser) {
const finishedSession = { ...activeSession, endTime: Date.now() };
await updateActiveSession(currentUser.id, finishedSession);
setSessions(prev => [finishedSession, ...prev]);
setActiveSession(null);
setActivePlan(null);
// Refetch user to get updated weight
const res = await getMe();
if (res.success && res.user) {
setCurrentUser(res.user);
}
}
};
const handleAddSet = (set: WorkoutSet) => {
if (activeSession && currentUser) {
const updatedSession = {
...activeSession,
sets: [...activeSession.sets, set]
};
setActiveSession(updatedSession);
}
};
const handleRemoveSetFromActive = async (setId: string) => {
if (activeSession && currentUser) {
await deleteSetFromActiveSession(currentUser.id, setId);
const updatedSession = {
...activeSession,
sets: activeSession.sets.filter(s => s.id !== setId)
};
setActiveSession(updatedSession);
}
};
const handleUpdateSetInActive = async (updatedSet: WorkoutSet) => {
if (activeSession && currentUser) {
const response = await updateSetInActiveSession(currentUser.id, updatedSet.id, updatedSet);
const updatedSession = {
...activeSession,
sets: activeSession.sets.map(s => s.id === updatedSet.id ? response : s)
};
setActiveSession(updatedSession);
}
};
const handleQuitSession = async () => {
if (currentUser) {
await deleteActiveSession(currentUser.id);
setActiveSession(null);
setActivePlan(null);
}
};
const handleUpdateSession = (updatedSession: WorkoutSession) => {
if (!currentUser) return;
saveSession(currentUser.id, updatedSession);
setSessions(prev => prev.map(s => s.id === updatedSession.id ? updatedSession : s));
};
const handleDeleteSession = (sessionId: string) => {
if (!currentUser) return;
deleteSession(currentUser.id, sessionId);
setSessions(prev => prev.filter(s => s.id !== sessionId));
};
if (!currentUser) {
return <Login onLogin={handleLogin} language={language} onLanguageChange={handleLanguageChange} />;
if (!currentUser && location.pathname !== '/login') {
return <Navigate to="/login" />;
}
return (
<div className="h-screen w-screen bg-surface text-on-surface font-sans flex flex-col md:flex-row overflow-hidden">
{/* Desktop Navigation Rail (Left) */}
<Navbar currentTab={currentTab} onTabChange={setCurrentTab} lang={language} />
{currentUser && (
<Navbar lang={language} />
)}
{/* Main Content Area */}
<main className="flex-1 h-full relative w-full max-w-5xl mx-auto md:px-4">
<div className="h-full w-full pb-20 md:pb-0 bg-surface">
{currentTab === 'TRACK' && (
<Tracker
userId={currentUser.id}
userWeight={currentUser.profile?.weight}
activeSession={activeSession}
activePlan={activePlan}
onSessionStart={handleStartSession}
onSessionEnd={handleEndSession}
onSessionQuit={handleQuitSession}
onSetAdded={handleAddSet}
onRemoveSet={handleRemoveSetFromActive}
onUpdateSet={handleUpdateSetInActive}
lang={language}
/>
)}
{currentTab === 'PLANS' && (
<Plans userId={currentUser.id} onStartPlan={handleStartSession} lang={language} />
)}
{currentTab === 'HISTORY' && (
<History
sessions={sessions}
onUpdateSession={handleUpdateSession}
onDeleteSession={handleDeleteSession}
lang={language}
/>
)}
{currentTab === 'STATS' && <Stats sessions={sessions} lang={language} />}
{currentTab === 'AI_COACH' && <AICoach history={sessions} userProfile={currentUser.profile} plans={plans} lang={language} />}
{currentTab === 'PROFILE' && (
<Profile
user={currentUser}
onLogout={handleLogout}
lang={language}
onLanguageChange={handleLanguageChange}
onUserUpdate={handleUserUpdate}
/>
)}
<Routes>
<Route path="/login" element={
!currentUser ? (
<Login onLogin={handleLogin} language={language} onLanguageChange={setLanguage} />
) : (
<Navigate to="/" />
)
} />
<Route path="/" element={
<Tracker
userId={currentUser?.id || ''}
userWeight={currentUser?.profile?.weight}
activeSession={activeSession}
activePlan={activePlan}
onSessionStart={startSession}
onSessionEnd={endSession}
onSessionQuit={quitSession}
onSetAdded={addSet}
onRemoveSet={removeSet}
onUpdateSet={updateSet}
lang={language}
/>
} />
<Route path="/plans" element={
<Plans userId={currentUser?.id || ''} onStartPlan={startSession} lang={language} />
} />
<Route path="/history" element={
<History
sessions={sessions}
onUpdateSession={updateSession}
onDeleteSession={deleteSessionById}
lang={language}
/>
} />
<Route path="/stats" element={
<Stats sessions={sessions} lang={language} />
} />
<Route path="/coach" element={
<AICoach history={sessions} userProfile={currentUser?.profile} plans={plans} lang={language} />
} />
<Route path="/profile" element={
<Profile
user={currentUser}
onLogout={handleLogout}
lang={language}
onLanguageChange={setLanguage}
onUserUpdate={updateUser}
/>
} />
<Route path="*" element={<Navigate to="/" />} />
</Routes>
</div>
</main>
{/* Mobile Navigation (rendered inside Navbar component, fixed to bottom) */}
</div>
);
}