import { Box, Stack, TextField, Typography } from "@mui/material"; import Grid from "@mui/material/Grid"; import { useBodyWeightQuery } from "@/components/Weight"; import { LoadingPlaceholder } from "@/core/ui/LoadingWidget/LoadingWidget"; import { WgerContainerRightSidebar } from "@/core/ui/Widgets/Container"; import { useProfileQuery } from "@/components/User"; import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { Area, AreaChart, CartesianGrid, ReferenceDot, Tooltip, XAxis, YAxis, } from "recharts"; const bmiRanges = [ { range: "obese", color: "#FF5733", min: 30, max: 100 }, { range: "overweight", color: "#FFC107", min: 25, max: 30 }, { range: "normal", color: "#90EE90", min: 18.5, max: 25 }, { range: "underweight", color: "#FFC300", min: 0, max: 18.5 }, ]; const getRangeColor = (name: string) => { const range = bmiRanges.find((bmiRange) => bmiRange.range === name); return range ? range.color : 'gray'; }; export const BmiCalculator = () => { const [t] = useTranslation(); const weightQuery = useBodyWeightQuery(); const profileQuery = useProfileQuery(); const [height, setHeight] = useState(); const [weight, setWeight] = useState(); // Set default weight from last weight entry useEffect(() => { if (weightQuery.data && weightQuery.data.length > 0) { const lastWeightEntry = weightQuery.data[0]; const weightInKg = profileQuery.data?.useMetric ? lastWeightEntry.weight : lastWeightEntry.weight * 0.453592; // Convert lb to kg setWeight(weightInKg); } }, [weightQuery.data, profileQuery.data]); useEffect(() => { if (profileQuery.data?.height) { setHeight(profileQuery.data.height); } }, [profileQuery.data]); const calculateBMI = () => { if (height && weight) { const heightInMeters = height / 100; return weight / (heightInMeters * heightInMeters); } return null; }; const bmi = calculateBMI(); if (weightQuery.isLoading || profileQuery.isLoading) { return ; } // Generate chart data with BMI values for different heights const chartData: { height: number; [key: string]: number }[] = []; for (let h = 140; h <= 220; h += 10) { const heightInMeters = h / 100; const dataPoint: { height: number; [key: string]: number } = { height: h }; let cumulativeWeight = 0; bmiRanges.forEach((range, index) => { const bmiValue = range.max > 100 ? 100 : range.max; let weightForRange = bmiValue * heightInMeters * heightInMeters - cumulativeWeight; // Cap the weightForRange at 150kg weightForRange = Math.min(weightForRange, 150 - cumulativeWeight); // Correctly set the data point for the stacked area chart if (index === 0) { dataPoint[range.range] = weightForRange; } else { dataPoint[range.range] = dataPoint[bmiRanges[index - 1].range] + weightForRange; } cumulativeWeight = Math.min(bmiValue * heightInMeters * heightInMeters, 150); // Cap cumulative weight as well }); chartData.push(dataPoint); } return ( {t('cm')} }, htmlInput: { inputMode: 'decimal' } }} type="number" value={height ?? ""} onChange={(e) => setHeight(parseFloat(e.target.value))} /> {t('server.kg')} }, htmlInput: { inputMode: 'decimal' } }} fullWidth type="number" value={weight ?? ""} onChange={(e) => setWeight(parseFloat(e.target.value))} /> {bmi !== null && {t('bmi.result', { value: bmi.toFixed(1) })} } Math.round(value).toString()} // Format as integers unit="kg" /> [Math.round(value as number), t('bmi.' + (name as string))]} /> {bmiRanges.map((range) => ( ))} {bmi !== null && } {t('bmi.obese')} {t('bmi.overweight')} {t('bmi.normal')} {t('bmi.underweight')} } /> ); };