import React, { useState, useEffect } from 'react'; import { User, Language, ExerciseDef, ExerciseType } from '../types'; import { createUser, changePassword, updateUserProfile, getCurrentUserProfile, getUsers, deleteUser, toggleBlockUser, adminResetPassword, getMe } from '../services/auth'; import { getExercises, saveExercise } from '../services/storage'; import { User as UserIcon, LogOut, Save, Shield, UserPlus, Lock, Calendar, Ruler, Scale, PersonStanding, Globe, ChevronDown, ChevronUp, Trash2, Ban, KeyRound, Dumbbell, Archive, ArchiveRestore, Pencil, Plus } from 'lucide-react'; import ExerciseModal from './ExerciseModal'; import { t } from '../services/i18n'; import Snackbar from './Snackbar'; interface ProfileProps { user: User; onLogout: () => void; lang: Language; onLanguageChange: (lang: Language) => void; onUserUpdate?: (user: User) => void; } const Profile: React.FC = ({ user, onLogout, lang, onLanguageChange, onUserUpdate }) => { // Profile Data const [weight, setWeight] = useState(''); const [height, setHeight] = useState(''); const [birthDate, setBirthDate] = useState(''); const [gender, setGender] = useState('MALE'); // Admin: Create User const [newUserEmail, setNewUserEmail] = useState(''); const [newUserPass, setNewUserPass] = useState(''); const [createMsg, setCreateMsg] = useState(''); // Admin: User List const [showUserList, setShowUserList] = useState(false); const [allUsers, setAllUsers] = useState([]); const [adminPassResetInput, setAdminPassResetInput] = useState<{ [key: string]: string }>({}); // Change Password const [newPassword, setNewPassword] = useState(''); const [passMsg, setPassMsg] = useState(''); // Account Deletion const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); // Exercise Management const [showExercises, setShowExercises] = useState(false); const [exercises, setExercises] = useState([]); const [showArchived, setShowArchived] = useState(false); const [editingExercise, setEditingExercise] = useState(null); const [isCreatingEx, setIsCreatingEx] = useState(false); const [exerciseNameFilter, setExerciseNameFilter] = useState(''); const exerciseTypeLabels: Record = { [ExerciseType.STRENGTH]: t('type_strength', lang), [ExerciseType.BODYWEIGHT]: t('type_bodyweight', lang), [ExerciseType.CARDIO]: t('type_cardio', lang), [ExerciseType.STATIC]: t('type_static', lang), [ExerciseType.HIGH_JUMP]: t('type_height', lang), [ExerciseType.LONG_JUMP]: t('type_dist', lang), [ExerciseType.PLYOMETRIC]: t('type_jump', lang), }; useEffect(() => { // Load profile data from user object (comes from /auth/me endpoint) if (user.profile) { if (user.profile.weight) setWeight(user.profile.weight.toString()); if (user.profile.height) setHeight(user.profile.height.toString()); if (user.profile.gender) setGender(user.profile.gender); if (user.profile.birthDate) setBirthDate(new Date(user.profile.birthDate).toISOString().split('T')[0]); } if (user.role === 'ADMIN') { refreshUserList(); } refreshExercises(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [user.id, user.role, JSON.stringify(user.profile)]); const refreshUserList = () => { setAllUsers(getUsers()); }; const refreshExercises = async () => { const exercises = await getExercises(user.id); setExercises(exercises); }; // Snackbar State const [snackbar, setSnackbar] = useState<{ isOpen: boolean; message: string; type: 'success' | 'error' | 'info' }>({ isOpen: false, message: '', type: 'info' }); const showSnackbar = (message: string, type: 'success' | 'error' | 'info' = 'info') => { setSnackbar({ isOpen: true, message, type }); }; const handleSaveProfile = async () => { const res = await updateUserProfile(user.id, { weight: parseFloat(weight) || undefined, height: parseFloat(height) || undefined, gender: gender as any, birthDate: birthDate ? new Date(birthDate).toISOString() : undefined, language: lang }); if (res.success) { showSnackbar(t('profile_saved', lang) || 'Profile saved successfully', 'success'); // Refetch user data to update the profile in the app state const userRes = await getMe(); if (userRes.success && userRes.user && onUserUpdate) { onUserUpdate(userRes.user); } } else { showSnackbar(res.error || 'Failed to save profile', 'error'); } }; const handleChangePassword = async () => { if (newPassword.length < 4) { setPassMsg('Password too short'); return; } const res = await changePassword(user.id, newPassword); if (res.success) { setPassMsg('Password changed'); setNewPassword(''); } else { setPassMsg(res.error || 'Error changing password'); } }; const handleCreateUser = async () => { const res = await createUser(newUserEmail, newUserPass); if (res.success) { setCreateMsg(`${t('user_created', lang)}: ${newUserEmail}`); setNewUserEmail(''); setNewUserPass(''); refreshUserList(); } else { setCreateMsg(res.error || 'Error'); } }; const handleAdminDeleteUser = (uid: string) => { if (confirm(t('delete_confirm', lang))) { deleteUser(uid); refreshUserList(); } }; const handleAdminBlockUser = (uid: string, isBlocked: boolean) => { toggleBlockUser(uid, isBlocked); refreshUserList(); }; const handleAdminResetPass = (uid: string) => { const pass = adminPassResetInput[uid]; if (pass && pass.length >= 4) { adminResetPassword(uid, pass); alert(t('pass_reset', lang)); setAdminPassResetInput({ ...adminPassResetInput, [uid]: '' }); } }; const handleDeleteMyAccount = () => { deleteUser(user.id); onLogout(); }; // Exercise Management Handlers const handleArchiveExercise = async (ex: ExerciseDef, archive: boolean) => { const updated = { ...ex, isArchived: archive }; await saveExercise(user.id, updated); await refreshExercises(); }; const handleSaveExerciseEdit = async () => { if (editingExercise && editingExercise.name) { await saveExercise(user.id, editingExercise); setEditingExercise(null); await refreshExercises(); } }; const handleCreateExercise = async (newEx: ExerciseDef) => { await saveExercise(user.id, newEx); setIsCreatingEx(false); await refreshExercises(); }; return (

{t('profile_title', lang)}

{/* User Info Card */}
{user.email[0].toUpperCase()}
{user.email}
{user.role === 'ADMIN' && } {user.role}

{t('personal_data', lang)}

setWeight(e.target.value)} className="w-full bg-transparent text-on-surface focus:outline-none" />
setHeight(e.target.value)} className="w-full bg-transparent text-on-surface focus:outline-none" />
setBirthDate(e.target.value)} className="w-full bg-transparent text-on-surface focus:outline-none text-sm py-1" />
{/* EXERCISE MANAGER */}
{showExercises && (
setExerciseNameFilter(e.target.value)} placeholder={t('type_to_filter', lang) || 'Type to filter...'} className="w-full bg-transparent text-on-surface focus:outline-none" />
setShowArchived(e.target.checked)} className="accent-primary" />
{exercises .filter(e => showArchived || !e.isArchived) .filter(e => e.name.toLowerCase().includes(exerciseNameFilter.toLowerCase())) .sort((a, b) => a.name.localeCompare(b.name)) .map(ex => (
{ex.name}
{exerciseTypeLabels[ex.type]}
))}
)}
{/* Change Password */}

{t('change_pass_btn', lang)}

setNewPassword(e.target.value)} className="flex-1 bg-surface-container-high border-b border-outline-variant px-3 py-2 text-on-surface focus:outline-none rounded-t-lg" />
{passMsg &&

{passMsg}

}
{/* User Self Deletion (Not for Admin) */} {user.role !== 'ADMIN' && (

{t('delete_account', lang)}

{!showDeleteConfirm ? ( ) : (

{t('delete_account_confirm', lang)}

)}
)} {/* ADMIN AREA */} {user.role === 'ADMIN' && (

{t('admin_area', lang)}

{/* Create User */}

{t('create_user', lang)}

setNewUserEmail(e.target.value)} className="w-full bg-surface-container-high border-b border-outline-variant px-3 py-2 text-on-surface focus:outline-none rounded-t-lg" /> setNewUserPass(e.target.value)} className="w-full bg-surface-container-high border-b border-outline-variant px-3 py-2 text-on-surface focus:outline-none rounded-t-lg" /> {createMsg &&

{createMsg}

}
{/* User List */}
{showUserList && (
{allUsers.map(u => (
{u.email}
{u.role} {u.isBlocked && {t('block', lang)}}
{u.role !== 'ADMIN' && ( <> )}
{u.role !== 'ADMIN' && (
setAdminPassResetInput({ ...adminPassResetInput, [u.id]: e.target.value })} />
)}
))}
)}
)} {/* Edit Exercise Modal */} {editingExercise && (

{t('edit', lang)}

setEditingExercise({ ...editingExercise, name: e.target.value })} className="w-full bg-transparent text-on-surface focus:outline-none" />
{editingExercise.type === ExerciseType.BODYWEIGHT && (
setEditingExercise({ ...editingExercise, bodyWeightPercentage: parseFloat(e.target.value) })} className="w-full bg-transparent text-on-surface focus:outline-none" />
)}
)} {/* Create Exercise Modal */} {isCreatingEx && ( setIsCreatingEx(false)} onSave={handleCreateExercise} lang={lang} existingExercises={exercises} /> )}
setSnackbar(prev => ({ ...prev, isOpen: false }))} />
); }; export default Profile;