Track weight and blood indicators.
+ +Get personalized diet & workout plans.
+ ); diff --git a/frontend/src/pages/Health.jsx b/frontend/src/pages/Health.jsx new file mode 100644 index 0000000..80f8a6f --- /dev/null +++ b/frontend/src/pages/Health.jsx @@ -0,0 +1,240 @@ +import { useState, useEffect, useMemo } from 'react'; +import client from '../api/client'; +import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts'; + +const Health = () => { + const [metrics, setMetrics] = useState([]); + const [goals, setGoals] = useState([]); + const [newMetric, setNewMetric] = useState({ metric_type: 'weight', value: '', unit: 'kg' }); + const [newGoal, setNewGoal] = useState({ goal_type: 'lose_weight', target_value: '', target_date: '' }); + const [loading, setLoading] = useState(false); + const [selectedMetricType, setSelectedMetricType] = useState('weight'); + + useEffect(() => { + fetchData(); + }, []); + + const fetchData = async () => { + try { + const [metricsRes, goalsRes] = await Promise.all([ + client.get('/health/metrics'), + client.get('/health/goals') + ]); + setMetrics(metricsRes.data); + setGoals(goalsRes.data); + } catch (error) { + console.error('Failed to fetch health data', error); + } + }; + + const handleAddMetric = async (e) => { + e.preventDefault(); + setLoading(true); + try { + await client.post('/health/metrics', newMetric); + setNewMetric({ ...newMetric, value: '' }); + fetchData(); + } catch (error) { + console.error(error); + alert('Failed to add metric'); + } finally { + setLoading(false); + } + }; + + const handleAddGoal = async (e) => { + e.preventDefault(); + setLoading(true); + try { + await client.post('/health/goals', { + ...newGoal, + target_date: newGoal.target_date || null + }); + setNewGoal({ ...newGoal, target_value: '', target_date: '' }); + fetchData(); + } catch (error) { + console.error(error); + alert('Failed to add goal'); + } finally { + setLoading(false); + } + }; + + const chartData = useMemo(() => { + return metrics + .filter(m => m.metric_type === selectedMetricType) + .sort((a, b) => new Date(a.timestamp) - new Date(b.timestamp)) + .map(m => ({ + date: new Date(m.timestamp).toLocaleDateString(), + value: m.value + })); + }, [metrics, selectedMetricType]); + + return ( +No active goals.
+ ) : ( + goals.map((g) => ( ++ Target: {new Date(g.target_date).toLocaleDateString()} +
+ )} +