diff --git a/android/build.gradle b/android/build.gradle
index 75a0af56c4c2..f336c55df1d8 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -25,6 +25,8 @@ buildscript {
allprojects {
repositories {
+ maven { url "https://dl.bintray.com/onfido/maven" }
+
mavenLocal()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
diff --git a/apple-app-site-association b/apple-app-site-association
index 725beaea300a..59887c1f66d0 100644
--- a/apple-app-site-association
+++ b/apple-app-site-association
@@ -12,6 +12,7 @@
"/v/*",
"/add-bank-account/*",
"/iou/*",
+ "/enable-payments/*",
]
}
]
diff --git a/config/webpack/webpack.common.js b/config/webpack/webpack.common.js
index 872ff9fe96a8..dcc26ce71ec6 100644
--- a/config/webpack/webpack.common.js
+++ b/config/webpack/webpack.common.js
@@ -122,6 +122,10 @@ const webpackConfig = {
},
],
},
+ {
+ test: /\.css$/i,
+ use: ['style-loader', 'css-loader'],
+ },
],
},
resolve: {
diff --git a/ios/ExpensifyCash.xcodeproj/project.pbxproj b/ios/ExpensifyCash.xcodeproj/project.pbxproj
index bcb683c206ba..6b7d7a919afc 100644
--- a/ios/ExpensifyCash.xcodeproj/project.pbxproj
+++ b/ios/ExpensifyCash.xcodeproj/project.pbxproj
@@ -507,11 +507,13 @@
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ExpensifyCash-ExpensifyCashTests/Pods-ExpensifyCash-ExpensifyCashTests-frameworks.sh",
+ "${PODS_XCFRAMEWORKS_BUILD_DIR}/Onfido/Onfido.framework/Onfido",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL/OpenSSL.framework/OpenSSL",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/LinkKit/LinkKit.framework/LinkKit",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Onfido.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/LinkKit.framework",
);
@@ -537,11 +539,13 @@
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ExpensifyCash/Pods-ExpensifyCash-frameworks.sh",
+ "${PODS_XCFRAMEWORKS_BUILD_DIR}/Onfido/Onfido.framework/Onfido",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL/OpenSSL.framework/OpenSSL",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/LinkKit/LinkKit.framework/LinkKit",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Onfido.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/LinkKit.framework",
);
diff --git a/ios/ExpensifyCash/Info.plist b/ios/ExpensifyCash/Info.plist
index a58d21006572..403a68a328bf 100644
--- a/ios/ExpensifyCash/Info.plist
+++ b/ios/ExpensifyCash/Info.plist
@@ -63,8 +63,10 @@
+ NSMicrophoneUsageDescription
+ Required for video capture
NSCameraUsageDescription
- Your camera is used to create chat attachments.
+ Your camera is used to create chat attachments, documents, and facial capture.
NSLocationWhenInUseUsageDescription
Your location is used to determine your default currency.
NSPhotoLibraryAddUsageDescription
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index ce1061149197..5aef1f975e3c 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -150,6 +150,10 @@ PODS:
- nanopb/encode (= 1.30906.0)
- nanopb/decode (1.30906.0)
- nanopb/encode (1.30906.0)
+ - Onfido (20.1.0)
+ - onfido-react-native-sdk (1.3.3):
+ - Onfido (= 20.1.0)
+ - React
- OpenSSL-Universal (1.1.180)
- Permission-LocationAccuracy (3.0.1):
- RNPermissions
@@ -473,6 +477,7 @@ DEPENDENCIES:
- FlipperKit/SKIOSNetworkPlugin (= 0.75.1)
- Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`)
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
+ - "onfido-react-native-sdk (from `../node_modules/@onfido/react-native-sdk`)"
- Permission-LocationAccuracy (from `../node_modules/react-native-permissions/ios/LocationAccuracy`)
- Permission-LocationAlways (from `../node_modules/react-native-permissions/ios/LocationAlways`)
- Permission-LocationWhenInUse (from `../node_modules/react-native-permissions/ios/LocationWhenInUse`)
@@ -549,6 +554,7 @@ SPEC REPOS:
- GoogleUtilities
- libevent
- nanopb
+ - Onfido
- OpenSSL-Universal
- Plaid
- PromisesObjC
@@ -565,6 +571,8 @@ EXTERNAL SOURCES:
:podspec: "../node_modules/react-native/third-party-podspecs/Folly.podspec"
glog:
:podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec"
+ onfido-react-native-sdk:
+ :path: "../node_modules/@onfido/react-native-sdk"
Permission-LocationAccuracy:
:path: "../node_modules/react-native-permissions/ios/LocationAccuracy"
Permission-LocationAlways:
@@ -691,6 +699,8 @@ SPEC CHECKSUMS:
GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
+ Onfido: 116a268e4cb8b767c15285e8071c2e8304673cdf
+ onfido-react-native-sdk: b8f1b7cbe1adab6479d735275772390161630dcd
OpenSSL-Universal: 1aa4f6a6ee7256b83db99ec1ccdaa80d10f9af9b
Permission-LocationAccuracy: e8adff9ede1b23b43b7054a4500113d515fc87a8
Permission-LocationAlways: 7f7f373d086af7a81b2f4f20d65d29266ca2043b
diff --git a/package-lock.json b/package-lock.json
index d661555812ff..654b62486c5f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2308,6 +2308,15 @@
"regenerator-runtime": "^0.13.4"
}
},
+ "@babel/runtime-corejs3": {
+ "version": "7.14.0",
+ "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.0.tgz",
+ "integrity": "sha512-0R0HTZWHLk6G8jIk0FtoX+AatCtKnswS98VhXwGImFc759PJRp4Tru0PQYZofyijTFUr+gT8Mu7sgXVJLQ0ceg==",
+ "requires": {
+ "core-js-pure": "^3.0.0",
+ "regenerator-runtime": "^0.13.4"
+ }
+ },
"@babel/template": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz",
@@ -5187,6 +5196,11 @@
"@types/node": ">= 8"
}
},
+ "@onfido/react-native-sdk": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@onfido/react-native-sdk/-/react-native-sdk-1.3.3.tgz",
+ "integrity": "sha512-V8aU5wmYjCZWyQIkBkSxDvcuMBsxLMtzDfTOtA1o0rQ0vcw9iZ564pbtkQOMv4A0RcMErK/Gm1yUMb2GRYMmLg=="
+ },
"@pmmmwh/react-refresh-webpack-plugin": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.4.3.tgz",
@@ -5844,6 +5858,63 @@
"react-native-iphone-x-helper": "^1.3.0"
}
},
+ "@sentry/browser": {
+ "version": "5.30.0",
+ "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.30.0.tgz",
+ "integrity": "sha512-rOb58ZNVJWh1VuMuBG1mL9r54nZqKeaIlwSlvzJfc89vyfd7n6tQ1UXMN383QBz/MS5H5z44Hy5eE+7pCrYAfw==",
+ "requires": {
+ "@sentry/core": "5.30.0",
+ "@sentry/types": "5.30.0",
+ "@sentry/utils": "5.30.0",
+ "tslib": "^1.9.3"
+ }
+ },
+ "@sentry/core": {
+ "version": "5.30.0",
+ "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz",
+ "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==",
+ "requires": {
+ "@sentry/hub": "5.30.0",
+ "@sentry/minimal": "5.30.0",
+ "@sentry/types": "5.30.0",
+ "@sentry/utils": "5.30.0",
+ "tslib": "^1.9.3"
+ }
+ },
+ "@sentry/hub": {
+ "version": "5.30.0",
+ "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz",
+ "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==",
+ "requires": {
+ "@sentry/types": "5.30.0",
+ "@sentry/utils": "5.30.0",
+ "tslib": "^1.9.3"
+ }
+ },
+ "@sentry/minimal": {
+ "version": "5.30.0",
+ "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz",
+ "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==",
+ "requires": {
+ "@sentry/hub": "5.30.0",
+ "@sentry/types": "5.30.0",
+ "tslib": "^1.9.3"
+ }
+ },
+ "@sentry/types": {
+ "version": "5.30.0",
+ "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz",
+ "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw=="
+ },
+ "@sentry/utils": {
+ "version": "5.30.0",
+ "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz",
+ "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==",
+ "requires": {
+ "@sentry/types": "5.30.0",
+ "tslib": "^1.9.3"
+ }
+ },
"@sindresorhus/is": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
@@ -8829,6 +8900,27 @@
}
}
},
+ "css-loader": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz",
+ "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.3.1",
+ "cssesc": "^3.0.0",
+ "icss-utils": "^4.1.1",
+ "loader-utils": "^1.2.3",
+ "normalize-path": "^3.0.0",
+ "postcss": "^7.0.32",
+ "postcss-modules-extract-imports": "^2.0.0",
+ "postcss-modules-local-by-default": "^3.0.2",
+ "postcss-modules-scope": "^2.2.0",
+ "postcss-modules-values": "^3.0.0",
+ "postcss-value-parser": "^4.1.0",
+ "schema-utils": "^2.7.0",
+ "semver": "^6.3.0"
+ }
+ },
"electron-to-chromium": {
"version": "1.3.727",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.727.tgz",
@@ -8956,6 +9048,12 @@
"integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==",
"dev": true
},
+ "normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true
+ },
"p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -9012,6 +9110,29 @@
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true
},
+ "style-loader": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.3.0.tgz",
+ "integrity": "sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q==",
+ "dev": true,
+ "requires": {
+ "loader-utils": "^2.0.0",
+ "schema-utils": "^2.7.0"
+ },
+ "dependencies": {
+ "loader-utils": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
+ "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
+ "dev": true,
+ "requires": {
+ "big.js": "^5.2.2",
+ "emojis-list": "^3.0.0",
+ "json5": "^2.1.2"
+ }
+ }
+ }
+ },
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -11355,6 +11476,27 @@
"integrity": "sha512-Ne9DKPHTObRuB09Dru5AjwKjY4cJHVGu+y5f7coGn1E9Grkc3p2iBwE9AI/nJzsE29mQF7oq+mhYYRqOMFN1Bw==",
"dev": true
},
+ "css-loader": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz",
+ "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.3.1",
+ "cssesc": "^3.0.0",
+ "icss-utils": "^4.1.1",
+ "loader-utils": "^1.2.3",
+ "normalize-path": "^3.0.0",
+ "postcss": "^7.0.32",
+ "postcss-modules-extract-imports": "^2.0.0",
+ "postcss-modules-local-by-default": "^3.0.2",
+ "postcss-modules-scope": "^2.2.0",
+ "postcss-modules-values": "^3.0.0",
+ "postcss-value-parser": "^4.1.0",
+ "schema-utils": "^2.7.0",
+ "semver": "^6.3.0"
+ }
+ },
"detect-port": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.3.0.tgz",
@@ -11497,6 +11639,12 @@
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
},
+ "normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true
+ },
"p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -11624,6 +11772,29 @@
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true
},
+ "style-loader": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.3.0.tgz",
+ "integrity": "sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q==",
+ "dev": true,
+ "requires": {
+ "loader-utils": "^2.0.0",
+ "schema-utils": "^2.7.0"
+ },
+ "dependencies": {
+ "loader-utils": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
+ "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
+ "dev": true,
+ "requires": {
+ "big.js": "^5.2.2",
+ "emojis-list": "^3.0.0",
+ "json5": "^2.1.2"
+ }
+ }
+ }
+ },
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -12656,12 +12827,25 @@
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
"dev": true
},
+ "@types/component-emitter": {
+ "version": "1.2.10",
+ "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.10.tgz",
+ "integrity": "sha512-bsjleuRKWmGqajMerkzox19aGbscQX5rmmvvXl3wlIp5gMG1HgkiwPxsN5p070fBDKTNSPgojVbuY1+HWMbFhg=="
+ },
"@types/debug": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz",
"integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==",
"dev": true
},
+ "@types/dompurify": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-2.2.2.tgz",
+ "integrity": "sha512-8nNWfAa8/oZjH3OLY5Wsxu9ueo0NwVUotIi353g0P2+N5BuTLJyAVOnF4xBUY0NyFUGJHY05o1pO2bqLto+lmA==",
+ "requires": {
+ "@types/trusted-types": "*"
+ }
+ },
"@types/eslint-visitor-keys": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
@@ -12940,6 +13124,11 @@
"integrity": "sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==",
"dev": true
},
+ "@types/trusted-types": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.0.tgz",
+ "integrity": "sha512-I8MnZqNXsOLHsU111oHbn3khtvKMi5Bn4qVFsIWSJcCP1KKDiXX5AEw8UPk0nSopeC+Hvxt6yAy1/a5PailFqg=="
+ },
"@types/uglify-js": {
"version": "3.11.0",
"resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.11.0.tgz",
@@ -13873,6 +14062,11 @@
"resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
"integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E="
},
+ "array-flat-polyfill": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/array-flat-polyfill/-/array-flat-polyfill-1.0.1.tgz",
+ "integrity": "sha512-hfJmKupmQN0lwi0xG6FQ5U8Rd97RnIERplymOv/qpq8AoNKPPAnxJadjFA23FNWm88wykh9HmpLJUUwUtNU/iw=="
+ },
"array-flatten": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
@@ -14857,6 +15051,11 @@
"integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
"dev": true
},
+ "backo2": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
+ "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
+ },
"bail": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
@@ -14923,6 +15122,11 @@
"resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz",
"integrity": "sha1-eAqZyE59YAJgNhURxId2E78k9rs="
},
+ "base64-arraybuffer": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz",
+ "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI="
+ },
"base64-js": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
@@ -15032,6 +15236,11 @@
"bluebird": "^3.5.5"
}
},
+ "blueimp-load-image": {
+ "version": "2.29.0",
+ "resolved": "https://registry.npmjs.org/blueimp-load-image/-/blueimp-load-image-2.29.0.tgz",
+ "integrity": "sha512-psm81GlZ0ffKxVT0QN9dvhpzXMv1KxgXSg8ars0XGAcEGsTwFT2IPo59HDXlw4Lo2oImdPzwrwkliZSiLLUpIw=="
+ },
"bmp-js": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz",
@@ -15704,7 +15913,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
- "dev": true,
"requires": {
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.2"
@@ -16891,8 +17099,7 @@
"core-js-pure": {
"version": "3.12.1",
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.12.1.tgz",
- "integrity": "sha512-1cch+qads4JnDSWsvc7d6nzlKAippwjUlf6vykkTLW53VSV+NkE6muGBToAjEA8pG90cSfcud3JgVmW2ds5TaQ==",
- "dev": true
+ "integrity": "sha512-1cch+qads4JnDSWsvc7d6nzlKAippwjUlf6vykkTLW53VSV+NkE6muGBToAjEA8pG90cSfcud3JgVmW2ds5TaQ=="
},
"core-util-is": {
"version": "1.0.2",
@@ -17193,67 +17400,122 @@
}
},
"css-loader": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz",
- "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==",
+ "version": "5.2.4",
+ "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-5.2.4.tgz",
+ "integrity": "sha512-OFYGyINCKkdQsTrSYxzGSFnGS4gNjcXkKkQgWxK138jgnPt+lepxdjSZNc8sHAl5vP3DhsJUxufWIjOwI8PMMw==",
"dev": true,
"requires": {
- "camelcase": "^5.3.1",
- "cssesc": "^3.0.0",
- "icss-utils": "^4.1.1",
- "loader-utils": "^1.2.3",
- "normalize-path": "^3.0.0",
- "postcss": "^7.0.32",
- "postcss-modules-extract-imports": "^2.0.0",
- "postcss-modules-local-by-default": "^3.0.2",
- "postcss-modules-scope": "^2.2.0",
- "postcss-modules-values": "^3.0.0",
+ "camelcase": "^6.2.0",
+ "icss-utils": "^5.1.0",
+ "loader-utils": "^2.0.0",
+ "postcss": "^8.2.10",
+ "postcss-modules-extract-imports": "^3.0.0",
+ "postcss-modules-local-by-default": "^4.0.0",
+ "postcss-modules-scope": "^3.0.0",
+ "postcss-modules-values": "^4.0.0",
"postcss-value-parser": "^4.1.0",
- "schema-utils": "^2.7.0",
- "semver": "^6.3.0"
+ "schema-utils": "^3.0.0",
+ "semver": "^7.3.5"
},
"dependencies": {
- "json5": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
- "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
+ "camelcase": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz",
+ "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==",
+ "dev": true
+ },
+ "colorette": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz",
+ "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==",
+ "dev": true
+ },
+ "icss-utils": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
+ "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
+ "dev": true
+ },
+ "lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"requires": {
- "minimist": "^1.2.0"
+ "yallist": "^4.0.0"
}
},
- "loader-utils": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
- "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
+ "nanoid": {
+ "version": "3.1.23",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
+ "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==",
+ "dev": true
+ },
+ "postcss": {
+ "version": "8.2.15",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.15.tgz",
+ "integrity": "sha512-2zO3b26eJD/8rb106Qu2o7Qgg52ND5HPjcyQiK2B98O388h43A448LCslC0dI2P97wCAQRJsFvwTRcXxTKds+Q==",
"dev": true,
"requires": {
- "big.js": "^5.2.2",
- "emojis-list": "^3.0.0",
- "json5": "^1.0.1"
+ "colorette": "^1.2.2",
+ "nanoid": "^3.1.23",
+ "source-map": "^0.6.1"
}
},
- "normalize-path": {
+ "postcss-modules-extract-imports": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
+ "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
"dev": true
},
- "schema-utils": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
- "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==",
+ "postcss-modules-local-by-default": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz",
+ "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==",
"dev": true,
"requires": {
- "@types/json-schema": "^7.0.5",
- "ajv": "^6.12.4",
- "ajv-keywords": "^3.5.2"
+ "icss-utils": "^5.0.0",
+ "postcss-selector-parser": "^6.0.2",
+ "postcss-value-parser": "^4.1.0"
+ }
+ },
+ "postcss-modules-scope": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz",
+ "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==",
+ "dev": true,
+ "requires": {
+ "postcss-selector-parser": "^6.0.4"
+ }
+ },
+ "postcss-modules-values": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz",
+ "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==",
+ "dev": true,
+ "requires": {
+ "icss-utils": "^5.0.0"
}
},
"semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+ "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ },
+ "yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
}
}
@@ -17390,6 +17652,11 @@
"integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==",
"dev": true
},
+ "custom-event-polyfill": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/custom-event-polyfill/-/custom-event-polyfill-1.0.7.tgz",
+ "integrity": "sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w=="
+ },
"cyclist": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
@@ -18100,6 +18367,11 @@
"domelementtype": "1"
}
},
+ "dompurify": {
+ "version": "2.2.8",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.2.8.tgz",
+ "integrity": "sha512-9H0UL59EkDLgY3dUFjLV6IEUaHm5qp3mxSqWw7Yyx4Zhk2Jn2cmLe+CNPP3xy13zl8Bqg+0NehQzkdMoVhGRww=="
+ },
"domutils": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
@@ -18693,6 +18965,45 @@
"objectorarray": "^1.0.4"
}
},
+ "engine.io-client": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-5.1.1.tgz",
+ "integrity": "sha512-jPFpw2HLL0lhZ2KY0BpZhIJdleQcUO9W1xkIpo0h3d6s+5D6+EV/xgQw9qWOmymszv2WXef/6KUUehyxEKomlQ==",
+ "requires": {
+ "base64-arraybuffer": "0.1.4",
+ "component-emitter": "~1.3.0",
+ "debug": "~4.3.1",
+ "engine.io-parser": "~4.0.1",
+ "has-cors": "1.1.0",
+ "parseqs": "0.0.6",
+ "parseuri": "0.0.6",
+ "ws": "~7.4.2",
+ "yeast": "0.1.2"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+ "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "ws": {
+ "version": "7.4.5",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz",
+ "integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g=="
+ }
+ }
+ },
+ "engine.io-parser": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-4.0.2.tgz",
+ "integrity": "sha512-sHfEQv6nmtJrq6TKuIz5kyEKH/qSdK56H/A+7DnAuUPWosnIZAS2NHNcPLmyjtY3cGS/MqJdZbUjW97JU72iYg==",
+ "requires": {
+ "base64-arraybuffer": "0.1.4"
+ }
+ },
"enhanced-resolve": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz",
@@ -18727,6 +19038,11 @@
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
"dev": true
},
+ "enumerate-devices": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/enumerate-devices/-/enumerate-devices-1.1.1.tgz",
+ "integrity": "sha512-8zDbrc7ocusTL1ZGmvgy0cTwdyCaM7sGZoYLRmnWJalLQzmftDtce+uDU91gafOTo9MCtgjSIxyMv/F4+Hcchw=="
+ },
"env-paths": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
@@ -20287,6 +20603,11 @@
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
},
+ "eventemitter2": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-2.1.3.tgz",
+ "integrity": "sha1-vXIB+FxZVIOA4eQ7P2pyhtTac0k="
+ },
"eventemitter3": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
@@ -21331,6 +21652,14 @@
"integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==",
"dev": true
},
+ "for-each": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
+ "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
+ "requires": {
+ "is-callable": "^1.1.3"
+ }
+ },
"for-in": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
@@ -21786,7 +22115,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
"integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
- "dev": true,
"requires": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
@@ -22181,8 +22509,12 @@
"has-bigints": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz",
- "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==",
- "dev": true
+ "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA=="
+ },
+ "has-cors": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
+ "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk="
},
"has-flag": {
"version": "4.0.0",
@@ -22410,6 +22742,28 @@
"integrity": "sha512-oFLl873u4usRM9K63j4ME9u3etNF0PLiJhSQ8rdfuL51Wn3zkD6drf9ZW0dOzjnZI22YYG24z30JcmfCZjMgYg==",
"dev": true
},
+ "history": {
+ "version": "4.5.1",
+ "resolved": "https://registry.npmjs.org/history/-/history-4.5.1.tgz",
+ "integrity": "sha1-RJNaUQIeO45n66wmejVnVzKrpWk=",
+ "requires": {
+ "invariant": "^2.2.1",
+ "loose-envify": "^1.2.0",
+ "resolve-pathname": "^2.0.0",
+ "value-equal": "^0.2.0",
+ "warning": "^3.0.0"
+ },
+ "dependencies": {
+ "warning": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz",
+ "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=",
+ "requires": {
+ "loose-envify": "^1.0.0"
+ }
+ }
+ }
+ },
"hmac-drbg": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
@@ -23013,8 +23367,7 @@
"is-bigint": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz",
- "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==",
- "dev": true
+ "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA=="
},
"is-binary-path": {
"version": "2.1.0",
@@ -23028,7 +23381,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz",
"integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==",
- "dev": true,
"requires": {
"call-bind": "^1.0.2"
}
@@ -23223,8 +23575,7 @@
"is-number-object": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz",
- "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==",
- "dev": true
+ "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw=="
},
"is-obj": {
"version": "1.0.1",
@@ -23308,8 +23659,7 @@
"is-string": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz",
- "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==",
- "dev": true
+ "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ=="
},
"is-symbol": {
"version": "1.0.3",
@@ -30069,6 +30419,17 @@
}
}
},
+ "node-polyglot": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/node-polyglot/-/node-polyglot-2.4.0.tgz",
+ "integrity": "sha512-KRzKwzMWm3wSAjOSop7/WwNyzaMkCe9ddkwXTQsIZEJmvEnqy/bCqLpAVw6xBszKfy4iLdYVA0d83L+cIkYPbA==",
+ "requires": {
+ "for-each": "^0.3.3",
+ "has": "^1.0.3",
+ "string.prototype.trim": "^1.1.2",
+ "warning": "^4.0.3"
+ }
+ },
"node-releases": {
"version": "1.1.63",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.63.tgz",
@@ -30471,6 +30832,33 @@
"mimic-fn": "^1.0.0"
}
},
+ "onfido-sdk-ui": {
+ "version": "6.8.0",
+ "resolved": "https://registry.npmjs.org/onfido-sdk-ui/-/onfido-sdk-ui-6.8.0.tgz",
+ "integrity": "sha512-z230fiijqX3ZZDXVzpExSsz+qDhTvYgfiqLzJu53Dv03TQM1rkitbe4icRJTuk5Y8tSvcdX59hr8RSHn0pCrcQ==",
+ "requires": {
+ "@babel/runtime-corejs3": "^7.8.7",
+ "@sentry/browser": "^5.14.2",
+ "@types/dompurify": "^2.2.1",
+ "array-flat-polyfill": "^1.0.1",
+ "blueimp-load-image": "~2.29.0",
+ "classnames": "~2.2.5",
+ "custom-event-polyfill": "^1.0.7",
+ "dompurify": "^2.2.6",
+ "enumerate-devices": "^1.1.0",
+ "eventemitter2": "~2.1.3",
+ "history": "~4.5.1",
+ "hoist-non-react-statics": "^3.3.2",
+ "node-polyglot": "^2.2.2",
+ "parse-unit": "~1.0.1",
+ "pdfobject": "~2.0.201604172",
+ "preact": "^10.5.4",
+ "redux": "^4.0.5",
+ "socket.io-client": "^4.0.1",
+ "supports-webp": "~1.0.3",
+ "visibilityjs": "~1.2.4"
+ }
+ },
"open": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz",
@@ -30845,12 +31233,27 @@
"integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
"dev": true
},
+ "parse-unit": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parse-unit/-/parse-unit-1.0.1.tgz",
+ "integrity": "sha1-fhu21b7zh0wo45JSaiVBFwKR7s8="
+ },
"parse5": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
"integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==",
"dev": true
},
+ "parseqs": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz",
+ "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w=="
+ },
+ "parseuri": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz",
+ "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow=="
+ },
"parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@@ -30949,6 +31352,11 @@
"resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.5.207.tgz",
"integrity": "sha512-xGDUhnCYPfHy+unMXCLCJtlpZaaZ17Ew3WIL0tnSgKFUZXHAPD49GO9xScyszSsQMoutNDgRb+rfBXIaX/lJbw=="
},
+ "pdfobject": {
+ "version": "2.0.201604172",
+ "resolved": "https://registry.npmjs.org/pdfobject/-/pdfobject-2.0.201604172.tgz",
+ "integrity": "sha1-ES7fk7mL4SGl54Cwbn9feK0xqz8="
+ },
"pend": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
@@ -31409,6 +31817,11 @@
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz",
"integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ=="
},
+ "preact": {
+ "version": "10.5.13",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.5.13.tgz",
+ "integrity": "sha512-q/vlKIGNwzTLu+jCcvywgGrt+H/1P/oIRSD6mV4ln3hmlC+Aa34C7yfPI4+5bzW8pONyVXYS7SvXosy2dKKtWQ=="
+ },
"prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -33549,6 +33962,14 @@
"strip-indent": "^2.0.0"
}
},
+ "redux": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.0.tgz",
+ "integrity": "sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==",
+ "requires": {
+ "@babel/runtime": "^7.9.2"
+ }
+ },
"refractor": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/refractor/-/refractor-3.3.1.tgz",
@@ -34185,6 +34606,11 @@
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
"integrity": "sha1-six699nWiBvItuZTM17rywoYh0g="
},
+ "resolve-pathname": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.2.0.tgz",
+ "integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg=="
+ },
"resolve-url": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
@@ -34953,6 +35379,50 @@
}
}
},
+ "socket.io-client": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.1.2.tgz",
+ "integrity": "sha512-RDpWJP4DQT1XeexmeDyDkm0vrFc0+bUsHDKiVGaNISJvJonhQQOMqV9Vwfg0ZpPJ27LCdan7iqTI92FRSOkFWQ==",
+ "requires": {
+ "@types/component-emitter": "^1.2.10",
+ "backo2": "~1.0.2",
+ "component-emitter": "~1.3.0",
+ "debug": "~4.3.1",
+ "engine.io-client": "~5.1.1",
+ "parseuri": "0.0.6",
+ "socket.io-parser": "~4.0.4"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+ "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "requires": {
+ "ms": "2.1.2"
+ }
+ }
+ }
+ },
+ "socket.io-parser": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.4.tgz",
+ "integrity": "sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g==",
+ "requires": {
+ "@types/component-emitter": "^1.2.10",
+ "component-emitter": "~1.3.0",
+ "debug": "~4.3.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+ "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "requires": {
+ "ms": "2.1.2"
+ }
+ }
+ }
+ },
"sockjs": {
"version": "0.3.20",
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.20.tgz",
@@ -35613,6 +36083,99 @@
}
}
},
+ "string.prototype.trim": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.4.tgz",
+ "integrity": "sha512-hWCk/iqf7lp0/AgTF7/ddO1IWtSNPASjlzCicV5irAVdE1grjsneK26YG6xACMBEdCvO8fUST0UzDMh/2Qy+9Q==",
+ "requires": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.2"
+ },
+ "dependencies": {
+ "es-abstract": {
+ "version": "1.18.0",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz",
+ "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==",
+ "requires": {
+ "call-bind": "^1.0.2",
+ "es-to-primitive": "^1.2.1",
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.2",
+ "is-callable": "^1.2.3",
+ "is-negative-zero": "^2.0.1",
+ "is-regex": "^1.1.2",
+ "is-string": "^1.0.5",
+ "object-inspect": "^1.9.0",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.2",
+ "string.prototype.trimend": "^1.0.4",
+ "string.prototype.trimstart": "^1.0.4",
+ "unbox-primitive": "^1.0.0"
+ }
+ },
+ "has-symbols": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
+ "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
+ },
+ "is-callable": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz",
+ "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ=="
+ },
+ "is-negative-zero": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz",
+ "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w=="
+ },
+ "is-regex": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz",
+ "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==",
+ "requires": {
+ "call-bind": "^1.0.2",
+ "has-symbols": "^1.0.2"
+ }
+ },
+ "object-inspect": {
+ "version": "1.10.3",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz",
+ "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw=="
+ },
+ "object.assign": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
+ "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
+ "requires": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "has-symbols": "^1.0.1",
+ "object-keys": "^1.1.1"
+ }
+ },
+ "string.prototype.trimend": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz",
+ "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==",
+ "requires": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.3"
+ }
+ },
+ "string.prototype.trimstart": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz",
+ "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==",
+ "requires": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.3"
+ }
+ }
+ }
+ },
"string.prototype.trimend": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz",
@@ -35719,26 +36282,13 @@
"dev": true
},
"style-loader": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.3.0.tgz",
- "integrity": "sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-2.0.0.tgz",
+ "integrity": "sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ==",
"dev": true,
"requires": {
"loader-utils": "^2.0.0",
- "schema-utils": "^2.7.0"
- },
- "dependencies": {
- "schema-utils": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
- "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==",
- "dev": true,
- "requires": {
- "@types/json-schema": "^7.0.5",
- "ajv": "^6.12.4",
- "ajv-keywords": "^3.5.2"
- }
- }
+ "schema-utils": "^3.0.0"
}
},
"style-to-object": {
@@ -35791,6 +36341,11 @@
"supports-color": "^7.0.0"
}
},
+ "supports-webp": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/supports-webp/-/supports-webp-1.0.7.tgz",
+ "integrity": "sha512-ZlqT+sCgZKcykOLrk8DYR4t3Em+nyVSHpiV3q7uzOutLwKIYU23n88KibCLw3FzM4NCQeRorvZ55AV/77lQyOQ=="
+ },
"svg-parser": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz",
@@ -36683,8 +37238,7 @@
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
- "dev": true
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
},
"tsutils": {
"version": "3.17.1",
@@ -36805,7 +37359,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",
"integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==",
- "dev": true,
"requires": {
"function-bind": "^1.1.1",
"has-bigints": "^1.0.1",
@@ -36816,8 +37369,7 @@
"has-symbols": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
- "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
- "dev": true
+ "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
}
}
},
@@ -37298,6 +37850,11 @@
"spdx-expression-parse": "^3.0.0"
}
},
+ "value-equal": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-0.2.1.tgz",
+ "integrity": "sha1-wiCjBDYfzmmU277ao8fhobiVhx0="
+ },
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@@ -37350,6 +37907,11 @@
"unist-util-stringify-position": "^2.0.0"
}
},
+ "visibilityjs": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/visibilityjs/-/visibilityjs-1.2.8.tgz",
+ "integrity": "sha512-Y+aL3OUX88b+/VSmkmC2ApuLbf0grzbNLpCfIDSw3BzTU6PqcPsdgIOaw8b+eZoy+DdQqnVN3y/Evow9vQq9Ig=="
+ },
"vlq": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz",
@@ -37459,7 +38021,6 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
- "dev": true,
"requires": {
"loose-envify": "^1.0.0"
}
@@ -38640,7 +39201,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
"integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
- "dev": true,
"requires": {
"is-bigint": "^1.0.1",
"is-boolean-object": "^1.1.0",
@@ -38969,6 +39529,11 @@
"fd-slicer": "~1.1.0"
}
},
+ "yeast": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
+ "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk="
+ },
"yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
diff --git a/package.json b/package.json
index befbe74395e5..e6ea00966653 100644
--- a/package.json
+++ b/package.json
@@ -38,6 +38,7 @@
"@formatjs/intl-locale": "^2.4.21",
"@formatjs/intl-numberformat": "^6.2.5",
"@formatjs/intl-pluralrules": "^4.0.13",
+ "@onfido/react-native-sdk": "^1.3.3",
"@react-native-community/async-storage": "^1.11.0",
"@react-native-community/cli": "4.13.1",
"@react-native-community/clipboard": "^1.5.1",
@@ -66,6 +67,7 @@
"metro-config": "^0.64.0",
"moment": "^2.27.0",
"moment-timezone": "^0.5.31",
+ "onfido-sdk-ui": "^6.7.2",
"prop-types": "^15.7.2",
"pusher-js": "^7.0.0",
"react": "^16.13.1",
@@ -128,6 +130,7 @@
"clean-webpack-plugin": "^3.0.0",
"concurrently": "^5.3.0",
"copy-webpack-plugin": "^6.0.3",
+ "css-loader": "^5.2.4",
"detox": "^17.8.3",
"diff-so-fancy": "^1.3.0",
"electron": "^11.4.8",
@@ -151,6 +154,7 @@
"react-native-svg-transformer": "^0.14.3",
"react-test-renderer": "16.13.1",
"semver": "^7.3.4",
+ "style-loader": "^2.0.0",
"wait-port": "^0.2.9",
"webpack": "^4.44.1",
"webpack-bundle-analyzer": "^4.4.0",
diff --git a/src/CONST.js b/src/CONST.js
index ae6100b1b24a..ccdbe11abab4 100755
--- a/src/CONST.js
+++ b/src/CONST.js
@@ -18,6 +18,10 @@ const CONST = {
PRESSED: 'pressed',
COMPLETE: 'complete',
},
+ PLATFORM: {
+ IOS: 'ios',
+ ANDROID: 'android',
+ },
CURRENCY: {
USD: 'USD',
},
@@ -152,6 +156,26 @@ const CONST = {
RECONNECT: 1000,
},
+ WALLET: {
+ ERROR: {
+ IDENTITY_NOT_FOUND: 'Identity not found',
+ INVALID_SSN: 'Invalid SSN',
+ UNEXPECTED: 'Unexpected error',
+ MISSING_FIELD: 'Missing required additional details fields',
+ UNABLE_TO_VERIFY: 'Unable to verify identity',
+ },
+ STEP: {
+ ONFIDO: 'OnfidoStep',
+ ADDITIONAL_DETAILS: 'AdditionalDetailsStep',
+ TERMS: 'TermsStep',
+ ACTIVATE: 'ActivateStep',
+ },
+ STATUS: {
+ GOLD: 'GOLD',
+ SILVER: 'SILVER',
+ },
+ },
+
PLAID: {
EVENT: {
ERROR: 'ERROR',
@@ -159,6 +183,21 @@ const CONST = {
},
},
+ ONFIDO: {
+ CONTAINER_ID: 'onfido-mount',
+ TYPE: {
+ DOCUMENT: 'document',
+ FACE: 'face',
+ },
+ VARIANT: {
+ VIDEO: 'video',
+ },
+ SMS_NUMBER_COUNTRY_CODE: 'US',
+ ERROR: {
+ USER_CANCELLED: 'User canceled flow',
+ },
+ },
+
OS: {
WINDOWS: 'Windows',
MAC_OS: 'Mac OS',
diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js
index 13b64d521e4f..d7fcd65074f3 100755
--- a/src/ONYXKEYS.js
+++ b/src/ONYXKEYS.js
@@ -86,4 +86,16 @@ export default {
// Indicates which locale should be used
PREFERRED_LOCALE: 'preferredLocale',
+
+ // User's Expensify Wallet
+ USER_WALLET: 'userWallet',
+
+ // Object containing Onfido SDK Token + applicantID
+ WALLET_ONFIDO: 'walletOnfido',
+
+ // Stores information about additional details form entry
+ WALLET_ADDITIONAL_DETAILS: 'walletAdditionalDetails',
+
+ // Object containing Wallet terms step state
+ WALLET_TERMS: 'walletTerms',
};
diff --git a/src/ROUTES.js b/src/ROUTES.js
index 87dd0cdb4cc4..61c8542be45f 100644
--- a/src/ROUTES.js
+++ b/src/ROUTES.js
@@ -46,6 +46,7 @@ export default {
getReportParticipantRoute: (reportID, login) => `r/${reportID}/participants/${login}`,
VALIDATE_LOGIN: 'v',
VALIDATE_LOGIN_WITH_VALIDATE_CODE: 'v/:accountID/:validateCode',
+ ENABLE_PAYMENTS: 'enable-payments',
/**
* @param {String} route
diff --git a/src/components/Checkbox.js b/src/components/Checkbox.js
index 468ad305d0da..5d42345e0b42 100644
--- a/src/components/Checkbox.js
+++ b/src/components/Checkbox.js
@@ -17,7 +17,7 @@ const propTypes = {
};
const defaultProps = {
- label: '',
+ label: undefined,
};
const Checkbox = ({
diff --git a/src/components/FullscreenLoadingIndicator.js b/src/components/FullscreenLoadingIndicator.js
index 088aa7a50855..6a203a9690bb 100644
--- a/src/components/FullscreenLoadingIndicator.js
+++ b/src/components/FullscreenLoadingIndicator.js
@@ -6,7 +6,11 @@ import themeColors from '../styles/themes/default';
const propTypes = {
/** Controls whether the loader is mounted and displayed */
- visible: PropTypes.bool.isRequired,
+ visible: PropTypes.bool,
+};
+
+const defaultProps = {
+ visible: true,
};
/**
@@ -21,5 +25,6 @@ const FullScreenLoadingIndicator = ({visible}) => visible && (
);
FullScreenLoadingIndicator.propTypes = propTypes;
+FullScreenLoadingIndicator.defaultProps = defaultProps;
export default FullScreenLoadingIndicator;
diff --git a/src/components/Onfido/index.css b/src/components/Onfido/index.css
new file mode 100644
index 000000000000..fdee60611880
--- /dev/null
+++ b/src/components/Onfido/index.css
@@ -0,0 +1,13 @@
+/* These style overrides are necessary so that the Onfido modal looks nice */
+.onfido-sdk-ui-Modal-inner {
+ border-style: none !important;
+ width: 100% !important;
+}
+@media only screen and (max-width: 600px) {
+ .onfido-sdk-ui-Modal-inner {
+ /* This keeps the bottom of the Onfido window from being cut off on mobile web because the height was being
+ set to 100%, but we have a header on the top of the page that can be used to cancel out of the flow. This
+ spacing makes room for the header without cutting off the bottom of the Onfido window. */
+ height: 92% !important;
+ }
+}
diff --git a/src/components/Onfido/index.js b/src/components/Onfido/index.js
new file mode 100644
index 000000000000..1a5a64d83d1f
--- /dev/null
+++ b/src/components/Onfido/index.js
@@ -0,0 +1,71 @@
+import './index.css';
+import React from 'react';
+import * as OnfidoSDK from 'onfido-sdk-ui';
+import withLocalize, {withLocalizePropTypes} from '../withLocalize';
+import onfidoPropTypes from './onfidoPropTypes';
+import CONST from '../../CONST';
+import Growl from '../../libs/Growl';
+
+const propTypes = {
+ ...withLocalizePropTypes,
+ ...onfidoPropTypes,
+};
+
+class Onfido extends React.Component {
+ componentDidMount() {
+ this.onfidoOut = OnfidoSDK.init({
+ token: this.props.sdkToken,
+ containerId: CONST.ONFIDO.CONTAINER_ID,
+ steps: [
+ {
+ type: CONST.ONFIDO.TYPE.DOCUMENT,
+ options: {
+ useLiveDocumentCapture: true,
+ forceCrossDevice: true,
+ showCountrySelection: false,
+ documentTypes: {
+ national_identity_card: {
+ country: null,
+ },
+ residence_permit: {
+ country: null,
+ },
+ passport: true,
+ },
+ },
+ },
+ {
+ type: CONST.ONFIDO.TYPE.FACE,
+ options: {
+ requestedVariant: CONST.ONFIDO.VARIANT.VIDEO,
+ uploadFallback: false,
+ },
+ },
+ ],
+ smsNumberCountryCode: CONST.ONFIDO.SMS_NUMBER_COUNTRY_CODE.US,
+ showCountrySelection: false,
+ onComplete: this.props.onSuccess,
+ onError: () => {
+ this.props.onUserExit();
+ Growl.show(this.props.translate('onfidoStep.genericError'), CONST.GROWL.ERROR);
+ },
+ onUserExit: this.props.onUserExit,
+ onModalRequestClose: () => {},
+ });
+ }
+
+ componentWillUnmount() {
+ if (this.onfidoOut) {
+ this.onfidoOut.tearDown();
+ }
+ }
+
+ render() {
+ return (
+
+ );
+ }
+}
+
+Onfido.propTypes = propTypes;
+export default withLocalize(Onfido);
diff --git a/src/components/Onfido/index.native.js b/src/components/Onfido/index.native.js
new file mode 100644
index 000000000000..9f46b56361f0
--- /dev/null
+++ b/src/components/Onfido/index.native.js
@@ -0,0 +1,48 @@
+import React from 'react';
+import {
+ Onfido as OnfidoSDK,
+ OnfidoCaptureType,
+ OnfidoDocumentType,
+ OnfidoCountryCode,
+} from '@onfido/react-native-sdk';
+import onfidoPropTypes from './onfidoPropTypes';
+import CONST from '../../CONST';
+import withLocalize, {withLocalizePropTypes} from '../withLocalize';
+import Growl from '../../libs/Growl';
+
+const propTypes = {
+ ...withLocalizePropTypes,
+ ...onfidoPropTypes,
+};
+
+class Onfido extends React.Component {
+ componentDidMount() {
+ OnfidoSDK.start({
+ sdkToken: this.props.sdkToken,
+ flowSteps: {
+ welcome: true,
+ captureFace: {
+ type: OnfidoCaptureType.VIDEO,
+ },
+ captureDocument: {
+ docType: OnfidoDocumentType.GENERIC,
+ countryCode: OnfidoCountryCode.USA,
+ },
+ },
+ })
+ .then(this.props.onSuccess)
+ .catch((error) => {
+ if (error.message === CONST.ONFIDO.ERROR.USER_CANCELLED) {
+ this.props.onUserExit();
+ Growl.show(this.props.translate('onfidoStep.genericError'), CONST.GROWL.ERROR);
+ }
+ });
+ }
+
+ render() {
+ return null;
+ }
+}
+
+Onfido.propTypes = propTypes;
+export default withLocalize(Onfido);
diff --git a/src/components/Onfido/onfidoPropTypes.js b/src/components/Onfido/onfidoPropTypes.js
new file mode 100644
index 000000000000..a45b124c1398
--- /dev/null
+++ b/src/components/Onfido/onfidoPropTypes.js
@@ -0,0 +1,12 @@
+import PropTypes from 'prop-types';
+
+export default {
+ /** Token used to initialize the Onfido SDK */
+ sdkToken: PropTypes.string.isRequired,
+
+ /** Called when the user intentionally exits the flow without completing it */
+ onUserExit: PropTypes.func.isRequired,
+
+ /** Called when the user is totally done with Onfido */
+ onSuccess: PropTypes.func.isRequired,
+};
diff --git a/src/components/TextInputWithLabel.js b/src/components/TextInputWithLabel.js
new file mode 100644
index 000000000000..e129dd6fb462
--- /dev/null
+++ b/src/components/TextInputWithLabel.js
@@ -0,0 +1,36 @@
+import _ from 'underscore';
+import React from 'react';
+import {Text, TextInput} from 'react-native';
+import PropTypes from 'prop-types';
+import styles from '../styles/styles';
+
+const propTypes = {
+ /** Label text */
+ label: PropTypes.string.isRequired,
+
+ /** Text to show if there is an error */
+ errorText: PropTypes.string,
+};
+
+const defaultProps = {
+ errorText: '',
+};
+
+const TextInputWithLabel = props => (
+ <>
+ {props.label}
+
+ {props.errorText !== '' && (
+ {props.errorText}
+ )}
+ >
+);
+
+TextInputWithLabel.propTypes = propTypes;
+TextInputWithLabel.defaultProps = defaultProps;
+TextInputWithLabel.displayName = 'TextInputWithLabel';
+export default TextInputWithLabel;
diff --git a/src/components/TextLink.js b/src/components/TextLink.js
new file mode 100644
index 000000000000..9c538073c0e4
--- /dev/null
+++ b/src/components/TextLink.js
@@ -0,0 +1,44 @@
+import _ from 'underscore';
+import React from 'react';
+import PropTypes from 'prop-types';
+import {Text, Pressable} from 'react-native';
+import openURLInNewTab from '../libs/openURLInNewTab';
+import styles from '../styles/styles';
+
+const propTypes = {
+ /** Link to open in new tab */
+ href: PropTypes.string.isRequired,
+
+ /** Text content child */
+ children: PropTypes.string.isRequired,
+
+ /** Additional style props */
+ style: PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object)]),
+};
+
+const defaultProps = {
+ style: [],
+};
+
+const TextLink = (props) => {
+ const additionalStyles = _.isArray(props.style) ? props.style : [props.style];
+ return (
+ {
+ openURLInNewTab(props.href);
+ }}
+ >
+ {({hovered, pressed}) => (
+
+ {props.children}
+
+ )}
+
+ );
+};
+
+TextLink.defaultProps = defaultProps;
+TextLink.propTypes = propTypes;
+TextLink.displayName = 'TextLink';
+export default TextLink;
diff --git a/src/languages/en.js b/src/languages/en.js
index 33fb0d8c39cd..da87f117e21b 100755
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -26,6 +26,7 @@ export default {
email: 'Email',
and: 'and',
details: 'Details',
+ privacyPolicy: 'Privacy Policy',
delete: 'Delete',
contacts: 'Contacts',
recents: 'Recents',
@@ -275,6 +276,45 @@ export default {
noPhoneNumber: 'Please enter a phone number including the country code e.g +447814266907',
maxParticipantsReached: 'You\'ve reached the maximum number of participants for a group chat.',
},
+ onfidoStep: {
+ acceptTerms: 'By continuing with the request to activate your Expensify wallet, you confirm that you have read, understand and accept ',
+ facialScan: 'Onfido’s Facial Scan Policy and Release',
+ termsOfService: 'Terms of Service',
+ tryAgain: 'Try Again',
+ verifyIdentity: 'Verify Identity',
+ genericError: 'There was an error while processing this step. Please try again.',
+ },
+ additionalDetailsStep: {
+ headerTitle: 'Additional Details',
+ helpText: 'We need to confirm the following information before we can process this payment.',
+ helpLink: 'Learn more about why we need this.',
+ legalFirstNameLabel: 'Legal First Name',
+ legalMiddleNameLabel: 'Legal Middle Name',
+ legalLastNameLabel: 'Legal Last Name',
+ addressLabel: 'Address (no P.O. boxes)',
+ cityLabel: 'City',
+ stateLabel: 'State',
+ zipCodeLabel: 'Zip Code',
+ phoneNumberLabel: 'Phone Number',
+ dobLabel: 'Date of Birth',
+ ssnLabel: 'Social Security Number',
+ continueButtonText: 'Save & Continue',
+ isRequiredField: 'is a required field.',
+ },
+ termsStep: {
+ headerTitle: 'Terms and Fees',
+ haveReadAndAgree: 'I have read and agree to receive ',
+ electronicDisclosures: 'electronic disclosures',
+ agreeToThe: 'I agree to the ',
+ walletAgreement: 'Wallet Agreement',
+ enablePayments: 'Enable Payments',
+ termsMustBeAccepted: 'Terms must be accepted',
+ },
+ activateStep: {
+ headerTitle: 'Enable Payments',
+ activated: 'Your Expensify Wallet is ready to use.',
+ checkBackLater: 'We\'re still reviewing your information. Please check back later.',
+ },
session: {
offlineMessage: 'Looks like you\'re not connected to internet. Can you check your connection and try again?',
},
diff --git a/src/libs/API.js b/src/libs/API.js
index 0fc178bd4473..5a3918173bbf 100644
--- a/src/libs/API.js
+++ b/src/libs/API.js
@@ -5,6 +5,7 @@ import CONFIG from '../CONFIG';
import ONYXKEYS from '../ONYXKEYS';
import redirectToSignIn from './actions/SignInRedirect';
import * as Network from './Network';
+import isViaExpensifyCashNative from './isViaExpensifyCashNative';
let isAuthenticating;
let credentials;
@@ -736,6 +737,18 @@ function CreateIOUSplit(parameters) {
return Network.post(commandName, parameters);
}
+/**
+ * @returns {Promise}
+ */
+function Wallet_GetOnfidoSDKToken() {
+ return Network.post('Wallet_GetOnfidoSDKToken', {
+ // We need to pass this so we can request a token with the correct referrer
+ // This value comes from a cross-platform module which returns true for native
+ // platforms and false for non-native platforms.
+ isViaExpensifyCashNative,
+ }, CONST.NETWORK.METHOD.POST, true);
+}
+
/**
* @returns {Promise}
*/
@@ -743,6 +756,20 @@ function Plaid_GetLinkToken() {
return Network.post('Plaid_GetLinkToken', {}, CONST.NETWORK.METHOD.POST, true);
}
+/**
+ * @param {Object} parameters
+ * @param {String} parameters.currentStep
+ * @param {String} [parameters.onfidoData] - JSON string
+ * @param {String} [parameters.personalDetails] - JSON string
+ * @param {Boolean} [parameters.hasAcceptedTerms]
+ * @returns {Promise}
+ */
+function Wallet_Activate(parameters) {
+ const commandName = 'Wallet_Activate';
+ requireParameters(['currentStep'], parameters, commandName);
+ return Network.post(commandName, parameters, CONST.NETWORK.METHOD.POST, true);
+}
+
/**
* @param {Object} parameters
* @param {String} parameters.publicToken
@@ -860,6 +887,8 @@ export {
CreateIOUTransaction,
CreateIOUSplit,
ValidateEmail,
+ Wallet_Activate,
+ Wallet_GetOnfidoSDKToken,
GetPreferredCurrency,
GetCurrencyList,
};
diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js
index 5c59b384e353..1df7250464ef 100644
--- a/src/libs/Navigation/AppNavigator/AuthScreens.js
+++ b/src/libs/Navigation/AppNavigator/AuthScreens.js
@@ -48,6 +48,7 @@ import {
NewGroupModalStackNavigator,
NewChatModalStackNavigator,
SettingsModalStackNavigator,
+ EnablePaymentsStackNavigator,
AddBankAccountModalStackNavigator,
} from './ModalStackNavigators';
import SCREENS from '../../../SCREENS';
@@ -253,6 +254,12 @@ class AuthScreens extends React.Component {
component={IOUBillStackNavigator}
listeners={modalScreenListeners}
/>
+
{
+ const apiResult = lodashGet(response, ['requestorIdentityOnfido', 'apiResult'], {});
+ Onyx.merge(ONYXKEYS.WALLET_ONFIDO, {
+ applicantID: apiResult.applicantID,
+ sdkToken: apiResult.sdkToken,
+ loading: false,
+ hasAcceptedPrivacyPolicy: true,
+ });
+ })
+ .catch(() => Onyx.set(ONYXKEYS.WALLET_ONFIDO, {loading: false, error: CONST.WALLET.ERROR.UNEXPECTED}));
+}
+
+/**
+ * Privately used to update the additionalDetails object in Onyx (which will have various effects on the UI)
+ *
+ * @param {Boolean} loading whether we are making the API call to validate the user's provided personal details
+ * @param {String[]} [errorFields] an array of field names that should display errors in the UI
+ * @param {String} [additionalErrorMessage] an additional error message to display in the UI
+ * @private
+ */
+function setAdditionalDetailsStep(loading, errorFields = null, additionalErrorMessage = '') {
+ Onyx.merge(ONYXKEYS.WALLET_ADDITIONAL_DETAILS, {loading, errorFields, additionalErrorMessage});
+}
+
+/**
+ * This action can be called repeatedly with different steps until an Expensify Wallet has been activated.
+ *
+ * Possible steps:
+ *
+ * - OnfidoStep - Creates an identity check by calling Onfido's API (via Web-Secure) with data returned from the SDK
+ * - AdditionalDetailsStep - Validates a user's provided details against a series of checks
+ * - TermsStep - Ensures that a user has agreed to all of the terms and conditions
+ *
+ * The API will always return the updated userWallet in the response as a convenience so we can avoid calling
+ * Get&returnValueList=userWallet after we call Wallet_Activate.
+ *
+ * @param {String} currentStep
+ * @param {Object} parameters
+ * @param {String} [parameters.onfidoData] - JSON string
+ * @param {Object} [parameters.personalDetails] - JSON string
+ * @param {Boolean} [parameters.hasAcceptedTerms]
+ */
+function activateWallet(currentStep, parameters) {
+ let personalDetails;
+ let onfidoData;
+ let hasAcceptedTerms;
+
+ if (!_.contains(CONST.WALLET.STEP, currentStep)) {
+ throw new Error('Invalid currentStep passed to activateWallet()');
+ }
+
+ if (currentStep === CONST.WALLET.STEP.ONFIDO) {
+ onfidoData = parameters.onfidoData;
+ Onyx.merge(ONYXKEYS.WALLET_ONFIDO, {error: '', loading: true});
+ } else if (currentStep === CONST.WALLET.STEP.ADDITIONAL_DETAILS) {
+ setAdditionalDetailsStep(true);
+
+ // Personal details are heavily validated on the API side. We will only do a quick check to ensure the values
+ // exist in some capacity and then stringify them.
+ const errorFields = _.reduce(CONST.WALLET.REQUIRED_ADDITIONAL_DETAILS_FIELDS, (missingFields, fieldName) => (
+ !personalDetails[fieldName] ? [...missingFields, fieldName] : missingFields
+ ), []);
+
+ if (!_.isEmpty(errorFields)) {
+ setAdditionalDetailsStep(false, errorFields);
+ return;
+ }
+
+ personalDetails = JSON.stringify(parameters.personalDetails);
+ } else if (currentStep === CONST.WALLET.STEP.TERMS) {
+ hasAcceptedTerms = parameters.hasAcceptedTerms;
+ Onyx.merge(ONYXKEYS.WALLET_TERMS, {loading: true});
+ }
+
+ API.Wallet_Activate({
+ currentStep,
+ personalDetails,
+ onfidoData,
+ hasAcceptedTerms,
+ })
+ .then((response) => {
+ if (response.jsonCode !== 200) {
+ if (currentStep === CONST.WALLET.STEP.ONFIDO) {
+ Onyx.merge(ONYXKEYS.WALLET_ONFIDO, {error: response.message, loading: false});
+ return;
+ }
+
+ if (currentStep === CONST.WALLET.STEP.ADDITIONAL_DETAILS) {
+ if (response.title === CONST.WALLET.ERROR.MISSING_FIELD) {
+ setAdditionalDetailsStep(false, response.data.fieldNames);
+ return;
+ }
+
+ const errorTitles = [
+ CONST.WALLET.ERROR.IDENTITY_NOT_FOUND,
+ CONST.WALLET.ERROR.INVALID_SSN,
+ CONST.WALLET.ERROR.UNEXPECTED,
+ CONST.WALLET.ERROR.UNABLE_TO_VERIFY,
+ ];
+
+ if (errorTitles.includes(response.title)) {
+ setAdditionalDetailsStep(false, null, response.message);
+ return;
+ }
+
+ setAdditionalDetailsStep(false);
+ return;
+ }
+
+ return;
+ }
+
+ Onyx.merge(ONYXKEYS.USER_WALLET, response.userWallet);
+
+ if (currentStep === CONST.WALLET.STEP.ONFIDO) {
+ Onyx.merge(ONYXKEYS.WALLET_ONFIDO, {error: '', loading: true});
+ } else if (currentStep === CONST.WALLET.STEP.ADDITIONAL_DETAILS) {
+ setAdditionalDetailsStep(false);
+ } else if (currentStep === CONST.WALLET.STEP.TERMS) {
+ Onyx.merge(ONYXKEYS.WALLET_TERMS, {loading: false});
+ }
+ });
+}
+
+/**
+ * Fetches information about a user's Expensify Wallet
+ *
+ * @typedef {Object} UserWallet
+ * @property {Number} availableBalance
+ * @property {Number} currentBalance
+ * @property {String} currentStep - used to track which step of the "activate wallet" flow a user is in
+ * @property {('SILVER'|'GOLD')} status - will be GOLD when fully activated. SILVER is able to recieve funds only.
+ */
+function fetchUserWallet() {
+ API.Get({returnValueList: 'userWallet'})
+ .then((response) => {
+ if (response.jsonCode !== 200) {
+ return;
+ }
+
+ Onyx.merge(ONYXKEYS.USER_WALLET, response.userWallet);
+ });
+}
+
export {
fetchPlaidLinkToken,
addPlaidBankAccount,
getPlaidBankAccounts,
clearPlaidBankAccounts,
+ fetchOnfidoToken,
+ activateWallet,
+ fetchUserWallet,
};
diff --git a/src/libs/getPlatform/index.android.js b/src/libs/getPlatform/index.android.js
index f7dc545d49f6..1a343700a2f9 100644
--- a/src/libs/getPlatform/index.android.js
+++ b/src/libs/getPlatform/index.android.js
@@ -1,3 +1,5 @@
+import CONST from '../../CONST';
+
export default function getPlatform() {
- return 'android';
+ return CONST.PLATFORM.ANDROID;
}
diff --git a/src/libs/getPlatform/index.ios.js b/src/libs/getPlatform/index.ios.js
index a74a94edcc45..d91604a5c41a 100644
--- a/src/libs/getPlatform/index.ios.js
+++ b/src/libs/getPlatform/index.ios.js
@@ -1,3 +1,5 @@
+import CONST from '../../CONST';
+
export default function getPlatform() {
- return 'ios';
+ return CONST.PLATFORM.IOS;
}
diff --git a/src/libs/isViaExpensifyCashNative/index.js b/src/libs/isViaExpensifyCashNative/index.js
new file mode 100644
index 000000000000..21e5dd254a47
--- /dev/null
+++ b/src/libs/isViaExpensifyCashNative/index.js
@@ -0,0 +1,8 @@
+/**
+ * The API library has a request for Wallet_GetOnfidoSDKToken which needs to know if the request is coming from
+ * the native platform or the non-native platform. This module will return true for the native platforms and false
+ * for the non-native platforms
+ * @type {boolean}
+ */
+const isViaExpensifyCashNative = false;
+export default isViaExpensifyCashNative;
diff --git a/src/libs/isViaExpensifyCashNative/index.native.js b/src/libs/isViaExpensifyCashNative/index.native.js
new file mode 100644
index 000000000000..44d4c5e456d2
--- /dev/null
+++ b/src/libs/isViaExpensifyCashNative/index.native.js
@@ -0,0 +1,8 @@
+/**
+ * The API library has a request for Wallet_GetOnfidoSDKToken which needs to know if the request is coming from
+ * the native platform or the non-native platform. This module will return true for the native platforms and false
+ * for the non-native platforms
+ * @type {boolean}
+ */
+const isViaExpensifyCashNative = true;
+export default isViaExpensifyCashNative;
diff --git a/src/pages/EnablePayments/ActivateStep.js b/src/pages/EnablePayments/ActivateStep.js
new file mode 100644
index 000000000000..e6ab3b805547
--- /dev/null
+++ b/src/pages/EnablePayments/ActivateStep.js
@@ -0,0 +1,40 @@
+import React from 'react';
+import {View, Text} from 'react-native';
+import ScreenWrapper from '../../components/ScreenWrapper';
+import HeaderWithCloseButton from '../../components/HeaderWithCloseButton';
+import Navigation from '../../libs/Navigation/Navigation';
+import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
+import styles from '../../styles/styles';
+import userWalletPropTypes from './userWalletPropTypes';
+import CONST from '../../CONST';
+
+const propTypes = {
+ ...withLocalizePropTypes,
+ ...userWalletPropTypes,
+};
+
+const defaultProps = {
+ userWallet: {},
+};
+
+const ActivateStep = props => (
+
+ Navigation.dismissModal()}
+ />
+
+ {props.userWallet.status === CONST.WALLET.STATUS.GOLD && (
+ {props.translate('activateStep.activated')}
+ )}
+ {props.userWallet.status === CONST.WALLET.STATUS.SILVER && (
+ {props.translate('activateStep.checkBackLater')}
+ )}
+
+
+);
+
+ActivateStep.propTypes = propTypes;
+ActivateStep.defaultProps = defaultProps;
+ActivateStep.displayName = 'ActivateStep';
+export default withLocalize(ActivateStep);
diff --git a/src/pages/EnablePayments/AdditionalDetailsStep.js b/src/pages/EnablePayments/AdditionalDetailsStep.js
new file mode 100644
index 000000000000..b919799b1d1f
--- /dev/null
+++ b/src/pages/EnablePayments/AdditionalDetailsStep.js
@@ -0,0 +1,173 @@
+import _ from 'underscore';
+import React from 'react';
+import PropTypes from 'prop-types';
+import {withOnyx} from 'react-native-onyx';
+import {
+ View, Text, ScrollView, KeyboardAvoidingView,
+} from 'react-native';
+import ScreenWrapper from '../../components/ScreenWrapper';
+import HeaderWithCloseButton from '../../components/HeaderWithCloseButton';
+import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
+import Navigation from '../../libs/Navigation/Navigation';
+import styles from '../../styles/styles';
+import Button from '../../components/Button';
+import TextInputWithLabel from '../../components/TextInputWithLabel';
+import {activateWallet} from '../../libs/actions/BankAccounts';
+import CONST from '../../CONST';
+import compose from '../../libs/compose';
+import ONYXKEYS from '../../ONYXKEYS';
+import TextLink from '../../components/TextLink';
+
+const propTypes = {
+ ...withLocalizePropTypes,
+
+ /** Stores additional information about the additional details step e.g. loading state and errors with fields */
+ walletAdditionalDetails: PropTypes.shape({
+ /** Are we waiting for a response? */
+ loading: PropTypes.bool,
+
+ /** Which field needs attention? */
+ errorFields: PropTypes.arrayOf(PropTypes.string),
+
+ /** Any additional error message to show */
+ additionalErrorMessage: PropTypes.string,
+ }),
+};
+
+const defaultProps = {
+ walletAdditionalDetails: {
+ errorFields: [],
+ loading: false,
+ additionalErrorMessage: '',
+ },
+};
+
+class AdditionalDetailsStep extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.requiredText = props.translate('additionalDetailsStep.isRequiredField');
+ this.fields = [
+ {
+ label: props.translate('additionalDetailsStep.legalFirstNameLabel'),
+ fieldName: 'legalFirstName',
+ },
+ {
+ label: props.translate('additionalDetailsStep.legalMiddleNameLabel'),
+ fieldName: 'legalMiddleName',
+ },
+ {
+ label: props.translate('additionalDetailsStep.legalLastNameLabel'),
+ fieldName: 'legalLastName',
+ },
+ {
+ label: props.translate('additionalDetailsStep.addressLabel'),
+ fieldName: 'addressStreet',
+ },
+ {
+ label: props.translate('additionalDetailsStep.cityLabel'),
+ fieldName: 'addressCity',
+ },
+ {
+ label: props.translate('additionalDetailsStep.stateLabel'),
+ fieldName: 'addressState',
+ },
+ {
+ label: props.translate('additionalDetailsStep.zipCodeLabel'),
+ fieldName: 'addressZip',
+ },
+ {
+ label: props.translate('additionalDetailsStep.phoneNumberLabel'),
+ fieldName: 'phoneNumber',
+ },
+ {
+ label: props.translate('additionalDetailsStep.dobLabel'),
+ fieldName: 'dob',
+ },
+ {
+ label: props.translate('additionalDetailsStep.ssnLabel'),
+ fieldName: 'ssn',
+ },
+ ];
+
+ this.state = {
+ firstName: '',
+ legalMiddleName: '',
+ legalLastName: '',
+ address: '',
+ city: '',
+ state: '',
+ zipCode: '',
+ phoneNumber: '',
+ dob: '',
+ ssn: '',
+ };
+ }
+
+ render() {
+ const errorFields = this.props.walletAdditionalDetails.errorFields || [];
+ return (
+
+
+ Navigation.dismissModal()}
+ />
+
+
+ {this.props.translate('additionalDetailsStep.helpText')}
+
+ {this.props.translate('additionalDetailsStep.helpLink')}
+
+
+
+ {_.map(this.fields, field => (
+ this.setState({[field.fieldName]: val})}
+ value={this.state[field.fieldName]}
+ errorText={errorFields.includes(field.fieldName)
+ ? `${field.label} ${this.requiredText}`
+ : ''}
+ />
+ ))}
+
+
+ {this.props.walletAdditionalDetails.additionalErrorMessage.length > 0 && (
+
+ {this.props.walletAdditionalDetails.additionalErrorMessage}
+
+ )}
+
+
+
+
+ );
+ }
+}
+
+AdditionalDetailsStep.propTypes = propTypes;
+AdditionalDetailsStep.defaultProps = defaultProps;
+export default compose(
+ withLocalize,
+ withOnyx({
+ walletAdditionalDetails: {
+ key: ONYXKEYS.WALLET_ADDITIONAL_DETAILS,
+ initWithStoredValues: false,
+ },
+ }),
+)(AdditionalDetailsStep);
diff --git a/src/pages/EnablePayments/OnfidoStep.js b/src/pages/EnablePayments/OnfidoStep.js
new file mode 100644
index 000000000000..d6c231d41470
--- /dev/null
+++ b/src/pages/EnablePayments/OnfidoStep.js
@@ -0,0 +1,157 @@
+import React from 'react';
+import {View, Text} from 'react-native';
+import {withOnyx} from 'react-native-onyx';
+import PropTypes from 'prop-types';
+import Onfido from '../../components/Onfido';
+import FullscreenLoadingIndicator from '../../components/FullscreenLoadingIndicator';
+import ONYXKEYS from '../../ONYXKEYS';
+import {activateWallet, fetchOnfidoToken} from '../../libs/actions/BankAccounts';
+import Navigation from '../../libs/Navigation/Navigation';
+import CONST from '../../CONST';
+import Button from '../../components/Button';
+import HeaderWithCloseButton from '../../components/HeaderWithCloseButton';
+import styles from '../../styles/styles';
+import TextLink from '../../components/TextLink';
+import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
+import compose from '../../libs/compose';
+
+const propTypes = {
+ /** Stores various information used to build the UI and call any APIs */
+ walletOnfidoData: PropTypes.shape({
+
+ /** Unique identifier returned from fetchOnfidoToken then re-sent to ActivateWallet with Onfido response data */
+ applicantID: PropTypes.string,
+
+ /** Token used to initialize the Onfido SDK token */
+ sdkToken: PropTypes.string,
+
+ /** Loading state to provide feedback when we are waiting for a request to finish */
+ loading: PropTypes.bool,
+
+ /** Error message to inform the user of any problem that might occur */
+ error: PropTypes.string,
+
+ /** Whether the user has accepted the privacy policy of Onfido or not */
+ hasAcceptedPrivacyPolicy: PropTypes.bool,
+ }),
+
+ ...withLocalizePropTypes,
+};
+
+const defaultProps = {
+ walletOnfidoData: {
+ loading: false,
+ hasAcceptedPrivacyPolicy: false,
+ },
+};
+
+class OnfidoStep extends React.Component {
+ /**
+ * @returns {boolean|*}
+ */
+ canShowOnfido() {
+ return this.props.walletOnfidoData.hasAcceptedPrivacyPolicy
+ && !this.props.walletOnfidoData.loading
+ && !this.props.walletOnfidoData.error
+ && this.props.walletOnfidoData.sdkToken;
+ }
+
+ render() {
+ return (
+ <>
+ Navigation.goBack()}
+ />
+ {
+ this.canShowOnfido() ? (
+ {
+ Navigation.goBack();
+ }}
+ onSuccess={(data) => {
+ activateWallet(CONST.WALLET.STEP.ONFIDO, {
+ onfidoData: JSON.stringify({
+ ...data,
+ applicantID: this.props.walletOnfidoData.applicantID,
+ }),
+ });
+ }}
+ />
+ ) : (
+
+ {!this.props.walletOnfidoData.hasAcceptedPrivacyPolicy && (
+ <>
+
+
+ {this.props.translate('onfidoStep.acceptTerms')}
+
+ {this.props.translate('onfidoStep.facialScan')}
+
+ {', '}
+
+ {this.props.translate('common.privacyPolicy')}
+
+ {` ${this.props.translate('common.and')} `}
+
+ {this.props.translate('onfidoStep.termsOfService')}
+
+ .
+
+
+
+ )
+ }
+ >
+ );
+ }
+}
+
+OnfidoStep.propTypes = propTypes;
+OnfidoStep.defaultProps = defaultProps;
+
+export default compose(
+ withLocalize,
+ withOnyx({
+ walletOnfidoData: {
+ key: ONYXKEYS.WALLET_ONFIDO,
+
+ // Let's get a new onfido token each time the user hits this flow (as it should only be once)
+ initWithStoredValues: false,
+ },
+ }),
+)(OnfidoStep);
diff --git a/src/pages/EnablePayments/TermsStep.js b/src/pages/EnablePayments/TermsStep.js
new file mode 100644
index 000000000000..0286aba8ab3b
--- /dev/null
+++ b/src/pages/EnablePayments/TermsStep.js
@@ -0,0 +1,164 @@
+import React from 'react';
+import {
+ View, ScrollView, Text, TouchableOpacity,
+} from 'react-native';
+import {withOnyx} from 'react-native-onyx';
+import PropTypes from 'prop-types';
+import ScreenWrapper from '../../components/ScreenWrapper';
+import HeaderWithCloseButton from '../../components/HeaderWithCloseButton';
+import Navigation from '../../libs/Navigation/Navigation';
+import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
+import Checkbox from '../../components/Checkbox';
+import styles from '../../styles/styles';
+import Button from '../../components/Button';
+import {activateWallet} from '../../libs/actions/BankAccounts';
+import CONST from '../../CONST';
+import TextLink from '../../components/TextLink';
+import compose from '../../libs/compose';
+import ONYXKEYS from '../../ONYXKEYS';
+
+const propTypes = {
+ /** Comes from Onyx. Information about the terms for the wallet */
+ walletTerms: PropTypes.shape({
+ /** Whether or not the information is currently loading */
+ loading: PropTypes.bool,
+ }),
+ ...withLocalizePropTypes,
+};
+
+const defaultProps = {
+ walletTerms: {
+ loading: false,
+ },
+};
+
+class TermsStep extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.toggleDisclosure = this.toggleDisclosure.bind(this);
+ this.togglePrivacyPolicy = this.togglePrivacyPolicy.bind(this);
+ this.state = {
+ hasAcceptedDisclosure: false,
+ hasAcceptedPrivacyPolicyAndWalletAgreement: false,
+ error: false,
+ };
+ }
+
+ toggleDisclosure() {
+ this.setState(prevState => ({hasAcceptedDisclosure: !prevState.hasAcceptedDisclosure}));
+ }
+
+ togglePrivacyPolicy() {
+ this.setState(prevState => ({
+ hasAcceptedPrivacyPolicyAndWalletAgreement: !prevState.hasAcceptedPrivacyPolicyAndWalletAgreement,
+ }));
+ }
+
+ render() {
+ const toggleStyles = [
+ styles.ml2,
+ styles.pr2,
+ styles.w100,
+ styles.flexRow,
+ styles.flexWrap,
+ styles.alignItemsCenter,
+ ];
+ return (
+
+ Navigation.dismissModal()}
+ />
+
+
+
+ {/* @TODO build out the terms page */}
+ {/* eslint-disable-next-line max-len */}
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+
+
+
+
+
+
+ {`${this.props.translate('termsStep.haveReadAndAgree')} `}
+
+
+ {`${this.props.translate('termsStep.electronicDisclosures')}.`}
+
+
+
+
+
+
+
+
+ {`${this.props.translate('termsStep.agreeToThe')} `}
+
+
+
+ {`${this.props.translate('common.privacyPolicy')} `}
+
+
+ {`${this.props.translate('common.and')} `}
+
+
+ {`${this.props.translate('termsStep.walletAgreement')}.`}
+
+
+
+ {this.state.error && (
+
+ {this.props.translate('termsStep.termsMustBeAccepted')}
+
+ )}
+
+ {
+ if (!this.state.hasAcceptedDisclosure
+ || !this.state.hasAcceptedPrivacyPolicyAndWalletAgreement) {
+ this.setState({error: true});
+ return;
+ }
+
+ this.setState({error: false});
+ activateWallet(CONST.WALLET.STEP.TERMS, {
+ hasAcceptedTerms: this.state.hasAcceptedDisclosure
+ && this.state.hasAcceptedPrivacyPolicyAndWalletAgreement,
+ });
+ }}
+ />
+
+
+
+ );
+ }
+}
+
+TermsStep.propTypes = propTypes;
+TermsStep.defaultProps = defaultProps;
+export default compose(
+ withLocalize,
+ withOnyx({
+ walletTerms: {
+ key: ONYXKEYS.WALLET_TERMS,
+ initWithStoredValues: false,
+ },
+ }),
+)(TermsStep);
diff --git a/src/pages/EnablePayments/index.js b/src/pages/EnablePayments/index.js
new file mode 100644
index 000000000000..8012df050e5c
--- /dev/null
+++ b/src/pages/EnablePayments/index.js
@@ -0,0 +1,58 @@
+import _ from 'underscore';
+import React from 'react';
+import {withOnyx} from 'react-native-onyx';
+import ScreenWrapper from '../../components/ScreenWrapper';
+import {fetchUserWallet} from '../../libs/actions/BankAccounts';
+import ONYXKEYS from '../../ONYXKEYS';
+import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator';
+import CONST from '../../CONST';
+import userWalletPropTypes from './userWalletPropTypes';
+
+// Steps
+import OnfidoStep from './OnfidoStep';
+import AdditionalDetailsStep from './AdditionalDetailsStep';
+import TermsStep from './TermsStep';
+import ActivateStep from './ActivateStep';
+
+const propTypes = {
+ ...userWalletPropTypes,
+};
+
+const defaultProps = {
+ userWallet: {},
+};
+
+class EnablePaymentsPage extends React.Component {
+ componentDidMount() {
+ fetchUserWallet();
+ }
+
+ render() {
+ if (_.isEmpty(this.props.userWallet)) {
+ return ;
+ }
+
+ const currentStep = this.props.userWallet.currentStep || CONST.WALLET.STEP.ONFIDO;
+ return (
+
+ {currentStep === CONST.WALLET.STEP.ONFIDO && }
+ {currentStep === CONST.WALLET.STEP.ADDITIONAL_DETAILS && }
+ {currentStep === CONST.WALLET.STEP.TERMS && }
+ {currentStep === CONST.WALLET.STEP.ACTIVATE && }
+
+ );
+ }
+}
+
+EnablePaymentsPage.propTypes = propTypes;
+EnablePaymentsPage.defaultProps = defaultProps;
+
+export default withOnyx({
+ userWallet: {
+ key: ONYXKEYS.USER_WALLET,
+
+ // We want to refresh the wallet each time the user attempts to activate the wallet so we won't use the
+ // stored values here.
+ initWithStoredValues: false,
+ },
+})(EnablePaymentsPage);
diff --git a/src/pages/EnablePayments/userWalletPropTypes.js b/src/pages/EnablePayments/userWalletPropTypes.js
new file mode 100644
index 000000000000..e7171f89d096
--- /dev/null
+++ b/src/pages/EnablePayments/userWalletPropTypes.js
@@ -0,0 +1,12 @@
+import PropTypes from 'prop-types';
+
+export default {
+ /** User's wallet information */
+ userWallet: PropTypes.shape({
+ /** What step in the activation flow are we on? */
+ currentStep: PropTypes.string,
+
+ /** Status of wallet - e.g. SILVER or GOLD */
+ status: PropTypes.string,
+ }),
+};
diff --git a/src/styles/colors.js b/src/styles/colors.js
index 89c10430fca0..5a9aa09dba1c 100644
--- a/src/styles/colors.js
+++ b/src/styles/colors.js
@@ -7,6 +7,7 @@ export default {
dark: '#0b1b34',
black: '#000000',
blue: '#0185ff',
+ blueHover: '#0063bf',
green: '#03d47c',
greenHover: '#03c775',
red: '#fc3826',
diff --git a/src/styles/styles.js b/src/styles/styles.js
index 2c7cbf52d24e..f2632fac2a70 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -33,6 +33,10 @@ const styles = {
fontFamily: fontFamily.GTA,
},
+ linkHovered: {
+ color: themeColors.linkHover,
+ },
+
h1: {
color: themeColors.heading,
fontFamily: fontFamily.GTA_BOLD,
diff --git a/src/styles/themes/default.js b/src/styles/themes/default.js
index 58a04a03ba13..da111070c325 100644
--- a/src/styles/themes/default.js
+++ b/src/styles/themes/default.js
@@ -3,6 +3,7 @@ import colors from '../colors';
export default {
shadow: colors.black,
link: colors.blue,
+ linkHover: colors.blueHover,
componentBG: colors.white,
hoverComponentBG: colors.gray1,
activeComponentBG: colors.gray2,
diff --git a/src/styles/utilities/spacing.js b/src/styles/utilities/spacing.js
index 5e06fbea10dc..387acfb11c7e 100644
--- a/src/styles/utilities/spacing.js
+++ b/src/styles/utilities/spacing.js
@@ -25,6 +25,10 @@ export default {
marginHorizontal: 4,
},
+ mh5: {
+ marginHorizontal: 20,
+ },
+
mv1: {
marginVertical: 4,
},
@@ -43,6 +47,7 @@ export default {
mv5: {
marginVertical: 20,
},
+
mr0: {
marginRight: 0,
},