diff --git a/.well-known/apple-app-site-association b/.well-known/apple-app-site-association
index 28ee9ee23fbd..fcd7138da7e6 100644
--- a/.well-known/apple-app-site-association
+++ b/.well-known/apple-app-site-association
@@ -43,6 +43,10 @@
{
"/": "/statements/*",
"comment": "Wallet statements"
+ },
+ {
+ "/": "/concierge/*",
+ "comment": "Concierge"
}
]
}
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 225a526c3acb..1cdaa76a4443 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -156,8 +156,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
- versionCode 1001020600
- versionName "1.2.6-0"
+ versionCode 1001021000
+ versionName "1.2.10-0"
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
if (isNewArchitectureEnabled()) {
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 5b4e43c86366..eb109cc8a30e 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -61,6 +61,7 @@
+
@@ -72,6 +73,7 @@
+
diff --git a/desktop/dev.js b/desktop/dev.js
new file mode 100644
index 000000000000..43a2122f6846
--- /dev/null
+++ b/desktop/dev.js
@@ -0,0 +1,9 @@
+// Development entry point of the desktop app with support for live reload
+// We keep this file (dev.js) out Webpack bundling process and provide it raw to Electron
+// Reloading Electron on change requires some native Node dependencies which cannot be
+// easily bundled with webpack, and we don't really need them bundled for staging/prod
+// We are free to load any bundled code from this file, and we load the bundled main.js from dist
+
+// The `dist` folder is not part of the source and does not exist until we build or start Desktop
+// eslint-disable-next-line import/extensions
+require('./dist/main');
diff --git a/desktop/start.js b/desktop/start.js
index 79e62d7187ed..815be335c46f 100644
--- a/desktop/start.js
+++ b/desktop/start.js
@@ -9,25 +9,35 @@ portfinder.getPortPromise({
port: basePort,
}).then((port) => {
const devServer = `webpack-dev-server --config config/webpack/webpack.dev.js --port ${port} --env platform=desktop`;
- const buildMain = 'webpack --config config/webpack/webpack.desktop.js --config-name desktop-main --mode=development';
+ const buildMain = 'webpack watch --config config/webpack/webpack.desktop.js --config-name desktop-main --mode=development';
+
+ const env = {
+ PORT: port,
+ NODE_ENV: 'development',
+ };
const processes = [
+ {
+ command: buildMain,
+ name: 'Main',
+ prefixColor: 'blue.dim',
+ env,
+ },
{
command: devServer,
name: 'Renderer',
prefixColor: 'red.dim',
+ env,
},
{
- command: `${buildMain} && wait-port localhost:${port} && electron desktop/dist/main.js`,
- name: 'Main',
+ command: `wait-port localhost:${port} && npx electronmon ./desktop/dev.js`,
+ name: 'Electron',
prefixColor: 'cyan.dim',
- env: {
- PORT: port,
- NODE_ENV: 'development',
- },
+ env,
},
];
- concurrently(processes, {
+
+ return concurrently(processes, {
inputStream: process.stdin,
prefix: 'name',
diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss
index 95a68ce345e1..2dd52ac40375 100644
--- a/docs/_sass/_main.scss
+++ b/docs/_sass/_main.scss
@@ -61,6 +61,7 @@ body {
height: 100%;
min-height: 100%;
background: $color-white;
+ overflow: auto;
}
hr {
diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist
index b9d8e2ec5dfb..d442f5fc21cd 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -17,7 +17,7 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 1.2.6
+ 1.2.10
CFBundleSignature
????
CFBundleURLTypes
@@ -30,7 +30,7 @@
CFBundleVersion
- 1.2.6.0
+ 1.2.10.0
ITSAppUsesNonExemptEncryption
LSApplicationQueriesSchemes
diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist
index ebb0f6355386..319b0779092c 100644
--- a/ios/NewExpensifyTests/Info.plist
+++ b/ios/NewExpensifyTests/Info.plist
@@ -15,10 +15,10 @@
CFBundlePackageType
BNDL
CFBundleShortVersionString
- 1.2.6
+ 1.2.10
CFBundleSignature
????
CFBundleVersion
- 1.2.6.0
+ 1.2.10.0
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 4bb2ef56eac2..4475434729bc 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -217,9 +217,9 @@ PODS:
- nanopb/encode (= 2.30908.0)
- nanopb/decode (2.30908.0)
- nanopb/encode (2.30908.0)
- - Onfido (25.1.0)
- - onfido-react-native-sdk (5.4.0):
- - Onfido (= 25.1.0)
+ - Onfido (26.0.1)
+ - onfido-react-native-sdk (6.0.0):
+ - Onfido (= 26.0.1)
- React
- OpenSSL-Universal (1.1.1100)
- Permission-LocationAccuracy (3.6.1):
@@ -941,8 +941,8 @@ SPEC CHECKSUMS:
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
libwebp: 60305b2e989864154bd9be3d772730f08fc6a59c
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
- Onfido: a1645279c7b6ca8de5bb95d27af53c523ffd731c
- onfido-react-native-sdk: cfdfd1d4acf53e469a82b9684f92982d39744bb8
+ Onfido: 91935f0dcee9a6647fdb386fa87cb4af9d9a3c70
+ onfido-react-native-sdk: bc72114ac430a2636cd2f02972ddf5b8b3b397c6
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
Permission-LocationAccuracy: 76df17de5c6b8bc2eee34e61ee92cdd7a864c73d
Permission-LocationAlways: 8d99b025c9f73c696e0cdb367e42525f2e9a26f2
diff --git a/jest/setup.js b/jest/setup.js
index 10918039ae25..549b02eb2546 100644
--- a/jest/setup.js
+++ b/jest/setup.js
@@ -75,3 +75,14 @@ jest.mock('../src/components/Icon/Expensicons', () => {
return {...prev, [key]: fn};
}, {});
});
+
+// Set up manual mocks for any Logging methods that are supposed hit the 'server',
+// this is needed because before, the Logging queue would get flushed while tests were running,
+// causing unexpected calls to HttpUtils.xhr() which would cause mock mismatches and flaky tests.
+/* eslint-disable no-console */
+jest.mock('../src/libs/Log', () => ({
+ info: message => console.log(`[info] ${message} (mocked)`),
+ alert: message => console.log(`[alert] ${message} (mocked)`),
+ warn: message => console.log(`[warn] ${message} (mocked)`),
+ hmmm: message => console.log(`[hmmm] ${message} (mocked)`),
+}));
diff --git a/package-lock.json b/package-lock.json
index 0f4142fb61b0..589a57e2f85b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "new.expensify",
- "version": "1.2.6-0",
+ "version": "1.2.10-0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "new.expensify",
- "version": "1.2.6-0",
+ "version": "1.2.10-0",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -16,7 +16,7 @@
"@formatjs/intl-numberformat": "^6.2.5",
"@formatjs/intl-pluralrules": "^4.0.13",
"@oguzhnatly/react-native-image-manipulator": "github:Expensify/react-native-image-manipulator#c5f654fc9d0ad7cc5b89d50b34ecf8b0e3f4d050",
- "@onfido/react-native-sdk": "github:Expensify/react-native-sdk#d70947f263b2e59899d82f8d1ef3841d053927ff",
+ "@onfido/react-native-sdk": "6.0.0",
"@pieter-pot/react-native-fast-image": "8.5.11",
"@react-native-async-storage/async-storage": "^1.17.10",
"@react-native-community/cameraroll": "git+https://github.com/react-native-cameraroll/react-native-cameraroll.git#3f0aed96db68e134f199171c7b06c1b4d6cb382b",
@@ -129,7 +129,6 @@
"electron": "^17.4.11",
"electron-builder": "23.5.0",
"electron-notarize": "^1.2.1",
- "electron-reloader": "^1.2.1",
"eslint": "^7.6.0",
"eslint-config-expensify": "2.0.30",
"eslint-loader": "^4.0.2",
@@ -4154,12 +4153,11 @@
}
},
"node_modules/@onfido/react-native-sdk": {
- "version": "5.4.0",
- "resolved": "git+ssh://git@github.com/Expensify/react-native-sdk.git#d70947f263b2e59899d82f8d1ef3841d053927ff",
- "integrity": "sha512-xqQ9ERZhnJPkWVaaPBaoeBQ8UMHVy/cCPxEzow5rBuPuzmA1KYvrbu1FUqTMriUhVnLFR57TDCyZR8s/+u/eRg==",
- "license": "MIT",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@onfido/react-native-sdk/-/react-native-sdk-6.0.0.tgz",
+ "integrity": "sha512-TJWeiEh0Vil37/Xm9H+uiOpiuYD2NhOhixdvaAkohTzLI3uUNiG7bph66jCUa+SpqFURQdCZMYWFwHwj2nXs2Q==",
"peerDependencies": {
- "react": ">=16.8.1 <=18.x.x",
+ "react": ">=16.8.1",
"react-native": ">=0.60.0-rc.0 <1.0.x"
}
},
@@ -20430,18 +20428,6 @@
"url": "https://opencollective.com/date-fns"
}
},
- "node_modules/date-time": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/date-time/-/date-time-3.1.0.tgz",
- "integrity": "sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==",
- "dev": true,
- "dependencies": {
- "time-zone": "^1.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/dayjs": {
"version": "1.11.5",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.5.tgz",
@@ -21378,12 +21364,6 @@
"node": ">=12"
}
},
- "node_modules/electron-is-dev": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-1.2.0.tgz",
- "integrity": "sha512-R1oD5gMBPS7PVU8gJwH6CtT0e6VSoD0+SzSnYpNm+dBkcijgA+K7VAMHDfnRq/lkKPZArpzplTW6jfiMYosdzw==",
- "dev": true
- },
"node_modules/electron-notarize": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/electron-notarize/-/electron-notarize-1.2.1.tgz",
@@ -21545,92 +21525,6 @@
"node": ">=8"
}
},
- "node_modules/electron-reloader": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/electron-reloader/-/electron-reloader-1.2.3.tgz",
- "integrity": "sha512-aDnACAzNg0QvQhzw7LYOx/nVS10mEtbuG6M0QQvNQcLnJEwFs6is+EGRCnM+KQlQ4KcTbdwnt07nd7ZjHpY4iw==",
- "dev": true,
- "dependencies": {
- "chalk": "^4.1.0",
- "chokidar": "^3.5.0",
- "date-time": "^3.1.0",
- "electron-is-dev": "^1.2.0",
- "find-up": "^5.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/electron-reloader/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/electron-reloader/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/electron-reloader/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/electron-reloader/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/electron-reloader/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/electron-reloader/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/electron-to-chromium": {
"version": "1.4.223",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.223.tgz",
@@ -40373,15 +40267,6 @@
"integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==",
"dev": true
},
- "node_modules/time-zone": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz",
- "integrity": "sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/timers-browserify": {
"version": "2.0.12",
"resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz",
@@ -46067,9 +45952,9 @@
}
},
"@onfido/react-native-sdk": {
- "version": "git+ssh://git@github.com/Expensify/react-native-sdk.git#d70947f263b2e59899d82f8d1ef3841d053927ff",
- "integrity": "sha512-xqQ9ERZhnJPkWVaaPBaoeBQ8UMHVy/cCPxEzow5rBuPuzmA1KYvrbu1FUqTMriUhVnLFR57TDCyZR8s/+u/eRg==",
- "from": "@onfido/react-native-sdk@github:Expensify/react-native-sdk#d70947f263b2e59899d82f8d1ef3841d053927ff",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@onfido/react-native-sdk/-/react-native-sdk-6.0.0.tgz",
+ "integrity": "sha512-TJWeiEh0Vil37/Xm9H+uiOpiuYD2NhOhixdvaAkohTzLI3uUNiG7bph66jCUa+SpqFURQdCZMYWFwHwj2nXs2Q==",
"requires": {}
},
"@pieter-pot/react-native-fast-image": {
@@ -58567,15 +58452,6 @@
"integrity": "sha512-dlLD5rKaKxpFdnjrs+5azHDFOPEu4ANy/LTh04A1DTzMM7qoajmKCBc8pkKRFT41CNzw+4gQh79X5C+Jq27HAw==",
"dev": true
},
- "date-time": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/date-time/-/date-time-3.1.0.tgz",
- "integrity": "sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==",
- "dev": true,
- "requires": {
- "time-zone": "^1.0.0"
- }
- },
"dayjs": {
"version": "1.11.5",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.5.tgz",
@@ -59323,12 +59199,6 @@
}
}
},
- "electron-is-dev": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-1.2.0.tgz",
- "integrity": "sha512-R1oD5gMBPS7PVU8gJwH6CtT0e6VSoD0+SzSnYpNm+dBkcijgA+K7VAMHDfnRq/lkKPZArpzplTW6jfiMYosdzw==",
- "dev": true
- },
"electron-notarize": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/electron-notarize/-/electron-notarize-1.2.1.tgz",
@@ -59456,70 +59326,6 @@
}
}
},
- "electron-reloader": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/electron-reloader/-/electron-reloader-1.2.3.tgz",
- "integrity": "sha512-aDnACAzNg0QvQhzw7LYOx/nVS10mEtbuG6M0QQvNQcLnJEwFs6is+EGRCnM+KQlQ4KcTbdwnt07nd7ZjHpY4iw==",
- "dev": true,
- "requires": {
- "chalk": "^4.1.0",
- "chokidar": "^3.5.0",
- "date-time": "^3.1.0",
- "electron-is-dev": "^1.2.0",
- "find-up": "^5.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
"electron-to-chromium": {
"version": "1.4.223",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.223.tgz",
@@ -73964,12 +73770,6 @@
"integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==",
"dev": true
},
- "time-zone": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz",
- "integrity": "sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==",
- "dev": true
- },
"timers-browserify": {
"version": "2.0.12",
"resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz",
diff --git a/package.json b/package.json
index 0ea810cf9c41..72db7454f40d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "1.2.6-0",
+ "version": "1.2.10-0",
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
@@ -43,7 +43,7 @@
"@formatjs/intl-numberformat": "^6.2.5",
"@formatjs/intl-pluralrules": "^4.0.13",
"@oguzhnatly/react-native-image-manipulator": "github:Expensify/react-native-image-manipulator#c5f654fc9d0ad7cc5b89d50b34ecf8b0e3f4d050",
- "@onfido/react-native-sdk": "github:Expensify/react-native-sdk#d70947f263b2e59899d82f8d1ef3841d053927ff",
+ "@onfido/react-native-sdk": "6.0.0",
"@pieter-pot/react-native-fast-image": "8.5.11",
"@react-native-async-storage/async-storage": "^1.17.10",
"@react-native-community/cameraroll": "git+https://github.com/react-native-cameraroll/react-native-cameraroll.git#3f0aed96db68e134f199171c7b06c1b4d6cb382b",
@@ -156,7 +156,6 @@
"electron": "^17.4.11",
"electron-builder": "23.5.0",
"electron-notarize": "^1.2.1",
- "electron-reloader": "^1.2.1",
"eslint": "^7.6.0",
"eslint-config-expensify": "2.0.30",
"eslint-loader": "^4.0.2",
diff --git a/src/CONST.js b/src/CONST.js
index d497376b5a9e..76e6151a37f8 100755
--- a/src/CONST.js
+++ b/src/CONST.js
@@ -69,9 +69,6 @@ const CONST = {
},
VERIFICATIONS: {
ERROR_MESSAGE: 'verifications.errorMessage',
- EXTERNAL_API_RESPONSES: 'verifications.externalApiResponses',
- REQUESTOR_IDENTITY_ID: 'verifications.externalApiResponses.requestorIdentityID',
- REQUESTOR_IDENTITY_ONFIDO: 'verifications.externalApiResponses.requestorIdentityOnfido',
THROTTLED: 'verifications.throttled',
},
FIELDS_TYPE: {
@@ -351,8 +348,6 @@ const CONST = {
HOMEPAGE_REPORTS_LOADED: 'homepage_reports_loaded',
SWITCH_REPORT: 'switch_report',
SIDEBAR_LOADED: 'sidebar_loaded',
- PERSONAL_DETAILS_FORMATTED: 'personal_details_formatted',
- SIDEBAR_LINKS_FILTER_REPORTS: 'sidebar_links_filter_reports',
COLD: 'cold',
REPORT_ACTION_ITEM_LAYOUT_DEBOUNCE_TIME: 1500,
TOOLTIP_SENSE: 1000,
@@ -418,7 +413,7 @@ const CONST = {
FREQUENTLY_USED_EMOJIS: 'expensify_frequentlyUsedEmojis',
},
DEFAULT_TIME_ZONE: {automatic: true, selected: 'America/Los_Angeles'},
- DEFAULT_ACCOUNT_DATA: {errors: null, success: '', loading: false},
+ DEFAULT_ACCOUNT_DATA: {errors: null, success: '', isLoading: false},
APP_STATE: {
ACTIVE: 'active',
BACKGROUND: 'background',
@@ -460,6 +455,7 @@ const CONST = {
NUMBER_PAD: 'number-pad',
DECIMAL_PAD: 'decimal-pad',
VISIBLE_PASSWORD: 'visible-password',
+ EMAIL_ADDRESS: 'email-address',
},
ATTACHMENT_SOURCE_ATTRIBUTE: 'data-expensify-source',
diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js
index ab94c4dff47c..713dfa3df45a 100755
--- a/src/ONYXKEYS.js
+++ b/src/ONYXKEYS.js
@@ -5,6 +5,9 @@ export default {
// Holds information about the users account that is logging in
ACCOUNT: 'account',
+ // Holds the reportID for the report between the user and their account manager
+ ACCOUNT_MANAGER_REPORT_ID: 'accountManagerReportID',
+
// Boolean flag only true when first set
NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER: 'isFirstTimeNewExpensifyUser',
@@ -67,6 +70,9 @@ export default {
// Contains the user's payPalMe address
NVP_PAYPAL_ME_ADDRESS: 'nvp_paypalMeAddress',
+ // Contains the user's payPalMe data
+ PAYPAL: 'paypal',
+
// Contains the user preference for the LHN priority mode
NVP_PRIORITY_MODE: 'nvp_priorityMode',
@@ -79,6 +85,9 @@ export default {
// Token needed to initialize Plaid link
PLAID_LINK_TOKEN: 'plaidLinkToken',
+ // Token needed to initialize Onfido
+ ONFIDO_TOKEN: 'onfidoToken',
+
// Collection Keys
COLLECTION: {
REPORT: 'report_',
diff --git a/src/components/AddPaymentMethodMenu.js b/src/components/AddPaymentMethodMenu.js
index c450642df1c8..e71e42e1d15a 100644
--- a/src/components/AddPaymentMethodMenu.js
+++ b/src/components/AddPaymentMethodMenu.js
@@ -9,6 +9,8 @@ import CONST from '../CONST';
import withWindowDimensions from './withWindowDimensions';
import Permissions from '../libs/Permissions';
import PopoverMenu from './PopoverMenu';
+import paypalMeDataPropTypes from './paypalMeDataPropTypes';
+import * as BankAccounts from '../libs/actions/BankAccounts';
const propTypes = {
isVisible: PropTypes.bool.isRequired,
@@ -18,8 +20,8 @@ const propTypes = {
left: PropTypes.number,
}),
- /** Username for PayPal.Me */
- payPalMeUsername: PropTypes.string,
+ /** Account details for PayPal.Me */
+ payPalMeData: paypalMeDataPropTypes,
/** Should we show the Paypal option */
shouldShowPaypal: PropTypes.bool,
@@ -32,7 +34,7 @@ const propTypes = {
const defaultProps = {
anchorPosition: {},
- payPalMeUsername: '',
+ payPalMeData: {},
shouldShowPaypal: true,
betas: [],
};
@@ -47,7 +49,10 @@ const AddPaymentMethodMenu = props => (
{
text: props.translate('common.bankAccount'),
icon: Expensicons.Bank,
- onSelected: () => props.onItemSelected(CONST.PAYMENT_METHODS.BANK_ACCOUNT),
+ onSelected: () => {
+ BankAccounts.clearPlaid();
+ props.onItemSelected(CONST.PAYMENT_METHODS.BANK_ACCOUNT);
+ },
},
...(Permissions.canUseWallet(props.betas) ? [{
text: props.translate('common.debitCard'),
@@ -55,7 +60,7 @@ const AddPaymentMethodMenu = props => (
onSelected: () => props.onItemSelected(CONST.PAYMENT_METHODS.DEBIT_CARD),
},
] : []),
- ...(props.shouldShowPaypal && !props.payPalMeUsername ? [{
+ ...(props.shouldShowPaypal && !props.payPalMeData.description ? [{
text: props.translate('common.payPalMe'),
icon: Expensicons.PayPal,
onSelected: () => props.onItemSelected(CONST.PAYMENT_METHODS.PAYPAL),
@@ -73,8 +78,8 @@ export default compose(
withWindowDimensions,
withLocalize,
withOnyx({
- payPalMeUsername: {
- key: ONYXKEYS.NVP_PAYPAL_ME_ADDRESS,
+ payPalMeData: {
+ key: ONYXKEYS.PAYPAL,
},
betas: {
key: ONYXKEYS.BETAS,
diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js
index c0f926430b0c..96fa3dee7559 100644
--- a/src/components/AddPlaidBankAccount.js
+++ b/src/components/AddPlaidBankAccount.js
@@ -58,7 +58,7 @@ const defaultProps = {
bankName: '',
plaidAccessToken: '',
bankAccounts: [],
- loading: false,
+ isLoading: false,
error: '',
},
plaidLinkToken: '',
@@ -77,21 +77,14 @@ class AddPlaidBankAccount extends React.Component {
this.selectAccount = this.selectAccount.bind(this);
this.getPlaidLinkToken = this.getPlaidLinkToken.bind(this);
-
- this.state = {
- selectedIndex: undefined,
- institution: {},
- };
}
componentDidMount() {
// If we're coming from Plaid OAuth flow then we need to reuse the existing plaidLinkToken
- // Otherwise, clear the existing token and fetch a new one
- if (this.props.receivedRedirectURI && this.props.plaidLinkOAuthToken) {
+ if ((this.props.receivedRedirectURI && this.props.plaidLinkOAuthToken) || !_.isEmpty(this.props.plaidData)) {
return;
}
- BankAccounts.clearPlaid();
BankAccounts.openPlaidBankLogin(this.props.allowDebit, this.props.bankAccountID);
}
@@ -119,30 +112,30 @@ class AddPlaidBankAccount extends React.Component {
/**
* Triggered when user selects a Plaid bank account.
- * @param {String} index
+ * @param {String} plaidAccountID
*/
- selectAccount(index) {
- this.setState({selectedIndex: Number(index)}, () => {
- const selectedPlaidBankAccount = this.getPlaidBankAccounts()[this.state.selectedIndex];
- selectedPlaidBankAccount.bankName = this.props.plaidData.bankName;
- selectedPlaidBankAccount.plaidAccessToken = this.props.plaidData.plaidAccessToken;
- this.props.onSelect({selectedPlaidBankAccount});
- });
+ selectAccount(plaidAccountID) {
+ const selectedPlaidBankAccount = _.findWhere(this.getPlaidBankAccounts(), {plaidAccountID});
+ selectedPlaidBankAccount.bankName = this.props.plaidData.bankName;
+ selectedPlaidBankAccount.plaidAccessToken = this.props.plaidData.plaidAccessToken;
+ this.props.onSelect({selectedPlaidBankAccount});
}
render() {
const plaidBankAccounts = this.getPlaidBankAccounts();
const token = this.getPlaidLinkToken();
- const options = _.map(plaidBankAccounts, (account, index) => ({
- value: index, label: `${account.addressName} ${account.mask}`,
+ const options = _.map(plaidBankAccounts, account => ({
+ value: account.plaidAccountID, label: `${account.addressName} ${account.mask}`,
}));
- const {icon, iconSize} = getBankIcon(this.state.institution.name);
+ const institutionName = lodashGet(this.props, 'plaidData.institution.name', '');
+ const selectedPlaidBankAccount = lodashGet(this.props, 'plaidData.selectedPlaidBankAccount', {});
+ const {icon, iconSize} = getBankIcon();
// Plaid Link view
if (!plaidBankAccounts.length) {
return (
- {(!token || this.props.plaidData.loading)
+ {(!token || this.props.plaidData.isLoading)
&& (
@@ -159,7 +152,7 @@ class AddPlaidBankAccount extends React.Component {
onSuccess={({publicToken, metadata}) => {
Log.info('[PlaidLink] Success!');
BankAccounts.openPlaidBankAccountSelector(publicToken, metadata.institution.name, this.props.allowDebit);
- this.setState({institution: metadata.institution});
+ BankAccounts.updatePlaidData({institution: metadata.institution});
}}
onError={(error) => {
Log.hmmm('[PlaidLink] Error: ', error.message);
@@ -187,18 +180,18 @@ class AddPlaidBankAccount extends React.Component {
height={iconSize}
width={iconSize}
/>
- {this.state.institution.name}
+ {institutionName}
diff --git a/src/components/ArchivedReportFooter.js b/src/components/ArchivedReportFooter.js
index bcb204c98369..c271b0f8c0bc 100644
--- a/src/components/ArchivedReportFooter.js
+++ b/src/components/ArchivedReportFooter.js
@@ -9,6 +9,7 @@ import compose from '../libs/compose';
import personalDetailsPropType from '../pages/personalDetailsPropType';
import ONYXKEYS from '../ONYXKEYS';
import * as ReportUtils from '../libs/ReportUtils';
+import reportPropTypes from '../pages/reportPropTypes';
const propTypes = {
/** The reason this report was archived */
@@ -27,10 +28,7 @@ const propTypes = {
}),
/** The archived report */
- report: PropTypes.shape({
- /** The policy this report is attached to */
- policyID: PropTypes.string,
- }).isRequired,
+ report: reportPropTypes.isRequired,
/** Personal details of all users */
personalDetails: PropTypes.objectOf(personalDetailsPropType).isRequired,
@@ -72,6 +70,7 @@ const ArchivedReportFooter = (props) => {
policyName: `${ReportUtils.getPolicyName(props.report, props.policies)}`,
})}
shouldRenderHTML={archiveReason !== CONST.REPORT.ARCHIVE_REASON.DEFAULT}
+ shouldShowIcon
/>
);
};
diff --git a/src/components/AvatarCropModal/AvatarCropModal.js b/src/components/AvatarCropModal/AvatarCropModal.js
index 8fb25102cef6..a7df10467272 100644
--- a/src/components/AvatarCropModal/AvatarCropModal.js
+++ b/src/components/AvatarCropModal/AvatarCropModal.js
@@ -266,8 +266,7 @@ const AvatarCropModal = (props) => {
diff --git a/src/components/Banner.js b/src/components/Banner.js
index 87808c22af24..3b5a8d66e3aa 100644
--- a/src/components/Banner.js
+++ b/src/components/Banner.js
@@ -1,6 +1,7 @@
import React, {memo} from 'react';
import PropTypes from 'prop-types';
-import {View} from 'react-native';
+import {View, Pressable} from 'react-native';
+import compose from '../libs/compose';
import Hoverable from './Hoverable';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
@@ -9,17 +10,45 @@ import Text from './Text';
import styles from '../styles/styles';
import * as StyleUtils from '../styles/StyleUtils';
import getButtonState from '../libs/getButtonState';
+import Tooltip from './Tooltip';
+import withLocalize, {withLocalizePropTypes} from './withLocalize';
const propTypes = {
/** Text to display in the banner. */
text: PropTypes.string.isRequired,
+ /** Should this component render the left-aligned exclamation icon? */
+ shouldShowIcon: PropTypes.bool,
+
+ /** Should this component render a close button? */
+ shouldShowCloseButton: PropTypes.bool,
+
/** Should this component render the text as HTML? */
shouldRenderHTML: PropTypes.bool,
+
+ /** Callback called when the close button is pressed */
+ onClose: PropTypes.func,
+
+ /** Callback called when the message is pressed */
+ onPress: PropTypes.func,
+
+ // eslint-disable-next-line react/forbid-prop-types
+ containerStyles: PropTypes.arrayOf(PropTypes.object),
+
+ // eslint-disable-next-line react/forbid-prop-types
+ textStyles: PropTypes.arrayOf(PropTypes.object),
+
+ ...withLocalizePropTypes,
};
const defaultProps = {
shouldRenderHTML: false,
+ shouldShowIcon: false,
+ shouldShowCloseButton: false,
+ onClose: () => {},
+ onPress: () => {},
+ containerStyles: [],
+ textStyles: [],
};
const Banner = props => (
@@ -32,19 +61,35 @@ const Banner = props => (
styles.borderRadiusNormal,
isHovered ? styles.activeComponentBG : styles.hoveredComponentBG,
styles.breakAll,
+ ...props.containerStyles,
]}
>
-
-
+
+ {props.shouldShowIcon && (
+
+
+
+ )}
+ {
+ props.shouldRenderHTML
+ ?
+ : {props.text}
+ }
- {
- props.shouldRenderHTML
- ?
- : {props.text}
- }
+ {props.shouldShowCloseButton && (
+
+
+
+
+
+ )}
)}
@@ -54,4 +99,7 @@ Banner.propTypes = propTypes;
Banner.defaultProps = defaultProps;
Banner.displayName = 'Banner';
-export default memo(Banner);
+export default compose(
+ withLocalize,
+ memo,
+)(Banner);
diff --git a/src/components/BigNumberPad.js b/src/components/BigNumberPad.js
index 56dc37d5a440..867b946f25bc 100644
--- a/src/components/BigNumberPad.js
+++ b/src/components/BigNumberPad.js
@@ -78,6 +78,7 @@ class BigNumberPad extends React.Component {
ControlSelection.unblock();
this.props.longPressHandlerStateChanged(false);
}}
+ textSelectable={false}
/>
);
})}
diff --git a/src/components/Button.js b/src/components/Button.js
index e50d13abcbb0..e71652d52382 100644
--- a/src/components/Button.js
+++ b/src/components/Button.js
@@ -106,6 +106,9 @@ const propTypes = {
/** Id to use for this button */
nativeID: PropTypes.string,
+
+ /** Whether text in Button should selectable */
+ textSelectable: PropTypes.bool,
};
const defaultProps = {
@@ -136,6 +139,7 @@ const defaultProps = {
shouldRemoveLeftBorderRadius: false,
shouldEnableHapticFeedback: false,
nativeID: '',
+ textSelectable: true,
};
class Button extends Component {
@@ -179,7 +183,7 @@ class Button extends Component {
const textComponent = (
{this.props.text}
diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js
index 470f570603f3..cee52c9b6272 100755
--- a/src/components/EmojiPicker/EmojiPickerMenu/index.js
+++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js
@@ -439,7 +439,13 @@ class EmojiPickerMenu extends Component {
return (
this.addToFrequentAndSelectEmoji(emoji, item)}
- onHover={() => this.setState({highlightedIndex: index})}
+ onHoverIn={() => this.setState({highlightedIndex: index})}
+ onHoverOut={() => {
+ if (this.state.arePointerEventsDisabled) {
+ return;
+ }
+ this.setState({highlightedIndex: -1});
+ }}
emoji={emojiCode}
isHighlighted={index === this.state.highlightedIndex}
/>
diff --git a/src/components/EmojiPicker/EmojiPickerMenuItem.js b/src/components/EmojiPicker/EmojiPickerMenuItem.js
index ee24d689f87d..929930efe27e 100644
--- a/src/components/EmojiPicker/EmojiPickerMenuItem.js
+++ b/src/components/EmojiPicker/EmojiPickerMenuItem.js
@@ -4,7 +4,6 @@ import {Pressable} from 'react-native';
import styles from '../../styles/styles';
import * as StyleUtils from '../../styles/StyleUtils';
import getButtonState from '../../libs/getButtonState';
-import Hoverable from '../Hoverable';
import Text from '../Text';
const propTypes = {
@@ -15,7 +14,10 @@ const propTypes = {
onPress: PropTypes.func.isRequired,
/** Handles what to do when we hover over this item with our cursor */
- onHover: PropTypes.func,
+ onHoverIn: PropTypes.func,
+
+ /** Handles what to do when the hover is out */
+ onHoverOut: PropTypes.func,
/** Whether this menu item is currently highlighted or not */
isHighlighted: PropTypes.bool,
@@ -24,6 +26,8 @@ const propTypes = {
const EmojiPickerMenuItem = props => (
props.onPress(props.emoji)}
+ onHoverIn={props.onHoverIn}
+ onHoverOut={props.onHoverOut}
style={({
pressed,
}) => ([
@@ -33,11 +37,9 @@ const EmojiPickerMenuItem = props => (
styles.emojiItem,
])}
>
-
-
- {props.emoji}
-
-
+
+ {props.emoji}
+
);
@@ -45,7 +47,8 @@ EmojiPickerMenuItem.propTypes = propTypes;
EmojiPickerMenuItem.displayName = 'EmojiPickerMenuItem';
EmojiPickerMenuItem.defaultProps = {
isHighlighted: false,
- onHover: () => {},
+ onHoverIn: () => {},
+ onHoverOut: () => {},
};
// Significantly speeds up re-renders of the EmojiPickerMenu's FlatList
diff --git a/src/components/EmojiPicker/EmojiSkinToneList.js b/src/components/EmojiPicker/EmojiSkinToneList.js
index 45dc28755592..d8efbcc0ec21 100644
--- a/src/components/EmojiPicker/EmojiSkinToneList.js
+++ b/src/components/EmojiPicker/EmojiSkinToneList.js
@@ -84,7 +84,8 @@ class EmojiSkinToneList extends Component {
_.map(Emojis.skinTones, skinToneEmoji => (
this.updateSelectedSkinTone(skinToneEmoji)}
- onHover={() => this.setState({highlightedIndex: skinToneEmoji.skinTone})}
+ onHoverIn={() => this.setState({highlightedIndex: skinToneEmoji.skinTone})}
+ onHoverOut={() => this.setState({highlightedIndex: -1})}
key={skinToneEmoji.code}
emoji={skinToneEmoji.code}
isHighlighted={skinToneEmoji.skinTone === this.state.highlightedIndex}
diff --git a/src/components/FormAlertWithSubmitButton.js b/src/components/FormAlertWithSubmitButton.js
index ca1e86d817ea..c3ef4b464c9a 100644
--- a/src/components/FormAlertWithSubmitButton.js
+++ b/src/components/FormAlertWithSubmitButton.js
@@ -32,6 +32,9 @@ const propTypes = {
/** Submit function */
onSubmit: PropTypes.func.isRequired,
+
+ /** Should the button be enabled when offline */
+ enabledWhenOffline: PropTypes.bool,
};
const defaultProps = {
@@ -41,6 +44,7 @@ const defaultProps = {
containerStyles: [],
isLoading: false,
onFixTheErrorsPressed: () => {},
+ enabledWhenOffline: false,
};
const FormAlertWithSubmitButton = props => (
@@ -51,7 +55,7 @@ const FormAlertWithSubmitButton = props => (
message={props.message}
onFixTheErrorsPressed={props.onFixTheErrorsPressed}
>
- {isOffline => (isOffline ? (
+ {isOffline => ((isOffline && !props.enabledWhenOffline) ? (
-
+ PaymentMethods.clearWalletError()} errors={this.props.userWallet.errors} errorRowStyles={[styles.ph6, styles.pv2]}>
+
+
- PaymentMethods.clearWalletError()} errors={this.props.userWallet.errors} errorRowStyles={[styles.ph6, styles.pv2]} />
);
}
diff --git a/src/pages/settings/Payments/TransferBalancePage.js b/src/pages/settings/Payments/TransferBalancePage.js
index 01a64e375d35..50cfff844f2a 100644
--- a/src/pages/settings/Payments/TransferBalancePage.js
+++ b/src/pages/settings/Payments/TransferBalancePage.js
@@ -59,9 +59,9 @@ const propTypes = {
};
const defaultProps = {
- userWallet: {},
bankAccountList: {},
cardList: {},
+ userWallet: {},
walletTransfer: {},
};
@@ -115,8 +115,6 @@ class TransferBalancePage extends React.Component {
const paymentMethods = PaymentUtils.formatPaymentMethods(
this.props.bankAccountList,
this.props.cardList,
- '',
- this.props.userWallet,
);
const defaultAccount = _.find(paymentMethods, method => method.isDefault);
@@ -138,8 +136,6 @@ class TransferBalancePage extends React.Component {
const combinedPaymentMethods = PaymentUtils.formatPaymentMethods(
this.props.bankAccountList,
this.props.cardList,
- '',
- this.props.userWallet,
);
const filteredMethods = _.filter(combinedPaymentMethods, paymentMethod => paymentMethod.accountType === filterPaymentMethodType);
diff --git a/src/pages/settings/Security/CloseAccountPage.js b/src/pages/settings/Security/CloseAccountPage.js
index f6e411d29135..22baa8d66a36 100644
--- a/src/pages/settings/Security/CloseAccountPage.js
+++ b/src/pages/settings/Security/CloseAccountPage.js
@@ -1,5 +1,5 @@
import React, {Component} from 'react';
-import {Linking, ScrollView} from 'react-native';
+import {Linking, ScrollView, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';
import Str from 'expensify-common/lib/str';
@@ -13,7 +13,6 @@ import ScreenWrapper from '../../../components/ScreenWrapper';
import TextInput from '../../../components/TextInput';
import Button from '../../../components/Button';
import Text from '../../../components/Text';
-import FixedFooter from '../../../components/FixedFooter';
import ConfirmModal from '../../../components/ConfirmModal';
import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';
@@ -73,47 +72,48 @@ class CloseAccountPage extends Component {
styles.p5,
]}
>
- {this.props.translate('closeAccountPage.reasonForLeavingPrompt')}
- this.setState({reasonForLeaving})}
- label={this.props.translate('closeAccountPage.enterMessageHere')}
- containerStyles={[styles.mt5, styles.closeAccountMessageInput]}
- />
-
-
- {this.props.translate('closeAccountPage.closeAccountWarning')}
+
+ {this.props.translate('closeAccountPage.reasonForLeavingPrompt')}
+ this.setState({reasonForLeaving})}
+ label={this.props.translate('closeAccountPage.enterMessageHere')}
+ containerStyles={[styles.mt5, styles.closeAccountMessageInput]}
+ />
+
+
+ {this.props.translate('closeAccountPage.closeAccountWarning')}
+
+ {' '}
+ {this.props.translate('closeAccountPage.closeAccountPermanentlyDeleteData')}
- {' '}
- {this.props.translate('closeAccountPage.closeAccountPermanentlyDeleteData')}
-
-
-
- {this.props.translate('closeAccountPage.defaultContact')}
+
+
+ {this.props.translate('closeAccountPage.defaultContact')}
+
+ {' '}
+ {userEmailOrPhone}
- {' '}
- {userEmailOrPhone}
-
- this.setState({phoneOrEmail: phoneOrEmail.toLowerCase()})}
- label={this.props.translate('closeAccountPage.enterDefaultContact')}
- containerStyles={[styles.mt5]}
- />
-
-
+ this.setState({phoneOrEmail: phoneOrEmail.toLowerCase()})}
+ label={this.props.translate('closeAccountPage.enterDefaultContact')}
+ containerStyles={[styles.mt5]}
+ />
+
User.closeAccount(this.state.reasonForLeaving)}
isDisabled={Str.removeSMSDomain(userEmailOrPhone).toLowerCase() !== this.state.phoneOrEmail.toLowerCase()}
+ style={[styles.mt5]}
/>
-
+
+
>
);
}
@@ -213,4 +221,5 @@ export default compose(
account: {key: ONYXKEYS.ACCOUNT},
}),
withToggleVisibilityView,
+ withNetwork(),
)(PasswordForm);
diff --git a/src/pages/workspace/WorkspaceBankAccountPage.js b/src/pages/workspace/WorkspaceBankAccountPage.js
index 64bd69cb9bd3..844ccc67bfa9 100644
--- a/src/pages/workspace/WorkspaceBankAccountPage.js
+++ b/src/pages/workspace/WorkspaceBankAccountPage.js
@@ -40,7 +40,7 @@ const propTypes = {
const defaultProps = {
reimbursementAccount: {
- loading: true,
+ isLoading: true,
},
};
diff --git a/src/pages/workspace/WorkspaceInvitePage.js b/src/pages/workspace/WorkspaceInvitePage.js
index 86fcc48b9757..4d58db2782fe 100644
--- a/src/pages/workspace/WorkspaceInvitePage.js
+++ b/src/pages/workspace/WorkspaceInvitePage.js
@@ -219,7 +219,8 @@ class WorkspaceInvitePage extends React.Component {
const logins = _.map(this.state.selectedOptions, option => option.login);
const filteredLogins = _.uniq(_.compact(_.map(logins, login => login.toLowerCase().trim())));
- Policy.invite(filteredLogins, this.state.welcomeNote || this.getWelcomeNote(), this.props.route.params.policyID);
+ Policy.addMembersToWorkspace(filteredLogins, this.state.welcomeNote || this.getWelcomeNote(), this.props.route.params.policyID);
+ Navigation.goBack();
}
/**
@@ -318,6 +319,7 @@ class WorkspaceInvitePage extends React.Component {
onFixTheErrorsLinkPressed={() => {}}
message={this.props.policy.alertMessage}
containerStyles={[styles.flexReset, styles.mb0, styles.flexGrow0, styles.flexShrink0, styles.flexBasisAuto]}
+ enabledWhenOffline
/>
{
diff --git a/src/pages/workspace/reimburse/WorkspaceReimburseView.js b/src/pages/workspace/reimburse/WorkspaceReimburseView.js
index 8f08b28e829d..8b6bf8ad7523 100644
--- a/src/pages/workspace/reimburse/WorkspaceReimburseView.js
+++ b/src/pages/workspace/reimburse/WorkspaceReimburseView.js
@@ -26,11 +26,9 @@ import networkPropTypes from '../../../components/networkPropTypes';
import Log from '../../../libs/Log';
const propTypes = {
- /** The policy ID currently being configured */
- policyID: PropTypes.string.isRequired,
-
/** Policy values needed in the component */
policy: PropTypes.shape({
+ id: PropTypes.string,
customUnits: PropTypes.objectOf(
PropTypes.shape({
customUnitID: PropTypes.string,
@@ -112,7 +110,7 @@ class WorkspaceReimburseView extends React.Component {
return;
}
- Policy.openWorkspaceReimburseView(this.props.policyID);
+ Policy.openWorkspaceReimburseView(this.props.policy.id);
}
getRateDisplayValue(value) {
diff --git a/src/styles/styles.js b/src/styles/styles.js
index 4af46956b06d..e219382ac4fd 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -321,6 +321,10 @@ const styles = {
backgroundColor: 'transparent',
},
+ bgDark: {
+ backgroundColor: colors.dark,
+ },
+
opacity0: {
opacity: 0,
},
@@ -2642,10 +2646,6 @@ const styles = {
height: 153,
},
- avatarCropModalContainer: {
- maxWidth: 450, // this width was chosen to match layout to average mobile device
- },
-
imageCropContainer: {
borderRadius: variables.componentBorderRadiusCard,
overflow: 'hidden',
diff --git a/tests/actions/ReimbursementAccountTest.js b/tests/actions/ReimbursementAccountTest.js
index cd0ae97aeda6..83401473d452 100644
--- a/tests/actions/ReimbursementAccountTest.js
+++ b/tests/actions/ReimbursementAccountTest.js
@@ -61,7 +61,7 @@ describe('actions/BankAccounts', () => {
return waitForPromisesToResolve()
.then(() => {
// THEN we should expect it to stop loading and bring us to the BankAccountStep
- expect(reimbursementAccount.loading).toBe(false);
+ expect(reimbursementAccount.isLoading).toBe(false);
expect(reimbursementAccount.error).toBe('');
expect(reimbursementAccount.achData.currentStep).toBe(CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT);
expect(reimbursementAccount.achData.isInSetup).toBe(true);
@@ -83,7 +83,7 @@ describe('actions/BankAccounts', () => {
})
.then(() => {
// THEN we should advance to the CompanyStep and the enableCardAfterVerified param should be added
- expect(reimbursementAccount.loading).toBe(false);
+ expect(reimbursementAccount.isLoading).toBe(false);
expect(reimbursementAccount.error).toBe('');
expect(reimbursementAccount.achData.currentStep).toBe(CONST.BANK_ACCOUNT.STEP.COMPANY);
expect(reimbursementAccount.achData.enableCardAfterVerified).toBe(true);
@@ -121,7 +121,7 @@ describe('actions/BankAccounts', () => {
})
.then(() => {
// THEN we should advance to the RequestorStep
- expect(reimbursementAccount.loading).toBe(false);
+ expect(reimbursementAccount.isLoading).toBe(false);
expect(reimbursementAccount.error).toBe('');
expect(reimbursementAccount.achData.currentStep).toBe(CONST.BANK_ACCOUNT.STEP.REQUESTOR);
});
@@ -151,7 +151,7 @@ describe('actions/BankAccounts', () => {
return waitForPromisesToResolve()
.then(() => {
// THEN we should to navigate to the RequestorStep
- expect(reimbursementAccount.loading).toBe(false);
+ expect(reimbursementAccount.isLoading).toBe(false);
expect(reimbursementAccount.error).toBe('');
expect(reimbursementAccount.achData.currentStep).toBe(CONST.BANK_ACCOUNT.STEP.REQUESTOR);
expect(reimbursementAccount.achData.bankAccountID).toBe(TEST_BANK_ACCOUNT_ID);
@@ -190,7 +190,7 @@ describe('actions/BankAccounts', () => {
})
.then(() => {
// THEN we should move to the ACHContract step and Onfido should be marked as complete
- expect(reimbursementAccount.loading).toBe(false);
+ expect(reimbursementAccount.isLoading).toBe(false);
expect(reimbursementAccount.error).toBe('');
expect(reimbursementAccount.achData.currentStep).toBe(CONST.BANK_ACCOUNT.STEP.ACH_CONTRACT);
expect(reimbursementAccount.achData.isOnfidoSetupComplete).toBe(true);
@@ -223,7 +223,7 @@ describe('actions/BankAccounts', () => {
return waitForPromisesToResolve()
.then(() => {
// THEN we should expect it redirect the user back to the RequestorStep because they still need to do Onfido
- expect(reimbursementAccount.loading).toBe(false);
+ expect(reimbursementAccount.isLoading).toBe(false);
expect(reimbursementAccount.error).toBe('');
expect(reimbursementAccount.achData.currentStep).toBe(CONST.BANK_ACCOUNT.STEP.REQUESTOR);
});
@@ -255,7 +255,7 @@ describe('actions/BankAccounts', () => {
return waitForPromisesToResolve()
.then(() => {
// THEN we should expect to be navigated to the ACHContractStep step
- expect(reimbursementAccount.loading).toBe(false);
+ expect(reimbursementAccount.isLoading).toBe(false);
expect(reimbursementAccount.error).toBe('');
expect(reimbursementAccount.achData.currentStep).toBe(CONST.BANK_ACCOUNT.STEP.ACH_CONTRACT);
@@ -296,7 +296,7 @@ describe('actions/BankAccounts', () => {
})
.then(() => {
// THEN we should expect to have an account in the PENDING state and be brought to the ValidationStep
- expect(reimbursementAccount.loading).toBe(false);
+ expect(reimbursementAccount.isLoading).toBe(false);
expect(reimbursementAccount.error).toBe('');
expect(reimbursementAccount.achData.currentStep).toBe(CONST.BANK_ACCOUNT.STEP.VALIDATION);
expect(reimbursementAccount.achData.state).toBe(BankAccount.STATE.PENDING);
@@ -330,7 +330,7 @@ describe('actions/BankAccounts', () => {
return waitForPromisesToResolve()
.then(() => {
// THEN we should see that we are directed to the ValidationStep
- expect(reimbursementAccount.loading).toBe(false);
+ expect(reimbursementAccount.isLoading).toBe(false);
expect(reimbursementAccount.error).toBe('');
expect(reimbursementAccount.achData.currentStep).toBe(CONST.BANK_ACCOUNT.STEP.VALIDATION);
expect(reimbursementAccount.achData.state).toBe(BankAccount.STATE.PENDING);
@@ -366,7 +366,7 @@ describe('actions/BankAccounts', () => {
return waitForPromisesToResolve()
.then(() => {
// THEN it should have maxAttemptsReached set to true and show the correct data set in Onyx
- expect(reimbursementAccount.loading).toBe(false);
+ expect(reimbursementAccount.isLoading).toBe(false);
expect(reimbursementAccount.error).toBe('');
expect(reimbursementAccount.maxAttemptsReached).toBe(true);
});
diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js
index 10adbab78db5..9531266efe2b 100644
--- a/tests/ui/UnreadIndicatorsTest.js
+++ b/tests/ui/UnreadIndicatorsTest.js
@@ -25,6 +25,8 @@ beforeAll(() => {
// behavior. But here we just want to treat all API requests as a generic "success" and in the cases where we need to
// simulate data arriving we will just set it into Onyx directly with Onyx.merge() or Onyx.set() etc.
global.fetch = TestHelper.getGlobalFetchMock();
+
+ jest.setTimeout(15000);
Linking.setInitialURL('https://new.expensify.com/r/1');
appSetup();
});
diff --git a/tests/unit/LHNOrderTest.js b/tests/unit/LHNOrderTest.js
index 85e38d8282ba..d51de490b5c3 100644
--- a/tests/unit/LHNOrderTest.js
+++ b/tests/unit/LHNOrderTest.js
@@ -72,7 +72,7 @@ const fakePersonalDetails = {
};
const fakeReport1 = {
- reportID: 1,
+ reportID: '1',
reportName: 'Report One',
maxSequenceNumber: TEST_MAX_SEQUENCE_NUMBER,
lastReadSequenceNumber: TEST_MAX_SEQUENCE_NUMBER,
@@ -82,7 +82,7 @@ const fakeReport1 = {
participants: ['email1@test.com', 'email2@test.com'],
};
const fakeReport2 = {
- reportID: 2,
+ reportID: '2',
reportName: 'Report Two',
maxSequenceNumber: TEST_MAX_SEQUENCE_NUMBER,
lastReadSequenceNumber: TEST_MAX_SEQUENCE_NUMBER,
@@ -90,7 +90,7 @@ const fakeReport2 = {
participants: ['email3@test.com', 'email4@test.com'],
};
const fakeReport3 = {
- reportID: 3,
+ reportID: '3',
reportName: 'Report Three',
maxSequenceNumber: TEST_MAX_SEQUENCE_NUMBER,
lastReadSequenceNumber: TEST_MAX_SEQUENCE_NUMBER,
@@ -98,7 +98,7 @@ const fakeReport3 = {
participants: ['email5@test.com', 'email6@test.com'],
};
const fakeReportIOU = {
- reportID: 4,
+ reportID: '4',
reportName: 'Report IOU Four',
maxSequenceNumber: TEST_MAX_SEQUENCE_NUMBER,
lastReadSequenceNumber: TEST_MAX_SEQUENCE_NUMBER,
@@ -499,6 +499,104 @@ describe('Sidebar', () => {
expect(reportOptions[2].children[0].props.children).toBe('ReportID, One');
});
});
+
+ it('alphabetizes all the chats that are pinned', () => {
+ const sidebarLinks = getDefaultRenderedSidebarLinks();
+
+ return waitForPromisesToResolve()
+
+ // Given the sidebar is rendered in default mode
+ // with all reports being pinned
+ .then(() => Onyx.multiSet({
+ [ONYXKEYS.NVP_PRIORITY_MODE]: 'default',
+ [ONYXKEYS.PERSONAL_DETAILS]: fakePersonalDetails,
+ [ONYXKEYS.CURRENTLY_VIEWED_REPORTID]: '1',
+ [`${ONYXKEYS.COLLECTION.REPORT}1`]: {...fakeReport1, isPinned: true},
+ [`${ONYXKEYS.COLLECTION.REPORT}2`]: {...fakeReport2, isPinned: true},
+ [`${ONYXKEYS.COLLECTION.REPORT}3`]: {...fakeReport3, isPinned: true},
+ [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}1`]: fakeReport1Actions,
+ [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}2`]: fakeReport2Actions,
+ [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}2`]: fakeReport3Actions,
+ }))
+
+ // Then the reports are in alphabetical order
+ .then(() => {
+ const reportOptions = sidebarLinks.queryAllByText(/ReportID, /);
+ expect(reportOptions).toHaveLength(3);
+ expect(reportOptions[0].children[0].props.children).toBe('ReportID, One');
+ expect(reportOptions[1].children[0].props.children).toBe('ReportID, Three');
+ expect(reportOptions[2].children[0].props.children).toBe('ReportID, Two');
+ })
+
+ // When a new report is added
+ .then(() => Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}4`, {
+ reportID: '4',
+ reportName: 'Report Four',
+ maxSequenceNumber: TEST_MAX_SEQUENCE_NUMBER,
+ isPinned: true,
+ lastMessageTimestamp: Date.now(),
+ participants: ['email7@test.com', 'email8@test.com'],
+ }))
+
+ // Then they are still in alphabetical order
+ .then(() => {
+ const reportOptions = sidebarLinks.queryAllByText(/ReportID, /);
+ expect(reportOptions).toHaveLength(4);
+ expect(reportOptions[0].children[0].props.children).toBe('ReportID, Four');
+ expect(reportOptions[1].children[0].props.children).toBe('ReportID, One');
+ expect(reportOptions[2].children[0].props.children).toBe('ReportID, Three');
+ expect(reportOptions[3].children[0].props.children).toBe('ReportID, Two');
+ });
+ });
+
+ it('alphabetizes all the chats that have drafts', () => {
+ const sidebarLinks = getDefaultRenderedSidebarLinks();
+
+ return waitForPromisesToResolve()
+
+ // Given the sidebar is rendered in default mode
+ // with all reports having drafts
+ .then(() => Onyx.multiSet({
+ [ONYXKEYS.NVP_PRIORITY_MODE]: 'default',
+ [ONYXKEYS.PERSONAL_DETAILS]: fakePersonalDetails,
+ [ONYXKEYS.CURRENTLY_VIEWED_REPORTID]: '5',
+ [`${ONYXKEYS.COLLECTION.REPORT}1`]: {...fakeReport1, hasDraft: true},
+ [`${ONYXKEYS.COLLECTION.REPORT}2`]: {...fakeReport2, hasDraft: true},
+ [`${ONYXKEYS.COLLECTION.REPORT}3`]: {...fakeReport3, hasDraft: true},
+ [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}1`]: fakeReport1Actions,
+ [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}2`]: fakeReport2Actions,
+ [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}2`]: fakeReport3Actions,
+ }))
+
+ // Then the reports are in alphabetical order
+ .then(() => {
+ const reportOptions = sidebarLinks.queryAllByText(/ReportID, /);
+ expect(reportOptions).toHaveLength(3);
+ expect(reportOptions[0].children[0].props.children).toBe('ReportID, One');
+ expect(reportOptions[1].children[0].props.children).toBe('ReportID, Three');
+ expect(reportOptions[2].children[0].props.children).toBe('ReportID, Two');
+ })
+
+ // When a new report is added
+ .then(() => Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}4`, {
+ reportID: '4',
+ reportName: 'Report Four',
+ maxSequenceNumber: TEST_MAX_SEQUENCE_NUMBER,
+ hasDraft: true,
+ lastMessageTimestamp: Date.now(),
+ participants: ['email7@test.com', 'email8@test.com'],
+ }))
+
+ // Then they are still in alphabetical order
+ .then(() => {
+ const reportOptions = sidebarLinks.queryAllByText(/ReportID, /);
+ expect(reportOptions).toHaveLength(4);
+ expect(reportOptions[0].children[0].props.children).toBe('ReportID, Four');
+ expect(reportOptions[1].children[0].props.children).toBe('ReportID, One');
+ expect(reportOptions[2].children[0].props.children).toBe('ReportID, Three');
+ expect(reportOptions[3].children[0].props.children).toBe('ReportID, Two');
+ });
+ });
});
describe('in #focus mode', () => {
diff --git a/tests/unit/fetchFreePlanVerifiedBankAccountTest.js b/tests/unit/fetchFreePlanVerifiedBankAccountTest.js
index db253a66422b..634e6aae53e3 100644
--- a/tests/unit/fetchFreePlanVerifiedBankAccountTest.js
+++ b/tests/unit/fetchFreePlanVerifiedBankAccountTest.js
@@ -9,7 +9,7 @@ describe('getCurrentStep', () => {
const achData = {};
// WHEN we get the current step
- const currentStep = fetchFreePlanVerifiedBankAccount.getCurrentStep('', '', achData, nullBankAccount, false);
+ const currentStep = fetchFreePlanVerifiedBankAccount.getCurrentStep('', achData, nullBankAccount, false);
// THEN it will be the BankAccountStep
expect(currentStep).toBe(CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT);
@@ -28,7 +28,7 @@ describe('getCurrentStep', () => {
};
// WHEN we get the current step
- const currentStep = fetchFreePlanVerifiedBankAccount.getCurrentStep('', '', achData, nullBankAccount, false);
+ const currentStep = fetchFreePlanVerifiedBankAccount.getCurrentStep('', achData, nullBankAccount, false);
// THEN it will be the BankAccountStep
expect(currentStep).toBe(CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT);
@@ -41,7 +41,7 @@ describe('getCurrentStep', () => {
const stepToOpen = CONST.BANK_ACCOUNT.STEP.COMPANY;
// WHEN we get the current step
- const currentStep = fetchFreePlanVerifiedBankAccount.getCurrentStep(stepToOpen, '', achData, nullBankAccount, false);
+ const currentStep = fetchFreePlanVerifiedBankAccount.getCurrentStep(stepToOpen, achData, nullBankAccount, false);
// THEN it will be whatever we set the stepToOpen to be
expect(currentStep).toBe(CONST.BANK_ACCOUNT.STEP.COMPANY);
@@ -54,7 +54,7 @@ describe('getCurrentStep', () => {
const stepToOpen = '';
// WHEN we get the current step
- const currentStep = fetchFreePlanVerifiedBankAccount.getCurrentStep(stepToOpen, '', achData, bankAccount, false);
+ const currentStep = fetchFreePlanVerifiedBankAccount.getCurrentStep(stepToOpen, achData, bankAccount, false);
// THEN it will be the logical next step
expect(currentStep).toBe(CONST.BANK_ACCOUNT.STEP.REQUESTOR);
@@ -71,7 +71,7 @@ describe('getCurrentStep', () => {
const stepToOpen = '';
// WHEN we get the current step
- const currentStep = fetchFreePlanVerifiedBankAccount.getCurrentStep(stepToOpen, '', achData, bankAccount, false);
+ const currentStep = fetchFreePlanVerifiedBankAccount.getCurrentStep(stepToOpen, achData, bankAccount, false);
// THEN we will stay on the requestor step
expect(currentStep).toBe(CONST.BANK_ACCOUNT.STEP.REQUESTOR);
@@ -86,7 +86,7 @@ describe('getCurrentStep', () => {
const stepToOpen = '';
// WHEN we get the current step
- const currentStep = fetchFreePlanVerifiedBankAccount.getCurrentStep(stepToOpen, '', achData, bankAccount, false);
+ const currentStep = fetchFreePlanVerifiedBankAccount.getCurrentStep(stepToOpen, achData, bankAccount, false);
// THEN it will be the validation step
expect(currentStep).toBe(CONST.BANK_ACCOUNT.STEP.VALIDATION);
@@ -101,31 +101,13 @@ describe('getCurrentStep', () => {
const stepToOpen = '';
// WHEN we get the current step
- const currentStep = fetchFreePlanVerifiedBankAccount.getCurrentStep(stepToOpen, '', achData, bankAccount, false);
+ const currentStep = fetchFreePlanVerifiedBankAccount.getCurrentStep(stepToOpen, achData, bankAccount, false);
// THEN it will be the validation step
expect(currentStep).toBe(CONST.BANK_ACCOUNT.STEP.VALIDATION);
});
- it('Returns step based on open BankAccount that needs to pass checks', () => {
- // GIVEN an open bank account that needs to pass checks
- const bankAccount = new BankAccount({
- state: BankAccount.STATE.OPEN,
- additionalData: {
- hasFullSSN: false,
- },
- });
- const achData = {};
- const stepToOpen = '';
-
- // WHEN we get the current step
- const currentStep = fetchFreePlanVerifiedBankAccount.getCurrentStep(stepToOpen, '', achData, bankAccount, false);
-
- // THEN it will be the company step
- expect(currentStep).toBe(CONST.BANK_ACCOUNT.STEP.COMPANY);
- });
-
- it('Returns step based on open BankAccount that does not need to pass checks', () => {
+ it('Returns step based on open BankAccount', () => {
// GIVEN an open bank account that does not need to pass checks
const bankAccount = new BankAccount({
state: BankAccount.STATE.OPEN,
@@ -139,26 +121,13 @@ describe('getCurrentStep', () => {
},
}],
requestorAddressCity: 'Portland',
- verifications: {
- externalApiResponses: {
- realSearchResult: {
- status: 'pass',
- },
- lexisNexisInstantIDResult: {
- status: 'pass',
- },
- requestorIdentityID: {
- status: 'pass',
- },
- },
- },
},
});
const achData = {};
const stepToOpen = '';
// WHEN we get the current step
- const currentStep = fetchFreePlanVerifiedBankAccount.getCurrentStep(stepToOpen, '', achData, bankAccount, true);
+ const currentStep = fetchFreePlanVerifiedBankAccount.getCurrentStep(stepToOpen, achData, bankAccount, true);
// THEN it will be the enable step
expect(currentStep).toBe(CONST.BANK_ACCOUNT.STEP.ENABLE);
@@ -173,7 +142,7 @@ describe('getCurrentStep', () => {
const stepToOpen = '';
// WHEN we get the current step
- const currentStep = fetchFreePlanVerifiedBankAccount.getCurrentStep(stepToOpen, '', achData, bankAccount, true);
+ const currentStep = fetchFreePlanVerifiedBankAccount.getCurrentStep(stepToOpen, achData, bankAccount, true);
// THEN it will be the bank account step
expect(currentStep).toBe(CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT);
diff --git a/tests/utils/TestHelper.js b/tests/utils/TestHelper.js
index 032f97fe2b1e..7b582a0aa449 100644
--- a/tests/utils/TestHelper.js
+++ b/tests/utils/TestHelper.js
@@ -1,4 +1,5 @@
import Onyx from 'react-native-onyx';
+import Str from 'expensify-common/lib/str';
import CONST from '../../src/CONST';
import * as Session from '../../src/libs/actions/Session';
import HttpUtils from '../../src/libs/HttpUtils';
@@ -78,10 +79,42 @@ function signInWithTestUser(accountID = 1, login = 'test@user.com', password = '
// Response is the same for calls to Authenticate and CreateLogin
HttpUtils.xhr
.mockImplementation(() => Promise.resolve({
+ onyxData: [
+ {
+ onyxMethod: CONST.ONYX.METHOD.MERGE,
+ key: ONYXKEYS.SESSION,
+ value: {
+ shouldShowComposeInput: true,
+ authToken,
+ accountID,
+ email: login,
+ encryptedAuthToken: authToken,
+ },
+ },
+ {
+ onyxMethod: CONST.ONYX.METHOD.MERGE,
+ key: ONYXKEYS.CREDENTIALS,
+ value: {
+ autoGeneratedLogin: Str.guid('expensify.cash-'),
+ autoGeneratedPassword: Str.guid(),
+ },
+ },
+ {
+ onyxMethod: CONST.ONYX.METHOD.MERGE,
+ key: ONYXKEYS.USER,
+ value: {
+ isUsingExpensifyCard: false,
+ },
+ },
+ {
+ onyxMethod: CONST.ONYX.METHOD.MERGE,
+ key: ONYXKEYS.BETAS,
+ value: {
+ betas: ['all'],
+ },
+ },
+ ],
jsonCode: 200,
- accountID,
- authToken,
- email: login,
}));
Session.signIn(password);
return waitForPromisesToResolve()