@tryvital/vital-health-react-native 0.3.2 → 1.1.0

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.
@@ -134,6 +134,11 @@ dependencies {
134
134
  //noinspection GradleDynamicVersion
135
135
  implementation "com.facebook.react:react-native:+"
136
136
  implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
137
+ implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1"
138
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4"
139
+ implementation 'com.github.tryVital.vital-android:VitalClient:v1.0.0-alpha.16'
140
+ implementation 'com.github.tryVital.vital-android:VitalHealthConnect:v1.0.0-alpha.16'
141
+ implementation "androidx.health.connect:connect-client:1.0.0-alpha08"
137
142
  // From node_modules
138
143
  }
139
144
 
@@ -1,5 +1,5 @@
1
1
  VitalHealthReactNative_kotlinVersion=1.7.0
2
- VitalHealthReactNative_minSdkVersion=21
2
+ VitalHealthReactNative_minSdkVersion=26
3
3
  VitalHealthReactNative_targetSdkVersion=31
4
4
  VitalHealthReactNative_compileSdkVersion=31
5
5
  VitalHealthReactNative_ndkversion=21.4.7075529
@@ -0,0 +1,19 @@
1
+ package com.vitalhealthreactnative
2
+
3
+ sealed class VitalHealthEvent(val value: String) {
4
+ object Status : VitalHealthEvent("Status")
5
+
6
+ companion object {
7
+ fun values(): Array<VitalHealthEvent> {
8
+ return arrayOf(Status)
9
+ }
10
+
11
+ fun valueOf(value: String): VitalHealthEvent {
12
+ return when (value) {
13
+ "Status" -> Status
14
+ else -> throw IllegalArgumentException("Invalid VitalHealthEvent value: $value")
15
+ }
16
+ }
17
+ }
18
+
19
+ }
@@ -1,49 +1,410 @@
1
1
  package com.vitalhealthreactnative
2
2
 
3
- import com.facebook.react.bridge.ReactApplicationContext
4
- import com.facebook.react.bridge.ReactContextBaseJavaModule
5
- import com.facebook.react.bridge.ReactMethod
6
- import com.facebook.react.bridge.Promise
3
+ import android.app.Activity
4
+ import android.content.Intent
5
+ import android.util.Log
6
+ import androidx.health.connect.client.PermissionController
7
+ import androidx.health.connect.client.permission.HealthPermission
8
+ import androidx.health.connect.client.records.*
9
+ import com.facebook.react.bridge.*
10
+ import com.facebook.react.modules.core.DeviceEventManagerModule
11
+ import io.tryvital.client.Environment
12
+ import io.tryvital.client.Region
13
+ import io.tryvital.client.VitalClient
14
+ import io.tryvital.client.utils.VitalLogger
15
+ import io.tryvital.vitalhealthconnect.VitalHealthConnectManager
16
+ import io.tryvital.vitalhealthconnect.model.HealthResource
17
+ import io.tryvital.vitalhealthconnect.model.SyncStatus
18
+ import kotlinx.coroutines.*
19
+ import java.time.Instant
20
+ import kotlin.reflect.KClass
7
21
 
8
22
  class VitalHealthReactNativeModule(reactContext: ReactApplicationContext) :
9
- ReactContextBaseJavaModule(reactContext) {
23
+ ReactContextBaseJavaModule(reactContext), ActivityEventListener {
24
+
25
+ private val logger = VitalLogger.create()
26
+
27
+ private var vitalClient: VitalClient? = null
28
+ private var vitalHealthConnectManager: VitalHealthConnectManager? = null
29
+
30
+ private var askForResourcesResult: Promise? = null
31
+ private var askedHealthPermissions: Set<HealthPermission>? = null
32
+
33
+ private var mainScope: CoroutineScope? = null
34
+ private var statusScope: CoroutineScope? = null
35
+ private var writeScope: CoroutineScope? = null
10
36
 
11
37
  override fun getName(): String {
12
38
  return NAME
13
39
  }
14
40
 
41
+ init {
42
+ reactContext.addActivityEventListener(this)
43
+ }
44
+
15
45
  @ReactMethod
16
46
  fun configure(
17
- backgroundDeliveryEnabled: Boolean,
47
+ syncOnAppStart: Boolean,
18
48
  numberOfDaysToBackFill: Int,
19
49
  enableLogs: Boolean,
20
50
  promise: Promise
21
51
  ) {
52
+ if (vitalClient == null) {
53
+ promise.reject(
54
+ "VitalClient is not configured",
55
+ "VitalClient is not configured",
56
+ )
57
+ }
58
+
59
+ vitalHealthConnectManager = VitalHealthConnectManager.create(
60
+ reactApplicationContext,
61
+ vitalClient!!.apiKey,
62
+ vitalClient!!.region,
63
+ vitalClient!!.environment
64
+ )
65
+
66
+ mainScope?.cancel()
67
+ mainScope = MainScope()
68
+ mainScope!!.launch {
69
+ vitalHealthConnectManager!!.configureHealthConnectClient(
70
+ logsEnabled = enableLogs,
71
+ syncOnAppStart = syncOnAppStart,
72
+ numberOfDaysToBackFill = numberOfDaysToBackFill,
73
+ )
74
+ }
75
+
76
+ startStatusUpdate()
77
+
22
78
  promise.resolve(null)
23
79
  }
24
80
 
25
81
  @ReactMethod
26
- fun askForResources(resources: List<String>, promise: Promise) {
82
+ fun setUserId(userId: String, promise: Promise) {
83
+ if (vitalHealthConnectManager == null) {
84
+ promise.reject(
85
+ "VitalHealthConnect is not configured",
86
+ "VitalHealthConnect is not configured",
87
+ )
88
+ return
89
+ }
90
+
91
+ mainScope?.cancel()
92
+ mainScope = MainScope()
93
+ mainScope!!.launch {
94
+ vitalHealthConnectManager!!.setUserId(userId)
95
+ promise.resolve(null)
96
+ }
97
+ }
98
+
99
+ @ReactMethod
100
+ fun configureClient(
101
+ apiKey: String,
102
+ environment: String,
103
+ region: String,
104
+ enableLogs: Boolean,
105
+ promise: Promise
106
+ ) {
107
+ logger.enabled = enableLogs
108
+
109
+ vitalClient = VitalClient(
110
+ reactApplicationContext,
111
+ stringToRegion(region),
112
+ stringToEnvironment(environment),
113
+ apiKey
114
+ )
115
+
27
116
  promise.resolve(null)
28
117
  }
29
118
 
119
+ @ReactMethod
120
+ fun askForResources(
121
+ resources: ReadableArray,
122
+ promise: Promise
123
+ ) {
124
+ return ask(resources, null, promise)
125
+ }
126
+
127
+ @ReactMethod
128
+ fun ask(
129
+ readResources: ReadableArray,
130
+ writeResources: ReadableArray?,
131
+ promise: Promise
132
+ ) {
133
+ val requestPermissionActivityContract =
134
+ PermissionController.createRequestPermissionResultContract()
135
+ val healthPermissions =
136
+ readResources.toArrayList().toList().map { mapReadResourceToHealthRecord(it as String) }
137
+ .flatten()
138
+ .map { HealthPermission.createReadPermission(it) }.toSet().plus(
139
+ writeResources?.toArrayList()?.toList()
140
+ ?.map { mapWriteResourceToHealthRecord(it as String) }
141
+ ?.flatten()
142
+ ?.map { HealthPermission.createWritePermission(it) }?.toSet() ?: emptySet()
143
+ )
144
+
145
+ askForResourcesResult = promise
146
+ askedHealthPermissions = healthPermissions
147
+
148
+ currentActivity?.startActivityForResult(
149
+ requestPermissionActivityContract.createIntent(
150
+ reactApplicationContext,
151
+ healthPermissions
152
+ ), 666
153
+ )
154
+ }
155
+
30
156
  @ReactMethod
31
157
  fun hasAskedForPermission(resource: String, promise: Promise) {
32
- promise.resolve(null)
158
+ promise.resolve(false)
33
159
  }
34
160
 
35
161
  @ReactMethod
36
- fun syncData(resources: List<String>, promise: Promise) {
37
- promise.resolve(null)
162
+ fun syncData(resources: ReadableArray, promise: Promise) {
163
+ if (vitalHealthConnectManager == null) {
164
+ promise.reject(
165
+ "VitalHealthConnect is not configured",
166
+ "VitalHealthConnect is not configured",
167
+ )
168
+ return
169
+ }
170
+
171
+ mainScope?.cancel()
172
+ mainScope = MainScope()
173
+ mainScope!!.launch {
174
+ vitalHealthConnectManager!!.syncData(
175
+ resources.toArrayList().toList().mapNotNull { mapStringToHealthResource(it as String) }
176
+ .toSet()
177
+ )
178
+ promise.resolve(null)
179
+ }
38
180
  }
39
181
 
40
182
  @ReactMethod
41
183
  fun cleanUp(promise: Promise) {
184
+ statusScope?.cancel()
185
+ writeScope?.cancel()
186
+ mainScope?.cancel()
187
+
42
188
  promise.resolve(null)
43
189
  }
44
190
 
191
+ @ReactMethod
192
+ private fun writeHealthData(
193
+ resource: String,
194
+ startDate: Long,
195
+ endDate: Long,
196
+ value: Double,
197
+ promise: Promise
198
+ ) {
199
+ if (vitalHealthConnectManager == null) {
200
+ promise.reject(
201
+ "VitalHealthConnect is not configured",
202
+ "VitalHealthConnect is not configured",
203
+ )
204
+ return
205
+ }
206
+
207
+ writeScope?.cancel()
208
+ writeScope = MainScope()
209
+ writeScope!!.launch {
210
+ try {
211
+ vitalHealthConnectManager!!.addHealthResource(
212
+ mapStringToHealthResource(resource)!!,
213
+ startDate = Instant.ofEpochMilli(startDate),
214
+ endDate = Instant.ofEpochMilli(endDate),
215
+ value = value,
216
+ )
217
+ promise.resolve(null)
218
+ } catch (e: Exception) {
219
+ promise.reject(
220
+ "Failed to write data",
221
+ e.message,
222
+ e
223
+ )
224
+ }
225
+ }
226
+ }
227
+
228
+ @ReactMethod
229
+ fun addListener(eventName: String?) {
230
+ // Keep: Required for RN built in Event Emitter Calls.
231
+ }
232
+
233
+ @ReactMethod
234
+ fun removeListeners(count: Int) {
235
+ // Keep: Required for RN built in Event Emitter Calls.
236
+ }
237
+
238
+ private fun startStatusUpdate() {
239
+ statusScope?.cancel()
240
+ statusScope = MainScope()
241
+ statusScope?.launch {
242
+ try {
243
+ withContext(Dispatchers.Default) {
244
+ vitalHealthConnectManager?.status?.collect {
245
+ logger.logI("Status: $it")
246
+ withContext(Dispatchers.Main) {
247
+ when (it) {
248
+ is SyncStatus.ResourceSyncFailed -> {
249
+ sendEvent(VitalHealthEvent.Status, WritableNativeMap().apply {
250
+ putString("status", "failedSyncing")
251
+ putString("resource", it.resource.name)
252
+ })
253
+ }
254
+ is SyncStatus.ResourceNothingToSync -> {
255
+ sendEvent(VitalHealthEvent.Status, WritableNativeMap().apply {
256
+ putString("status", "nothingToSync")
257
+ putString("resource", it.resource.name)
258
+ })
259
+ }
260
+ is SyncStatus.ResourceSyncing -> {
261
+ sendEvent(VitalHealthEvent.Status, WritableNativeMap().apply {
262
+ putString("status", "syncing")
263
+ putString("resource", it.resource.name)
264
+ })
265
+ }
266
+ is SyncStatus.ResourceSyncingComplete -> {
267
+ sendEvent(VitalHealthEvent.Status, WritableNativeMap().apply {
268
+ putString("status", "successSyncing")
269
+ putString("resource", it.resource.name)
270
+ })
271
+ }
272
+ SyncStatus.SyncingCompleted -> {
273
+ sendEvent(VitalHealthEvent.Status, WritableNativeMap().apply {
274
+ putString("status", "syncingCompleted")
275
+ })
276
+ }
277
+ SyncStatus.Unknown -> {
278
+ sendEvent(VitalHealthEvent.Status, WritableNativeMap().apply {
279
+ putString("status", "unknown")
280
+ })
281
+ }
282
+ }
283
+ }
284
+ }
285
+ }
286
+ } catch (e: Exception) {
287
+ withContext(Dispatchers.Main) {
288
+ sendEvent(VitalHealthEvent.Status, WritableNativeMap().apply {
289
+ putString("status", "failedSyncing")
290
+ })
291
+ }
292
+ }
293
+ }
294
+ }
295
+
296
+ private fun sendEvent(event: VitalHealthEvent, params: Any) {
297
+ try {
298
+ reactApplicationContext
299
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
300
+ .emit(event.value, params)
301
+ } catch (e: Exception) {
302
+ Log.e("VitalHealth", "sendEvent: $e")
303
+ }
304
+ }
305
+
306
+ override fun getConstants(): MutableMap<String, Any> {
307
+ return VitalHealthEvent.values().associate { it.value to it.value }.toMutableMap()
308
+ }
45
309
 
46
310
  companion object {
47
311
  const val NAME = "VitalHealthReactNative"
48
312
  }
313
+
314
+ override fun onActivityResult(p0: Activity?, p1: Int, p2: Int, p3: Intent?) {
315
+ if (p1 == 666) {
316
+ mainScope?.cancel()
317
+ mainScope = MainScope()
318
+ mainScope!!.launch {
319
+ val grantedPermissions =
320
+ vitalHealthConnectManager!!.getGrantedPermissions(reactApplicationContext).toSet()
321
+
322
+ val notGrantedPermissions = (askedHealthPermissions
323
+ ?: emptySet()).filter { !grantedPermissions.contains(it) }
324
+
325
+ if (notGrantedPermissions.isEmpty()) {
326
+ askForResourcesResult?.resolve(true)
327
+ } else {
328
+ vitalClient?.vitalLogger?.logI("Not granted permissions: $notGrantedPermissions")
329
+ askForResourcesResult?.resolve(false)
330
+ }
331
+ askedHealthPermissions = null
332
+ askForResourcesResult = null
333
+ }
334
+ }
335
+ }
336
+
337
+ override fun onNewIntent(p0: Intent?) {
338
+ // Not used
339
+ }
340
+ }
341
+
342
+ private fun stringToRegion(region: String): Region {
343
+ when (region) {
344
+ "eu" -> return Region.EU
345
+ "us" -> return Region.US
346
+ }
347
+
348
+ throw Exception("Unsupported region $region")
349
+ }
350
+
351
+ private fun stringToEnvironment(environment: String): Environment {
352
+ when (environment) {
353
+ "production" -> return Environment.Production
354
+ "sandbox" -> return Environment.Sandbox
355
+ "dev" -> return Environment.Dev
356
+ }
357
+
358
+ throw Exception("Unsupported environment $environment")
359
+ }
360
+
361
+ private fun mapReadResourceToHealthRecord(resource: String): List<KClass<out Record>> {
362
+ when (resource) {
363
+ "profile" -> return listOf(HeightRecord::class, WeightRecord::class)
364
+ "body" -> return listOf(BodyFatRecord::class)
365
+ "workout" -> return listOf(ExerciseSessionRecord::class)
366
+ "activity" -> return listOf(
367
+ ActiveCaloriesBurnedRecord::class,
368
+ BasalMetabolicRateRecord::class,
369
+ StepsRecord::class,
370
+ DistanceRecord::class,
371
+ FloorsClimbedRecord::class,
372
+ Vo2MaxRecord::class
373
+ )
374
+ "sleep" -> return listOf(SleepSessionRecord::class)
375
+ "glucose" -> return listOf(BloodGlucoseRecord::class)
376
+ "bloodPressure" -> return listOf(BloodPressureRecord::class)
377
+ "heartRate" -> return listOf(HeartRateVariabilitySdnnRecord::class)
378
+ "steps" -> return listOf(StepsRecord::class)
379
+ "activeEnergyBurned" -> return listOf(ActiveCaloriesBurnedRecord::class)
380
+ "basalEnergyBurned" -> return listOf(BasalMetabolicRateRecord::class)
381
+ "water" -> return listOf(HydrationRecord::class)
382
+ }
383
+ return listOf()
384
+ }
385
+
386
+ private fun mapWriteResourceToHealthRecord(resource: String): List<KClass<out Record>> {
387
+ when (resource) {
388
+ "water" -> return listOf(HydrationRecord::class)
389
+ }
390
+
391
+ return listOf()
392
+ }
393
+
394
+ private fun mapStringToHealthResource(resource: String): HealthResource? {
395
+ return when (resource) {
396
+ "profile" -> return HealthResource.Profile
397
+ "body" -> return HealthResource.Body
398
+ "workout" -> return HealthResource.Workout
399
+ "activity" -> return HealthResource.Activity
400
+ "sleep" -> return HealthResource.Sleep
401
+ "glucose" -> return HealthResource.Glucose
402
+ "bloodPressure" -> return HealthResource.BloodPressure
403
+ "heartRate" -> return HealthResource.HeartRate
404
+ "steps" -> return HealthResource.Steps
405
+ "activeEnergyBurned" -> return HealthResource.ActiveEnergyBurned
406
+ "basalEnergyBurned" -> return HealthResource.BasalEnergyBurned
407
+ "water" -> return HealthResource.Water
408
+ else -> null
409
+ }
49
410
  }
@@ -8,6 +8,17 @@ RCT_EXTERN_METHOD(configure:(BOOL)backgroundDeliveryEnabled
8
8
  resolver:(RCTPromiseResolveBlock)resolve
9
9
  rejecter:(RCTPromiseRejectBlock)reject)
10
10
 
11
+ RCT_EXTERN_METHOD(setUserId:(NSString *)userId
12
+ resolver:(RCTPromiseResolveBlock)resolve
13
+ rejecter:(RCTPromiseRejectBlock)reject)
14
+
15
+ RCT_EXTERN_METHOD(configureClient:(NSString *)apiKey
16
+ environment:(NSString *)environment
17
+ region:(NSString *)region
18
+ enableLogs:(BOOL)enableLogs
19
+ resolver:(RCTPromiseResolveBlock)resolve
20
+ rejecter:(RCTPromiseRejectBlock)reject)
21
+
11
22
  RCT_EXTERN_METHOD(askForResources:(NSArray<NSString *> *)resources
12
23
  resolver:(RCTPromiseResolveBlock)resolve
13
24
  rejecter:(RCTPromiseRejectBlock)reject)
@@ -41,12 +41,12 @@ class VitalHealthReactNative: RCTEventEmitter {
41
41
  payload["status"] = "completed"
42
42
  }
43
43
 
44
- self.sendEvent(withName: "status", body: payload)
44
+ self.sendEvent(withName: "Status", body: payload)
45
45
  }
46
46
  }
47
47
 
48
48
  override func supportedEvents() -> [String]! {
49
- return ["status"]
49
+ return ["Status"]
50
50
  }
51
51
 
52
52
  @objc(configure:numberOfDaysToBackFill:enableLogs:resolver:rejecter:)
@@ -69,6 +69,49 @@ class VitalHealthReactNative: RCTEventEmitter {
69
69
  }
70
70
  }
71
71
 
72
+ @objc(setUserId:resolver:rejecter:)
73
+ func setUserId(_ userId: String, resolve: @escaping RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) {
74
+ guard let userId = UUID.init(uuidString: userId) else {
75
+ reject(nil, "userId must be an UUID", nil)
76
+ return
77
+ }
78
+
79
+ Task {
80
+ await VitalClient.setUserId(userId)
81
+ resolve(())
82
+ }
83
+ }
84
+
85
+ @objc(configureClient:environment:region:enableLogs:resolver:rejecter:)
86
+ func configureClient(
87
+ _ apiKey: String,
88
+ environment: String,
89
+ region: String,
90
+ enableLogs: Bool,
91
+ resolve:@escaping RCTPromiseResolveBlock,
92
+ reject:RCTPromiseRejectBlock
93
+ ) {
94
+
95
+ let env: Environment
96
+ switch (environment, region) {
97
+ case ("production", "us"):
98
+ env = .production(.us)
99
+ case ("production", "eu"):
100
+ env = .production(.eu)
101
+ case ("sandbox", "us"):
102
+ env = .sandbox(.us)
103
+ case ("sandbox", "eu"):
104
+ env = .sandbox(.eu)
105
+ default:
106
+ reject(nil, "enviroment / region values not accepted", nil)
107
+ return
108
+ }
109
+
110
+ Task {
111
+ await VitalClient.configure(apiKey: apiKey, environment: env, configuration: .init(logsEnable: enableLogs))
112
+ resolve(())
113
+ }
114
+ }
72
115
 
73
116
  @objc(ask:writeResources:resolver:rejecter:)
74
117
  func ask(
@@ -0,0 +1,13 @@
1
+ export declare class HealthConfig {
2
+ logsEnabled: boolean;
3
+ numberOfDaysToBackFill: number;
4
+ androidConfig: AndroidHealthConfig;
5
+ iOSConfig: IOSHealthConfig;
6
+ }
7
+ export declare class AndroidHealthConfig {
8
+ syncOnAppStart: boolean;
9
+ }
10
+ export declare class IOSHealthConfig {
11
+ dataPushMode: string;
12
+ backgroundDeliveryEnabled: boolean;
13
+ }
@@ -0,0 +1,13 @@
1
+ export class HealthConfig {
2
+ logsEnabled = true;
3
+ numberOfDaysToBackFill = 90;
4
+ androidConfig = new AndroidHealthConfig();
5
+ iOSConfig = new IOSHealthConfig();
6
+ }
7
+ export class AndroidHealthConfig {
8
+ syncOnAppStart = true;
9
+ }
10
+ export class IOSHealthConfig {
11
+ dataPushMode = 'automatic';
12
+ backgroundDeliveryEnabled = true;
13
+ }
package/lib/index.d.ts CHANGED
@@ -1,7 +1,14 @@
1
1
  import { NativeEventEmitter } from 'react-native';
2
+ import type { HealthConfig } from './health_config';
3
+ export declare const VitalHealthReactNativeModule: any;
4
+ export declare const VitalHealthEvents: {
5
+ statusEvent: string;
6
+ };
2
7
  export declare class VitalHealth {
3
8
  static status: NativeEventEmitter;
4
- static configure(backgroundDeliveryEnabled: boolean, numberOfDaysToBackFill: number, enableLogs: boolean): Promise<void>;
9
+ static configure(healthConfig: HealthConfig): Promise<void>;
10
+ static setUserId(userId: string): Promise<void>;
11
+ static configureClient(apiKey: string, environment: string, region: string, enableLogs: boolean): Promise<void>;
5
12
  static askForResources(resources: VitalResource[]): Promise<void>;
6
13
  static ask(readResources: VitalResource[], writeResources: VitalWriteResource[]): Promise<void>;
7
14
  static writeHealthData(resource: VitalWriteResource, value: number, startDate: Date, endDate: Date): Promise<void>;
package/lib/index.js CHANGED
@@ -10,10 +10,25 @@ const VitalHealthReactNative = NativeModules.VitalHealthReactNative
10
10
  throw new Error(LINKING_ERROR);
11
11
  },
12
12
  });
13
+ export const VitalHealthReactNativeModule = VitalHealthReactNative;
14
+ export const VitalHealthEvents = {
15
+ statusEvent: 'Status',
16
+ };
13
17
  export class VitalHealth {
14
18
  static status = new NativeEventEmitter(VitalHealthReactNative);
15
- static configure(backgroundDeliveryEnabled, numberOfDaysToBackFill, enableLogs) {
16
- return VitalHealthReactNative.configure(backgroundDeliveryEnabled, numberOfDaysToBackFill, enableLogs);
19
+ static configure(healthConfig) {
20
+ if (Platform.OS === 'android') {
21
+ return VitalHealthReactNative.configure(healthConfig.androidConfig.syncOnAppStart, healthConfig.numberOfDaysToBackFill, healthConfig.logsEnabled);
22
+ }
23
+ else {
24
+ return VitalHealthReactNative.configure(healthConfig.iOSConfig.backgroundDeliveryEnabled, healthConfig.numberOfDaysToBackFill, healthConfig.logsEnabled);
25
+ }
26
+ }
27
+ static setUserId(userId) {
28
+ return VitalHealthReactNative.setUserId(userId);
29
+ }
30
+ static configureClient(apiKey, environment, region, enableLogs) {
31
+ return VitalHealthReactNative.configureClient(apiKey, environment, region, enableLogs);
17
32
  }
18
33
  static askForResources(resources) {
19
34
  return VitalHealthReactNative.ask(resources, []);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tryvital/vital-health-react-native",
3
- "version": "0.3.2",
3
+ "version": "1.1.0",
4
4
  "description": "Client to access iOS's HealthKit and Android HealthConnect",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -30,7 +30,6 @@
30
30
  "test": "jest",
31
31
  "typescript": "tsc --declaration",
32
32
  "lint": "eslint \"**/*.{js,ts,tsx}\"",
33
- "release": "release-it",
34
33
  "example": "yarn --cwd example",
35
34
  "bootstrap": "yarn example && yarn install && yarn example pods",
36
35
  "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build"
@@ -54,14 +53,10 @@
54
53
  "react-native": "*"
55
54
  },
56
55
  "devDependencies": {
57
- "@arkweid/lefthook": "^0.7.7",
58
- "@commitlint/config-conventional": "^17.0.2",
59
56
  "@react-native-community/eslint-config": "^3.0.2",
60
- "@release-it/conventional-changelog": "^5.0.0",
61
57
  "@types/jest": "^28.1.2",
62
58
  "@types/react": "~17.0.21",
63
59
  "@types/react-native": "0.70.0",
64
- "commitlint": "^17.0.2",
65
60
  "del-cli": "^5.0.0",
66
61
  "eslint": "^8.4.1",
67
62
  "eslint-config-prettier": "^8.5.0",
@@ -74,7 +69,6 @@
74
69
  "react-native": "0.70.6",
75
70
  "react-native-builder-bob": "^0.20.2",
76
71
  "react-native-version": "^4.0.0",
77
- "release-it": "^15.0.0",
78
72
  "typescript": "^4.5.2"
79
73
  },
80
74
  "resolutions": {
@@ -91,28 +85,6 @@
91
85
  "<rootDir>/lib/"
92
86
  ]
93
87
  },
94
- "commitlint": {
95
- "extends": [
96
- "@commitlint/config-conventional"
97
- ]
98
- },
99
- "release-it": {
100
- "git": {
101
- "commitMessage": "chore: release ${version}",
102
- "tagName": "v${version}"
103
- },
104
- "npm": {
105
- "publish": true
106
- },
107
- "github": {
108
- "release": true
109
- },
110
- "plugins": {
111
- "@release-it/conventional-changelog": {
112
- "preset": "angular"
113
- }
114
- }
115
- },
116
88
  "eslintConfig": {
117
89
  "root": true,
118
90
  "extends": [
@@ -0,0 +1,15 @@
1
+ export class HealthConfig {
2
+ logsEnabled = true;
3
+ numberOfDaysToBackFill = 90;
4
+ androidConfig = new AndroidHealthConfig();
5
+ iOSConfig = new IOSHealthConfig();
6
+ }
7
+
8
+ export class AndroidHealthConfig {
9
+ syncOnAppStart = true;
10
+ }
11
+
12
+ export class IOSHealthConfig {
13
+ dataPushMode = 'automatic';
14
+ backgroundDeliveryEnabled = true;
15
+ }
package/src/index.tsx CHANGED
@@ -1,4 +1,5 @@
1
1
  import { NativeEventEmitter, NativeModules, Platform } from 'react-native';
2
+ import type { HealthConfig } from './health_config';
2
3
 
3
4
  const LINKING_ERROR =
4
5
  `The package 'vital-health-react-native' doesn't seem to be linked. Make sure: \n\n` +
@@ -17,17 +18,45 @@ const VitalHealthReactNative = NativeModules.VitalHealthReactNative
17
18
  }
18
19
  );
19
20
 
21
+ export const VitalHealthReactNativeModule = VitalHealthReactNative;
22
+
23
+ export const VitalHealthEvents = {
24
+ statusEvent: 'Status',
25
+ };
26
+
20
27
  export class VitalHealth {
21
28
  static status = new NativeEventEmitter(VitalHealthReactNative);
22
29
 
23
- static configure(
24
- backgroundDeliveryEnabled: boolean,
25
- numberOfDaysToBackFill: number,
30
+ static configure(healthConfig: HealthConfig): Promise<void> {
31
+ if (Platform.OS === 'android') {
32
+ return VitalHealthReactNative.configure(
33
+ healthConfig.androidConfig.syncOnAppStart,
34
+ healthConfig.numberOfDaysToBackFill,
35
+ healthConfig.logsEnabled
36
+ );
37
+ } else {
38
+ return VitalHealthReactNative.configure(
39
+ healthConfig.iOSConfig.backgroundDeliveryEnabled,
40
+ healthConfig.numberOfDaysToBackFill,
41
+ healthConfig.logsEnabled
42
+ );
43
+ }
44
+ }
45
+
46
+ static setUserId(userId: string): Promise<void> {
47
+ return VitalHealthReactNative.setUserId(userId);
48
+ }
49
+
50
+ static configureClient(
51
+ apiKey: string,
52
+ environment: string,
53
+ region: string,
26
54
  enableLogs: boolean
27
55
  ): Promise<void> {
28
- return VitalHealthReactNative.configure(
29
- backgroundDeliveryEnabled,
30
- numberOfDaysToBackFill,
56
+ return VitalHealthReactNative.configureClient(
57
+ apiKey,
58
+ environment,
59
+ region,
31
60
  enableLogs
32
61
  );
33
62
  }