-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathApp.tsx
More file actions
178 lines (157 loc) · 6.5 KB
/
App.tsx
File metadata and controls
178 lines (157 loc) · 6.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
import React, { useState, useEffect, useRef } from 'react';
import { NavigationTab, Routine } from './types';
import Dashboard from './components/Dashboard';
import ExerciseManager from './components/ExerciseManager';
import RoutineManager from './components/RoutineManager';
import ActiveWorkout from './components/ActiveWorkout';
import History from './components/History';
import Statistics from './components/Statistics';
import BodyMeasurements from './components/BodyMeasurements';
import MaxCalculator from './components/MaxCalculator';
import Settings from './components/Settings';
import { getTheme, applyTheme, getActiveSession, getRoutines, getWakeLockEnabled } from './services/storageService';
import { unlockAudioContext } from './services/audioService';
import { t } from './services/translationService';
import { LayoutDashboard, Dumbbell, ClipboardList, History as HistoryIcon, BarChart2 } from 'lucide-react';
const App: React.FC = () => {
const [activeTab, setActiveTab] = useState<NavigationTab>(() => {
return (localStorage.getItem('iron_track_active_tab') as NavigationTab) || 'dashboard';
});
const [workoutSession, setWorkoutSession] = useState<{ routine: Routine | null, dayId: string | null } | null>(null);
const [langKey, setLangKey] = useState(0);
const globalWakeLockRef = useRef<any>(null);
const requestGlobalWakeLock = async () => {
if (getWakeLockEnabled() && 'wakeLock' in navigator) {
try {
// @ts-ignore
globalWakeLockRef.current = await navigator.wakeLock.request('screen');
console.log("Global Wake Lock attivo.");
} catch (err) {
console.warn("Global Wake Lock fallito.");
}
}
};
useEffect(() => {
applyTheme(getTheme());
const handleGlobalInteraction = () => {
unlockAudioContext();
};
document.addEventListener('touchstart', handleGlobalInteraction, { capture: true, passive: true });
document.addEventListener('click', handleGlobalInteraction, { capture: true, passive: true });
document.addEventListener('keydown', handleGlobalInteraction, { capture: true, passive: true });
// Gestione Wake Lock Globale e Visibilità
const handleVisibility = async () => {
if (document.visibilityState === 'visible') {
await requestGlobalWakeLock();
}
};
requestGlobalWakeLock();
document.addEventListener('visibilitychange', handleVisibility);
const savedSession = getActiveSession();
if (savedSession) {
let routineToPass: Routine | null = null;
if (savedSession.routineId) {
const routines = getRoutines();
routineToPass = routines.find(r => r.id === savedSession.routineId) || null;
}
setWorkoutSession({
routine: routineToPass,
dayId: savedSession.dayId || null
});
}
return () => {
document.removeEventListener('touchstart', handleGlobalInteraction);
document.removeEventListener('click', handleGlobalInteraction);
document.removeEventListener('keydown', handleGlobalInteraction);
document.removeEventListener('visibilitychange', handleVisibility);
if (globalWakeLockRef.current) {
globalWakeLockRef.current.release().catch(() => {});
}
};
}, []);
useEffect(() => {
localStorage.setItem('iron_track_active_tab', activeTab);
}, [activeTab]);
const handleLanguageUpdate = () => {
setLangKey(prev => prev + 1);
};
const startWorkout = (routine: Routine, dayId: string) => {
unlockAudioContext();
setWorkoutSession({ routine, dayId });
};
const finishWorkout = () => {
setWorkoutSession(null);
setActiveTab('history');
};
if (workoutSession) {
return (
<ActiveWorkout
routine={workoutSession.routine}
dayId={workoutSession.dayId}
onFinish={finishWorkout}
/>
);
}
const renderContent = () => {
switch (activeTab) {
case 'dashboard': return <Dashboard onStartWorkout={startWorkout} changeTab={setActiveTab} />;
case 'exercises': return <ExerciseManager />;
case 'routines': return <RoutineManager />;
case 'history': return <History />;
case 'stats': return <Statistics />;
case 'measurements': return <BodyMeasurements />;
case 'calculator': return <MaxCalculator />;
case 'settings': return <Settings onLanguageChange={handleLanguageUpdate} />;
default: return <Dashboard onStartWorkout={startWorkout} changeTab={setActiveTab} />;
}
};
return (
<div key={langKey} className="bg-dark min-h-screen text-slate-100 font-sans selection:bg-primary selection:text-white">
<div className="w-full mx-auto min-h-screen relative bg-dark">
{renderContent()}
<div className="fixed bottom-0 left-0 right-0 bg-surface/95 backdrop-blur-md border-t border-slate-700/50 flex justify-around items-center py-3 px-2 z-50 shadow-[0_-5px_15px_rgba(0,0,0,0.3)]">
<NavBtn
isActive={activeTab === 'dashboard'}
onClick={() => setActiveTab('dashboard')}
icon={<LayoutDashboard size={20} />}
label={t('nav_home')}
/>
<NavBtn
isActive={activeTab === 'routines'}
onClick={() => setActiveTab('routines')}
icon={<ClipboardList size={20} />}
label={t('nav_routines')}
/>
<NavBtn
isActive={activeTab === 'exercises'}
onClick={() => setActiveTab('exercises')}
icon={<Dumbbell size={20} />}
label={t('nav_exercises')}
/>
<NavBtn
isActive={activeTab === 'stats'}
onClick={() => setActiveTab('stats')}
icon={<BarChart2 size={20} />}
label={t('nav_stats')}
/>
<NavBtn
isActive={activeTab === 'history'}
onClick={() => setActiveTab('history')}
icon={<HistoryIcon size={20} />}
label={t('nav_history')}
/>
</div>
</div>
</div>
);
};
const NavBtn = ({ isActive, onClick, icon, label }: { isActive: boolean, onClick: () => void, icon: React.ReactNode, label: string }) => (
<button
onClick={onClick}
className={`flex flex-col items-center gap-1 transition-all duration-300 ${isActive ? 'text-primary scale-110' : 'text-gray-500 hover:text-gray-300'}`}
>
{icon}
<span className={`text-[10px] font-bold ${isActive ? 'opacity-100' : 'opacity-70'}`}>{label}</span>
</button>
);
export default App;