About this project
it-programming / web-development
Open
Project overview
/* HealthApp.jsx Single-file React prototype (Tailwind + recharts) Features included in this prototype: Onboarding header + quick stats Body metrics (weight, height) and BMI calculator with suggestions Daily targets (water, steps, calories) Activity log and progress chart (Recharts) Simple reminders placeholder and profile card How to run: 1. Create a React app (Vite or CRA) 2. Install dependencies: react, react-dom, tailwindcss, recharts npm i react react-dom recharts 3. Ensure Tailwind is configured in the project 4. Save this file as src/HealthApp.jsx and import it from src/main.jsx Note: This prototype uses local component state and dummy data. For production add backend (GraphQL/REST), auth, data persistence, and notifications. */ Import React, { useState, useMemo } from "react"; import { LineChart, Line, XAxis, YAxis, Tooltip, ResponsiveContainer, CartesianGrid } from "recharts"; export default function HealthApp() { // Sample user profile & metrics const [profile, setProfile] = useState({ name: "Usuário", age: 29, heightCm: 178, weightKg: 78 }); const [water, setWater] = useState({ goalMl: 3000, drankMl: 1600 }); const [steps, setSteps] = useState({ goal: 10000, current: 6240 }); const [activities, setActivities] = useState([ { id: 1, date: "2025-10-28", type: "Caminhada", durationMin: 40, calories: 230 }, { id: 2, date: "2025-10-29", type: "Treino de Força", durationMin: 50, calories: 350 }, { id: 3, date: "2025-10-30", type: "Corrida", durationMin: 25, calories: 300 }, { id: 4, date: "2025-10-31", type: "Yoga", durationMin: 30, calories: 120 }, { id: 5, date: "2025-11-01", type: "Caminhada", durationMin: 60, calories: 360 }, ]); const bmi = useMemo(() => { const h = profile.heightCm / 100; return +(profile.weightKg / (h * h)).toFixed(1); }, [profile.heightCm, profile.weightKg]); const bmiCategory = useMemo(() => { if (bmi < 18.5) return "Abaixo do peso"; if (bmi < 25) return "Normal"; if (bmi < 30) return "Sobrepeso"; return "Obesidade"; }, [bmi]); const progressData = activities.map((a, i) => ({ name: a.date.slice(5), calories: a.calories, steps: Math.min(12000, (a.durationMin * 100) + (i * 200)), })); // Quick actions function logWater(amountMl) { setWater((w) => ({ ...W, drankMl: Math.min(w.goalMl, w.drankMl + amountMl) })); } function addActivity(activity) { setActivities((arr) => [activity, ...Arr].slice(0, 20)); } return ( <div className="min-h-screen bg-gray-50 p-6 font-sans"> <header className="max-w-4xl mx-auto"> <div className="flex items-center justify-between"> <div> <h1 className="text-2xl font-bold">Saúde Corporal</h1> <p className="text-sm text-gray-600">Resumo diário e controle de métricas</p> </div> <div className="flex items-center gap-4"> <div className="text-right"> <div className="text-sm text-gray-500">Olá,</div> <div className="font-medium">{profile.name}</div> </div> <div className="w-12 h-12 rounded-full bg-gradient-to-br from-indigo-500 to-purple-500 flex items-center justify-center text-white">{profile.name[0]}</div> </div> </div> </header> <main className="max-w-4xl mx-auto mt-6 grid grid-cols-1 lg:grid-cols-3 gap-6"> {/* Left column - profile & goals */} <section className="lg:col-span-1 space-y-4"> <div className="p-4 bg-white rounded-2xl shadow-sm"> <h2 className="font-semibold">Perfil</h2> <div className="mt-3 text-sm text-gray-700 space-y-2"> <div>Idade: {profile.age} anos</div> <div>Altura: {profile.heightCm} cm</div> <div>Peso: {profile.weightKg} kg</div> <div>BMI: <span className="font-medium">{bmi} ({bmiCategory})</span></div> </div> <div className="mt-4 flex gap-2"> <button className="px-3 py-2 bg-indigo-600 text-white rounded-xl text-sm" onClick={() => setProfile({...Profile, weightKg: Math.max(40, profile.weightKg - 1)})}>-1 kg</button> <button className="px-3 py-2 bg-green-600 text-white rounded-xl text-sm" onClick={() => setProfile({...Profile, weightKg: profile.weightKg + 1})}>+1 kg</button> </div> </div> <div className="p-4 bg-white rounded-2xl shadow-sm"> <h3 className="font-semibold">Hidratação</h3> <div className="mt-3"> <div className="text-sm text-gray-600">{water.drankMl} / {water.goalMl} ml</div> <div className="w-full bg-gray-200 rounded-full h-3 mt-2 overflow-hidden"> <div style={{ width: `${(water.drankMl / water.goalMl) * 100}%` }} className="h-3 bg-gradient-to-r from-blue-400 to-cyan-400" /> </div> <div className="mt-3 flex gap-2"> <button className="px-2 py-1 bg-blue-50 rounded-md text-sm" onClick={() => logWater(200)}>+200 ml</button> <button className="px-2 py-1 bg-blue-50 rounded-md text-sm" onClick={() => logWater(500)}>+500 ml</button> <button className="px-2 py-1 bg-red-50 rounded-md text-sm" onClick={() => setWater({...Water, drankMl: 0})}>Reset</button> </div> </div> </div> <div className="p-4 bg-white rounded-2xl shadow-sm"> <h3 className="font-semibold">Metas diárias</h3> <div className="mt-3 space-y-2 text-sm text-gray-700"> <div>Passos: {steps.current} / {steps.goal}</div> <div>Consumo calórico estimado: 2000 kcal</div> </div> <div className="mt-3"> <button className="px-3 py-2 bg-indigo-600 text-white rounded-xl text-sm" onClick={() => setSteps({...Steps, current: Math.min(steps.goal, steps.current + 1000)})}>+1000 passos</button> </div> </div> </section> {/* Middle column - main dashboard */} <section className="lg:col-span-2 space-y-6"> <div className="bg-white rounded-2xl p-4 shadow-sm"> <div className="flex items-center justify-between"> <h2 className="font-semibold">Resumo da semana</h2> <div className="text-sm text-gray-500">Últimos 7 dias</div> </div> <div className="mt-4 grid grid-cols-1 md:grid-cols-3 gap-4"> <StatCard title="Calorias queimadas" value={`${activities.reduce((s, a) => s + a.calories, 0)} kcal`} /> <StatCard title="Atividades" value={`${activities.length}`} /> <StatCard title="Média de passos" value={`${Math.round(activities.reduce((s, a)=> s + (a.durationMin*120),0)/activities.length)}`} /> </div> <div className="mt-6 h-48"> <ResponsiveContainer width="100%" height="100%"> <LineChart data={progressData} margin={{ top: 5, right: 20, left: 0, bottom: 5 }}> <CartesianGrid strokeDasharray="3 3" /> <XAxis dataKey="name" /> <YAxis /> <Tooltip /> <Line type="monotone" dataKey="calories" stroke="#8884d8" strokeWidth={2} /> </LineChart> </ResponsiveContainer> </div> </div> <div className="bg-white rounded-2xl p-4 shadow-sm"> <h3 className="font-semibold">Registro de atividades</h3> <div className="mt-3 space-y-3"> {activities.map((a) => ( <div key={a.id} className="flex items-center justify-between p-3 rounded-lg bg-gray-50"> <div> <div className="font-medium">{a.type}</div> <div className="text-sm text-gray-500">{a.date} • {a.durationMin} min • {a.calories} kcal</div> </div> <div className="text-sm text-gray-600">{a.durationMin}m</div> </div> ))} </div> <div className="mt-4 flex gap-2"> <button className="px-3 py-2 bg-green-600 text-white rounded-xl text-sm" onClick={() => addActivity({ id: Date.now(), date: new Date().toISOString().slice(0,10), type: "Caminhada", durationMin: 30, calories: 190 })}>Adicionar caminhada 30m</button> <button className="px-3 py-2 bg-yellow-500 text-white rounded-xl text-sm" onClick={() => addActivity({ id: Date.now()+1, date: new Date().toISOString().slice(0,10), type: "Corrida", durationMin: 20, calories: 260 })}>Adicionar corrida 20m</button> </div> </div> <div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="bg-white rounded-2xl p-4 shadow-sm"> <h4 className="font-semibold">Dicas rápidas</h4> <ul className="mt-3 list-disc list-inside text-sm text-gray-700"> <li>Beba água regularmente — meta pessoal: {water.goalMl} ml/dia.</Li> <li>Mantenha atividade física: 150 min de intensidade moderada/semana.</Li> <li>Durma 7–9 horas por noite.</Li> </ul> </div> <div className="bg-white rounded-2xl p-4 shadow-sm"> <h4 className="font-semibold">Lembretes</h4> <div className="mt-3 text-sm text-gray-700">Sem lembretes ativos. (Aqui você pode integrar notificações)</div> </div> </div> </section> </main> <footer className="max-w-4xl mx-auto mt-6 text-center text-sm text-gray-500">Protótipo • Personalize e conecte ao backend para produção</footer> </div> ); } function StatCard({ title, value }) { return ( <div className="p-3 bg-gray-50 rounded-xl text-center"> <div className="text-xs text-gray-500">{title}</div> <div className="mt-2 font-semibold text-lg">{value}</div> </div> ); }
Category IT & Programming
Subcategory Web development
What is the scope of the project? Medium-sized change
Is this a project or a position? Project
I currently have I have specifications
Required availability As needed
API Integrations Social media (Facebook, Twitter, etc.)
Roles needed Developer
Delivery term: Not specified
Skills needed