/** * HealthKit Native Module Interface * React Native TypeScript bindings for iOS HealthKit access */ import { requireNativeModule } from 'expo-modules-core'; export interface HealthKitPermissions { [key: string]: 'notDetermined' | 'denied' | 'authorized' | 'unknown'; } export interface HealthKitAuthorizationResult { success: boolean; permissions: HealthKitPermissions; } export interface SleepDataSource { name: string; bundleIdentifier: string; } export interface SleepDataSample { id: string; startDate: string; // ISO8601 format endDate: string; // ISO8601 format value: number; categoryType: 'inBed' | 'asleep' | 'awake' | 'core' | 'deep' | 'rem' | 'unknown'; duration: number; // Duration in seconds source: SleepDataSource; metadata: Record; } export interface SleepDataOptions { startDate?: string; // ISO8601 format, defaults to 7 days ago endDate?: string; // ISO8601 format, defaults to now limit?: number; // Maximum number of samples, defaults to 100 } export interface SleepDataResult { data: SleepDataSample[]; count: number; startDate: string; endDate: string; } export interface NutritionSaveOptions { amount: number; // Amount in grams recordedAt?: string; // ISO8601 format, defaults to now } export interface NutritionSaveResult { success: boolean; amount: number; recordedAt: string; } export interface HealthKitManagerInterface { /** * Request authorization to access HealthKit data * This will prompt the user for permission to read/write health data */ requestAuthorization(): Promise; /** * Get current authorization status for HealthKit data types * This checks the current permission status without prompting the user */ getAuthorizationStatus(): Promise; /** * Get sleep analysis data from HealthKit * @param options Query options including date range and limit */ getSleepData(options?: SleepDataOptions): Promise; /** * Save protein intake to HealthKit * @param options Nutrition save options including amount in grams and optional timestamp */ saveProteinToHealthKit(options: NutritionSaveOptions): Promise; /** * Save fat intake to HealthKit * @param options Nutrition save options including amount in grams and optional timestamp */ saveFatToHealthKit(options: NutritionSaveOptions): Promise; /** * Save carbohydrates intake to HealthKit * @param options Nutrition save options including amount in grams and optional timestamp */ saveCarbohydratesToHealthKit(options: NutritionSaveOptions): Promise; } // Native module interface const HealthKitManager: HealthKitManagerInterface = requireNativeModule('HealthKitManager'); export default HealthKitManager; // Utility functions for working with sleep data export class HealthKitUtils { /** * Convert seconds to hours and minutes */ static formatDuration(seconds: number): string { const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); if (hours > 0) { return `${hours}h ${minutes}m`; } return `${minutes}m`; } /** * Get total sleep duration from sleep samples for a specific date */ static getTotalSleepDuration(samples: SleepDataSample[], date: Date): number { const targetDate = date.toISOString().split('T')[0]; return samples .filter(sample => { const sampleDate = new Date(sample.startDate).toISOString().split('T')[0]; return sampleDate === targetDate && ['asleep', 'core', 'deep', 'rem'].includes(sample.categoryType); }) .reduce((total, sample) => total + sample.duration, 0); } /** * Group sleep samples by date */ static groupSamplesByDate(samples: SleepDataSample[]): Record { return samples.reduce((grouped, sample) => { const date = new Date(sample.startDate).toISOString().split('T')[0]; if (!grouped[date]) { grouped[date] = []; } grouped[date].push(sample); return grouped; }, {} as Record); } /** * Get sleep quality metrics from samples */ static getSleepQualityMetrics(samples: SleepDataSample[]) { const sleepSamples = samples.filter(s => ['asleep', 'core', 'deep', 'rem'].includes(s.categoryType) ); if (sleepSamples.length === 0) { return null; } const totalDuration = sleepSamples.reduce((sum, s) => sum + s.duration, 0); const deepSleepDuration = sleepSamples .filter(s => s.categoryType === 'deep') .reduce((sum, s) => sum + s.duration, 0); const remSleepDuration = sleepSamples .filter(s => s.categoryType === 'rem') .reduce((sum, s) => sum + s.duration, 0); return { totalDuration, deepSleepDuration, remSleepDuration, deepSleepPercentage: totalDuration > 0 ? (deepSleepDuration / totalDuration) * 100 : 0, remSleepPercentage: totalDuration > 0 ? (remSleepDuration / totalDuration) * 100 : 0, }; } /** * Check if HealthKit is available (iOS only) */ static isAvailable(): boolean { return HealthKitManager != null; } }