@kingstinct/react-native-healthkit 4.3.0 → 4.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ios.tsx CHANGED
@@ -1,21 +1,29 @@
1
- import { useCallback, useEffect, useState } from 'react';
1
+ import { useCallback, useEffect, useState } from 'react'
2
+
2
3
  import Native, {
3
4
  EventEmitter,
4
- HKCategorySampleRaw,
5
+ HKQuantityTypeIdentifier,
6
+ HKUnit,
5
7
  HKCategoryTypeIdentifier,
8
+ } from './native-types'
9
+
10
+ import type {
11
+ HealthkitReadAuthorization,
12
+ HealthkitWriteAuthorization,
13
+ HKAuthorizationRequestStatus,
14
+ HKCategorySampleRaw,
6
15
  HKCategoryValueForIdentifier,
7
- HKCharacteristicTypeIdentifier,
8
16
  HKCorrelationRaw,
9
17
  HKCorrelationTypeIdentifier,
10
18
  HKQuantitySampleRaw,
11
- HKQuantityTypeIdentifier,
12
- HKSampleTypeIdentifier,
13
- HKUnit,
14
19
  HKUnitSI,
15
20
  HKUnitSIPrefix,
16
21
  HKWorkoutRaw,
17
22
  MetadataMapperForCategoryIdentifier,
18
- } from './native-types';
23
+ ReadPermissions,
24
+ SampleTypeIdentifier,
25
+ WritePermissions,
26
+ } from './native-types'
19
27
  import type {
20
28
  GenericQueryOptions,
21
29
  GetMostRecentCategorySampleFn,
@@ -38,76 +46,73 @@ import type {
38
46
  SaveQuantitySampleFn,
39
47
  SaveWorkoutSampleFn,
40
48
  SubscribeToChangesFn,
41
- } from './types';
49
+ } from './types'
42
50
 
43
51
  const getPreferredUnit: GetPreferredUnitFn = async (type) => {
44
- const [unit] = await getPreferredUnits([type]);
45
- return unit;
46
- };
52
+ const [unit] = await getPreferredUnits([type])
53
+ return unit
54
+ }
47
55
 
48
56
  const ensureUnit = async <TUnit extends HKUnit>(
49
57
  type: HKQuantityTypeIdentifier,
50
- providedUnit?: TUnit
58
+ providedUnit?: TUnit,
51
59
  ) => {
52
60
  if (providedUnit) {
53
- return providedUnit;
61
+ return providedUnit
54
62
  }
55
- const unit = await Native.getPreferredUnits([type]);
56
- return unit[type] as TUnit;
57
- };
63
+ const unit = await Native.getPreferredUnits([type])
64
+ return unit[type] as TUnit
65
+ }
58
66
 
59
67
  function deserializeSample<
60
68
  TIdentifier extends HKQuantityTypeIdentifier,
61
69
  TUnit extends HKUnit
62
70
  >(
63
- sample: HKQuantitySampleRaw<TIdentifier, TUnit>
71
+ sample: HKQuantitySampleRaw<TIdentifier, TUnit>,
64
72
  ): HKQuantitySample<TIdentifier, TUnit> {
65
73
  return {
66
74
  ...sample,
67
75
  startDate: new Date(sample.startDate),
68
76
  endDate: new Date(sample.endDate),
69
- };
77
+ }
70
78
  }
71
79
 
72
80
  function deserializeWorkout<TEnergy extends HKUnit, TDistance extends HKUnit>(
73
- sample: HKWorkoutRaw<TEnergy, TDistance>
81
+ sample: HKWorkoutRaw<TEnergy, TDistance>,
74
82
  ): HKWorkout<TEnergy, TDistance> {
75
83
  return {
76
84
  ...sample,
77
85
  startDate: new Date(sample.startDate),
78
86
  endDate: new Date(sample.endDate),
79
- };
87
+ }
80
88
  }
81
89
 
82
90
  const deserializCategorySample = <T extends HKCategoryTypeIdentifier>(
83
- sample: HKCategorySampleRaw<T>
84
- ): HKCategorySample<T> => {
85
- return {
86
- ...sample,
87
- startDate: new Date(sample.startDate),
88
- endDate: new Date(sample.endDate),
89
- };
90
- };
91
+ sample: HKCategorySampleRaw<T>,
92
+ ): HKCategorySample<T> => ({
93
+ ...sample,
94
+ startDate: new Date(sample.startDate),
95
+ endDate: new Date(sample.endDate),
96
+ })
91
97
 
92
- const serializeDate = (date?: Date | null): string => {
93
- return date ? date.toISOString() : new Date(0).toISOString();
94
- };
98
+ const serializeDate = (date?: Date | null): string => (date ? date.toISOString() : new Date(0).toISOString())
95
99
 
96
100
  const prepareOptions = (options: GenericQueryOptions) => {
97
- const limit =
98
- !options.limit || options.limit === Infinity ? 0 : options.limit;
99
- const ascending = options.ascending ?? limit === 0;
100
- const from = serializeDate(options.from);
101
- const to = serializeDate(options.to);
102
- return { limit, ascending, from, to };
103
- };
101
+ const limit = !options.limit || options.limit === Infinity ? 0 : options.limit
102
+ const ascending = options.ascending ?? limit === 0
103
+ const from = serializeDate(options.from)
104
+ const to = serializeDate(options.to)
105
+ return {
106
+ limit, ascending, from, to,
107
+ }
108
+ }
104
109
 
105
110
  const queryQuantitySamples: QueryQuantitySamplesFn = async (
106
111
  identifier,
107
- options
112
+ options,
108
113
  ) => {
109
- const unit = await ensureUnit(identifier, options.unit);
110
- const opts = prepareOptions(options);
114
+ const unit = await ensureUnit(identifier, options.unit)
115
+ const opts = prepareOptions(options)
111
116
 
112
117
  const quantitySamples = await Native.queryQuantitySamples(
113
118
  identifier,
@@ -115,121 +120,155 @@ const queryQuantitySamples: QueryQuantitySamplesFn = async (
115
120
  opts.from,
116
121
  opts.to,
117
122
  opts.limit,
118
- opts.ascending
119
- );
123
+ opts.ascending,
124
+ )
125
+
126
+ return quantitySamples.map(deserializeSample)
127
+ }
120
128
 
121
- return quantitySamples.map(deserializeSample);
122
- };
129
+ async function getPreferredUnitsTyped<
130
+ TEnergy extends HKUnit,
131
+ TDistance extends HKUnit
132
+ >(options?: { readonly energyUnit?: TEnergy; readonly distanceUnit?: TDistance }) {
133
+ let energyUnit = options?.energyUnit
134
+ let distanceUnit = options?.distanceUnit
135
+ if (!energyUnit || !distanceUnit) {
136
+ const units = await Native.getPreferredUnits([
137
+ HKQuantityTypeIdentifier.distanceWalkingRunning,
138
+ HKQuantityTypeIdentifier.activeEnergyBurned,
139
+ ])
140
+ if (!energyUnit) {
141
+ energyUnit = units[HKQuantityTypeIdentifier.distanceWalkingRunning] as
142
+ | TEnergy
143
+ | undefined
144
+ }
145
+ if (!distanceUnit) {
146
+ distanceUnit = units[HKQuantityTypeIdentifier.activeEnergyBurned] as
147
+ | TDistance
148
+ | undefined
149
+ }
150
+ }
151
+ if (!energyUnit) {
152
+ energyUnit = HKUnit.Kilocalories as TEnergy
153
+ }
154
+ if (!distanceUnit) {
155
+ distanceUnit = HKUnit.Meters as TDistance
156
+ }
157
+ return { energyUnit, distanceUnit }
158
+ }
123
159
 
124
160
  const subscribeToChanges: SubscribeToChangesFn = async (
125
161
  identifier,
126
- callback
162
+ callback,
127
163
  ) => {
128
164
  const subscription = EventEmitter.addListener(
129
165
  'onChange',
130
166
  ({ typeIdentifier }) => {
131
167
  if (typeIdentifier === identifier) {
132
- callback();
168
+ callback()
133
169
  }
134
- }
135
- );
170
+ },
171
+ )
136
172
 
137
173
  const queryId = await Native.subscribeToObserverQuery(identifier).catch(
138
- (error) => {
139
- subscription.remove();
140
- return Promise.reject(error);
141
- }
142
- );
143
-
144
- return () => {
145
- subscription.remove();
146
- return Native.unsubscribeQuery(queryId);
147
- };
148
- };
174
+ async (error) => {
175
+ subscription.remove()
176
+ return Promise.reject(error)
177
+ },
178
+ )
179
+
180
+ return async () => {
181
+ subscription.remove()
182
+ return Native.unsubscribeQuery(queryId)
183
+ }
184
+ }
149
185
 
150
186
  const getMostRecentQuantitySample: GetMostRecentQuantitySampleFn = async (
151
187
  identifier,
152
- unit
188
+ unit,
153
189
  ) => {
154
190
  const samples = await queryQuantitySamples(identifier, {
155
191
  limit: 1,
156
- unit: unit,
157
- });
158
- return samples[0];
159
- };
192
+ unit,
193
+ })
194
+ return samples[0]
195
+ }
160
196
 
161
197
  function useMostRecentWorkout<
162
198
  TEnergy extends HKUnit,
163
199
  TDistance extends HKUnit
164
- >(options?: { energyUnit?: TEnergy; distanceUnit?: TDistance }) {
200
+ >(options?: { readonly energyUnit?: TEnergy; readonly distanceUnit?: TDistance }) {
165
201
  const [workout, setWorkout] = useState<HKWorkout<TEnergy, TDistance> | null>(
166
- null
167
- );
202
+ null,
203
+ )
168
204
  useEffect(() => {
169
- let cancelSubscription: (() => Promise<boolean>) | undefined;
205
+ let cancelSubscription: (() => Promise<boolean>) | undefined
170
206
 
171
207
  const init = async () => {
172
208
  const { energyUnit, distanceUnit } = await getPreferredUnitsTyped(
173
- options
174
- );
209
+ options,
210
+ )
175
211
 
176
212
  cancelSubscription = await subscribeToChanges(
177
213
  'HKWorkoutTypeIdentifier',
178
- () => {
179
- getMostRecentWorkout({ energyUnit, distanceUnit }).then(setWorkout);
180
- }
181
- );
182
- };
183
- init();
214
+ async () => {
215
+ const w = await getMostRecentWorkout({ energyUnit, distanceUnit })
216
+ setWorkout(w)
217
+ },
218
+ )
219
+ }
220
+ void init()
184
221
  return () => {
185
- cancelSubscription && cancelSubscription();
186
- };
187
- }, [options]);
188
- return workout;
222
+ void cancelSubscription?.()
223
+ }
224
+ }, [options])
225
+ return workout
189
226
  }
190
227
 
191
228
  const getMostRecentCategorySample: GetMostRecentCategorySampleFn = async (
192
- identifier
229
+ identifier,
193
230
  ) => {
194
231
  const samples = await queryCategorySamples(identifier, {
195
232
  limit: 1,
196
233
  ascending: false,
197
- });
198
-
199
- return samples[0];
200
- };
201
-
202
- function useMostRecentCategorySample<
203
- TCategory extends HKCategoryTypeIdentifier
204
- >(identifier: TCategory) {
205
- const [category, setCategory] = useState<HKCategorySample<TCategory> | null>(
206
- null
207
- );
208
- const updater = useCallback(() => {
209
- getMostRecentCategorySample(identifier).then(setCategory);
210
- }, [identifier]);
234
+ })
211
235
 
212
- useSubscribeToChanges(identifier, updater);
213
-
214
- return category;
236
+ return samples[0]
215
237
  }
216
238
 
217
- function useSubscribeToChanges<TIdentifier extends HKSampleTypeIdentifier>(
239
+ function useSubscribeToChanges<TIdentifier extends SampleTypeIdentifier>(
218
240
  identifier: TIdentifier,
219
- onChange: () => void
241
+ onChange: () => void,
220
242
  ): void {
221
243
  useEffect(() => {
222
- let cancelSubscription: (() => Promise<boolean>) | undefined;
244
+ let cancelSubscription: (() => Promise<boolean>) | undefined
223
245
 
224
246
  const init = async () => {
225
- cancelSubscription = await subscribeToChanges(identifier, onChange);
226
- };
227
- init();
247
+ cancelSubscription = await subscribeToChanges(identifier, onChange)
248
+ }
249
+ void init()
228
250
 
229
251
  return () => {
230
- cancelSubscription && cancelSubscription();
231
- };
232
- }, [identifier, onChange]);
252
+ void cancelSubscription?.()
253
+ }
254
+ }, [identifier, onChange])
255
+ }
256
+
257
+ useSubscribeToChanges(HKCategoryTypeIdentifier.appleStandHour, () => {})
258
+
259
+ function useMostRecentCategorySample<
260
+ TCategory extends HKCategoryTypeIdentifier
261
+ >(identifier: TCategory) {
262
+ const [category, setCategory] = useState<HKCategorySample<TCategory> | null>(
263
+ null,
264
+ )
265
+ const updater = useCallback(() => {
266
+ void getMostRecentCategorySample(identifier).then(setCategory)
267
+ }, [identifier])
268
+
269
+ useSubscribeToChanges(identifier, updater)
270
+
271
+ return category
233
272
  }
234
273
 
235
274
  function useMostRecentQuantitySample<
@@ -237,41 +276,40 @@ function useMostRecentQuantitySample<
237
276
  TUnit extends HKUnit = HKUnit
238
277
  >(identifier: TIdentifier, unit?: TUnit) {
239
278
  const [lastSample, setLastSample] = useState<HKQuantitySample<
240
- TIdentifier,
241
- TUnit
242
- > | null>(null);
279
+ TIdentifier,
280
+ TUnit
281
+ > | null>(null)
243
282
 
244
283
  useEffect(() => {
245
- let cancelSubscription: (() => Promise<boolean>) | undefined;
284
+ let cancelSubscription: (() => Promise<boolean>) | undefined
246
285
 
247
286
  const init = async () => {
248
- const actualUnit = await ensureUnit(identifier, unit);
287
+ const actualUnit = await ensureUnit(identifier, unit)
249
288
 
250
- cancelSubscription = await subscribeToChanges(identifier, () => {
251
- getMostRecentQuantitySample(identifier, actualUnit).then((value) => {
252
- setLastSample(value);
253
- });
254
- });
255
- };
256
- init();
289
+ cancelSubscription = await subscribeToChanges(identifier, async () => {
290
+ const value = await getMostRecentQuantitySample(identifier, actualUnit)
291
+ setLastSample(value)
292
+ })
293
+ }
294
+ void init()
257
295
 
258
296
  return () => {
259
- cancelSubscription && cancelSubscription();
260
- };
261
- }, [identifier, unit]);
297
+ void cancelSubscription?.()
298
+ }
299
+ }, [identifier, unit])
262
300
 
263
- return lastSample;
301
+ return lastSample
264
302
  }
265
303
 
266
- const saveQuantitySample: SaveQuantitySampleFn = (
304
+ const saveQuantitySample: SaveQuantitySampleFn = async (
267
305
  identifier,
268
306
  unit,
269
307
  value,
270
- options
308
+ options,
271
309
  ) => {
272
- const start = options?.start || options?.end || new Date();
273
- const end = options?.end || options?.start || new Date();
274
- const metadata = options?.metadata || {};
310
+ const start = options?.start || options?.end || new Date()
311
+ const end = options?.end || options?.start || new Date()
312
+ const metadata = options?.metadata || {}
275
313
 
276
314
  return Native.saveQuantitySample(
277
315
  identifier,
@@ -279,131 +317,91 @@ const saveQuantitySample: SaveQuantitySampleFn = (
279
317
  value,
280
318
  start.toISOString(),
281
319
  end.toISOString(),
282
- metadata
283
- );
284
- };
320
+ metadata,
321
+ )
322
+ }
285
323
 
286
324
  const queryStatisticsForQuantity: QueryStatisticsForQuantityFn = async (
287
325
  identifier,
288
326
  options,
289
327
  from,
290
328
  to,
291
- unit
329
+ unit,
292
330
  ) => {
293
- const actualUnit = await ensureUnit(identifier, unit);
294
- const toDate = to || new Date();
295
- const { mostRecentQuantityDateInterval, ...rawResponse } =
296
- await Native.queryStatisticsForQuantity(
297
- identifier,
298
- actualUnit,
299
- from.toISOString(),
300
- toDate.toISOString(),
301
- options
302
- );
331
+ const actualUnit = await ensureUnit(identifier, unit)
332
+ const toDate = to || new Date()
333
+ const { mostRecentQuantityDateInterval, ...rawResponse } = await Native.queryStatisticsForQuantity(
334
+ identifier,
335
+ actualUnit,
336
+ from.toISOString(),
337
+ toDate.toISOString(),
338
+ options,
339
+ )
303
340
 
304
341
  const response = {
305
342
  ...rawResponse,
306
343
  ...(mostRecentQuantityDateInterval
307
344
  ? {
308
- mostRecentQuantityDateInterval: {
309
- from: new Date(mostRecentQuantityDateInterval.from),
310
- to: new Date(mostRecentQuantityDateInterval.to),
311
- },
312
- }
345
+ mostRecentQuantityDateInterval: {
346
+ from: new Date(mostRecentQuantityDateInterval.from),
347
+ to: new Date(mostRecentQuantityDateInterval.to),
348
+ },
349
+ }
313
350
  : {}),
314
- };
351
+ }
315
352
 
316
- return response;
317
- };
353
+ return response
354
+ }
318
355
 
319
- const requestAuthorization = (
320
- read: (HKCharacteristicTypeIdentifier | HKSampleTypeIdentifier)[],
321
- write: HKSampleTypeIdentifier[] = []
356
+ const requestAuthorization = async (
357
+ read: readonly HealthkitReadAuthorization[],
358
+ write: readonly HealthkitWriteAuthorization[] = [],
322
359
  ): Promise<boolean> => {
323
- const readPermissions = read.reduce((obj, cur) => {
324
- return { ...obj, [cur]: true };
325
- }, {});
360
+ const readPermissions = read.reduce((obj, cur) => ({ ...obj, [cur]: true }), {} as ReadPermissions)
326
361
 
327
- const writePermissions = write.reduce((obj, cur) => {
328
- return { ...obj, [cur]: true };
329
- }, {});
362
+ const writePermissions = write.reduce((obj, cur) => ({ ...obj, [cur]: true }), {} as WritePermissions)
330
363
 
331
- return Native.requestAuthorization(writePermissions, readPermissions);
332
- };
364
+ return Native.requestAuthorization(writePermissions, readPermissions)
365
+ }
333
366
 
334
367
  const getDateOfBirth = async () => {
335
- const dateOfBirth = await Native.getDateOfBirth();
336
- return new Date(dateOfBirth);
337
- };
368
+ const dateOfBirth = await Native.getDateOfBirth()
369
+ return new Date(dateOfBirth)
370
+ }
338
371
 
339
- const getRequestStatusForAuthorization = (
340
- read: (HKCharacteristicTypeIdentifier | HKSampleTypeIdentifier)[],
341
- write: HKSampleTypeIdentifier[] = []
372
+ const getRequestStatusForAuthorization = async (
373
+ read: readonly HealthkitReadAuthorization[],
374
+ write: readonly HealthkitWriteAuthorization[] = [],
342
375
  ) => {
343
- const readPermissions = read.reduce((obj, cur) => {
344
- return { ...obj, [cur]: true };
345
- }, {});
376
+ const readPermissions = read.reduce((obj, cur) => ({ ...obj, [cur]: true }), {} as ReadPermissions)
346
377
 
347
- const writePermissions = write.reduce((obj, cur) => {
348
- return { ...obj, [cur]: true };
349
- }, {});
378
+ const writePermissions = write.reduce((obj, cur) => ({ ...obj, [cur]: true }), {} as WritePermissions)
350
379
 
351
380
  return Native.getRequestStatusForAuthorization(
352
381
  writePermissions,
353
- readPermissions
354
- );
355
- };
382
+ readPermissions,
383
+ )
384
+ }
356
385
 
357
386
  const queryCategorySamples: QueryCategorySamplesFn = async (
358
387
  identifier,
359
- options
388
+ options,
360
389
  ) => {
361
- const opts = prepareOptions(options);
390
+ const opts = prepareOptions(options)
362
391
  const results = await Native.queryCategorySamples(
363
392
  identifier,
364
393
  opts.from,
365
394
  opts.to,
366
395
  opts.limit,
367
- opts.ascending
368
- );
396
+ opts.ascending,
397
+ )
369
398
 
370
- return results.map(deserializCategorySample);
371
- };
372
-
373
- async function getPreferredUnitsTyped<
374
- TEnergy extends HKUnit,
375
- TDistance extends HKUnit
376
- >(options?: { energyUnit?: TEnergy; distanceUnit?: TDistance }) {
377
- let energyUnit = options?.energyUnit;
378
- let distanceUnit = options?.distanceUnit;
379
- if (!energyUnit || !distanceUnit) {
380
- const units = await Native.getPreferredUnits([
381
- HKQuantityTypeIdentifier.distanceWalkingRunning,
382
- HKQuantityTypeIdentifier.activeEnergyBurned,
383
- ]);
384
- if (!energyUnit) {
385
- energyUnit = units[HKQuantityTypeIdentifier.distanceWalkingRunning] as
386
- | TEnergy
387
- | undefined;
388
- }
389
- if (!distanceUnit) {
390
- distanceUnit = units[HKQuantityTypeIdentifier.activeEnergyBurned] as
391
- | TDistance
392
- | undefined;
393
- }
394
- }
395
- if (!energyUnit) {
396
- energyUnit = HKUnit.Kilocalories as TEnergy;
397
- }
398
- if (!distanceUnit) {
399
- distanceUnit = HKUnit.Meters as TDistance;
400
- }
401
- return { energyUnit, distanceUnit };
399
+ return results.map(deserializCategorySample)
402
400
  }
403
401
 
404
402
  const queryWorkouts: QueryWorkoutsFn = async (options) => {
405
- const { energyUnit, distanceUnit } = await getPreferredUnitsTyped(options);
406
- const opts = prepareOptions(options);
403
+ const { energyUnit, distanceUnit } = await getPreferredUnitsTyped(options)
404
+ const opts = prepareOptions(options)
407
405
 
408
406
  const workouts = await Native.queryWorkoutSamples(
409
407
  energyUnit,
@@ -411,11 +409,11 @@ const queryWorkouts: QueryWorkoutsFn = async (options) => {
411
409
  opts.from,
412
410
  opts.to,
413
411
  opts.limit,
414
- opts.ascending
415
- );
412
+ opts.ascending,
413
+ )
416
414
 
417
- return workouts.map(deserializeWorkout);
418
- };
415
+ return workouts.map(deserializeWorkout)
416
+ }
419
417
 
420
418
  const getMostRecentWorkout: GetMostRecentWorkoutFn = async (options) => {
421
419
  const workouts = await queryWorkouts({
@@ -423,41 +421,39 @@ const getMostRecentWorkout: GetMostRecentWorkoutFn = async (options) => {
423
421
  ascending: false,
424
422
  energyUnit: options?.energyUnit,
425
423
  distanceUnit: options?.distanceUnit,
426
- });
424
+ })
427
425
 
428
- return workouts[0];
429
- };
426
+ return workouts[0]
427
+ }
430
428
 
431
- function saveCategorySample<T extends HKCategoryTypeIdentifier>(
429
+ async function saveCategorySample<T extends HKCategoryTypeIdentifier>(
432
430
  identifier: T,
433
431
  value: HKCategoryValueForIdentifier<T>,
434
432
  options?: {
435
- start?: Date;
436
- end?: Date;
437
- metadata?: MetadataMapperForCategoryIdentifier<T>;
438
- }
433
+ readonly start?: Date;
434
+ readonly end?: Date;
435
+ readonly metadata?: MetadataMapperForCategoryIdentifier<T>;
436
+ },
439
437
  ) {
440
- const start = options?.start || options?.end || new Date();
441
- const end = options?.end || options?.start || new Date();
442
- const metadata = options?.metadata || {};
438
+ const start = options?.start || options?.end || new Date()
439
+ const end = options?.end || options?.start || new Date()
440
+ const metadata = options?.metadata || {}
443
441
 
444
442
  return Native.saveCategorySample(
445
443
  identifier,
446
444
  value,
447
445
  start.toISOString(),
448
446
  end.toISOString(),
449
- metadata || {}
450
- );
447
+ metadata || {},
448
+ )
451
449
  }
452
450
 
453
451
  const getPreferredUnits: GetPreferredUnitsFn = async (identifiers) => {
454
- const units = await Native.getPreferredUnits(identifiers);
455
- return identifiers.map((i) => units[i]);
456
- };
452
+ const units = await Native.getPreferredUnits(identifiers)
453
+ return identifiers.map((i) => units[i])
454
+ }
457
455
 
458
- const buildUnitWithPrefix = (prefix: HKUnitSIPrefix, unit: HKUnitSI) => {
459
- return `${prefix}${unit}` as HKUnit;
460
- };
456
+ const buildUnitWithPrefix = (prefix: HKUnitSIPrefix, unit: HKUnitSI) => `${prefix}${unit}` as HKUnit
461
457
 
462
458
  function deserializeCorrelation<
463
459
  TIdentifier extends HKCorrelationTypeIdentifier
@@ -465,79 +461,78 @@ function deserializeCorrelation<
465
461
  return {
466
462
  ...s,
467
463
  objects: s.objects.map((o) => {
464
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
468
465
  // @ts-ignore
469
466
  if (o.quantity !== undefined) {
470
- return deserializeSample(o as HKQuantitySampleRaw);
467
+ return deserializeSample(o as HKQuantitySampleRaw)
471
468
  }
472
469
 
473
- return deserializCategorySample(o as HKCategorySampleRaw);
470
+ return deserializCategorySample(o as HKCategorySampleRaw)
474
471
  }),
475
472
  endDate: new Date(s.endDate),
476
473
  startDate: new Date(s.startDate),
477
- };
474
+ }
478
475
  }
479
476
 
480
477
  function ensureMetadata<TMetadata>(metadata?: TMetadata) {
481
- return metadata || ({} as TMetadata);
478
+ return metadata || ({} as TMetadata)
482
479
  }
483
480
 
484
481
  const queryCorrelationSamples: QueryCorrelationSamplesFn = async (
485
482
  typeIdentifier,
486
- options
483
+ options,
487
484
  ) => {
488
- const opts = prepareOptions(options);
485
+ const opts = prepareOptions(options)
489
486
  const correlations = await Native.queryCorrelationSamples(
490
487
  typeIdentifier,
491
488
  opts.from,
492
- opts.to
493
- );
489
+ opts.to,
490
+ )
494
491
 
495
- return correlations.map(deserializeCorrelation);
496
- };
492
+ return correlations.map(deserializeCorrelation)
493
+ }
497
494
 
498
495
  const saveCorrelationSample: SaveCorrelationSampleFn = async (
499
496
  typeIdentifier,
500
497
  samples,
501
- options
498
+ options,
502
499
  ) => {
503
- const start = (options?.start || new Date()).toISOString();
504
- const end = (options?.end || new Date()).toISOString();
500
+ const start = (options?.start || new Date()).toISOString()
501
+ const end = (options?.end || new Date()).toISOString()
505
502
 
506
503
  return Native.saveCorrelationSample(
507
504
  typeIdentifier,
508
505
  samples,
509
506
  start,
510
507
  end,
511
- ensureMetadata(options?.metadata)
512
- );
513
- };
508
+ ensureMetadata(options?.metadata),
509
+ )
510
+ }
514
511
 
515
- const saveWorkoutSample: SaveWorkoutSampleFn = (
512
+ const saveWorkoutSample: SaveWorkoutSampleFn = async (
516
513
  typeIdentifier,
517
514
  quantities,
518
515
  _start,
519
- options
516
+ options,
520
517
  ) => {
521
- const start = _start.toISOString();
522
- const end = (options?.end || new Date()).toISOString();
518
+ const start = _start.toISOString()
519
+ const end = (options?.end || new Date()).toISOString()
523
520
 
524
521
  return Native.saveWorkoutSample(
525
522
  typeIdentifier,
526
523
  quantities,
527
524
  start,
528
525
  end,
529
- ensureMetadata(options?.metadata)
530
- );
531
- };
526
+ ensureMetadata(options?.metadata),
527
+ )
528
+ }
532
529
 
533
- const getWorkoutRoutes: GetWorkoutRoutesFn = (workoutUUID: string) => {
534
- return Native.getWorkoutRoutes(workoutUUID);
535
- };
530
+ const getWorkoutRoutes: GetWorkoutRoutesFn = async (workoutUUID: string) => Native.getWorkoutRoutes(workoutUUID)
536
531
 
537
532
  const Healthkit: ReactNativeHealthkit = {
538
- authorizationStatusFor: Native.authorizationStatusFor,
533
+ authorizationStatusFor: Native.authorizationStatusFor.bind(Native),
539
534
 
540
- isHealthDataAvailable: Native.isHealthDataAvailable,
535
+ isHealthDataAvailable: Native.isHealthDataAvailable.bind(Native),
541
536
 
542
537
  buildUnitWithPrefix,
543
538
 
@@ -546,10 +541,10 @@ const Healthkit: ReactNativeHealthkit = {
546
541
  enableBackgroundDelivery: Native.enableBackgroundDelivery,
547
542
 
548
543
  // simple convenience getters
549
- getBiologicalSex: Native.getBiologicalSex,
550
- getFitzpatrickSkinType: Native.getFitzpatrickSkinType,
544
+ getBiologicalSex: Native.getBiologicalSex.bind(Native),
545
+ getFitzpatrickSkinType: Native.getFitzpatrickSkinType.bind(Native),
551
546
  getWheelchairUse: Native.getWheelchairUse,
552
- getBloodType: Native.getBloodType,
547
+ getBloodType: Native.getBloodType.bind(Native),
553
548
  getDateOfBirth,
554
549
 
555
550
  getMostRecentQuantitySample,
@@ -587,9 +582,40 @@ const Healthkit: ReactNativeHealthkit = {
587
582
  useMostRecentWorkout,
588
583
 
589
584
  useSubscribeToChanges,
590
- };
591
585
 
592
- export * from './native-types';
593
- export * from './types';
586
+ useIsHealthDataAvailable: () => {
587
+ const [isAvailable, setIsAvailable] = useState<boolean | null>(null)
588
+ useEffect(() => {
589
+ const init = async () => {
590
+ const res = await Native.isHealthDataAvailable()
591
+ setIsAvailable(res)
592
+ }
593
+ void init()
594
+ }, [])
595
+ return isAvailable
596
+ },
597
+ useHealthkitAuthorization: (read, write) => {
598
+ const [status, setStatus] = useState<HKAuthorizationRequestStatus | null>(null)
599
+ const refreshAuthStatus = useCallback(async () => {
600
+ const auth = await getRequestStatusForAuthorization(read, write)
601
+ setStatus(auth)
602
+ return auth
603
+ }, [])
604
+
605
+ const request = useCallback(async () => {
606
+ await requestAuthorization(read, write)
607
+ return refreshAuthStatus()
608
+ }, [])
609
+
610
+ useEffect(() => {
611
+ void refreshAuthStatus()
612
+ }, [])
613
+
614
+ return [status, request]
615
+ },
616
+ }
617
+
618
+ export * from './native-types'
619
+ export * from './types'
594
620
 
595
- export default Healthkit;
621
+ export default Healthkit