diff --git a/server/prisma/test.db b/server/prisma/test.db index 882938a..b03caa9 100644 Binary files a/server/prisma/test.db and b/server/prisma/test.db differ diff --git a/server/src/controllers/exercise.controller.ts b/server/src/controllers/exercise.controller.ts index 28c4481..381e4c0 100644 --- a/server/src/controllers/exercise.controller.ts +++ b/server/src/controllers/exercise.controller.ts @@ -7,7 +7,8 @@ export class ExerciseController { static async getAllExercises(req: any, res: Response) { try { const userId = req.user.userId; - const exercises = await ExerciseService.getAllExercises(userId); + const includeArchived = req.query.includeArchived === 'true'; + const exercises = await ExerciseService.getAllExercises(userId, includeArchived); return sendSuccess(res, exercises); } catch (error) { logger.error('Error in getAllExercises', { error }); diff --git a/server/src/services/exercise.service.ts b/server/src/services/exercise.service.ts index a864e86..908de64 100644 --- a/server/src/services/exercise.service.ts +++ b/server/src/services/exercise.service.ts @@ -1,12 +1,17 @@ import prisma from '../lib/prisma'; export class ExerciseService { - static async getAllExercises(userId: string) { + static async getAllExercises(userId: string, includeArchived: boolean = false) { const exercises = await prisma.exercise.findMany({ where: { - OR: [ - { userId: null }, // System default - { userId } // User custom + AND: [ + { + OR: [ + { userId: null }, // System default + { userId } // User custom + ] + }, + includeArchived ? {} : { isArchived: false } ] } }); diff --git a/src/components/FilledInput.tsx b/src/components/FilledInput.tsx index dab88f1..b5f4090 100644 --- a/src/components/FilledInput.tsx +++ b/src/components/FilledInput.tsx @@ -1,5 +1,5 @@ import React, { useId } from 'react'; -import { X } from 'lucide-react'; +import { X, Eye, EyeOff } from 'lucide-react'; interface FilledInputProps { label: string; @@ -18,15 +18,19 @@ interface FilledInputProps { rightElement?: React.ReactNode; multiline?: boolean; rows?: number; + showPasswordToggle?: boolean; } const FilledInput: React.FC = ({ label, value, onChange, onClear, onFocus, onBlur, type = "number", icon, autoFocus, step, inputMode, autocapitalize, autoComplete, rightElement, - multiline = false, rows = 3 + multiline = false, rows = 3, showPasswordToggle = false }) => { const id = useId(); const inputRef = React.useRef(null); + const [showPassword, setShowPassword] = React.useState(false); + + const actualType = type === 'password' && showPassword ? 'text' : type; const handleClear = () => { const syntheticEvent = { @@ -47,11 +51,11 @@ const FilledInput: React.FC = ({ } id={id} - type={type} + type={actualType} step={step} inputMode={inputMode || (type === 'number' ? 'decimal' : 'text')} autoFocus={autoFocus} - className={`w-full h-[56px] pt-5 pb-1 pl-4 bg-transparent text-body-lg text-on-surface focus:outline-none placeholder-transparent ${rightElement ? 'pr-20' : 'pr-10'}`} + className={`w-full h-[56px] pt-5 pb-1 pl-4 bg-transparent text-body-lg text-on-surface focus:outline-none placeholder-transparent ${rightElement ? 'pr-20' : (showPasswordToggle && type === 'password' ? 'pr-20' : 'pr-10')}`} placeholder=" " value={value} onChange={onChange} @@ -80,12 +84,24 @@ const FilledInput: React.FC = ({ type="button" onClick={handleClear} aria-label="Clear input" - className={`absolute top-1/2 -translate-y-1/2 p-2 text-on-surface-variant hover:text-on-surface rounded-full transition-opacity ${rightElement ? 'right-12' : 'right-2'}`} + className={`absolute top-1/2 -translate-y-1/2 p-2 text-on-surface-variant hover:text-on-surface rounded-full transition-opacity ${(rightElement || (showPasswordToggle && type === 'password')) ? 'right-12' : 'right-2'}`} tabIndex={-1} > )} + + {showPasswordToggle && type === 'password' && ( + + )} { rightElement && (
diff --git a/src/components/Login.tsx b/src/components/Login.tsx index d2b9f62..1041335 100644 --- a/src/components/Login.tsx +++ b/src/components/Login.tsx @@ -66,6 +66,7 @@ const Login: React.FC = ({ onLogin, language, onLanguageChange }) => value={newPassword} onChange={(e) => setNewPassword(e.target.value)} type="password" + showPasswordToggle />
diff --git a/src/components/Profile.tsx b/src/components/Profile.tsx index 8698c41..a84fafb 100644 --- a/src/components/Profile.tsx +++ b/src/components/Profile.tsx @@ -4,7 +4,8 @@ import { User, Language, ExerciseDef, ExerciseType, BodyWeightRecord } from '../ import { createUser, changePassword, updateUserProfile, getCurrentUserProfile, getUsers, deleteUser, toggleBlockUser, adminResetPassword, getMe } from '../services/auth'; import { getExercises, saveExercise } from '../services/storage'; import { getWeightHistory, logWeight } from '../services/weight'; -import { User as UserIcon, LogOut, Save, Shield, UserPlus, Lock, Calendar, Ruler, Scale, PersonStanding, Globe, ChevronDown, ChevronUp, Trash2, Ban, KeyRound, Dumbbell, Archive, ArchiveRestore, Pencil, Plus, RefreshCcw } from 'lucide-react'; +import { generatePassword } from '../utils/password'; +import { User as UserIcon, LogOut, Save, Shield, UserPlus, Lock, Calendar, Ruler, Scale, PersonStanding, Globe, ChevronDown, ChevronUp, Trash2, Ban, KeyRound, Dumbbell, Archive, ArchiveRestore, Pencil, Plus, RefreshCcw, Sparkles } from 'lucide-react'; import ExerciseModal from './ExerciseModal'; import FilledInput from './FilledInput'; import { t } from '../services/i18n'; @@ -115,7 +116,7 @@ const Profile: React.FC = ({ user, onLogout, lang, onLanguageChang }; const refreshExercises = async () => { - const exercises = await getExercises(user.id); + const exercises = await getExercises(user.id, true); setExercises(exercises); }; @@ -478,15 +479,17 @@ const Profile: React.FC = ({ user, onLogout, lang, onLanguageChang {/* 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" - /> - +
+
+ setNewPassword(e.target.value)} + type="password" + showPasswordToggle + /> +
+
{passMsg &&

{passMsg}

} @@ -533,6 +536,16 @@ const Profile: React.FC = ({ user, onLogout, lang, onLanguageChang value={newUserPass} onChange={(e) => setNewUserPass(e.target.value)} type="text" + rightElement={ + + } />
{u.role !== 'ADMIN' && ( -
-
- - +
+ setAdminPassResetInput({ ...adminPassResetInput, [u.id]: e.target.value })} + onChange={(e: any) => setAdminPassResetInput({ ...adminPassResetInput, [u.id]: e.target.value })} + type="password" + showPasswordToggle />