import { Database } from '@/packages/supabase/src/database.types'; import { type ClassValue, clsx } from 'clsx'; import Isikukood, { Gender } from 'isikukood'; import { twMerge } from 'tailwind-merge'; import { BmiCategory } from './types/bmi'; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } export function toArray(input?: T | T[] | null): T[] { if (!input) return []; return Array.isArray(input) ? input : [input]; } export function toTitleCase(str?: string) { return ( str ?.toLowerCase() .replace(/[^-'’\s]+/g, (match) => match.replace(/^./, (first) => first.toUpperCase()), ) ?? "" ); } export function sortByDate( 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() ); }); } export const bmiFromMetric = (kg: number, cm: number) => { const m = cm / 100; const bmi = kg / (m * m); return bmi ? Math.round(bmi) : NaN; }; 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: case BmiCategory.OVER_WEIGHT: return 'bg-warning'; case BmiCategory.NORMAL: return 'bg-success'; case BmiCategory.VERY_OVERWEIGHT: case BmiCategory.OBESE: return 'bg-destructive'; default: return 'bg-success'; } } export function getGenderStringFromPersonalCode(personalCode: string) { const person = new Isikukood(personalCode); if (person.getGender() === Gender.FEMALE) return 'common:female'; if (person.getGender() === Gender.MALE) return 'common:male'; return 'common:unknown'; }