Separated weight tracking
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { User, Language, ExerciseDef, ExerciseType } from '../types';
|
||||
import { User, Language, ExerciseDef, ExerciseType, BodyWeightRecord } from '../types';
|
||||
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 } from 'lucide-react';
|
||||
import ExerciseModal from './ExerciseModal';
|
||||
import { t } from '../services/i18n';
|
||||
@@ -23,6 +24,11 @@ const Profile: React.FC<ProfileProps> = ({ user, onLogout, lang, onLanguageChang
|
||||
const [birthDate, setBirthDate] = useState<string>('');
|
||||
const [gender, setGender] = useState<string>('MALE');
|
||||
|
||||
// Weight Tracker
|
||||
const [weightHistory, setWeightHistory] = useState<BodyWeightRecord[]>([]);
|
||||
const [todayWeight, setTodayWeight] = useState<string>('');
|
||||
const [showWeightTracker, setShowWeightTracker] = useState(false);
|
||||
|
||||
// Admin: Create User
|
||||
const [newUserEmail, setNewUserEmail] = useState('');
|
||||
const [newUserPass, setNewUserPass] = useState('');
|
||||
@@ -72,9 +78,22 @@ const Profile: React.FC<ProfileProps> = ({ user, onLogout, lang, onLanguageChang
|
||||
refreshUserList();
|
||||
}
|
||||
refreshExercises();
|
||||
refreshWeightHistory();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [user.id, user.role, JSON.stringify(user.profile)]);
|
||||
|
||||
const refreshWeightHistory = async () => {
|
||||
const history = await getWeightHistory();
|
||||
setWeightHistory(history);
|
||||
|
||||
// Check if we have a weight for today
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
const todayRecord = history.find(r => r.dateStr === today);
|
||||
if (todayRecord) {
|
||||
setTodayWeight(todayRecord.weight.toString());
|
||||
}
|
||||
};
|
||||
|
||||
const refreshUserList = async () => {
|
||||
const res = await getUsers();
|
||||
if (res.success && res.users) {
|
||||
@@ -99,6 +118,27 @@ const Profile: React.FC<ProfileProps> = ({ user, onLogout, lang, onLanguageChang
|
||||
setSnackbar({ isOpen: true, message, type });
|
||||
};
|
||||
|
||||
const handleLogWeight = async () => {
|
||||
if (!todayWeight) return;
|
||||
const weightVal = parseFloat(todayWeight);
|
||||
if (isNaN(weightVal)) return;
|
||||
|
||||
const res = await logWeight(weightVal);
|
||||
if (res) {
|
||||
showSnackbar('Weight logged successfully', 'success');
|
||||
refreshWeightHistory();
|
||||
// Also update the profile weight display if it's today
|
||||
setWeight(todayWeight);
|
||||
// And trigger user update to sync across app
|
||||
const userRes = await getMe();
|
||||
if (userRes.success && userRes.user && onUserUpdate) {
|
||||
onUserUpdate(userRes.user);
|
||||
}
|
||||
} else {
|
||||
showSnackbar('Failed to log weight', 'error');
|
||||
}
|
||||
};
|
||||
|
||||
const handleSaveProfile = async () => {
|
||||
const res = await updateUserProfile(user.id, {
|
||||
weight: parseFloat(weight) || undefined,
|
||||
@@ -267,6 +307,55 @@ const Profile: React.FC<ProfileProps> = ({ user, onLogout, lang, onLanguageChang
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* WEIGHT TRACKER */}
|
||||
<div className="bg-surface-container rounded-xl p-4 border border-outline-variant/20">
|
||||
<button
|
||||
onClick={() => setShowWeightTracker(!showWeightTracker)}
|
||||
className="w-full flex justify-between items-center text-sm font-bold text-primary"
|
||||
>
|
||||
<span className="flex items-center gap-2"><Scale size={14} /> Weight Tracker</span>
|
||||
{showWeightTracker ? <ChevronUp size={16} /> : <ChevronDown size={16} />}
|
||||
</button>
|
||||
|
||||
{showWeightTracker && (
|
||||
<div className="mt-4 space-y-4">
|
||||
<div className="flex gap-2 items-end">
|
||||
<div className="bg-surface-container-high rounded-t-lg border-b border-outline-variant px-3 py-2 flex-1">
|
||||
<label className="text-[10px] text-on-surface-variant font-medium">Today's Weight (kg)</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.1"
|
||||
value={todayWeight}
|
||||
onChange={(e) => setTodayWeight(e.target.value)}
|
||||
className="w-full bg-transparent text-on-surface focus:outline-none"
|
||||
placeholder="Enter weight..."
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
onClick={handleLogWeight}
|
||||
className="bg-primary text-on-primary px-4 py-3 rounded-lg font-medium text-sm mb-[1px]"
|
||||
>
|
||||
Log
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2 max-h-60 overflow-y-auto">
|
||||
<h4 className="text-xs font-medium text-on-surface-variant">History</h4>
|
||||
{weightHistory.length === 0 ? (
|
||||
<p className="text-xs text-on-surface-variant italic">No weight records yet.</p>
|
||||
) : (
|
||||
weightHistory.map(record => (
|
||||
<div key={record.id} className="flex justify-between items-center p-3 bg-surface-container-high rounded-lg">
|
||||
<span className="text-sm text-on-surface">{new Date(record.date).toLocaleDateString()}</span>
|
||||
<span className="text-sm font-bold text-primary">{record.weight} kg</span>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* EXERCISE MANAGER */}
|
||||
<div className="bg-surface-container rounded-xl p-4 border border-outline-variant/20">
|
||||
<button
|
||||
|
||||
Reference in New Issue
Block a user