react-native-okhi 1.2.4 → 1.2.5-beta.1

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.
Files changed (35) hide show
  1. package/android/build.gradle +1 -1
  2. package/android/src/main/java/com/reactnativeokhi/OkhiModule.java +2 -0
  3. package/ios/Okhi.m +4 -0
  4. package/ios/Okhi.swift +29 -0
  5. package/lib/commonjs/OkCollect/OkHiLocationManager.js +100 -7
  6. package/lib/commonjs/OkCollect/OkHiLocationManager.js.map +1 -1
  7. package/lib/commonjs/OkCollect/Util.js +29 -25
  8. package/lib/commonjs/OkCollect/Util.js.map +1 -1
  9. package/lib/commonjs/OkCollect/types.js.map +1 -1
  10. package/lib/commonjs/OkCore/index.js +1 -0
  11. package/lib/commonjs/OkCore/index.js.map +1 -1
  12. package/lib/commonjs/OkCore/types.js +4 -0
  13. package/lib/commonjs/OkCore/types.js.map +1 -1
  14. package/lib/commonjs/OkHiNativeModule/index.js.map +1 -1
  15. package/lib/module/OkCollect/OkHiLocationManager.js +101 -8
  16. package/lib/module/OkCollect/OkHiLocationManager.js.map +1 -1
  17. package/lib/module/OkCollect/Util.js +29 -25
  18. package/lib/module/OkCollect/Util.js.map +1 -1
  19. package/lib/module/OkCollect/types.js.map +1 -1
  20. package/lib/module/OkCore/index.js +1 -0
  21. package/lib/module/OkCore/index.js.map +1 -1
  22. package/lib/module/OkCore/types.js +1 -1
  23. package/lib/module/OkCore/types.js.map +1 -1
  24. package/lib/module/OkHiNativeModule/index.js.map +1 -1
  25. package/lib/typescript/OkCollect/types.d.ts +3 -5
  26. package/lib/typescript/OkCore/types.d.ts +2 -1
  27. package/lib/typescript/OkHiNativeModule/index.d.ts +3 -0
  28. package/package.json +1 -1
  29. package/react-native-okhi.podspec +1 -1
  30. package/src/OkCollect/OkHiLocationManager.tsx +127 -5
  31. package/src/OkCollect/Util.ts +37 -29
  32. package/src/OkCollect/types.ts +4 -2
  33. package/src/OkCore/index.ts +1 -0
  34. package/src/OkCore/types.ts +3 -1
  35. package/src/OkHiNativeModule/index.ts +7 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-okhi",
3
- "version": "1.2.4",
3
+ "version": "1.2.5-beta.1",
4
4
  "description": "The OkHi React Native library enables you to collect and verify addresses from your users",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -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 "OkHi", "1.9.9"
20
+ s.dependency "OkHi", "1.9.17-beta"
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
@@ -20,7 +20,13 @@ import { start as sv } from '../OkVerify';
20
20
  import type { OkVerifyStartConfiguration } from '../OkVerify/types';
21
21
  import {
22
22
  getApplicationConfiguration,
23
+ isBackgroundLocationPermissionGranted,
24
+ isLocationPermissionGranted,
25
+ isLocationServicesEnabled,
26
+ openAppSettings,
23
27
  openProtectedAppsSettings,
28
+ requestBackgroundLocationPermission,
29
+ requestLocationPermission,
24
30
  } from '../OkCore';
25
31
  import { OkHiNativeModule } from '../OkHiNativeModule';
26
32
 
@@ -38,10 +44,12 @@ export const OkHiLocationManager = (props: OkHiLocationManagerProps) => {
38
44
  ? { ...props.style, ...defaultStyle }
39
45
  : defaultStyle;
40
46
 
41
- const { user, onSuccess, onCloseRequest, onError, loader, launch } = props;
47
+ const { user, onSuccess, onCloseRequest, onError, loader, launch, config } =
48
+ props;
42
49
  const webViewRef = useRef<WebView | null>(null);
43
50
  const startMessage =
44
51
  props.mode === 'create' ? 'start_app' : 'select_location';
52
+ const [ready, setReady] = useState(false);
45
53
 
46
54
  useEffect(() => {
47
55
  if (applicationConfiguration == null && token == null && user.phone) {
@@ -92,21 +100,131 @@ export const OkHiLocationManager = (props: OkHiLocationManagerProps) => {
92
100
  }
93
101
  }, [applicationConfiguration, props, token]);
94
102
 
103
+ useEffect(() => {
104
+ if (launch) {
105
+ if (
106
+ typeof config?.permissionsOnboarding === 'boolean' &&
107
+ !config.permissionsOnboarding
108
+ ) {
109
+ isBackgroundLocationPermissionGranted().then((result) => {
110
+ if (!result) {
111
+ onError(
112
+ new OkHiException({
113
+ code: OkHiException.PERMISSION_DENIED_CODE,
114
+ message:
115
+ 'Always location permission must be granted to launch OkCollect',
116
+ })
117
+ );
118
+ } else {
119
+ setReady(true);
120
+ }
121
+ });
122
+ } else {
123
+ setReady(true);
124
+ }
125
+ } else {
126
+ setReady(false);
127
+ }
128
+ }, [launch, config?.permissionsOnboarding]);
129
+
130
+ const runWebViewCallback = (value: string) => {
131
+ if (webViewRef.current) {
132
+ const jsString = `(function (){ if (typeof runOkHiLocationManagerCallback === "function") { runOkHiLocationManagerCallback("${value}") } })()`;
133
+ webViewRef.current.injectJavaScript(jsString);
134
+ }
135
+ };
136
+
137
+ const handleAndroidRequestLocationPermission = async (
138
+ level: 'whenInUse' | 'always'
139
+ ) => {
140
+ if (level === 'whenInUse') {
141
+ const result = await requestLocationPermission();
142
+ runWebViewCallback(result ? 'whenInUse' : 'denied');
143
+ } else if (level === 'always') {
144
+ const result = await requestBackgroundLocationPermission();
145
+ if (result) {
146
+ runWebViewCallback('always');
147
+ } else {
148
+ const isWhenInUseGranted = await isLocationPermissionGranted();
149
+ runWebViewCallback(isWhenInUseGranted ? 'whenInUse' : 'denied');
150
+ }
151
+ }
152
+ };
153
+
154
+ const handleIOSRequestLocationPermission = async (
155
+ level: 'whenInUse' | 'always'
156
+ ) => {
157
+ const unknownError = new OkHiException({
158
+ code: OkHiException.UNKNOWN_ERROR_CODE,
159
+ message:
160
+ 'Something went wrong while requesting permissions. Please try again later.',
161
+ });
162
+ try {
163
+ const isServiceAvailable = await isLocationServicesEnabled();
164
+ if (!isServiceAvailable) {
165
+ openAppSettings();
166
+ } else if (level === 'whenInUse') {
167
+ const result = await requestLocationPermission();
168
+ runWebViewCallback(result ? level : 'denied');
169
+ } else if (level === 'always') {
170
+ const granted = await isBackgroundLocationPermissionGranted();
171
+ if (granted) {
172
+ runWebViewCallback(level);
173
+ } else {
174
+ openAppSettings();
175
+ }
176
+ }
177
+ } catch (error) {
178
+ onError(unknownError);
179
+ }
180
+ };
181
+
182
+ const handleRequestLocationPermission = async ({
183
+ level,
184
+ }: {
185
+ level: 'whenInUse' | 'always';
186
+ }) => {
187
+ if (Platform.OS === 'android') {
188
+ handleAndroidRequestLocationPermission(level);
189
+ } else if (Platform.OS === 'ios') {
190
+ handleIOSRequestLocationPermission(level);
191
+ }
192
+ };
193
+
194
+ const handleOpenAppSettings = async () => {
195
+ try {
196
+ const granted = await isBackgroundLocationPermissionGranted();
197
+ if (granted) {
198
+ runWebViewCallback('always');
199
+ } else {
200
+ await openAppSettings();
201
+ }
202
+ } catch (error) {
203
+ const err = error as OkHiException;
204
+ onError(err);
205
+ }
206
+ };
207
+
95
208
  const handleOnMessage = ({ nativeEvent: { data } }: WebViewMessageEvent) => {
96
209
  try {
97
210
  const response: OkHiLocationManagerResponse = JSON.parse(data);
211
+
98
212
  if (response.message === 'fatal_exit') {
99
213
  onError(
100
214
  new OkHiException({
101
215
  code: OkHiException.UNKNOWN_ERROR_CODE,
102
- message: response.payload.toString(),
216
+ message: 'Something went wrong, please try again later.',
103
217
  })
104
218
  );
105
219
  } else if (response.message === 'exit_app') {
106
220
  onCloseRequest();
107
221
  } else if (response.message === 'request_enable_protected_apps') {
108
222
  openProtectedAppsSettings();
109
- } else {
223
+ } else if (
224
+ response.message === 'location_created' ||
225
+ response.message === 'location_selected' ||
226
+ response.message === 'location_updated'
227
+ ) {
110
228
  onSuccess({
111
229
  user: {
112
230
  ...response.payload.user,
@@ -139,6 +257,10 @@ export const OkHiLocationManager = (props: OkHiLocationManagerProps) => {
139
257
  });
140
258
  },
141
259
  });
260
+ } else if (response.message === 'request_location_permission') {
261
+ handleRequestLocationPermission(response.payload);
262
+ } else if (response.message === 'open_app_settings') {
263
+ handleOpenAppSettings();
142
264
  }
143
265
  } catch (error) {
144
266
  let errorMessage = 'Something went wrong';
@@ -204,10 +326,10 @@ export const OkHiLocationManager = (props: OkHiLocationManagerProps) => {
204
326
  <Modal
205
327
  animationType="slide"
206
328
  transparent={false}
207
- visible={launch}
329
+ visible={ready}
208
330
  onRequestClose={handleModalRequestClose}
209
331
  >
210
- {launch ? renderContent() : null}
332
+ {ready ? renderContent() : null}
211
333
  </Modal>
212
334
  );
213
335
  };
@@ -34,6 +34,8 @@ export const generateStartDataPayload = async (
34
34
  applicationConfiguration: AuthApplicationConfig
35
35
  ): Promise<OkHiLocationManagerStartDataPayload> => {
36
36
  const payload: any = {};
37
+ const { manufacturer, model, osVersion, platform } =
38
+ await OkHiNativeModule.retrieveDeviceInfo();
37
39
  payload.style = !props.theme
38
40
  ? undefined
39
41
  : {
@@ -67,6 +69,12 @@ export const generateStartDataPayload = async (
67
69
  platform: {
68
70
  name: 'react-native',
69
71
  },
72
+ device: {
73
+ manufacturer,
74
+ model,
75
+ platform,
76
+ osVersion,
77
+ },
70
78
  };
71
79
  payload.config = {
72
80
  streetView:
@@ -89,34 +97,39 @@ export const generateStartDataPayload = async (
89
97
  },
90
98
  protectedApps:
91
99
  Platform.OS === 'android' && (await canOpenProtectedAppsSettings()),
100
+ permissionsOnboarding:
101
+ typeof props.config?.permissionsOnboarding === 'boolean'
102
+ ? props.config.permissionsOnboarding
103
+ : true,
92
104
  };
93
105
 
94
106
  if (Platform.OS === 'ios') {
95
107
  const status = await OkHiNativeModule.fetchIOSLocationPermissionStatus();
96
- if (status !== 'notDetermined') {
97
- payload.context.permissions = {
98
- location:
99
- status === 'authorizedWhenInUse'
100
- ? 'whenInUse'
101
- : status === 'authorizedAlways' || status === 'authorized'
102
- ? 'always'
103
- : 'denided',
104
- };
105
- if (
106
- status === 'authorized' ||
107
- status === 'authorizedWhenInUse' ||
108
- status === 'authorizedAlways'
109
- ) {
110
- const location = await fetchCurrentLocation();
111
- if (location) {
112
- payload.context.coordinates = {
113
- currentLocation: {
114
- lat: location.lat,
115
- lng: location.lng,
116
- accuracy: location.accuracy,
117
- },
118
- };
119
- }
108
+ const locationPermission =
109
+ status === 'notDetermined'
110
+ ? 'notDetermined'
111
+ : status === 'authorizedWhenInUse'
112
+ ? 'whenInUse'
113
+ : status === 'authorizedAlways'
114
+ ? 'always'
115
+ : 'denied';
116
+ payload.context.permissions = {
117
+ location: locationPermission,
118
+ };
119
+ if (
120
+ status === 'authorized' ||
121
+ status === 'authorizedWhenInUse' ||
122
+ status === 'authorizedAlways'
123
+ ) {
124
+ const location = await fetchCurrentLocation();
125
+ if (location) {
126
+ payload.context.coordinates = {
127
+ currentLocation: {
128
+ lat: location.lat,
129
+ lng: location.lng,
130
+ accuracy: location.accuracy,
131
+ },
132
+ };
120
133
  }
121
134
  }
122
135
  } else if (Platform.OS === 'android') {
@@ -147,11 +160,6 @@ export const generateStartDataPayload = async (
147
160
  : 'denied',
148
161
  };
149
162
  }
150
- const { manufacturer, model } = await OkHiNativeModule.retrieveDeviceInfo();
151
- payload.context.device = {
152
- manufacturer,
153
- model,
154
- };
155
163
  } else {
156
164
  throw new OkHiException({
157
165
  code: OkHiException.UNSUPPORTED_PLATFORM_CODE,
@@ -79,6 +79,7 @@ export interface OkHiLocationManagerProps {
79
79
  home?: boolean;
80
80
  work?: boolean;
81
81
  };
82
+ permissionsOnboarding?: boolean;
82
83
  };
83
84
 
84
85
  /**
@@ -142,6 +143,7 @@ export interface OkHiLocationManagerResponse {
142
143
  | 'location_updated'
143
144
  | 'exit_app'
144
145
  | 'request_enable_protected_apps'
145
- | 'fatal_exit';
146
- payload: { user: any; location: any };
146
+ | 'fatal_exit'
147
+ | 'request_location_permission';
148
+ payload: any;
147
149
  }
@@ -30,6 +30,7 @@ export function initialize(
30
30
  configuration.credentials.clientKey,
31
31
  configuration.context.mode
32
32
  );
33
+ await OkHiNativeModule.onStart();
33
34
  }
34
35
  }
35
36
  });
@@ -1,3 +1,5 @@
1
+ import type { OkHiException } from './OkHiException';
2
+
1
3
  /**
2
4
  * Defines the structure of the user object requried by OkHi services and libraries.
3
5
  */
@@ -209,5 +211,5 @@ export type LocationRequestPermissionType = 'whenInUse' | 'always';
209
211
 
210
212
  export type LocationPermissionCallback = (
211
213
  status: LocationPermissionStatusCallback | null,
212
- error: OkHiError | null
214
+ error: OkHiException | null
213
215
  ) => any;
@@ -44,7 +44,12 @@ type OkHiNativeModuleType = {
44
44
  requestTrackingAuthorization(): Promise<string | null>;
45
45
  canOpenProtectedAppsSettings(): Promise<boolean>;
46
46
  openProtectedAppsSettings(): Promise<boolean>;
47
- retrieveDeviceInfo(): Promise<{ manufacturer: string; model: string }>;
47
+ retrieveDeviceInfo(): Promise<{
48
+ manufacturer: string;
49
+ model: string;
50
+ osVersion: string;
51
+ platform: 'android' | 'ios';
52
+ }>;
48
53
  setItem(key: string, value: string): Promise<boolean>;
49
54
  onNewToken(fcmPushNotificationToken: string): Promise<boolean>;
50
55
  onMessageReceived(): Promise<boolean>;
@@ -64,6 +69,7 @@ type OkHiNativeModuleType = {
64
69
  | 'authorized'
65
70
  | 'unknown'
66
71
  >;
72
+ onStart(): Promise<boolean>;
67
73
  };
68
74
 
69
75
  export const OkHiNativeModule: OkHiNativeModuleType = NativeModules.Okhi