react-native-persona 2.2.30 → 2.4.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.
- package/CHANGELOG.md +45 -0
- package/README.md +5 -2
- package/RNPersonaInquiry2.podspec +1 -1
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/withpersona/sdk2/reactnative/PersonaInquiryModule2.java +161 -3
- package/ios/PersonaInquiry2.swift +134 -120
- package/lib/commonjs/index.js +182 -5
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/index.js +166 -3
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/index.d.ts +90 -1
- package/package.json +1 -1
- package/src/index.ts +191 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,53 +7,98 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
7
7
|
|
|
8
8
|
## Unreleased
|
|
9
9
|
|
|
10
|
+
## [v2.4.0] - 2023-02-24
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Upgrade to iOS Inquiry SDK 2.7.0
|
|
15
|
+
- Upgrade to Android Inquiry SDK 2.4.0
|
|
16
|
+
- Deprecated the iosTheme(themeObject: Object) functions. The iosThemeToUse(themeObject: Object, themeSource: ThemeSource)
|
|
17
|
+
functions should be used instead. Pass in a themeSource of ThemeSource.SERVER to use theming set in the Persona Dashboard.
|
|
18
|
+
Pass in ThemeSource.CLIENT to keep current behavior that uses the client. Note that ThemeSource.CLIENT is also marked
|
|
19
|
+
as deprecated. Also note that the Android theme source will be derived from this ThemeSource as well. If iosTheme is
|
|
20
|
+
called instead of iosThemeToUse, ThemeSource.Client will be used. If neither iosThemeToUse nor iosTheme is called,
|
|
21
|
+
ThemeSource.SERVER will be used by default. The themeObject can still be used to control certain properties
|
|
22
|
+
like the initial loading icon even when the theme source is set to ThemeSource.SERVER.
|
|
23
|
+
|
|
24
|
+
## [v2.3.0] - 2023-02-16
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- Added optional support to receive data collected during inquiry flow on completion.
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- Upgrade to iOS Inquiry SDK 2.6.2
|
|
33
|
+
- Upgrade to Android Inquiry SDK 2.3.6
|
|
34
|
+
|
|
10
35
|
## [v2.2.30] - 2023-01-25
|
|
11
36
|
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
12
39
|
- Upgrade to iOS Inquiry SDK 2.5.11
|
|
13
40
|
- Upgrade to Android Inquiry SDK 2.3.5
|
|
14
41
|
|
|
15
42
|
## [v2.2.29] - 2022-12-15
|
|
16
43
|
|
|
44
|
+
### Changed
|
|
45
|
+
|
|
17
46
|
- Upgrade to iOS Inquiry SDK 2.5.4
|
|
18
47
|
- Upgrade to Android Inquiry SDK 2.3.0
|
|
19
48
|
|
|
20
49
|
## [v2.2.28] - 2022-11-30
|
|
21
50
|
|
|
51
|
+
### Changed
|
|
52
|
+
|
|
22
53
|
- Upgrade to iOS Inquiry SDK 2.5.3
|
|
23
54
|
- Upgrade to Android Inquiry SDK 2.2.45
|
|
24
55
|
|
|
25
56
|
## [v2.2.27] - 2022-11-16
|
|
26
57
|
|
|
58
|
+
### Changed
|
|
59
|
+
|
|
27
60
|
- Upgrade to iOS Inquiry SDK 2.5.0
|
|
28
61
|
- Upgrade to Android Inquiry SDK 2.2.43
|
|
29
62
|
|
|
30
63
|
## [v2.2.26] - 2022-10-20
|
|
31
64
|
|
|
65
|
+
### Changed
|
|
66
|
+
|
|
32
67
|
- Upgrade to iOS Inquiry SDK 2.4.3
|
|
33
68
|
- Upgrade to Android Inquiry SDK 2.2.41
|
|
34
69
|
|
|
35
70
|
## [v2.2.25] - 2022-10-06
|
|
36
71
|
|
|
72
|
+
### Changed
|
|
73
|
+
|
|
37
74
|
- Upgrade to iOS Inquiry SDK 2.4.2
|
|
38
75
|
- Upgrade to Android Inquiry SDK 2.2.40
|
|
39
76
|
|
|
40
77
|
## [v2.2.24] - 2022-09-22
|
|
41
78
|
|
|
79
|
+
### Changed
|
|
80
|
+
|
|
42
81
|
- Upgrade to iOS Inquiry SDK 2.4.0
|
|
43
82
|
- Upgrade to Android Inquiry SDK 2.2.37
|
|
44
83
|
|
|
45
84
|
## [v2.2.23] - 2022-09-07
|
|
46
85
|
|
|
86
|
+
### Changed
|
|
87
|
+
|
|
47
88
|
- Upgrade to iOS Inquiry SDK 2.3.9
|
|
48
89
|
- Upgrade to Android Inquiry SDK 2.2.36
|
|
49
90
|
|
|
50
91
|
## [v2.2.22] - 2022-08-25
|
|
51
92
|
|
|
93
|
+
### Changed
|
|
94
|
+
|
|
52
95
|
- Upgrade to iOS Inquiry SDK 2.3.6
|
|
53
96
|
- Upgrade to Android Inquiry SDK 2.2.31
|
|
54
97
|
|
|
55
98
|
## [v2.2.21] - 2022-08-18
|
|
56
99
|
|
|
100
|
+
### Fixed
|
|
101
|
+
|
|
57
102
|
- Fixed a bug where the inquiry flow failed to present on iOS
|
|
58
103
|
|
|
59
104
|
## [v2.2.20] - 2022-08-15
|
package/README.md
CHANGED
|
@@ -85,9 +85,12 @@ Inquiry.fromTemplate('itmpl_Ygs16MKTkA6obnF8C3Rb17dm')
|
|
|
85
85
|
|
|
86
86
|
### Theming
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
Set your own colors, buttons, fonts, and more. This can be done via the Persona Dashboard. For more information on using the theme editor, see our [help article](https://support.withpersona.com/hc/en-us/articles/13775762246547-Tutorial-Configure-a-Theme-with-Inquiry-Template-Editor).
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
|
|
91
|
+
Note that the following instructions are for deprecated client side theming only.
|
|
92
|
+
|
|
93
|
+
To test legacy client side themes, use the example app:
|
|
91
94
|
|
|
92
95
|
```
|
|
93
96
|
cd example
|
package/android/build.gradle
CHANGED
|
@@ -2,15 +2,20 @@ package com.withpersona.sdk2.reactnative;
|
|
|
2
2
|
|
|
3
3
|
import android.app.Activity;
|
|
4
4
|
import android.content.Intent;
|
|
5
|
+
|
|
5
6
|
import androidx.annotation.Nullable;
|
|
7
|
+
|
|
6
8
|
import com.facebook.react.bridge.ActivityEventListener;
|
|
7
9
|
import com.facebook.react.bridge.Arguments;
|
|
8
10
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
9
11
|
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
10
12
|
import com.facebook.react.bridge.ReactMethod;
|
|
13
|
+
import com.facebook.react.bridge.ReadableArray;
|
|
11
14
|
import com.facebook.react.bridge.ReadableMap;
|
|
15
|
+
import com.facebook.react.bridge.WritableArray;
|
|
12
16
|
import com.facebook.react.bridge.WritableMap;
|
|
13
17
|
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
18
|
+
import com.withpersona.sdk2.inquiry.ClientThemeSource;
|
|
14
19
|
import com.withpersona.sdk2.inquiry.Environment;
|
|
15
20
|
import com.withpersona.sdk2.inquiry.Fields;
|
|
16
21
|
import com.withpersona.sdk2.inquiry.Inquiry;
|
|
@@ -18,10 +23,19 @@ import com.withpersona.sdk2.inquiry.InquiryBuilder;
|
|
|
18
23
|
import com.withpersona.sdk2.inquiry.InquiryField;
|
|
19
24
|
import com.withpersona.sdk2.inquiry.InquiryResponse;
|
|
20
25
|
import com.withpersona.sdk2.inquiry.InquiryTemplateBuilder;
|
|
26
|
+
import com.withpersona.sdk2.inquiry.ServerThemeSource;
|
|
27
|
+
import com.withpersona.sdk2.inquiry.types.collected_data.CollectedData;
|
|
28
|
+
import com.withpersona.sdk2.inquiry.types.collected_data.DocumentFile;
|
|
29
|
+
import com.withpersona.sdk2.inquiry.types.collected_data.GovernmentIdCapture;
|
|
30
|
+
import com.withpersona.sdk2.inquiry.types.collected_data.SelfieCapture;
|
|
31
|
+
import com.withpersona.sdk2.inquiry.types.collected_data.StepData;
|
|
32
|
+
|
|
33
|
+
import org.jetbrains.annotations.NotNull;
|
|
34
|
+
|
|
21
35
|
import java.util.HashMap;
|
|
36
|
+
import java.util.List;
|
|
22
37
|
import java.util.Map;
|
|
23
38
|
import java.util.Objects;
|
|
24
|
-
import org.jetbrains.annotations.NotNull;
|
|
25
39
|
|
|
26
40
|
public class PersonaInquiryModule2 extends ReactContextBaseJavaModule
|
|
27
41
|
implements ActivityEventListener {
|
|
@@ -35,6 +49,8 @@ public class PersonaInquiryModule2 extends ReactContextBaseJavaModule
|
|
|
35
49
|
private static final String ENVIRONMENT = "environment";
|
|
36
50
|
private static final String FIELDS = "fields";
|
|
37
51
|
private static final String FIELD_ADDITIONAL_FIELDS = "additionalFields";
|
|
52
|
+
private static final String RETURN_COLLECTED_DATA = "returnCollectedData";
|
|
53
|
+
private static final String THEME_SOURCE = "themeSource";
|
|
38
54
|
|
|
39
55
|
private final ReactApplicationContext reactContext;
|
|
40
56
|
|
|
@@ -92,6 +108,8 @@ public class PersonaInquiryModule2 extends ReactContextBaseJavaModule
|
|
|
92
108
|
}
|
|
93
109
|
params.putMap("fields", fields);
|
|
94
110
|
|
|
111
|
+
params.putMap("collectedData", collectedDataToMap(complete.getCollectedData()));
|
|
112
|
+
|
|
95
113
|
jsModule.emit("onComplete", params);
|
|
96
114
|
} else if (response instanceof InquiryResponse.Cancel) {
|
|
97
115
|
InquiryResponse.Cancel cancel = (InquiryResponse.Cancel) response;
|
|
@@ -109,6 +127,137 @@ public class PersonaInquiryModule2 extends ReactContextBaseJavaModule
|
|
|
109
127
|
}
|
|
110
128
|
}
|
|
111
129
|
|
|
130
|
+
@Nullable
|
|
131
|
+
private ReadableMap collectedDataToMap(@Nullable CollectedData collectedData) {
|
|
132
|
+
if (collectedData == null) {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
WritableMap collectedDataMap = Arguments.createMap();
|
|
137
|
+
|
|
138
|
+
WritableArray stepDataMap = Arguments.createArray();
|
|
139
|
+
for (StepData stepDatum : collectedData.getStepData()) {
|
|
140
|
+
WritableMap stepDatumMap = Arguments.createMap();
|
|
141
|
+
stepDatumMap.putString("stepName", stepDatum.getStepName());
|
|
142
|
+
|
|
143
|
+
if (stepDatum instanceof StepData.DocumentStepData) {
|
|
144
|
+
WritableArray documentsArr = Arguments.createArray();
|
|
145
|
+
|
|
146
|
+
for (DocumentFile document : ((StepData.DocumentStepData) stepDatum).getDocuments()) {
|
|
147
|
+
WritableMap documentMap = Arguments.createMap();
|
|
148
|
+
documentMap.putString("absoluteFilePath", document.getData().getAbsolutePath());
|
|
149
|
+
documentsArr.pushMap(documentMap);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
stepDatumMap.putArray("documents", documentsArr);
|
|
153
|
+
stepDatumMap.putString("type", "DocumentStepData");
|
|
154
|
+
} else if (stepDatum instanceof StepData.GovernmentIdStepData) {
|
|
155
|
+
WritableArray capturesArr = Arguments.createArray();
|
|
156
|
+
|
|
157
|
+
for (GovernmentIdCapture capture : ((StepData.GovernmentIdStepData) stepDatum).getCaptures()) {
|
|
158
|
+
WritableMap captureMap = Arguments.createMap();
|
|
159
|
+
captureMap.putString("idClass", capture.getIdClass());
|
|
160
|
+
captureMap.putString("captureMethod", capture.getCaptureMethod().name());
|
|
161
|
+
captureMap.putString("side", capture.getSide().name());
|
|
162
|
+
|
|
163
|
+
WritableArray framesArr = Arguments.createArray();
|
|
164
|
+
for (GovernmentIdCapture.Frame frame : capture.getFrames()) {
|
|
165
|
+
WritableMap frameMap = Arguments.createMap();
|
|
166
|
+
frameMap.putString("absoluteFilePath", frame.getData().getAbsolutePath());
|
|
167
|
+
|
|
168
|
+
framesArr.pushMap(frameMap);
|
|
169
|
+
}
|
|
170
|
+
captureMap.putArray("frames", framesArr);
|
|
171
|
+
|
|
172
|
+
capturesArr.pushMap(captureMap);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
stepDatumMap.putArray("captures", capturesArr);
|
|
176
|
+
stepDatumMap.putString("type", "GovernmentIdStepData");
|
|
177
|
+
} else if (stepDatum instanceof StepData.SelfieStepData) {
|
|
178
|
+
StepData.SelfieStepData selfieStepData = (StepData.SelfieStepData) stepDatum;
|
|
179
|
+
ReadableMap centerCaptureMap = selfieCaptureToMap(selfieStepData.getCenterCapture());
|
|
180
|
+
ReadableMap leftCaptureMap = selfieCaptureToMap(selfieStepData.getLeftCapture());
|
|
181
|
+
ReadableMap rightCaptureMap = selfieCaptureToMap(selfieStepData.getRightCapture());
|
|
182
|
+
|
|
183
|
+
stepDatumMap.putMap("centerCapture", centerCaptureMap);
|
|
184
|
+
stepDatumMap.putMap("leftCapture", leftCaptureMap);
|
|
185
|
+
stepDatumMap.putMap("rightCapture", rightCaptureMap);
|
|
186
|
+
stepDatumMap.putString("type", "SelfieStepData");
|
|
187
|
+
} else if (stepDatum instanceof StepData.UiStepData) {
|
|
188
|
+
Map<String, Object> componentParams = ((StepData.UiStepData) stepDatum).getComponentParams();
|
|
189
|
+
|
|
190
|
+
stepDatumMap.putMap("componentParams", uiStepParamsMapToMap(componentParams));
|
|
191
|
+
stepDatumMap.putString("type", "UiStepData");
|
|
192
|
+
} else {
|
|
193
|
+
// do nothing
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
stepDataMap.pushMap(stepDatumMap);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
collectedDataMap.putArray("stepData", stepDataMap);
|
|
200
|
+
|
|
201
|
+
return collectedDataMap;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
private ReadableMap uiStepParamsMapToMap(Map<?, ?> map) {
|
|
205
|
+
WritableMap resultMap = Arguments.createMap();
|
|
206
|
+
for (Map.Entry<?, ?> param : map.entrySet()) {
|
|
207
|
+
Object key = param.getKey();
|
|
208
|
+
Object value = param.getValue();
|
|
209
|
+
|
|
210
|
+
if (!(key instanceof String)) {
|
|
211
|
+
continue; // All ui step params should have string keys.
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
String keyStr = (String) key;
|
|
215
|
+
|
|
216
|
+
if (value instanceof Map<?, ?>) {
|
|
217
|
+
resultMap.putMap(keyStr, uiStepParamsMapToMap((Map<?, ?>) value));
|
|
218
|
+
} else if (value instanceof List<?>) {
|
|
219
|
+
resultMap.putArray(keyStr, uiStepParamsArrToArr((List<?>) value));
|
|
220
|
+
} else if (value instanceof String) {
|
|
221
|
+
resultMap.putString(keyStr, (String) value);
|
|
222
|
+
} else if (value instanceof Boolean) {
|
|
223
|
+
resultMap.putBoolean(keyStr, (Boolean) value);
|
|
224
|
+
} else if (value instanceof Number) {
|
|
225
|
+
resultMap.putDouble(keyStr, (Double) value);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return resultMap;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
private ReadableArray uiStepParamsArrToArr(List<?> arr) {
|
|
233
|
+
WritableArray resultArr = Arguments.createArray();
|
|
234
|
+
|
|
235
|
+
for (Object element : arr) {
|
|
236
|
+
if (element instanceof String) {
|
|
237
|
+
resultArr.pushString((String) element);
|
|
238
|
+
} else if (element instanceof Boolean) {
|
|
239
|
+
resultArr.pushBoolean((Boolean) element);
|
|
240
|
+
} else if (element instanceof Number) {
|
|
241
|
+
resultArr.pushDouble((Double) element);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
return resultArr;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
private ReadableMap selfieCaptureToMap(@Nullable SelfieCapture selfieCapture) {
|
|
250
|
+
if (selfieCapture == null) {
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
WritableMap captureMap = Arguments.createMap();
|
|
255
|
+
captureMap.putString("captureMethod", selfieCapture.getCaptureMethod().name());
|
|
256
|
+
captureMap.putString("absoluteFilePath", selfieCapture.getData().getAbsolutePath());
|
|
257
|
+
return captureMap;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
|
|
112
261
|
private static ReadableMap wrapField(String type, String value) {
|
|
113
262
|
WritableMap map = Arguments.createMap();
|
|
114
263
|
map.putString("type", type);
|
|
@@ -140,7 +289,9 @@ public class PersonaInquiryModule2 extends ReactContextBaseJavaModule
|
|
|
140
289
|
if (inquiryId != null) {
|
|
141
290
|
InquiryBuilder builder = Inquiry.fromInquiry(inquiryId);
|
|
142
291
|
|
|
143
|
-
|
|
292
|
+
String themeSource = options.hasKey(THEME_SOURCE) ? options.getString(THEME_SOURCE) : null;
|
|
293
|
+
builder = builder.theme(themeSource != null && themeSource.equals("server") ?
|
|
294
|
+
new ServerThemeSource(R.style.Persona_Inquiry2_Theme) : new ClientThemeSource(R.style.Persona_Inquiry2_Theme));
|
|
144
295
|
|
|
145
296
|
String sessionToken = options.hasKey(ACCESS_TOKEN) ? options.getString(ACCESS_TOKEN) : null;
|
|
146
297
|
if (sessionToken != null) {
|
|
@@ -155,7 +306,9 @@ public class PersonaInquiryModule2 extends ReactContextBaseJavaModule
|
|
|
155
306
|
if (templateId != null) {
|
|
156
307
|
InquiryTemplateBuilder builder = Inquiry.fromTemplate(templateId);
|
|
157
308
|
|
|
158
|
-
|
|
309
|
+
String themeSource = options.hasKey(THEME_SOURCE) ? options.getString(THEME_SOURCE) : null;
|
|
310
|
+
builder = builder.theme(themeSource != null && themeSource.equals("server") ?
|
|
311
|
+
new ServerThemeSource(R.style.Persona_Inquiry2_Theme) : new ClientThemeSource(R.style.Persona_Inquiry2_Theme));
|
|
159
312
|
|
|
160
313
|
String referenceId = options.hasKey(REFERENCE_ID) ? options.getString(REFERENCE_ID) : null;
|
|
161
314
|
if (referenceId != null) {
|
|
@@ -201,6 +354,11 @@ public class PersonaInquiryModule2 extends ReactContextBaseJavaModule
|
|
|
201
354
|
builder = builder.fields(fieldsBuilder.build());
|
|
202
355
|
}
|
|
203
356
|
|
|
357
|
+
Boolean returnCollectedData = options.hasKey(RETURN_COLLECTED_DATA) ? options.getBoolean(RETURN_COLLECTED_DATA) : null;
|
|
358
|
+
if (returnCollectedData != null) {
|
|
359
|
+
builder = builder.returnCollectedData(returnCollectedData);
|
|
360
|
+
}
|
|
361
|
+
|
|
204
362
|
if (currentActivity != null) {
|
|
205
363
|
builder.build().start(currentActivity, PERSONA_INQUIRY_REQUEST_CODE);
|
|
206
364
|
}
|
|
@@ -11,6 +11,8 @@ import Persona2
|
|
|
11
11
|
@objc(PersonaInquiry2)
|
|
12
12
|
class PersonaInquiry2: RCTEventEmitter {
|
|
13
13
|
|
|
14
|
+
private var collectedData: InquiryData? = nil
|
|
15
|
+
|
|
14
16
|
override func supportedEvents() -> [String] {
|
|
15
17
|
["onComplete", "onCanceled", "onError"]
|
|
16
18
|
}
|
|
@@ -39,38 +41,41 @@ class PersonaInquiry2: RCTEventEmitter {
|
|
|
39
41
|
let environment = options["environment"] as? String
|
|
40
42
|
let sessionToken = options["sessionToken"] as? String
|
|
41
43
|
let themeObject = options["iosTheme"] as? [String: String]
|
|
44
|
+
let themeSource = options["themeSource"] as? String
|
|
42
45
|
let fieldsObject = options["fields"] as? [String: [String: Any]]
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
).start(from: viewController)
|
|
46
|
+
let returnCollectedData = options["returnCollectedData"] as? Bool ?? false
|
|
47
|
+
|
|
48
|
+
guard let config = InquiryConfiguration.build(
|
|
49
|
+
inquiryId: inquiryId,
|
|
50
|
+
sessionToken: sessionToken,
|
|
51
|
+
templateVersion: templateVersion,
|
|
52
|
+
templateId: templateId,
|
|
53
|
+
referenceId: referenceId,
|
|
54
|
+
accountId: accountId,
|
|
55
|
+
environment: Environment.from(rawValue: environment),
|
|
56
|
+
fields: fieldsFrom(fieldsObject),
|
|
57
|
+
theme: makeTheme(from: themeObject, themeSource: themeSource),
|
|
58
|
+
nfcAdapter: nil,
|
|
59
|
+
collectionDelegate: returnCollectedData ? self : nil
|
|
60
|
+
) else {
|
|
61
|
+
print("An error occurred while starting the Inquiry, invalid config.")
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
DispatchQueue.main.async {
|
|
65
|
+
guard let viewController = self.findTopViewController() else {
|
|
66
|
+
self.sendEvent(
|
|
67
|
+
withName: "onError",
|
|
68
|
+
body: [
|
|
69
|
+
"debugMessage": "Couldn't resolve a root view controller"
|
|
70
|
+
]
|
|
71
|
+
)
|
|
72
|
+
return
|
|
71
73
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
+
|
|
75
|
+
Inquiry(
|
|
76
|
+
config: config,
|
|
77
|
+
delegate: self
|
|
78
|
+
).start(from: viewController)
|
|
74
79
|
}
|
|
75
80
|
}
|
|
76
81
|
|
|
@@ -85,7 +90,7 @@ class PersonaInquiry2: RCTEventEmitter {
|
|
|
85
90
|
}
|
|
86
91
|
}
|
|
87
92
|
|
|
88
|
-
// MARK: -
|
|
93
|
+
// MARK: - InquiryDelegate
|
|
89
94
|
|
|
90
95
|
extension PersonaInquiry2: InquiryDelegate {
|
|
91
96
|
func inquiryComplete(inquiryId: String, status: String, fields: [String: InquiryField]) {
|
|
@@ -94,7 +99,8 @@ extension PersonaInquiry2: InquiryDelegate {
|
|
|
94
99
|
body: [
|
|
95
100
|
"inquiryId": inquiryId,
|
|
96
101
|
"status": status,
|
|
97
|
-
"fields": fieldsToDictionary(fields: fields)
|
|
102
|
+
"fields": fieldsToDictionary(fields: fields),
|
|
103
|
+
"collectedData": collectedData?.toDictionary()
|
|
98
104
|
]
|
|
99
105
|
)
|
|
100
106
|
}
|
|
@@ -120,109 +126,117 @@ extension PersonaInquiry2: InquiryDelegate {
|
|
|
120
126
|
}
|
|
121
127
|
}
|
|
122
128
|
|
|
123
|
-
// MARK: -
|
|
129
|
+
// MARK: - InquiryCollectionDelegate
|
|
124
130
|
|
|
125
|
-
extension PersonaInquiry2 {
|
|
131
|
+
extension PersonaInquiry2: InquiryCollectionDelegate {
|
|
126
132
|
|
|
127
|
-
|
|
128
|
-
|
|
133
|
+
func collectionComplete(data: InquiryData) {
|
|
134
|
+
self.collectedData = data
|
|
129
135
|
}
|
|
136
|
+
}
|
|
130
137
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
environment: environment,
|
|
170
|
-
fields: fields,
|
|
171
|
-
theme: theme
|
|
172
|
-
)
|
|
173
|
-
}
|
|
138
|
+
extension InquiryData {
|
|
139
|
+
|
|
140
|
+
func toDictionary() -> [String: Any?] {
|
|
141
|
+
var inquiryData = [[String: Any?]]()
|
|
142
|
+
for data in self.stepData {
|
|
143
|
+
var currentStepData = [String: Any?]()
|
|
144
|
+
|
|
145
|
+
switch data {
|
|
146
|
+
case .ui(let uiData):
|
|
147
|
+
currentStepData["type"] = "UiStepData"
|
|
148
|
+
currentStepData["stepName"] = uiData.name
|
|
149
|
+
currentStepData["componentParams"] = uiData.componentData.reduce(into: [[String: Any?]]()) { partial, element in
|
|
150
|
+
switch element {
|
|
151
|
+
case .int(let key, let value):
|
|
152
|
+
partial.append([key: value])
|
|
153
|
+
case .bool(let key, let value):
|
|
154
|
+
partial.append([key: value])
|
|
155
|
+
case .string(let key, let value):
|
|
156
|
+
partial.append([key: value])
|
|
157
|
+
case .strings(let key, let value):
|
|
158
|
+
partial.append([key: value])
|
|
159
|
+
case .double(let key, let value):
|
|
160
|
+
partial.append([key: value])
|
|
161
|
+
case .address(let key, let value):
|
|
162
|
+
partial.append([key: value])
|
|
163
|
+
default:
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
case .selfie(let selfieData):
|
|
168
|
+
currentStepData["type"] = "SelfieStepData"
|
|
169
|
+
currentStepData["stepName"] = selfieData.name
|
|
170
|
+
if let centerPhoto = selfieData.centerPhoto {
|
|
171
|
+
currentStepData["centerCapture"] = [
|
|
172
|
+
"captureMethod": centerPhoto.captureMethod,
|
|
173
|
+
"absoluteFilePath": centerPhoto.filePath
|
|
174
|
+
]
|
|
175
|
+
}
|
|
174
176
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
)
|
|
182
|
-
}
|
|
183
|
-
// Otherwise use the template version
|
|
184
|
-
else if let templateVersion = templateVersion {
|
|
185
|
-
|
|
186
|
-
// Use the account ID if we have it
|
|
187
|
-
if let accountId = accountId {
|
|
188
|
-
return InquiryConfiguration(
|
|
189
|
-
templateVersion: templateVersion,
|
|
190
|
-
accountId: accountId,
|
|
191
|
-
environment: environment,
|
|
192
|
-
fields: fields,
|
|
193
|
-
theme: theme
|
|
194
|
-
)
|
|
195
|
-
}
|
|
196
|
-
// Use the reference ID if we have it
|
|
197
|
-
else if let referenceId = referenceId {
|
|
198
|
-
return InquiryConfiguration(
|
|
199
|
-
templateVersion: templateVersion,
|
|
200
|
-
referenceId: referenceId,
|
|
201
|
-
environment: environment,
|
|
202
|
-
fields: fields,
|
|
203
|
-
theme: theme
|
|
204
|
-
)
|
|
205
|
-
}
|
|
177
|
+
if let leftPhoto = selfieData.leftPhoto {
|
|
178
|
+
currentStepData["leftCapture"] = [
|
|
179
|
+
"captureMethod": leftPhoto.captureMethod,
|
|
180
|
+
"absoluteFilePath": leftPhoto.filePath
|
|
181
|
+
]
|
|
182
|
+
}
|
|
206
183
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
184
|
+
if let rightPhoto = selfieData.rightPhoto {
|
|
185
|
+
currentStepData["rightCapture"] = [
|
|
186
|
+
"captureMethod": rightPhoto.captureMethod,
|
|
187
|
+
"absoluteFilePath": rightPhoto.filePath
|
|
188
|
+
]
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
case .governmentId(let govIdData):
|
|
192
|
+
currentStepData["type"] = "GovernmentIdStepData"
|
|
193
|
+
currentStepData["stepName"] = govIdData.name
|
|
194
|
+
|
|
195
|
+
var captures = [[String: Any]]()
|
|
196
|
+
for file in govIdData.files {
|
|
197
|
+
captures.append([
|
|
198
|
+
"idClass": govIdData.idClass,
|
|
199
|
+
"captureMethod": file.captureMethod,
|
|
200
|
+
"side": file.page,
|
|
201
|
+
"frames": file.frames.map {
|
|
202
|
+
["absoluteFilePath": $0.filePath]
|
|
203
|
+
}
|
|
204
|
+
])
|
|
205
|
+
}
|
|
206
|
+
currentStepData["captures"] = captures
|
|
207
|
+
case .document(let docData):
|
|
208
|
+
currentStepData["type"] = "DocumentStepData"
|
|
209
|
+
currentStepData["stepName"] = docData.name
|
|
210
|
+
|
|
211
|
+
var documents = [[String: String]]()
|
|
212
|
+
for file in docData.files {
|
|
213
|
+
documents.append(["absoluteFilePath": file.filePath])
|
|
214
|
+
}
|
|
215
|
+
currentStepData["documents"] = documents
|
|
216
|
+
default:
|
|
217
|
+
continue
|
|
218
|
+
}
|
|
219
|
+
inquiryData.append(currentStepData)
|
|
214
220
|
}
|
|
221
|
+
return ["stepData": inquiryData]
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// MARK: - Helpers
|
|
226
|
+
|
|
227
|
+
extension PersonaInquiry2 {
|
|
215
228
|
|
|
216
|
-
|
|
229
|
+
enum InvalidConfiguration: Error {
|
|
230
|
+
case argumentError(String)
|
|
217
231
|
}
|
|
218
232
|
|
|
219
233
|
/// Converts a dictionary into a theme
|
|
220
|
-
private func
|
|
234
|
+
private func makeTheme(from dictionary: [String: String]? = nil, themeSource: String? = nil) -> InquiryTheme? {
|
|
221
235
|
guard let dictionary = dictionary else {
|
|
222
236
|
return nil
|
|
223
237
|
}
|
|
224
238
|
|
|
225
|
-
var theme = InquiryTheme()
|
|
239
|
+
var theme = InquiryTheme(themeSource: themeSource == "server" ? .server : .client)
|
|
226
240
|
|
|
227
241
|
if let color = color(from: dictionary["backgroundColor"]) {
|
|
228
242
|
theme.backgroundColor = color
|