1
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
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]))
|
||||
}
|
||||
Reference in New Issue
Block a user