@tryvital/vital-health-react-native 0.3.0 → 0.3.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.
@@ -12,6 +12,18 @@ RCT_EXTERN_METHOD(askForResources:(NSArray<NSString *> *)resources
12
12
  resolver:(RCTPromiseResolveBlock)resolve
13
13
  rejecter:(RCTPromiseRejectBlock)reject)
14
14
 
15
+ RCT_EXTERN_METHOD(ask:(NSArray<NSString *> *)readResources
16
+ writeResources:(NSArray<NSString *> *)writeResources
17
+ resolver:(RCTPromiseResolveBlock)resolve
18
+ rejecter:(RCTPromiseRejectBlock)reject)
19
+
20
+ RCT_EXTERN_METHOD(writeHealthData:(NSString *)resource
21
+ value:(double)value
22
+ startDate:(double)startDate
23
+ endDate:(double)endDate
24
+ resolver:(RCTPromiseResolveBlock)resolve
25
+ rejecter:(RCTPromiseRejectBlock)reject)
26
+
15
27
  RCT_EXTERN_METHOD(cleanUp:(RCTPromiseResolveBlock)resolve
16
28
  rejecter:(RCTPromiseRejectBlock)reject)
17
29
 
@@ -18,17 +18,17 @@ class VitalHealthReactNative: RCTEventEmitter {
18
18
 
19
19
  cancellable = VitalHealthKitClient.shared.status.sink { status in
20
20
  var payload: [String: String] = [:]
21
-
21
+
22
22
  switch status {
23
23
  case let .failedSyncing(resource, error):
24
24
  payload["resource"] = String(describing: resource)
25
25
  payload["status"] = "failedSyncing"
26
26
  payload["extra"] = error?.localizedDescription
27
-
27
+
28
28
  case let .nothingToSync(resource):
29
29
  payload["resource"] = String(describing: resource)
30
30
  payload["status"] = "nothingToSync"
31
-
31
+
32
32
  case let .successSyncing(resource, _):
33
33
  payload["resource"] = String(describing: resource)
34
34
  payload["status"] = "successSyncing"
@@ -36,11 +36,11 @@ class VitalHealthReactNative: RCTEventEmitter {
36
36
  case let .syncing(resource):
37
37
  payload["resource"] = String(describing: resource)
38
38
  payload["status"] = "syncing"
39
-
39
+
40
40
  case .syncingCompleted:
41
41
  payload["status"] = "completed"
42
42
  }
43
-
43
+
44
44
  self.sendEvent(withName: "status", body: payload)
45
45
  }
46
46
  }
@@ -70,17 +70,18 @@ class VitalHealthReactNative: RCTEventEmitter {
70
70
  }
71
71
 
72
72
 
73
- @objc(askForResources:resolver:rejecter:)
74
- func askForResources(
75
- _ resources: [String],
73
+ @objc(ask:writeResources:resolver:rejecter:)
74
+ func ask(
75
+ _ readResources: [String],
76
+ writeResources: [String],
76
77
  resolve: @escaping RCTPromiseResolveBlock,
77
78
  reject: @escaping RCTPromiseRejectBlock
78
79
  ) {
79
80
  Task {
80
81
  do {
81
-
82
- let readPermissions = try resources.map { try mapResourceToVitalResource($0) }
83
- let outcome = await VitalHealthKitClient.shared.ask(readPermissions: readPermissions, writePermissions: [])
82
+ let readPermissions = try readResources.map { try mapResourceToReadableVitalResource($0) }
83
+ let writePermissions = try writeResources.map { try mapResourceToWritableVitalResource($0) }
84
+ let outcome = await VitalHealthKitClient.shared.ask(readPermissions: readPermissions, writePermissions: writePermissions)
84
85
 
85
86
  switch outcome {
86
87
  case .success:
@@ -105,7 +106,7 @@ class VitalHealthReactNative: RCTEventEmitter {
105
106
  reject: RCTPromiseRejectBlock
106
107
  ) {
107
108
  do {
108
- try VitalHealthKitClient.shared.syncData(for: resources.map { try mapResourceToVitalResource($0) })
109
+ try VitalHealthKitClient.shared.syncData(for: resources.map { try mapResourceToReadableVitalResource($0) })
109
110
  resolve(())
110
111
  } catch VitalError.UnsupportedResource(let errorMessage) {
111
112
  reject("UnsupportedResource", errorMessage, nil)
@@ -125,7 +126,7 @@ class VitalHealthReactNative: RCTEventEmitter {
125
126
  @objc(hasAskedForPermission:resolver:rejecter:)
126
127
  func hasAskedForPermission(_ resource: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
127
128
  do {
128
- let vitalResource = try mapResourceToVitalResource(resource)
129
+ let vitalResource = try mapResourceToReadableVitalResource(resource)
129
130
  let value: Bool = VitalHealthKitClient.shared.hasAskedForPermission(resource: vitalResource)
130
131
  resolve(value)
131
132
  } catch VitalError.UnsupportedResource(let errorMessage) {
@@ -134,9 +135,48 @@ class VitalHealthReactNative: RCTEventEmitter {
134
135
  reject(nil, "Unknown error", nil)
135
136
  }
136
137
  }
138
+
139
+ @objc(writeHealthData:value:startDate:endDate:resolver:rejecter:)
140
+ func writeHealthData(_ resource: String,
141
+ value: Double,
142
+ startDate: Double,
143
+ endDate: Double,
144
+ resolve: @escaping RCTPromiseResolveBlock,
145
+ reject: RCTPromiseRejectBlock
146
+ ){
147
+ do {
148
+ let resource = try mapResourceToReadableVitalResource(resource)
149
+
150
+ let startDate = Date(timeIntervalSince1970: startDate / 1000)
151
+ let endDate = Date(timeIntervalSince1970: endDate / 1000)
152
+
153
+ let dataInput: DataInput
154
+
155
+ switch resource {
156
+ case .nutrition(.water):
157
+ dataInput = .water(milliliters: Int(value))
158
+ case .nutrition(.caffeine):
159
+ dataInput = .caffeine(grams: Int(value))
160
+ case .vitals(.mindfulSession):
161
+ dataInput = .mindfulSession
162
+ default:
163
+ fatalError("\(resource) not supported for writing to HealthKit")
164
+ }
165
+
166
+ Task {
167
+ try await VitalHealthKitClient.shared.write(input: dataInput, startDate: startDate, endDate: endDate)
168
+ resolve(())
169
+ }
170
+ } catch VitalError.UnsupportedResource(let errorMessage) {
171
+ reject("UnsupportedResource", errorMessage, nil)
172
+ } catch {
173
+ reject(nil, "Unknown error", nil)
174
+ }
175
+ }
176
+
137
177
  }
138
178
 
139
- private func mapResourceToVitalResource(_ name: String) throws -> VitalResource {
179
+ private func mapResourceToReadableVitalResource(_ name: String) throws -> VitalResource {
140
180
  switch name {
141
181
  case "profile":
142
182
  return .profile
@@ -154,6 +194,8 @@ private func mapResourceToVitalResource(_ name: String) throws -> VitalResource
154
194
  return .vitals(.bloodPressure)
155
195
  case "heartRate":
156
196
  return .vitals(.hearthRate)
197
+ case "mindfulSession":
198
+ return .vitals(.mindfulSession)
157
199
  case "steps":
158
200
  return .individual(.steps)
159
201
  case "activeEnergyBurned":
@@ -170,6 +212,23 @@ private func mapResourceToVitalResource(_ name: String) throws -> VitalResource
170
212
  return .individual(.weight)
171
213
  case "bodyFat":
172
214
  return .individual(.bodyFat)
215
+ case "water":
216
+ return .nutrition(.water)
217
+ case "caffeine":
218
+ return .nutrition(.caffeine)
219
+ default:
220
+ throw VitalError.UnsupportedResource(name)
221
+ }
222
+ }
223
+
224
+ private func mapResourceToWritableVitalResource(_ name: String) throws -> WritableVitalResource {
225
+ switch name {
226
+ case "water":
227
+ return .water
228
+ case "caffeine":
229
+ return .caffeine
230
+ case "mindfulSession":
231
+ return .mindfulSession
173
232
  default:
174
233
  throw VitalError.UnsupportedResource(name)
175
234
  }
@@ -183,4 +242,4 @@ enum VitalError: Error {
183
242
  case UnsupportedProvider(String)
184
243
  case UnsupportedBrand(String)
185
244
  case UnsupportedKind(String)
186
- }
245
+ }
package/lib/index.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ import { NativeEventEmitter } from 'react-native';
2
+ export declare class VitalHealth {
3
+ static status: NativeEventEmitter;
4
+ static configure(backgroundDeliveryEnabled: boolean, numberOfDaysToBackFill: number, enableLogs: boolean): Promise<void>;
5
+ static askForResources(resources: VitalResource[]): Promise<void>;
6
+ static ask(readResources: VitalResource[], writeResources: VitalWriteResource[]): Promise<void>;
7
+ static writeHealthData(resource: VitalWriteResource, value: number, startDate: Date, endDate: Date): Promise<void>;
8
+ static hasAskedForPermission(resource: VitalResource): Promise<boolean>;
9
+ static syncData(resources: VitalResource[]): Promise<void>;
10
+ static cleanUp(): Promise<void>;
11
+ }
12
+ export declare enum VitalResource {
13
+ Profile = "profile",
14
+ Body = "body",
15
+ Workout = "workout",
16
+ Activity = "activity",
17
+ Sleep = "sleep",
18
+ Glucose = "glucose",
19
+ BloodPressure = "bloodPressure",
20
+ HeartRate = "heartRate",
21
+ Steps = "steps",
22
+ ActiveEnergyBurned = "activeEnergyBurned",
23
+ BasalEnergyBurned = "basalEnergyBurned",
24
+ Water = "water",
25
+ Caffeine = "caffeine",
26
+ MindfulSession = "mindfulSession"
27
+ }
28
+ export declare enum VitalWriteResource {
29
+ Water = "water",
30
+ Caffeine = "caffeine",
31
+ MindfulSession = "mindfulSession"
32
+ }
package/lib/index.js ADDED
@@ -0,0 +1,60 @@
1
+ import { NativeEventEmitter, NativeModules, Platform } from 'react-native';
2
+ const LINKING_ERROR = `The package 'vital-health-react-native' doesn't seem to be linked. Make sure: \n\n` +
3
+ Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
4
+ '- You rebuilt the app after installing the package\n' +
5
+ '- You are not using Expo Go\n';
6
+ const VitalHealthReactNative = NativeModules.VitalHealthReactNative
7
+ ? NativeModules.VitalHealthReactNative
8
+ : new Proxy({}, {
9
+ get() {
10
+ throw new Error(LINKING_ERROR);
11
+ },
12
+ });
13
+ export class VitalHealth {
14
+ static status = new NativeEventEmitter(VitalHealthReactNative);
15
+ static configure(backgroundDeliveryEnabled, numberOfDaysToBackFill, enableLogs) {
16
+ return VitalHealthReactNative.configure(backgroundDeliveryEnabled, numberOfDaysToBackFill, enableLogs);
17
+ }
18
+ static askForResources(resources) {
19
+ return VitalHealthReactNative.ask(resources, []);
20
+ }
21
+ static ask(readResources, writeResources) {
22
+ return VitalHealthReactNative.ask(readResources, writeResources);
23
+ }
24
+ static writeHealthData(resource, value, startDate, endDate) {
25
+ return VitalHealthReactNative.writeHealthData(resource, value, startDate.getTime(), endDate.getTime());
26
+ }
27
+ static hasAskedForPermission(resource) {
28
+ return VitalHealthReactNative.hasAskedForPermission(resource);
29
+ }
30
+ static syncData(resources) {
31
+ return VitalHealthReactNative.syncData(resources);
32
+ }
33
+ static cleanUp() {
34
+ return VitalHealthReactNative.cleanUp();
35
+ }
36
+ }
37
+ // noinspection JSUnusedGlobalSymbols
38
+ export var VitalResource;
39
+ (function (VitalResource) {
40
+ VitalResource["Profile"] = "profile";
41
+ VitalResource["Body"] = "body";
42
+ VitalResource["Workout"] = "workout";
43
+ VitalResource["Activity"] = "activity";
44
+ VitalResource["Sleep"] = "sleep";
45
+ VitalResource["Glucose"] = "glucose";
46
+ VitalResource["BloodPressure"] = "bloodPressure";
47
+ VitalResource["HeartRate"] = "heartRate";
48
+ VitalResource["Steps"] = "steps";
49
+ VitalResource["ActiveEnergyBurned"] = "activeEnergyBurned";
50
+ VitalResource["BasalEnergyBurned"] = "basalEnergyBurned";
51
+ VitalResource["Water"] = "water";
52
+ VitalResource["Caffeine"] = "caffeine";
53
+ VitalResource["MindfulSession"] = "mindfulSession";
54
+ })(VitalResource || (VitalResource = {}));
55
+ export var VitalWriteResource;
56
+ (function (VitalWriteResource) {
57
+ VitalWriteResource["Water"] = "water";
58
+ VitalWriteResource["Caffeine"] = "caffeine";
59
+ VitalWriteResource["MindfulSession"] = "mindfulSession";
60
+ })(VitalWriteResource || (VitalWriteResource = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tryvital/vital-health-react-native",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
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",
package/src/index.tsx CHANGED
@@ -33,7 +33,28 @@ export class VitalHealth {
33
33
  }
34
34
 
35
35
  static askForResources(resources: VitalResource[]): Promise<void> {
36
- return VitalHealthReactNative.askForResources(resources);
36
+ return VitalHealthReactNative.ask(resources, []);
37
+ }
38
+
39
+ static ask(
40
+ readResources: VitalResource[],
41
+ writeResources: VitalWriteResource[]
42
+ ): Promise<void> {
43
+ return VitalHealthReactNative.ask(readResources, writeResources);
44
+ }
45
+
46
+ static writeHealthData(
47
+ resource: VitalWriteResource,
48
+ value: number,
49
+ startDate: Date,
50
+ endDate: Date
51
+ ): Promise<void> {
52
+ return VitalHealthReactNative.writeHealthData(
53
+ resource,
54
+ value,
55
+ startDate.getTime(),
56
+ endDate.getTime()
57
+ );
37
58
  }
38
59
 
39
60
  static hasAskedForPermission(resource: VitalResource): Promise<boolean> {
@@ -49,6 +70,7 @@ export class VitalHealth {
49
70
  }
50
71
  }
51
72
 
73
+ // noinspection JSUnusedGlobalSymbols
52
74
  export enum VitalResource {
53
75
  Profile = 'profile',
54
76
  Body = 'body',
@@ -61,4 +83,13 @@ export enum VitalResource {
61
83
  Steps = 'steps',
62
84
  ActiveEnergyBurned = 'activeEnergyBurned',
63
85
  BasalEnergyBurned = 'basalEnergyBurned',
86
+ Water = 'water',
87
+ Caffeine = 'caffeine',
88
+ MindfulSession = 'mindfulSession',
89
+ }
90
+
91
+ export enum VitalWriteResource {
92
+ Water = 'water',
93
+ Caffeine = 'caffeine', // iOS only
94
+ MindfulSession = 'mindfulSession', // iOS only, value is ignored
64
95
  }
@@ -17,7 +17,7 @@ Pod::Spec.new do |s|
17
17
  s.source_files = "ios/**/*.{h,m,mm,swift}"
18
18
 
19
19
  s.dependency "React-Core"
20
- s.dependency "VitalHealthKit", "~> 0.7.11"
20
+ s.dependency "VitalHealthKit", "~> 0.7.13"
21
21
 
22
22
  # Don't install the dependencies when we run `pod install` in the old architecture.
23
23
  if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then