Files
haptika/src/features/ppg/health/healthKitService.ts
T
2026-07-31 16:20:10 +02:00

56 lines
1.8 KiB
TypeScript

import {
haptikaHealthKit,
type NativeHeartbeatSeriesSummary,
type NativeHealthMetricSample,
} from 'react-native-haptika-ppg';
import type {HealthKitContext, HealthMetricSample} from './healthTypes';
const mapSample = (sample: NativeHealthMetricSample): HealthMetricSample => ({
type: sample.type,
value: sample.value,
unit: sample.unit,
startDate: sample.startDate,
endDate: sample.endDate,
sourceName: sample.sourceName ?? null,
sourceBundleIdentifier: sample.sourceBundleIdentifier ?? null,
deviceName: sample.deviceName ?? null,
});
export const healthKitService = {
isAvailable(): boolean {
return haptikaHealthKit.isAvailable();
},
requestReadAuthorization(): Promise<boolean> {
return haptikaHealthKit.requestReadAuthorization();
},
async fetchContext(lookbackDays = 14): Promise<HealthKitContext> {
const context = await haptikaHealthKit.fetchContext(lookbackDays);
return {
available: context.available,
// The native field retains its generated ABI name, but represents only
// HKAuthorizationRequestStatus.unnecessary — never proof of read access.
authorizationRequestSettled: context.authorized,
latestRestingHeartRate:
context.latestRestingHeartRate === undefined
? null
: mapSample(context.latestRestingHeartRate),
latestHrvSdnn:
context.latestHrvSdnn === undefined
? null
: mapSample(context.latestHrvSdnn),
recentHeartRateSamples: context.recentHeartRateSamples.map(mapSample),
contextConfidence: context.contextConfidence,
fetchedAt: context.fetchedAt,
};
},
fetchLatestHeartbeatSeries(): Promise<
NativeHeartbeatSeriesSummary | undefined
> {
return haptikaHealthKit.fetchLatestHeartbeatSeries();
},
};