foodsnap/src/components/modals/CalculatorsModal.tsx

659 lines
No EOL
34 KiB
TypeScript

import React, { useState } from 'react';
import { X, Calculator, Droplets, Activity, Scale, ChevronRight, ArrowRight, Check, Dumbbell, Flame, Heart, Percent } from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
import { useLanguage } from '@/contexts/LanguageContext';
interface CalculatorsModalProps {
isOpen: boolean;
onClose: () => void;
}
type ToolType = 'bmi' | 'water' | 'bmr' | 'tdee' | 'orm' | 'bodyfat' | 'hr';
const CalculatorsModal: React.FC<CalculatorsModalProps> = ({ isOpen, onClose }) => {
const [activeTool, setActiveTool] = useState<ToolType>('bmi');
const { t } = useLanguage();
if (!isOpen) return null;
return (
<AnimatePresence>
<div className="fixed inset-0 z-[100] flex items-center justify-center p-4 sm:p-6">
{/* Backdrop Overlay */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={onClose}
className="absolute inset-0 bg-gray-950/70 backdrop-blur-md"
/>
{/* Modal Container */}
<motion.div
initial={{ opacity: 0, scale: 0.95, y: 20 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.95, y: 20 }}
className="relative bg-white w-full max-w-6xl h-[600px] md:h-[750px] max-h-[95vh] rounded-3xl shadow-2xl overflow-hidden flex flex-col md:flex-row ring-1 ring-gray-200"
>
{/* Close Button (Mobile) */}
<button
onClick={onClose}
className="md:hidden absolute top-4 right-4 z-20 p-2 bg-gray-100 rounded-full text-gray-500 hover:text-gray-900"
>
<X size={20} />
</button>
{/* Sidebar Navigation */}
<aside className="w-full md:w-80 bg-gray-50 border-b md:border-b-0 md:border-r border-gray-200 flex flex-col shrink-0">
<div className="p-4 md:p-6 border-b border-gray-100/50">
<div className="flex items-center gap-2">
<div className="bg-brand-600 p-2 rounded-lg text-white shadow-lg shadow-brand-500/20">
<Calculator size={20} />
</div>
<span className="font-bold text-lg text-gray-900 tracking-tight">FoodSnap Tools</span>
</div>
</div>
<nav className="flex-1 overflow-y-auto p-4 md:p-4 space-y-1 scrollbar-thin scrollbar-thumb-gray-200 flex flex-row md:flex-col gap-2 md:gap-1 overflow-x-auto md:overflow-x-visible pb-4 md:pb-0">
<NavButton
active={activeTool === 'bmi'}
onClick={() => setActiveTool('bmi')}
icon={<Scale size={18} />}
label={t.tools.bmi.title}
desc="Índice de Massa Corporal"
/>
<NavButton
active={activeTool === 'tdee'}
onClick={() => setActiveTool('tdee')}
icon={<Flame size={18} />}
label={t.tools.tdee.title}
desc="Gasto Total Diário"
/>
<NavButton
active={activeTool === 'water'}
onClick={() => setActiveTool('water')}
icon={<Droplets size={18} />}
label={t.tools.water.title}
desc="Hidratação Diária"
/>
<NavButton
active={activeTool === 'bmr'}
onClick={() => setActiveTool('bmr')}
icon={<Activity size={18} />}
label={t.tools.bmr.title}
desc="Taxa Metabólica Basal"
/>
<div className="hidden md:block h-px bg-gray-200 my-2 mx-4"></div>
<NavButton
active={activeTool === 'orm'}
onClick={() => setActiveTool('orm')}
icon={<Dumbbell size={18} />}
label={t.tools.orm.title}
desc="Força Máxima (1RM)"
/>
<NavButton
active={activeTool === 'bodyfat'}
onClick={() => setActiveTool('bodyfat')}
icon={<Percent size={18} />}
label={t.tools.bodyfat.title}
desc="Gordura Corporal"
/>
<NavButton
active={activeTool === 'hr'}
onClick={() => setActiveTool('hr')}
icon={<Heart size={18} />}
label={t.tools.hr.title}
desc="Zonas Cardíacas"
/>
</nav>
</aside>
{/* Main Content Area */}
<main className="flex-1 relative overflow-y-auto bg-white">
{/* Close Button (Desktop) */}
<button
onClick={onClose}
className="hidden md:block absolute top-6 right-6 p-2 text-gray-400 hover:text-gray-900 transition-colors bg-white hover:bg-gray-100 rounded-full z-10"
>
<X size={24} />
</button>
<div className="p-6 md:p-10 max-w-3xl mx-auto h-full flex flex-col justify-center min-h-[500px]">
<AnimatePresence mode="wait">
<motion.div
key={activeTool}
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -20 }}
transition={{ duration: 0.3 }}
className="w-full"
>
{activeTool === 'bmi' && <BMICalculator t={t} />}
{activeTool === 'water' && <WaterCalculator t={t} />}
{activeTool === 'bmr' && <BMRCalculator t={t} />}
{activeTool === 'tdee' && <TDEECalculator t={t} />}
{activeTool === 'orm' && <ORMCalculator t={t} />}
{activeTool === 'bodyfat' && <BodyFatCalculator t={t} />}
{activeTool === 'hr' && <HeartRateCalculator t={t} />}
</motion.div>
</AnimatePresence>
</div>
</main>
</motion.div>
</div>
</AnimatePresence>
);
};
// --- Components de Navegação ---
const NavButton = ({ active, onClick, icon, label, desc }: any) => (
<button
onClick={onClick}
className={`flex items-center gap-3 p-3 md:p-3.5 rounded-xl transition-all duration-200 w-full text-left min-w-[200px] md:min-w-0 md:mb-1 ${active
? 'bg-white shadow-md shadow-gray-200 ring-1 ring-gray-200'
: 'hover:bg-gray-100 text-gray-500 hover:text-gray-900'
}`}
>
<div className={`p-2 rounded-lg transition-colors shrink-0 ${active ? 'bg-brand-50 text-brand-600' : 'bg-gray-200/50 text-gray-500'}`}>
{icon}
</div>
<div className="min-w-0">
<span className={`block text-sm font-bold truncate ${active ? 'text-gray-900' : 'text-gray-600'}`}>{label}</span>
<span className="hidden md:block text-[10px] text-gray-400 font-medium leading-tight truncate">{desc}</span>
</div>
{active && <div className="hidden md:block ml-auto w-1.5 h-1.5 rounded-full bg-brand-500 shrink-0"></div>}
</button>
);
// --- Calculadoras (Existentes + Novas) ---
const BMICalculator = ({ t }: any) => {
const [weight, setWeight] = useState('');
const [height, setHeight] = useState('');
const [bmi, setBmi] = useState<number | null>(null);
const calculate = () => {
if (weight && height) {
const h = parseFloat(height) / 100;
const val = parseFloat(weight) / (h * h);
setBmi(parseFloat(val.toFixed(1)));
}
};
const getStatus = (val: number) => {
if (val < 18.5) return { label: 'Abaixo do peso', color: 'text-blue-500', bg: 'bg-blue-500', range: 0 };
if (val < 25) return { label: 'Peso ideal', color: 'text-green-500', bg: 'bg-green-500', range: 33 };
if (val < 30) return { label: 'Sobrepeso', color: 'text-yellow-500', bg: 'bg-yellow-500', range: 66 };
return { label: 'Obesidade', color: 'text-red-500', bg: 'bg-red-500', range: 100 };
};
const status = bmi ? getStatus(bmi) : null;
return (
<div className="space-y-8">
<div className="space-y-2">
<h2 className="text-2xl md:text-3xl font-bold text-gray-900">{t.tools.bmi.title}</h2>
<p className="text-gray-500">{t.tools.bmi.desc}</p>
</div>
<div className="grid grid-cols-2 gap-6">
<BigInput label={t.tools.bmi.labelWeight} value={weight} onChange={setWeight} placeholder="70" unit="kg" />
<BigInput label={t.tools.bmi.labelHeight} value={height} onChange={setHeight} placeholder="175" unit="cm" />
</div>
<button
onClick={calculate}
disabled={!weight || !height}
className="w-full bg-gray-900 hover:bg-black text-white font-bold py-4 rounded-xl transition-all shadow-lg hover:shadow-xl disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
>
{t.tools.calculate} <ArrowRight size={18} />
</button>
{bmi && status && (
<div className="bg-gray-50 rounded-2xl p-6 border border-gray-100 animate-in fade-in slide-in-from-bottom-4">
<div className="text-center mb-6">
<p className="text-sm text-gray-500 font-medium uppercase tracking-wide mb-1">Seu Resultado</p>
<div className="text-5xl font-extrabold text-gray-900 mb-2">{bmi}</div>
<span className={`inline-block px-3 py-1 rounded-full text-sm font-bold bg-white shadow-sm border border-gray-100 ${status.color}`}>
{status.label}
</span>
</div>
{/* Visual Bar */}
<div className="relative h-4 bg-gray-200 rounded-full overflow-hidden mb-2">
<div className="absolute inset-y-0 left-0 w-1/4 bg-blue-400"></div>
<div className="absolute inset-y-0 left-1/4 w-1/4 bg-green-400"></div>
<div className="absolute inset-y-0 left-2/4 w-1/4 bg-yellow-400"></div>
<div className="absolute inset-y-0 left-3/4 w-1/4 bg-red-400"></div>
</div>
<div className="relative h-4 w-full">
<div
className="absolute top-0 -translate-x-1/2 transition-all duration-500"
style={{ left: `${Math.min(Math.max((bmi / 40) * 100, 5), 95)}%` }}
>
<div className="w-0 h-0 border-l-[6px] border-l-transparent border-r-[6px] border-r-transparent border-b-[8px] border-b-gray-800 mx-auto"></div>
</div>
</div>
<div className="flex justify-between text-[10px] text-gray-400 font-medium mt-1">
<span>18.5</span>
<span>25.0</span>
<span>30.0</span>
</div>
</div>
)}
</div>
);
};
const WaterCalculator = ({ t }: any) => {
const [weight, setWeight] = useState('');
const [liters, setLiters] = useState<number | null>(null);
const calculate = () => {
if (weight) {
const val = parseFloat(weight) * 0.035;
setLiters(parseFloat(val.toFixed(1)));
}
};
return (
<div className="space-y-8">
<div className="space-y-2">
<h2 className="text-2xl md:text-3xl font-bold text-gray-900 text-cyan-900">{t.tools.water.title}</h2>
<p className="text-gray-500">{t.tools.water.desc}</p>
</div>
<div className="flex items-center gap-8">
<div className="flex-1 space-y-6">
<BigInput label={t.tools.bmi.labelWeight} value={weight} onChange={setWeight} placeholder="70" unit="kg" />
<button
onClick={calculate}
disabled={!weight}
className="w-full bg-cyan-500 hover:bg-cyan-600 text-white font-bold py-4 rounded-xl transition-all shadow-lg hover:shadow-xl disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
>
{t.tools.calculate} <ArrowRight size={18} />
</button>
</div>
{/* Visual Bottle */}
<div className="hidden md:flex w-32 h-64 bg-gray-100 rounded-[2rem] border-4 border-gray-200 relative overflow-hidden items-end justify-center shrink-0">
<div
className="absolute bottom-0 left-0 right-0 bg-cyan-400 transition-all duration-700 ease-out opacity-80"
style={{ height: liters ? '70%' : '10%' }}
>
<div className="w-full absolute -top-4 left-0 h-8 bg-cyan-400 rounded-[100%]"></div>
</div>
<div className="relative z-10 mb-8 text-center">
<Droplets className="text-white drop-shadow-md mx-auto mb-2" size={24} />
{liters && <span className="text-white font-bold text-xl drop-shadow-md">{liters}L</span>}
</div>
</div>
</div>
{liters && (
<div className="md:hidden bg-cyan-50 border border-cyan-100 p-6 rounded-2xl text-center">
<p className="text-sm text-cyan-800 font-medium uppercase tracking-wide mb-1">Meta Diária</p>
<p className="text-5xl font-extrabold text-cyan-600">{liters} L</p>
</div>
)}
</div>
);
};
const BMRCalculator = ({ t }: any) => {
const [gender, setGender] = useState<'male' | 'female'>('male');
const [weight, setWeight] = useState('');
const [height, setHeight] = useState('');
const [age, setAge] = useState('');
const [bmr, setBmr] = useState<number | null>(null);
const calculate = () => {
if (weight && height && age) {
let val = (10 * parseFloat(weight)) + (6.25 * parseFloat(height)) - (5 * parseFloat(age));
val = gender === 'male' ? val + 5 : val - 161;
setBmr(Math.round(val));
}
};
return (
<div className="space-y-6">
<div className="space-y-2">
<h2 className="text-2xl md:text-3xl font-bold text-gray-900">{t.tools.bmr.title}</h2>
<p className="text-gray-500">{t.tools.bmr.desc}</p>
</div>
<div className="grid grid-cols-2 gap-4">
<button onClick={() => setGender('male')} className={`p-4 rounded-xl border-2 transition-all flex flex-col items-center gap-2 ${gender === 'male' ? 'border-brand-500 bg-brand-50 text-brand-700' : 'border-gray-200 bg-white text-gray-400 hover:border-gray-300'}`}>
<div className="font-bold">{t.tools.bmr.male}</div>
{gender === 'male' && <div className="p-1 bg-brand-500 rounded-full text-white"><Check size={12} /></div>}
</button>
<button onClick={() => setGender('female')} className={`p-4 rounded-xl border-2 transition-all flex flex-col items-center gap-2 ${gender === 'female' ? 'border-brand-500 bg-brand-50 text-brand-700' : 'border-gray-200 bg-white text-gray-400 hover:border-gray-300'}`}>
<div className="font-bold">{t.tools.bmr.female}</div>
{gender === 'female' && <div className="p-1 bg-brand-500 rounded-full text-white"><Check size={12} /></div>}
</button>
</div>
<div className="grid grid-cols-3 gap-4">
<BigInput label={t.tools.bmi.labelWeight} value={weight} onChange={setWeight} placeholder="70" unit="kg" />
<BigInput label={t.tools.bmi.labelHeight} value={height} onChange={setHeight} placeholder="175" unit="cm" />
<BigInput label={t.tools.bmr.labelAge} value={age} onChange={setAge} placeholder="30" unit="anos" />
</div>
<button
onClick={calculate}
disabled={!weight || !height || !age}
className="w-full bg-gray-900 hover:bg-black text-white font-bold py-4 rounded-xl transition-all shadow-lg hover:shadow-xl disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
>
{t.tools.calculate} <ArrowRight size={18} />
</button>
{bmr && (
<div className="bg-orange-50 border border-orange-100 p-6 rounded-2xl flex items-center justify-between animate-in fade-in zoom-in">
<div>
<p className="text-sm text-orange-800 font-medium uppercase tracking-wide mb-1">Gasto em Repouso</p>
<p className="text-xs text-orange-600/70 max-w-[200px]">Calorias que você queima parado.</p>
</div>
<div className="text-right">
<p className="text-4xl font-extrabold text-orange-600">{bmr}</p>
<p className="text-xs font-bold text-orange-400 uppercase">kcal / dia</p>
</div>
</div>
)}
</div>
);
};
const TDEECalculator = ({ t }: any) => {
const [gender, setGender] = useState<'male' | 'female'>('male');
const [weight, setWeight] = useState('');
const [height, setHeight] = useState('');
const [age, setAge] = useState('');
const [activity, setActivity] = useState<number>(1.2);
const [tdee, setTdee] = useState<number | null>(null);
const calculate = () => {
if (weight && height && age) {
let bmr = (10 * parseFloat(weight)) + (6.25 * parseFloat(height)) - (5 * parseFloat(age));
bmr = gender === 'male' ? bmr + 5 : bmr - 161;
setTdee(Math.round(bmr * activity));
}
};
const activityLevels = [
{ val: 1.2, label: t.tools.tdee.sedentary },
{ val: 1.375, label: t.tools.tdee.light },
{ val: 1.55, label: t.tools.tdee.moderate },
{ val: 1.725, label: t.tools.tdee.active },
{ val: 1.9, label: t.tools.tdee.veryActive },
];
return (
<div className="space-y-6">
<div className="space-y-2">
<h2 className="text-2xl md:text-3xl font-bold text-gray-900">{t.tools.tdee.title}</h2>
<p className="text-gray-500">{t.tools.tdee.desc}</p>
</div>
<div className="grid grid-cols-2 gap-4">
<button onClick={() => setGender('male')} className={`p-3 rounded-xl border-2 transition-all flex justify-center items-center gap-2 ${gender === 'male' ? 'border-brand-500 bg-brand-50 text-brand-700' : 'border-gray-200 bg-white text-gray-400'}`}>{t.tools.bmr.male}</button>
<button onClick={() => setGender('female')} className={`p-3 rounded-xl border-2 transition-all flex justify-center items-center gap-2 ${gender === 'female' ? 'border-brand-500 bg-brand-50 text-brand-700' : 'border-gray-200 bg-white text-gray-400'}`}>{t.tools.bmr.female}</button>
</div>
<div className="grid grid-cols-3 gap-4">
<BigInput label={t.tools.bmi.labelWeight} value={weight} onChange={setWeight} placeholder="70" unit="kg" />
<BigInput label={t.tools.bmi.labelHeight} value={height} onChange={setHeight} placeholder="175" unit="cm" />
<BigInput label={t.tools.bmr.labelAge} value={age} onChange={setAge} placeholder="30" unit="anos" />
</div>
<div>
<label className="block text-xs font-bold text-gray-500 mb-2 uppercase tracking-wide">{t.tools.tdee.activity}</label>
<div className="grid grid-cols-1 gap-2">
{activityLevels.map((lvl) => (
<button
key={lvl.val}
onClick={() => setActivity(lvl.val)}
className={`text-left px-4 py-3 rounded-xl border transition-all flex justify-between items-center ${activity === lvl.val ? 'border-brand-500 bg-brand-50 text-brand-900 ring-1 ring-brand-500' : 'border-gray-200 bg-white text-gray-600 hover:bg-gray-50'}`}
>
<span className="font-medium text-sm">{lvl.label}</span>
{activity === lvl.val && <div className="w-2 h-2 rounded-full bg-brand-500"></div>}
</button>
))}
</div>
</div>
<button
onClick={calculate}
disabled={!weight || !height || !age}
className="w-full bg-gray-900 hover:bg-black text-white font-bold py-4 rounded-xl transition-all shadow-lg hover:shadow-xl disabled:opacity-50"
>
{t.tools.calculate}
</button>
{tdee && (
<div className="bg-brand-900 text-white p-6 rounded-2xl flex items-center justify-between animate-in fade-in zoom-in shadow-xl">
<div>
<p className="text-sm text-brand-300 font-bold uppercase tracking-wide mb-1">Gasto Calórico Total</p>
<p className="text-xs text-brand-200 opacity-80 max-w-[200px]">Energia necessária para manter seu peso atual.</p>
</div>
<div className="text-right">
<p className="text-4xl font-extrabold text-white">{tdee}</p>
<p className="text-xs font-bold text-brand-400 uppercase">kcal / dia</p>
</div>
</div>
)}
</div>
);
};
const ORMCalculator = ({ t }: any) => {
const [lift, setLift] = useState('');
const [reps, setReps] = useState('');
const [orm, setOrm] = useState<number | null>(null);
const calculate = () => {
if (lift && reps) {
// Epley Formula
const w = parseFloat(lift);
const r = parseFloat(reps);
if (r === 1) {
setOrm(w);
} else {
const val = w * (1 + r / 30);
setOrm(Math.round(val));
}
}
};
return (
<div className="space-y-8">
<div className="space-y-2">
<h2 className="text-2xl md:text-3xl font-bold text-gray-900">{t.tools.orm.title}</h2>
<p className="text-gray-500">{t.tools.orm.desc}</p>
</div>
<div className="grid grid-cols-2 gap-6">
<BigInput label={t.tools.orm.lift} value={lift} onChange={setLift} placeholder="100" unit="kg" />
<BigInput label={t.tools.orm.reps} value={reps} onChange={setReps} placeholder="5" unit="reps" />
</div>
<button
onClick={calculate}
disabled={!lift || !reps}
className="w-full bg-gray-900 hover:bg-black text-white font-bold py-4 rounded-xl transition-all shadow-lg hover:shadow-xl disabled:opacity-50"
>
{t.tools.calculate} <ArrowRight size={18} className="inline ml-2" />
</button>
{orm && (
<div className="bg-gray-100 p-6 rounded-2xl animate-in fade-in slide-in-from-bottom-2">
<div className="flex justify-between items-center mb-4">
<span className="text-gray-500 font-bold uppercase text-xs">Sua Força Máxima Estimada</span>
<Dumbbell className="text-gray-400" size={20} />
</div>
<div className="text-center py-4">
<span className="text-6xl font-black text-gray-900 tracking-tighter">{orm}</span>
<span className="text-2xl text-gray-400 font-bold ml-2">kg</span>
</div>
<div className="grid grid-cols-3 gap-2 mt-4 text-center">
<div className="bg-white p-2 rounded-lg shadow-sm">
<span className="block text-xs text-gray-400 font-bold">90%</span>
<span className="block font-bold text-gray-800">{Math.round(orm * 0.9)}kg</span>
</div>
<div className="bg-white p-2 rounded-lg shadow-sm">
<span className="block text-xs text-gray-400 font-bold">70% (Hipertrofia)</span>
<span className="block font-bold text-gray-800">{Math.round(orm * 0.7)}kg</span>
</div>
<div className="bg-white p-2 rounded-lg shadow-sm">
<span className="block text-xs text-gray-400 font-bold">50%</span>
<span className="block font-bold text-gray-800">{Math.round(orm * 0.5)}kg</span>
</div>
</div>
</div>
)}
</div>
);
};
const BodyFatCalculator = ({ t }: any) => {
const [gender, setGender] = useState<'male' | 'female'>('male');
const [waist, setWaist] = useState('');
const [neck, setNeck] = useState('');
const [hip, setHip] = useState('');
const [height, setHeight] = useState('');
const [bf, setBf] = useState<number | null>(null);
const calculate = () => {
// US Navy Method
const h = parseFloat(height);
const w = parseFloat(waist);
const n = parseFloat(neck);
if (gender === 'male' && h && w && n) {
const res = 495 / (1.0324 - 0.19077 * Math.log10(w - n) + 0.15456 * Math.log10(h)) - 450;
setBf(parseFloat(res.toFixed(1)));
} else if (gender === 'female' && h && w && n && hip) {
const hi = parseFloat(hip);
const res = 495 / (1.29579 - 0.35004 * Math.log10(w + hi - n) + 0.22100 * Math.log10(h)) - 450;
setBf(parseFloat(res.toFixed(1)));
}
};
return (
<div className="space-y-6">
<div className="space-y-2">
<h2 className="text-2xl md:text-3xl font-bold text-gray-900">{t.tools.bodyfat.title}</h2>
<p className="text-gray-500">{t.tools.bodyfat.desc}</p>
</div>
<div className="flex gap-4 mb-4">
<button onClick={() => setGender('male')} className={`flex-1 p-3 rounded-xl border-2 transition-all font-bold ${gender === 'male' ? 'border-brand-500 bg-brand-50 text-brand-700' : 'border-gray-200'}`}>{t.tools.bmr.male}</button>
<button onClick={() => setGender('female')} className={`flex-1 p-3 rounded-xl border-2 transition-all font-bold ${gender === 'female' ? 'border-brand-500 bg-brand-50 text-brand-700' : 'border-gray-200'}`}>{t.tools.bmr.female}</button>
</div>
<div className="grid grid-cols-2 gap-4">
<BigInput label={t.tools.bmi.labelHeight} value={height} onChange={setHeight} placeholder="175" unit="cm" />
<BigInput label={t.tools.bodyfat.neck} value={neck} onChange={setNeck} placeholder="40" unit="cm" />
<BigInput label={t.tools.bodyfat.waist} value={waist} onChange={setWaist} placeholder="90" unit="cm" />
{gender === 'female' && (
<BigInput label={t.tools.bodyfat.hip} value={hip} onChange={setHip} placeholder="100" unit="cm" />
)}
</div>
<button
onClick={calculate}
disabled={!height || !neck || !waist || (gender === 'female' && !hip)}
className="w-full bg-brand-600 hover:bg-brand-700 text-white font-bold py-4 rounded-xl transition-all shadow-lg"
>
{t.tools.calculate}
</button>
{bf && (
<div className="bg-brand-50 border border-brand-100 p-8 rounded-2xl text-center animate-in fade-in zoom-in">
<p className="text-sm text-brand-800 font-bold uppercase tracking-wide mb-2">Gordura Corporal Estimada</p>
<p className="text-6xl font-black text-brand-600">{bf}<span className="text-3xl">%</span></p>
<div className="mt-4 text-xs text-brand-500 font-medium bg-brand-100 inline-block px-3 py-1 rounded-full">
Método US Navy
</div>
</div>
)}
</div>
);
};
const HeartRateCalculator = ({ t }: any) => {
const [age, setAge] = useState('');
const [maxHr, setMaxHr] = useState<number | null>(null);
const calculate = () => {
if (age) {
const val = 220 - parseFloat(age);
setMaxHr(val);
}
};
return (
<div className="space-y-8">
<div className="space-y-2">
<h2 className="text-2xl md:text-3xl font-bold text-gray-900">{t.tools.hr.title}</h2>
<p className="text-gray-500">{t.tools.hr.desc}</p>
</div>
<div className="max-w-xs">
<BigInput label={t.tools.bmr.labelAge} value={age} onChange={setAge} placeholder="30" unit="anos" />
</div>
<button onClick={calculate} disabled={!age} className="w-full bg-red-600 hover:bg-red-700 text-white font-bold py-4 rounded-xl transition-all shadow-lg shadow-red-500/30">
{t.tools.calculate}
</button>
{maxHr && (
<div className="space-y-4 animate-in fade-in slide-in-from-bottom-2">
<div className="text-center mb-6">
<span className="text-sm font-bold text-gray-400 uppercase">Frequência Máxima Teórica</span>
<div className="text-5xl font-black text-gray-900">{maxHr} <span className="text-xl font-medium text-gray-400">bpm</span></div>
</div>
<div className="space-y-2">
<ZoneBar zone="5" color="bg-red-500" range="90-100%" val={`${Math.round(maxHr * 0.9)} - ${maxHr}`} label="Performance Máxima" />
<ZoneBar zone="4" color="bg-orange-500" range="80-90%" val={`${Math.round(maxHr * 0.8)} - ${Math.round(maxHr * 0.9)}`} label="Cardio Intenso" />
<ZoneBar zone="3" color="bg-green-500" range="70-80%" val={`${Math.round(maxHr * 0.7)} - ${Math.round(maxHr * 0.8)}`} label="Aeróbico (Queima)" />
<ZoneBar zone="2" color="bg-blue-500" range="60-70%" val={`${Math.round(maxHr * 0.6)} - ${Math.round(maxHr * 0.7)}`} label="Queima de Gordura / Aquecimento" />
</div>
</div>
)}
</div>
);
};
const ZoneBar = ({ zone, color, range, val, label }: any) => (
<div className="bg-gray-50 p-3 rounded-xl border border-gray-100 flex items-center gap-4">
<div className={`w-10 h-10 rounded-lg ${color} flex items-center justify-center text-white font-bold shrink-0`}>Z{zone}</div>
<div className="flex-1">
<div className="flex justify-between items-center mb-1">
<span className="font-bold text-gray-800 text-sm">{label}</span>
<span className="text-xs font-bold text-gray-400">{range}</span>
</div>
<div className="text-sm font-medium text-gray-600">{val} bpm</div>
</div>
</div>
);
const BigInput = ({ label, value, onChange, placeholder, unit }: any) => (
<div className="w-full">
<label className="block text-xs font-bold text-gray-500 mb-2 uppercase tracking-wide">{label}</label>
<div className="relative">
<input
type="number"
value={value}
onChange={(e) => onChange(e.target.value)}
className="w-full px-4 py-4 rounded-xl bg-gray-50 border border-gray-200 text-gray-900 font-bold text-lg focus:border-brand-500 focus:ring-2 focus:ring-brand-200 outline-none transition-all placeholder-gray-300"
placeholder={placeholder}
/>
{unit && <span className="absolute right-4 top-1/2 -translate-y-1/2 text-gray-400 font-medium text-sm">{unit}</span>}
</div>
</div>
);
export default CalculatorsModal;