profileStore.ts

Persists and loads the user physiological profile via AsyncStorage

Purpose

This module manages the user’s physiological profile, providing typed load and save operations backed by AsyncStorage. It is the single source of truth for profile data consumed by inference, the home screen, and the landing screen.

Its responsibilities include:

  • Defining the canonical UserProfile type with all physiological and preference fields
  • Providing a defaultProfile used for first-run and field fallback
  • Loading and merging persisted profile data with defaults to handle partial saves
  • Saving a complete UserProfile to AsyncStorage
  • Computing BMI from height and weight

Invariants

Default Merge on Load

loadProfile merges the persisted object with defaultProfile using spread:

{ ...defaultProfile, ...parsed }

This ensures any fields missing from an older persisted schema are filled with current defaults, providing forward compatibility.


Parse Failure Fallback

If the raw stored value cannot be parsed as JSON, loadProfile returns defaultProfile rather than throwing.


BMI Zero Guard

calcBMI returns 0 when heightCm is zero or falsy, preventing division by zero.


Constants

FieldDefault valueDescription
gender"male"Biological sex
unitSystem"metric"Display unit preference
age25Age in years
heightCm175Height in centimeters
weightKg75Weight in kilograms
daysActive144Active days in past 14

Exports

UserProfile

type UserProfile = {
	gender: Gender;
	unitSystem: "metric" | "imperial";
	age: number;
	heightCm: number;
	weightKg: number;
	daysActive14: number;
};

calcBMI(...)

function calcBMI(heightCm: number, weightKg: number): number

Returns weightKg / (heightM²), or 0 if heightCm is zero.


loadProfile()

async function loadProfile(): Promise<UserProfile>

Loads and returns the persisted profile merged with defaultProfile. Never throws.


saveProfile(...)

async function saveProfile(next: UserProfile): Promise<void>

Serializes and writes the full profile to AsyncStorage.