feat(dashboard, api): integrate BMI thresholds and enhance dashboard with health metrics

This commit is contained in:
Danel Kungla
2025-08-21 22:09:17 +03:00
parent b1b0846234
commit 1fb8df7c89
9 changed files with 269 additions and 101 deletions

View File

@@ -1,6 +1,9 @@
import { Database } from '@/packages/supabase/src/database.types';
import { type ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
import { BmiCategory } from './types/bmi';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
@@ -19,11 +22,63 @@ export function toTitleCase(str?: string) {
);
}
export function sortByDate<T>(a: T[] | undefined, key: keyof T): T[] | undefined {
export function sortByDate<T>(
a: T[] | undefined,
key: keyof T,
): T[] | undefined {
return a?.sort((a, b) => {
if (!a[key] || !b[key]) {
return 0;
}
return new Date(b[key] as string).getTime() - new Date(a[key] as string).getTime();
return (
new Date(b[key] as string).getTime() -
new Date(a[key] as string).getTime()
);
});
}
export const bmiFromMetric = (kg: number, cm: number) => {
const m = cm / 100;
return kg / (m * m);
};
export function getBmiStatus(
thresholds: Omit<
Database['medreport']['Tables']['bmi_thresholds']['Row'],
'id'
>[],
params: { age: number; height: number; weight: number },
): BmiCategory | null {
const age = params.age;
const thresholdByAge =
thresholds.find(
(b) => age >= b.age_min && (b.age_max == null || age <= b.age_max),
) || null;
const bmi = bmiFromMetric(params.weight, params.height);
if (!thresholdByAge || Number.isNaN(bmi)) return null;
if (bmi > thresholdByAge.obesity_min) return BmiCategory.OBESE;
if (bmi > thresholdByAge.strong_min) return BmiCategory.VERY_OVERWEIGHT;
if (bmi > thresholdByAge.overweight_min) return BmiCategory.OVER_WEIGHT;
if (bmi >= thresholdByAge.normal_min && bmi <= thresholdByAge.normal_max)
return BmiCategory.NORMAL;
return BmiCategory.UNDER_WEIGHT;
}
export function getBmiBackgroundColor(bmiStatus: BmiCategory | null): string {
switch (bmiStatus) {
case BmiCategory.UNDER_WEIGHT:
return 'bg-warning';
case BmiCategory.NORMAL:
return 'bg-success';
case BmiCategory.OVER_WEIGHT:
return 'bg-warning';
case BmiCategory.VERY_OVERWEIGHT:
return 'bg-destructive';
case BmiCategory.OBESE:
return 'bg-error';
default:
return 'bg-success';
}
}