56 lines
1.8 KiB
TypeScript
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();
|
|
},
|
|
};
|