Files
Evergreen-Health-Mobile/src/services/formValidation.ts
T
2026-10-09 16:46:35 +08:00

43 lines
2.4 KiB
TypeScript

import type { HealthAssessmentAnswers } from './health'
export function finiteNumberInRange(value: unknown, minimum: number, maximum: number, integer = false): value is number {
return typeof value === 'number' && Number.isFinite(value) && value >= minimum && value <= maximum && (!integer || Number.isInteger(value))
}
// Birthdays are calendar dates, not instants. Keep the displayed day unchanged
// even when the API serializes a DateTime or the browser has a UTC offset.
// Admin.NET returns yyyy-MM-dd HH:mm:ss; also accept date-only and ISO timestamps.
export function ageFromBirthday(value: unknown, today = new Date()): number | undefined {
if (typeof value !== 'string') return undefined
const match = /^(\d{4})-(\d{2})-(\d{2})(?:[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?)?$/.exec(value)
if (!match) return undefined
const [, yearText, monthText, dayText] = match
const year = Number(yearText), month = Number(monthText), day = Number(dayText)
const birthday = new Date(year, month - 1, day)
if (birthday.getFullYear() !== year || birthday.getMonth() !== month - 1 || birthday.getDate() !== day) return undefined
const currentDay = new Date(today.getFullYear(), today.getMonth(), today.getDate())
if (birthday > currentDay) return undefined
const beforeBirthday = today.getMonth() < month - 1 || (today.getMonth() === month - 1 && today.getDate() < day)
return today.getFullYear() - year - (beforeBirthday ? 1 : 0)
}
const healthAnswerOptions: Record<keyof HealthAssessmentAnswers, readonly string[]> = {
sleepDuration: ['<6', '6-7', '7-8', '>8'],
fallingAsleepSpeed: ['hard', 'normal', 'fast'],
temperaturePreference: ['heat_fear', 'cold_fear', 'normal'],
nightAwakening: ['frequent', 'light', 'none'],
mattressPreference: ['firm', 'medium', 'soft'],
exerciseFrequency: ['none', '1-2', '3-5', 'daily'],
muscleFatigueArea: ['back_neck', 'waist_back', 'legs', 'none'],
activeTimeOfDay: ['morning', 'evening', 'night', 'irregular'],
mealRegularity: ['regular', 'skip_breakfast', 'irregular'],
flavorPreference: ['light', 'moderate', 'heavy'],
lateNightEating: ['often', 'sometimes', 'rarely'],
dailyWaterIntake: ['abundant', 'moderate', 'scarce']
}
export function healthAnswersComplete(answers: HealthAssessmentAnswers): boolean {
return (Object.keys(healthAnswerOptions) as (keyof HealthAssessmentAnswers)[])
.every(key => healthAnswerOptions[key].includes(answers[key]))
}