health: smart-scale columns, deduped body measurement imports, quick-add form
All checks were successful
Deploy production / deploy (push) Successful in 2m32s

This commit is contained in:
2026-10-24 14:15:59 +00:00
parent b51fef14fd
commit 07d2c70973
9 changed files with 17305 additions and 14 deletions

View File

@@ -28,6 +28,32 @@ export const appointmentTypes = [
'other'
] as const;
/** Optional smart-scale (BIA) readings on body_measurements; ranges mirror the DB check. */
export const scaleFields = [
{
key: 'muscle_mass_kg',
label: 'Muscle mass (kg)',
type: 'number',
min: 5,
max: 250,
step: 0.01
},
{
key: 'skeletal_muscle_kg',
label: 'Skeletal muscle (kg)',
type: 'number',
min: 5,
max: 200,
step: 0.01
},
{ key: 'bone_mass_kg', label: 'Bone mass (kg)', type: 'number', min: 0.5, max: 20, step: 0.01 },
{ key: 'visceral_fat', label: 'Visceral fat', type: 'number', min: 1, max: 60, step: 0.1 },
{ key: 'body_water_pct', label: 'Body water (%)', type: 'number', min: 20, max: 85, step: 0.1 },
{ key: 'protein_pct', label: 'Protein (%)', type: 'number', min: 5, max: 40, step: 0.1 },
{ key: 'bmr_kcal', label: 'BMR (kcal)', type: 'integer', min: 500, max: 6000 },
{ key: 'bmi', label: 'BMI', type: 'number', min: 10, max: 80, step: 0.1 }
] as const satisfies readonly Field[];
const notes: Field = { key: 'notes', label: 'Notes', type: 'textarea', maxLength: 4000 };
const date: Field = { key: 'date', label: 'Date', type: 'date', required: true };
@@ -54,7 +80,8 @@ export const healthTables = {
body_measurements: {
label: 'Body measurements',
fields: [
date,
// Optional here: derived from measured_at when only that is given.
{ ...date, required: false },
{ key: 'weight_kg', label: 'Weight (kg)', type: 'number', min: 20, max: 400, step: 0.01 },
{
key: 'waist_cm',
@@ -65,6 +92,9 @@ export const healthTables = {
step: 0.1
},
{ key: 'body_fat_pct', label: 'Body fat (%)', type: 'number', min: 1, max: 75, step: 0.1 },
...scaleFields,
{ key: 'measured_at', label: 'Measured at', type: 'datetime' },
{ key: 'source', label: 'Source', type: 'text', maxLength: 100, placeholder: 'Renpho' },
notes
]
},