@quiltt/react-native 3.6.2 → 3.6.4

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/dist/index.js CHANGED
@@ -3,104 +3,17 @@ export * from '@quiltt/core';
3
3
  import { useQuilttSession, ConnectorSDKEventType } from '@quiltt/react';
4
4
  export { QuilttAuthProvider, QuilttProvider, QuilttSettingsProvider, useQuilttClient, useQuilttConnector, useQuilttSession, useQuilttSettings, useSession, useStorage } from '@quiltt/react';
5
5
  import { jsx, jsxs } from 'react/jsx-runtime';
6
- import { useRef, useMemo, useState, useCallback, useEffect } from 'react';
7
- import { StyleSheet, Platform, StatusBar, SafeAreaView, View, Text, Pressable, ActivityIndicator, Linking } from 'react-native';
6
+ import { useRef, useMemo, useState, useEffect, useCallback } from 'react';
8
7
  import { URL } from 'react-native-url-polyfill';
9
8
  import { WebView } from 'react-native-webview';
9
+ import { StyleSheet, Platform, StatusBar, SafeAreaView, View, Text, Pressable, ActivityIndicator, Linking } from 'react-native';
10
10
  import { generateStackTrace, makeBacktrace, getCauses } from '@honeybadger-io/core/build/src/util';
11
11
 
12
- const ErrorReporterConfig = {
13
- honeybadger_api_key: 'undefined'
14
- };
15
-
16
12
  // Generated by genversion.
17
- const version = '3.6.2';
18
-
19
- // Quick hack to send error to Honeybadger to debug why the connector is not routable
20
- const notifier = {
21
- name: 'Quiltt React Native SDK Reporter',
22
- url: 'https://www.quiltt.dev/guides/connector/react-native',
23
- version: version
24
- };
25
- class ErrorReporter {
26
- constructor(platform){
27
- this.noticeUrl = 'https://api.honeybadger.io/v1/notices';
28
- this.apiKey = ErrorReporterConfig.honeybadger_api_key;
29
- this.clientName = 'react-native-sdk';
30
- this.clientVersion = version;
31
- this.platform = platform;
32
- this.logger = console;
33
- this.userAgent = `${this.clientName} ${this.clientVersion}; ${this.platform}`;
34
- }
35
- async send(error, context) {
36
- const headers = {
37
- 'X-API-Key': this.apiKey,
38
- 'Content-Type': 'application/json',
39
- Accept: 'application/json',
40
- 'User-Agent': `${this.clientName} ${this.clientVersion}; ${this.platform}`
41
- };
42
- const payload = await this.buildPayload(error, context);
43
- const method = 'POST';
44
- const body = JSON.stringify(payload);
45
- const mode = 'cors';
46
- fetch(this.noticeUrl, {
47
- headers,
48
- method,
49
- body,
50
- mode
51
- }).then((response)=>{
52
- if (response.status !== 201) {
53
- this.logger.warn(`Error report failed: unknown response from server. code=${response.status}`);
54
- return;
55
- }
56
- return response.json();
57
- }).then((data)=>{
58
- if (data) {
59
- this.logger.info(`Error report sent ⚡ https://app.honeybadger.io/notice/${data?.id}`);
60
- }
61
- });
62
- }
63
- async buildPayload(error, localContext = {}) {
64
- const notice = error;
65
- notice.stack = generateStackTrace();
66
- notice.backtrace = makeBacktrace(notice.stack);
67
- return {
68
- notifier,
69
- error: {
70
- class: notice.name,
71
- message: notice.message,
72
- backtrace: notice.backtrace,
73
- // fingerprint: this.calculateFingerprint(notice),
74
- tags: notice.tags || [],
75
- causes: getCauses(notice, this.logger)
76
- },
77
- request: {
78
- url: notice.url,
79
- component: notice.component,
80
- action: notice.action,
81
- context: localContext || {},
82
- cgi_data: {},
83
- params: {},
84
- session: {}
85
- },
86
- server: {
87
- project_root: notice.projectRoot,
88
- environment_name: this.userAgent,
89
- revision: version,
90
- hostname: this.platform,
91
- time: new Date().toUTCString()
92
- },
93
- details: notice.details || {}
94
- };
95
- }
96
- }
13
+ const version = '3.6.4';
97
14
 
98
- const getErrorMessage = (responseStatus, error)=>{
99
- if (error) return `An error occurred while checking the connector URL: ${error?.name} \n${error?.message}`;
100
- return responseStatus ? `The URL is not routable. Response status: ${responseStatus}` : 'An error occurred while checking the connector URL';
101
- };
102
-
103
- const AndroidSafeAreaView = ({ children })=>/*#__PURE__*/ jsx(SafeAreaView, {
15
+ const AndroidSafeAreaView = ({ testId, children })=>/*#__PURE__*/ jsx(SafeAreaView, {
16
+ testID: testId,
104
17
  style: styles$1.AndroidSafeArea,
105
18
  children: children
106
19
  });
@@ -112,7 +25,8 @@ const styles$1 = StyleSheet.create({
112
25
  }
113
26
  });
114
27
 
115
- const ErrorScreen = ({ error, cta })=>/*#__PURE__*/ jsx(AndroidSafeAreaView, {
28
+ const ErrorScreen = ({ testId, error, cta })=>/*#__PURE__*/ jsx(AndroidSafeAreaView, {
29
+ testId: testId,
116
30
  children: /*#__PURE__*/ jsxs(View, {
117
31
  style: [
118
32
  styles.container,
@@ -195,7 +109,8 @@ const styles = StyleSheet.create({
195
109
  }
196
110
  });
197
111
 
198
- const LoadingScreen = ()=>/*#__PURE__*/ jsx(AndroidSafeAreaView, {
112
+ const LoadingScreen = ({ testId })=>/*#__PURE__*/ jsx(AndroidSafeAreaView, {
113
+ testId: testId,
199
114
  children: /*#__PURE__*/ jsx(View, {
200
115
  style: {
201
116
  flex: 1,
@@ -203,15 +118,152 @@ const LoadingScreen = ()=>/*#__PURE__*/ jsx(AndroidSafeAreaView, {
203
118
  alignItems: 'center'
204
119
  },
205
120
  children: /*#__PURE__*/ jsx(ActivityIndicator, {
121
+ testID: "activity-indicator",
206
122
  size: "large",
207
- color: "#0000ff"
123
+ color: "#5928A3"
208
124
  })
209
125
  })
210
126
  });
211
127
 
128
+ const ErrorReporterConfig = {
129
+ honeybadger_api_key: 'undefined'
130
+ };
131
+
132
+ // Quick hack to send error to Honeybadger to debug why the connector is not routable
133
+ const notifier = {
134
+ name: 'Quiltt React Native SDK Reporter',
135
+ url: 'https://www.quiltt.dev/guides/connector/react-native',
136
+ version: version
137
+ };
138
+ class ErrorReporter {
139
+ constructor(platform){
140
+ this.noticeUrl = 'https://api.honeybadger.io/v1/notices';
141
+ this.apiKey = ErrorReporterConfig.honeybadger_api_key;
142
+ this.clientName = 'react-native-sdk';
143
+ this.clientVersion = version;
144
+ this.platform = platform;
145
+ this.logger = console;
146
+ this.userAgent = `${this.clientName} ${this.clientVersion}; ${this.platform}`;
147
+ }
148
+ async send(error, context) {
149
+ const headers = {
150
+ 'X-API-Key': this.apiKey,
151
+ 'Content-Type': 'application/json',
152
+ Accept: 'application/json',
153
+ 'User-Agent': `${this.clientName} ${this.clientVersion}; ${this.platform}`
154
+ };
155
+ const payload = await this.buildPayload(error, context);
156
+ const method = 'POST';
157
+ const body = JSON.stringify(payload);
158
+ const mode = 'cors';
159
+ fetch(this.noticeUrl, {
160
+ headers,
161
+ method,
162
+ body,
163
+ mode
164
+ }).then((response)=>{
165
+ if (response.status !== 201) {
166
+ this.logger.warn(`Error report failed: unknown response from server. code=${response.status}`);
167
+ return;
168
+ }
169
+ return response.json();
170
+ }).then((data)=>{
171
+ if (data) {
172
+ this.logger.info(`Error report sent ⚡ https://app.honeybadger.io/notice/${data?.id}`);
173
+ }
174
+ });
175
+ }
176
+ async buildPayload(error, localContext = {}) {
177
+ const notice = error;
178
+ notice.stack = generateStackTrace();
179
+ notice.backtrace = makeBacktrace(notice.stack);
180
+ return {
181
+ notifier,
182
+ error: {
183
+ class: notice.name,
184
+ message: notice.message,
185
+ backtrace: notice.backtrace,
186
+ // fingerprint: this.calculateFingerprint(notice),
187
+ tags: notice.tags || [],
188
+ causes: getCauses(notice, this.logger)
189
+ },
190
+ request: {
191
+ url: notice.url,
192
+ component: notice.component,
193
+ action: notice.action,
194
+ context: localContext || {},
195
+ cgi_data: {},
196
+ params: {},
197
+ session: {}
198
+ },
199
+ server: {
200
+ project_root: notice.projectRoot,
201
+ environment_name: this.userAgent,
202
+ revision: version,
203
+ hostname: this.platform,
204
+ time: new Date().toUTCString()
205
+ },
206
+ details: notice.details || {}
207
+ };
208
+ }
209
+ }
210
+
211
+ const getErrorMessage = (responseStatus, error)=>{
212
+ if (error) return `An error occurred while checking the connector URL: ${error?.name} \n${error?.message}`;
213
+ return responseStatus ? `The URL is not routable. Response status: ${responseStatus}` : 'An error occurred while checking the connector URL';
214
+ };
215
+
212
216
  const errorReporter = new ErrorReporter(`${Platform.OS} ${Platform.Version}`);
213
217
  const PREFLIGHT_RETRY_COUNT = 3;
214
- const QuilttConnector = ({ connectorId, connectionId, institution, oauthRedirectUrl, onEvent, onLoad, onExit, onExitSuccess, onExitAbort, onExitError })=>{
218
+ const checkConnectorUrl = async (connectorUrl, retryCount = 0)=>{
219
+ let responseStatus;
220
+ let error;
221
+ let errorOccurred = false;
222
+ try {
223
+ const response = await fetch(connectorUrl);
224
+ if (!response.ok) {
225
+ console.error(`The URL ${connectorUrl} is not routable.`);
226
+ responseStatus = response.status;
227
+ errorOccurred = true;
228
+ } else {
229
+ console.log(`The URL ${connectorUrl} is routable.`);
230
+ return {
231
+ checked: true
232
+ };
233
+ }
234
+ } catch (e) {
235
+ error = e;
236
+ console.error(`An error occurred while checking the connector URL: ${error}`);
237
+ errorOccurred = true;
238
+ }
239
+ if (errorOccurred && retryCount < PREFLIGHT_RETRY_COUNT) {
240
+ const delay = 50 * Math.pow(2, retryCount);
241
+ await new Promise((resolve)=>setTimeout(resolve, delay));
242
+ console.log(`Retrying... Attempt number ${retryCount + 1}`);
243
+ return checkConnectorUrl(connectorUrl, retryCount + 1);
244
+ }
245
+ const errorMessage = getErrorMessage(responseStatus, error);
246
+ const errorToSend = error || new Error(errorMessage);
247
+ const context = {
248
+ connectorUrl,
249
+ responseStatus
250
+ };
251
+ if (responseStatus !== 404) await errorReporter.send(errorToSend, context);
252
+ return {
253
+ checked: true,
254
+ error: errorMessage
255
+ };
256
+ };
257
+
258
+ const handleOAuthUrl = (oauthUrl)=>{
259
+ if (oauthUrl.protocol !== 'https:') {
260
+ console.log(`handleOAuthUrl - Skipping non https url - ${oauthUrl.href}`);
261
+ return;
262
+ }
263
+ Linking.openURL(oauthUrl.href);
264
+ };
265
+
266
+ const QuilttConnector = ({ testId, connectorId, connectionId, institution, oauthRedirectUrl, onEvent, onLoad, onExit, onExitSuccess, onExitAbort, onExitError })=>{
215
267
  const webViewRef = useRef(null);
216
268
  const { session } = useQuilttSession();
217
269
  const encodedOAuthRedirectUrl = useMemo(()=>encodeURIComponent(oauthRedirectUrl), [
@@ -230,59 +282,15 @@ const QuilttConnector = ({ connectorId, connectionId, institution, oauthRedirect
230
282
  const [preFlightCheck, setPreFlightCheck] = useState({
231
283
  checked: false
232
284
  });
233
- const checkConnectorUrl = useCallback(async (retryCount = 0)=>{
234
- let responseStatus;
235
- let error;
236
- let errorOccurred = false;
237
- try {
238
- const response = await fetch(connectorUrl);
239
- if (!response.ok) {
240
- console.error(`The URL ${connectorUrl} is not routable.`);
241
- responseStatus = response.status;
242
- errorOccurred = true;
243
- } else {
244
- console.log(`The URL ${connectorUrl} is routable.`);
245
- return {
246
- checked: true
247
- };
248
- }
249
- } catch (e) {
250
- error = e;
251
- console.error(`An error occurred while checking the connector URL: ${error}`);
252
- errorOccurred = true;
253
- }
254
- // Retry logic in case of error or response not OK
255
- if (errorOccurred && retryCount < PREFLIGHT_RETRY_COUNT) {
256
- const delay = 50 * Math.pow(2, retryCount) // Exponential back-off
257
- ;
258
- await new Promise((resolve)=>setTimeout(resolve, delay)) // delay with exponential back-off for each retry
259
- ;
260
- console.log(`Retrying... Attempt number ${retryCount + 1}`);
261
- return checkConnectorUrl(retryCount + 1);
262
- }
263
- const errorMessage = getErrorMessage(responseStatus, error);
264
- const errorToSend = error || new Error(errorMessage);
265
- const context = {
266
- connectorUrl,
267
- responseStatus
268
- };
269
- if (responseStatus !== 404) errorReporter.send(errorToSend, context);
270
- return {
271
- checked: true,
272
- error: errorMessage
273
- };
274
- }, [
275
- connectorUrl
276
- ]);
277
285
  useEffect(()=>{
278
286
  if (preFlightCheck.checked) return;
279
287
  const fetchDataAndSetState = async ()=>{
280
- const connectorUrlStatus = await checkConnectorUrl();
288
+ const connectorUrlStatus = await checkConnectorUrl(connectorUrl);
281
289
  setPreFlightCheck(connectorUrlStatus);
282
290
  };
283
291
  fetchDataAndSetState();
284
292
  }, [
285
- checkConnectorUrl,
293
+ connectorUrl,
286
294
  preFlightCheck
287
295
  ]);
288
296
  const initInjectedJavaScript = useCallback(()=>{
@@ -312,7 +320,7 @@ const QuilttConnector = ({ connectorId, connectionId, institution, oauthRedirect
312
320
  ]);
313
321
  // allowedListUrl & shouldRender ensure we are only rendering Quiltt, MX and Plaid content in Webview
314
322
  // For other urls, we assume those are bank urls, which needs to be handle in external browser.
315
- // @todo Convert it to a list from Quiltt Server to prevent MX/ Plaid changes.
323
+ // TODO: Convert it to a list from Quiltt Server to prevent MX/ Plaid changes.
316
324
  const allowedListUrl = useMemo(()=>[
317
325
  'quiltt.app',
318
326
  'quiltt.dev',
@@ -334,13 +342,6 @@ const QuilttConnector = ({ connectorId, connectionId, institution, oauthRedirect
334
342
  const script = 'localStorage.clear();';
335
343
  webViewRef.current?.injectJavaScript(script);
336
344
  };
337
- const handleOAuthUrl = useCallback((oauthUrl)=>{
338
- if (oauthUrl.protocol !== 'https:') {
339
- console.log(`handleOAuthUrl - Skipping non https url - ${oauthUrl.href}`);
340
- return;
341
- }
342
- Linking.openURL(oauthUrl.href);
343
- }, []);
344
345
  const handleQuilttEvent = useCallback((url)=>{
345
346
  url.searchParams.delete('source');
346
347
  url.searchParams.append('connectorId', connectorId);
@@ -381,7 +382,6 @@ const QuilttConnector = ({ connectorId, connectionId, institution, oauthRedirect
381
382
  }
382
383
  }, [
383
384
  connectorId,
384
- handleOAuthUrl,
385
385
  initInjectedJavaScript,
386
386
  onEvent,
387
387
  onExit,
@@ -402,22 +402,26 @@ const QuilttConnector = ({ connectorId, connectionId, institution, oauthRedirect
402
402
  handleOAuthUrl(url);
403
403
  return false;
404
404
  }, [
405
- handleOAuthUrl,
406
405
  handleQuilttEvent,
407
406
  isQuilttEvent,
408
407
  shouldRender
409
408
  ]);
410
- if (!preFlightCheck.checked) return /*#__PURE__*/ jsx(LoadingScreen, {});
409
+ if (!preFlightCheck.checked) return /*#__PURE__*/ jsx(LoadingScreen, {
410
+ testId: "loading-screen"
411
+ });
411
412
  if (preFlightCheck.error) return /*#__PURE__*/ jsx(ErrorScreen, {
413
+ testId: "error-screen",
412
414
  error: preFlightCheck.error,
413
415
  cta: ()=>onExitError?.({
414
416
  connectorId
415
417
  })
416
418
  });
417
419
  return /*#__PURE__*/ jsx(AndroidSafeAreaView, {
420
+ testId: testId,
418
421
  children: /*#__PURE__*/ jsx(WebView, {
422
+ testID: "webview",
419
423
  ref: webViewRef,
420
- // Plaid keep sending window.location = 'about:srcdoc' and causes some noise in RN
424
+ // Plaid keeps sending window.location = 'about:srcdoc' and causes some noise in RN
421
425
  // All whitelists are now handled in requestHandler, handleQuilttEvent and handleOAuthUrl
422
426
  originWhitelist: [
423
427
  '*'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quiltt/react-native",
3
- "version": "3.6.2",
3
+ "version": "3.6.4",
4
4
  "description": "React Native components for Quiltt Connector",
5
5
  "homepage": "https://github.com/quiltt/quiltt-js/tree/main/packages/react-native#readme",
6
6
  "repository": {
@@ -11,13 +11,14 @@
11
11
  "license": "MIT",
12
12
  "type": "module",
13
13
  "exports": {
14
- ".": {
15
- "import": "./dist/index.js",
16
- "types": "./dist/index.d.ts"
14
+ "import": {
15
+ "default": "./dist/index.js"
16
+ },
17
+ "require": {
18
+ "default": "./dist/index.cjs"
17
19
  }
18
20
  },
19
21
  "main": "./dist/index.js",
20
- "module": "./dist/index.js",
21
22
  "types": "./dist/index.d.ts",
22
23
  "files": [
23
24
  "dist/**",
@@ -26,14 +27,14 @@
26
27
  ],
27
28
  "dependencies": {
28
29
  "@honeybadger-io/core": "6.6.0",
29
- "@quiltt/core": "3.6.2",
30
- "@quiltt/react": "3.6.2"
30
+ "@quiltt/core": "3.6.4",
31
+ "@quiltt/react": "3.6.4"
31
32
  },
32
33
  "devDependencies": {
33
34
  "@apollo/client": "3.9.9",
34
35
  "@trivago/prettier-plugin-sort-imports": "4.1.1",
35
36
  "@types/base-64": "0.1.0",
36
- "@types/node": "20.12.2",
37
+ "@types/node": "20.12.7",
37
38
  "@types/react": "18.2.73",
38
39
  "@types/react-native": "0.72.5",
39
40
  "@typescript-eslint/eslint-plugin": "5.60.1",
@@ -2,8 +2,14 @@ import { PropsWithChildren } from 'react'
2
2
 
3
3
  import { SafeAreaView, StyleSheet, Platform, StatusBar } from 'react-native'
4
4
 
5
- export const AndroidSafeAreaView = ({ children }: PropsWithChildren) => (
6
- <SafeAreaView style={styles.AndroidSafeArea}>{children}</SafeAreaView>
5
+ type AndroidSafeAreaViewProps = PropsWithChildren & {
6
+ testId?: string
7
+ }
8
+
9
+ export const AndroidSafeAreaView = ({ testId, children }: AndroidSafeAreaViewProps) => (
10
+ <SafeAreaView testID={testId} style={styles.AndroidSafeArea}>
11
+ {children}
12
+ </SafeAreaView>
7
13
  )
8
14
 
9
15
  const styles = StyleSheet.create({
@@ -2,13 +2,14 @@ import { View, Text, Pressable, StyleSheet } from 'react-native'
2
2
 
3
3
  import { AndroidSafeAreaView } from './AndroidSafeAreaView'
4
4
 
5
- type ErrorScreenProp = {
5
+ type ErrorScreenProps = {
6
+ testId?: string
6
7
  error: string
7
8
  cta: () => void
8
9
  }
9
10
 
10
- export const ErrorScreen = ({ error, cta }: ErrorScreenProp) => (
11
- <AndroidSafeAreaView>
11
+ export const ErrorScreen = ({ testId, error, cta }: ErrorScreenProps) => (
12
+ <AndroidSafeAreaView testId={testId}>
12
13
  <View style={[styles.container, styles.padding]}>
13
14
  <View style={{ flex: 1, justifyContent: 'center' }}>
14
15
  <View
@@ -2,10 +2,14 @@ import { ActivityIndicator, View } from 'react-native'
2
2
 
3
3
  import { AndroidSafeAreaView } from './AndroidSafeAreaView'
4
4
 
5
- export const LoadingScreen = () => (
6
- <AndroidSafeAreaView>
5
+ type LoadingScreenProps = {
6
+ testId?: string
7
+ }
8
+
9
+ export const LoadingScreen = ({ testId }: LoadingScreenProps) => (
10
+ <AndroidSafeAreaView testId={testId}>
7
11
  <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
8
- <ActivityIndicator size="large" color="#0000ff" />
12
+ <ActivityIndicator testID="activity-indicator" size="large" color="#5928A3" />
9
13
  </View>
10
14
  </AndroidSafeAreaView>
11
15
  )
@@ -1,6 +1,5 @@
1
1
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
2
2
 
3
- import { Linking, Platform } from 'react-native'
4
3
  // React Native's URL implementation is incomplete
5
4
  // https://github.com/facebook/react-native/issues/16434
6
5
  import { URL } from 'react-native-url-polyfill'
@@ -14,29 +13,23 @@ import {
14
13
  useQuilttSession,
15
14
  } from '@quiltt/react'
16
15
 
17
- import { ErrorReporter, getErrorMessage } from '../utils'
18
- import { version } from '../version'
16
+ import { version } from '@/version'
19
17
  import { AndroidSafeAreaView } from './AndroidSafeAreaView'
20
18
  import { ErrorScreen } from './ErrorScreen'
21
19
  import { LoadingScreen } from './LoadingScreen'
22
-
23
- const errorReporter = new ErrorReporter(`${Platform.OS} ${Platform.Version}`)
20
+ import { checkConnectorUrl, handleOAuthUrl } from '@/utils'
21
+ import type { PreFlightCheck } from '@/utils'
24
22
 
25
23
  type QuilttConnectorProps = {
24
+ testId?: string
26
25
  connectorId: string
27
26
  connectionId?: string
28
27
  institution?: string
29
28
  oauthRedirectUrl: string
30
29
  } & ConnectorSDKCallbacks
31
30
 
32
- type PreFlightCheck = {
33
- checked: boolean
34
- error?: string
35
- }
36
-
37
- const PREFLIGHT_RETRY_COUNT = 3
38
-
39
31
  const QuilttConnector = ({
32
+ testId,
40
33
  connectorId,
41
34
  connectionId,
42
35
  institution,
@@ -63,52 +56,14 @@ const QuilttConnector = ({
63
56
  }, [connectorId, encodedOAuthRedirectUrl])
64
57
  const [preFlightCheck, setPreFlightCheck] = useState<PreFlightCheck>({ checked: false })
65
58
 
66
- const checkConnectorUrl = useCallback(
67
- async (retryCount = 0): Promise<PreFlightCheck> => {
68
- let responseStatus
69
- let error
70
- let errorOccurred = false
71
- try {
72
- const response = await fetch(connectorUrl)
73
- if (!response.ok) {
74
- console.error(`The URL ${connectorUrl} is not routable.`)
75
- responseStatus = response.status
76
- errorOccurred = true
77
- } else {
78
- console.log(`The URL ${connectorUrl} is routable.`)
79
- return { checked: true }
80
- }
81
- } catch (e) {
82
- error = e
83
- console.error(`An error occurred while checking the connector URL: ${error}`)
84
- errorOccurred = true
85
- }
86
-
87
- // Retry logic in case of error or response not OK
88
- if (errorOccurred && retryCount < PREFLIGHT_RETRY_COUNT) {
89
- const delay = 50 * Math.pow(2, retryCount) // Exponential back-off
90
- await new Promise((resolve) => setTimeout(resolve, delay)) // delay with exponential back-off for each retry
91
- console.log(`Retrying... Attempt number ${retryCount + 1}`)
92
- return checkConnectorUrl(retryCount + 1)
93
- }
94
-
95
- const errorMessage = getErrorMessage(responseStatus, error as Error)
96
- const errorToSend = (error as Error) || new Error(errorMessage)
97
- const context = { connectorUrl, responseStatus }
98
- if (responseStatus !== 404) errorReporter.send(errorToSend, context)
99
- return { checked: true, error: errorMessage }
100
- },
101
- [connectorUrl]
102
- )
103
-
104
59
  useEffect(() => {
105
60
  if (preFlightCheck.checked) return
106
61
  const fetchDataAndSetState = async () => {
107
- const connectorUrlStatus = await checkConnectorUrl()
62
+ const connectorUrlStatus = await checkConnectorUrl(connectorUrl)
108
63
  setPreFlightCheck(connectorUrlStatus)
109
64
  }
110
65
  fetchDataAndSetState()
111
- }, [checkConnectorUrl, preFlightCheck])
66
+ }, [connectorUrl, preFlightCheck])
112
67
 
113
68
  const initInjectedJavaScript = useCallback(() => {
114
69
  const script = `\
@@ -133,7 +88,7 @@ const QuilttConnector = ({
133
88
 
134
89
  // allowedListUrl & shouldRender ensure we are only rendering Quiltt, MX and Plaid content in Webview
135
90
  // For other urls, we assume those are bank urls, which needs to be handle in external browser.
136
- // @todo Convert it to a list from Quiltt Server to prevent MX/ Plaid changes.
91
+ // TODO: Convert it to a list from Quiltt Server to prevent MX/ Plaid changes.
137
92
  const allowedListUrl = useMemo(
138
93
  () => [
139
94
  'quiltt.app',
@@ -162,14 +117,6 @@ const QuilttConnector = ({
162
117
  webViewRef.current?.injectJavaScript(script)
163
118
  }
164
119
 
165
- const handleOAuthUrl = useCallback((oauthUrl: URL) => {
166
- if (oauthUrl.protocol !== 'https:') {
167
- console.log(`handleOAuthUrl - Skipping non https url - ${oauthUrl.href}`)
168
- return
169
- }
170
- Linking.openURL(oauthUrl.href)
171
- }, [])
172
-
173
120
  const handleQuilttEvent = useCallback(
174
121
  (url: URL) => {
175
122
  url.searchParams.delete('source')
@@ -202,7 +149,7 @@ const QuilttConnector = ({
202
149
  onExitSuccess?.(metadata)
203
150
  break
204
151
  case 'Authenticate':
205
- // @todo handle Authenticate
152
+ // TODO: handle Authenticate
206
153
  break
207
154
  case 'OauthRequested':
208
155
  handleOAuthUrl(new URL(url.searchParams.get('oauthUrl') as string))
@@ -214,7 +161,6 @@ const QuilttConnector = ({
214
161
  },
215
162
  [
216
163
  connectorId,
217
- handleOAuthUrl,
218
164
  initInjectedJavaScript,
219
165
  onEvent,
220
166
  onExit,
@@ -239,18 +185,25 @@ const QuilttConnector = ({
239
185
  handleOAuthUrl(url)
240
186
  return false
241
187
  },
242
- [handleOAuthUrl, handleQuilttEvent, isQuilttEvent, shouldRender]
188
+ [handleQuilttEvent, isQuilttEvent, shouldRender]
243
189
  )
244
190
 
245
- if (!preFlightCheck.checked) return <LoadingScreen />
191
+ if (!preFlightCheck.checked) return <LoadingScreen testId="loading-screen" />
246
192
  if (preFlightCheck.error)
247
- return <ErrorScreen error={preFlightCheck.error} cta={() => onExitError?.({ connectorId })} />
193
+ return (
194
+ <ErrorScreen
195
+ testId="error-screen"
196
+ error={preFlightCheck.error}
197
+ cta={() => onExitError?.({ connectorId })}
198
+ />
199
+ )
248
200
 
249
201
  return (
250
- <AndroidSafeAreaView>
202
+ <AndroidSafeAreaView testId={testId}>
251
203
  <WebView
204
+ testID="webview"
252
205
  ref={webViewRef}
253
- // Plaid keep sending window.location = 'about:srcdoc' and causes some noise in RN
206
+ // Plaid keeps sending window.location = 'about:srcdoc' and causes some noise in RN
254
207
  // All whitelists are now handled in requestHandler, handleQuilttEvent and handleOAuthUrl
255
208
  originWhitelist={['*']}
256
209
  source={{ uri: connectorUrl }}