From 8cc9ab29b789d409d22df6153bc4937fb9b811be Mon Sep 17 00:00:00 2001 From: AG Date: Wed, 19 Nov 2025 22:52:32 +0200 Subject: [PATCH] 1. Change Password fixed. 2. Personal Data implemented. 3. New alerts style. 4. Better dropdowns. --- App.tsx | 16 +- components/Login.tsx | 12 +- components/Plans.tsx | 250 ++++----- components/Profile.tsx | 1003 ++++++++++++++++++----------------- components/Snackbar.tsx | 49 ++ index.css | 36 ++ index.tsx | 1 + package-lock.json | 379 +++++++++++++ package.json | 10 +- server/prisma/dev.db | Bin 61440 -> 61440 bytes server/prisma/schema.prisma | 6 +- server/src/routes/auth.ts | 96 +++- services/auth.ts | 36 +- services/i18n.ts | 4 + 14 files changed, 1266 insertions(+), 632 deletions(-) create mode 100644 components/Snackbar.tsx create mode 100644 index.css diff --git a/App.tsx b/App.tsx index 634dd26..e6cb5a9 100644 --- a/App.tsx +++ b/App.tsx @@ -10,7 +10,7 @@ import Login from './components/Login'; import Profile from './components/Profile'; import { TabView, WorkoutSession, WorkoutSet, WorkoutPlan, User, Language } from './types'; import { getSessions, saveSession, deleteSession } from './services/storage'; -import { getCurrentUserProfile } from './services/auth'; +import { getCurrentUserProfile, getMe } from './services/auth'; import { getSystemLanguage } from './services/i18n'; function App() { @@ -25,6 +25,20 @@ function App() { 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); + } else { + localStorage.removeItem('token'); + } + } + }; + restoreSession(); }, []); useEffect(() => { diff --git a/components/Login.tsx b/components/Login.tsx index 3241eb2..922efff 100644 --- a/components/Login.tsx +++ b/components/Login.tsx @@ -36,11 +36,15 @@ const Login: React.FC = ({ onLogin, language, onLanguageChange }) => } }; - const handleChangePassword = () => { + const handleChangePassword = async () => { if (tempUser && newPassword.length >= 4) { - changePassword(tempUser.id, newPassword); - const updatedUser = { ...tempUser, isFirstLogin: false }; - onLogin(updatedUser); + const res = await changePassword(tempUser.id, newPassword); + if (res.success) { + const updatedUser = { ...tempUser, isFirstLogin: false }; + onLogin(updatedUser); + } else { + setError(res.error || t('change_pass_error', language)); + } } else { setError(t('login_password_short', language)); } diff --git a/components/Plans.tsx b/components/Plans.tsx index c314acf..1bd5843 100644 --- a/components/Plans.tsx +++ b/components/Plans.tsx @@ -14,19 +14,29 @@ interface PlansProps { const Plans: React.FC = ({ userId, onStartPlan, lang }) => { const [plans, setPlans] = useState([]); const [isEditing, setIsEditing] = useState(false); - + const [editId, setEditId] = useState(null); const [name, setName] = useState(''); const [description, setDescription] = useState(''); const [steps, setSteps] = useState([]); - + const [availableExercises, setAvailableExercises] = useState([]); const [showExerciseSelector, setShowExerciseSelector] = useState(false); useEffect(() => { - setPlans(getPlans(userId)); - // Filter out archived exercises - setAvailableExercises(getExercises(userId).filter(e => !e.isArchived)); + const loadData = async () => { + const fetchedPlans = await getPlans(userId); + setPlans(fetchedPlans); + + const fetchedExercises = await getExercises(userId); + // Filter out archived exercises + if (Array.isArray(fetchedExercises)) { + setAvailableExercises(fetchedExercises.filter(e => !e.isArchived)); + } else { + setAvailableExercises([]); + } + }; + loadData(); }, [userId]); const handleCreateNew = () => { @@ -66,20 +76,20 @@ const Plans: React.FC = ({ userId, onStartPlan, lang }) => { }; const toggleWeighted = (stepId: string) => { - setSteps(steps.map(s => s.id === stepId ? { ...s, isWeighted: !s.isWeighted } : s)); + setSteps(steps.map(s => s.id === stepId ? { ...s, isWeighted: !s.isWeighted } : s)); }; const removeStep = (stepId: string) => { - setSteps(steps.filter(s => s.id !== stepId)); + setSteps(steps.filter(s => s.id !== stepId)); }; const moveStep = (index: number, direction: 'up' | 'down') => { - if (direction === 'up' && index === 0) return; - if (direction === 'down' && index === steps.length - 1) return; - const newSteps = [...steps]; - const targetIndex = direction === 'up' ? index - 1 : index + 1; - [newSteps[index], newSteps[targetIndex]] = [newSteps[targetIndex], newSteps[index]]; - setSteps(newSteps); + if (direction === 'up' && index === 0) return; + if (direction === 'down' && index === steps.length - 1) return; + const newSteps = [...steps]; + const targetIndex = direction === 'up' ? index - 1 : index + 1; + [newSteps[index], newSteps[targetIndex]] = [newSteps[targetIndex], newSteps[index]]; + setSteps(newSteps); }; if (isEditing) { @@ -96,7 +106,7 @@ const Plans: React.FC = ({ userId, onStartPlan, lang }) => {
- = ({ userId, onStartPlan, lang }) => {
-