diff --git a/.github/workflows/cherryPick.yml b/.github/workflows/cherryPick.yml index 350380aed2b9..51d7eae346a3 100644 --- a/.github/workflows/cherryPick.yml +++ b/.github/workflows/cherryPick.yml @@ -148,6 +148,7 @@ jobs: --body "🍒 Cherry pick https://github.com/Expensify/App/pull/${{ github.event.inputs.PULL_REQUEST_NUMBER }} to staging 🍒" \ --label "automerge" \ --base "staging" + sleep 5 echo "::set-output name=PR_NUMBER::$(gh pr view --json 'number' --jq '.number')" env: GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} @@ -205,7 +206,7 @@ jobs: - name: Auto-merge the PR # Important: only auto-merge if there was no merge conflict and the PR is mergable (not blocked by a missing status check)! if: ${{ fromJSON(steps.cherryPick.outputs.SHOULD_AUTOMERGE) && fromJSON(steps.isPullRequestMergeable.outputs.IS_MERGEABLE) }} - run: gh pr merge --merge --delete-branch + run: gh pr merge ${{ steps.createPullRequest.outputs.pr_number }} --merge --delete-branch env: GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} diff --git a/.github/workflows/platformDeploy.yml b/.github/workflows/platformDeploy.yml index 608aa21204e1..5575d05609f2 100644 --- a/.github/workflows/platformDeploy.yml +++ b/.github/workflows/platformDeploy.yml @@ -209,13 +209,12 @@ jobs: max_attempts: 5 command: npm ci - - uses: actions/cache@v2 - with: - path: ios/Pods - key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }} - - name: Install cocoapods - run: cd ios && pod install + uses: nick-invision/retry@7c68161adf97a48beb850a595b8784ec57a98cbb + with: + timeout_minutes: 10 + max_attempts: 5 + command: cd ios && pod install - name: Decrypt profile run: cd ios && gpg --quiet --batch --yes --decrypt --passphrase="$LARGE_SECRET_PASSPHRASE" --output chat_expensify_appstore.mobileprovision chat_expensify_appstore.mobileprovision.gpg diff --git a/.github/workflows/updateProtectedBranch.yml b/.github/workflows/updateProtectedBranch.yml index 40f00fb63cd0..b03689245b6f 100644 --- a/.github/workflows/updateProtectedBranch.yml +++ b/.github/workflows/updateProtectedBranch.yml @@ -86,6 +86,7 @@ jobs: --body "Update version to ${{ env.NEW_VERSION }}" \ --label "automerge" \ --base ${{ github.event.inputs.TARGET_BRANCH }} + sleep 5 echo "::set-output name=PR_NUMBER::$(gh pr view --json 'number' --jq '.number')" env: GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} @@ -129,7 +130,7 @@ jobs: run: exit 1 - name: Auto-merge the PR - run: gh pr merge --merge --delete-branch + run: gh pr merge ${{ steps.createPullRequest.outputs.PR_NUMBER }} --merge --delete-branch env: GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} diff --git a/FORMS.md b/FORMS.md index 65e9cfaeae0c..d80b2dff3310 100644 --- a/FORMS.md +++ b/FORMS.md @@ -210,4 +210,4 @@ Form.js will automatically provide the following props to any input with the inp - defaultValue: The input default value. - errorText: The translated error text that is returned by validate for that specific input. - onBlur: An onBlur handler that calls validate. -- onChange: An onChange handler that saves draft values and calls validate. +- onInputChange: An onChange handler that saves draft values and calls validate for that input (inputA). Passing an inputID as a second param allows inputA to manipulate the input value of the provided inputID (inputB). diff --git a/android/app/build.gradle b/android/app/build.gradle index 0b16d9136f37..d6d3e5dc1514 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -152,8 +152,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001016003 - versionName "1.1.60-3" + versionCode 1001017003 + versionName "1.1.70-3" } splits { abi { diff --git a/assets/images/avatars/fallback-avatar.svg b/assets/images/avatars/fallback-avatar.svg new file mode 100644 index 000000000000..dc1a1497cfe5 --- /dev/null +++ b/assets/images/avatars/fallback-avatar.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + diff --git a/assets/images/avatars/fallback-workspace-avatar.svg b/assets/images/avatars/fallback-workspace-avatar.svg new file mode 100644 index 000000000000..ac2f58122a0f --- /dev/null +++ b/assets/images/avatars/fallback-workspace-avatar.svg @@ -0,0 +1,15 @@ + + + + + + + diff --git a/assets/images/offline-cloud.svg b/assets/images/offline-cloud.svg new file mode 100644 index 000000000000..d7dea2037561 --- /dev/null +++ b/assets/images/offline-cloud.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/images/offline.svg b/assets/images/offline.svg index a4d539125f31..f3b58e11221f 100644 --- a/assets/images/offline.svg +++ b/assets/images/offline.svg @@ -1,5 +1,5 @@ - + diff --git a/config/webpack/webpack.common.js b/config/webpack/webpack.common.js index 99cc83dfc5b9..e6002e4166d0 100644 --- a/config/webpack/webpack.common.js +++ b/config/webpack/webpack.common.js @@ -15,7 +15,6 @@ const includeModules = [ 'react-native-webview', '@react-native-picker', 'react-native-modal', - 'react-native-onyx', 'react-native-gesture-handler', 'react-native-flipper', 'react-native-google-places-autocomplete', diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 93d6601ab4fa..e753f996c652 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.1.60 + 1.1.70 CFBundleSignature ???? CFBundleURLTypes @@ -30,7 +30,7 @@ CFBundleVersion - 1.1.60.3 + 1.1.70.3 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 5e9bf6b0f020..a0f1f6647e12 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.1.60 + 1.1.70 CFBundleSignature ???? CFBundleVersion - 1.1.60.3 + 1.1.70.3 diff --git a/ios/Podfile.lock b/ios/Podfile.lock index fb504dc289e7..a4a11efbb120 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -435,6 +435,8 @@ PODS: - React-jsinspector (0.66.4) - React-logger (0.66.4): - glog + - react-native-cameraroll (4.1.2): + - React-Core - react-native-config (1.4.5): - react-native-config/App (= 1.4.5) - react-native-config/App (1.4.5): @@ -445,7 +447,7 @@ PODS: - React-Core - react-native-image-picker (4.7.3): - React-Core - - react-native-netinfo (8.0.0): + - react-native-netinfo (8.3.0): - React-Core - react-native-pdf (6.2.2): - React-Core @@ -535,7 +537,7 @@ PODS: - React-Core - RNCMaskedView (0.2.4): - React-Core - - RNCPicker (1.9.11): + - RNCPicker (2.3.1): - React-Core - RNDateTimePicker (3.5.2): - React-Core @@ -659,6 +661,7 @@ DEPENDENCIES: - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) - React-logger (from `../node_modules/react-native/ReactCommon/logger`) + - "react-native-cameraroll (from `../node_modules/@react-native-community/cameraroll`)" - react-native-config (from `../node_modules/react-native-config`) - react-native-document-picker (from `../node_modules/react-native-document-picker`) - react-native-flipper (from `../node_modules/react-native-flipper`) @@ -787,6 +790,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/jsinspector" React-logger: :path: "../node_modules/react-native/ReactCommon/logger" + react-native-cameraroll: + :path: "../node_modules/@react-native-community/cameraroll" react-native-config: :path: "../node_modules/react-native-config" react-native-document-picker: @@ -878,7 +883,7 @@ SPEC CHECKSUMS: Airship: 29d674abeac754f783fc46c7d383d6f046687341 boost: a7c83b31436843459a1961bfd74b96033dc77234 CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 - DoubleConversion: cf9b38bf0b2d048436d9a82ad2abe1404f11e7de + DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662 FBLazyVector: e5569e42a1c79ca00521846c223173a57aca1fe1 FBReactNativeSpec: fe08c1cd7e2e205718d77ad14b34957cce949b58 Firebase: 54cdc8bc9c9b3de54f43dab86e62f5a76b47034f @@ -900,7 +905,7 @@ SPEC CHECKSUMS: Flipper-RSocket: d9d9ade67cbecf6ac10730304bf5607266dd2541 FlipperKit: d8d346844eca5d9120c17d441a2f38596e8ed2b9 fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 - glog: 73c2498ac6884b13ede40eda8228cb1eee9d9d62 + glog: 5337263514dd6f09803962437687240c5dc39aa4 GoogleAppMeasurement: 6b6a08fd9c71f4dbc89e0e812acca81d797aa342 GoogleDataTransport: 629c20a4d363167143f30ea78320d5a7eb8bd940 GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1 @@ -930,11 +935,12 @@ SPEC CHECKSUMS: React-jsiexecutor: 94ce921e1d8ce7023366873ec371f3441383b396 React-jsinspector: d0374f7509d407d2264168b6d0fad0b54e300b85 React-logger: 933f80c97c633ee8965d609876848148e3fef438 + react-native-cameraroll: 60ac50a5209777cbccfe8d7a62d0743a9da87060 react-native-config: 6502b1879f97ed5ac570a029961fc35ea606cd14 react-native-document-picker: 772d04a4bc5c35da9abe27b08ac271420ae3f9ef react-native-flipper: cd9eabd8917104c1bbdca2621717cdca3b2addef react-native-image-picker: ae1202414bd5c37c00b2a701daa5b6194a06b7d9 - react-native-netinfo: 0124c0695373fce63cea24aeebb97ab2d237947a + react-native-netinfo: ebbcd8fbe1a0ce7035e43cd18c5a545dcb93dd08 react-native-pdf: 4b5a9e4465a6a3b399e91dc4838eb44ddf716d1f react-native-performance: 8edfa2bbc9a2af4a02f01d342118e413a95145e0 react-native-plaid-link-sdk: 9e0ebdaed648a237b36d5f6f6292b5147af92da7 @@ -958,7 +964,7 @@ SPEC CHECKSUMS: RNCAsyncStorage: 8324611026e8dc3706f829953aa6e3899f581589 RNCClipboard: 5e299c6df8e0c98f3d7416b86ae563d3a9f768a3 RNCMaskedView: 138134c4d8a9421b4f2bf39055a79aa05c2d47b1 - RNCPicker: 6780c753e9e674065db90d9c965920516402579d + RNCPicker: f6c760d4b314585ff35165d8640d7917ae30afb1 RNDateTimePicker: c9911be59b1f8670b9f244b85af3a7c295e175ed RNFastImage: 1f2cab428712a4baaf78d6169eaec7f622556dd7 RNFBAnalytics: 8ba84c2d31c64374d054c8621b998f25145ffddc @@ -979,4 +985,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 431123d7514c52fa4516724b89c20d02c87ad8c8 -COCOAPODS: 1.11.2 +COCOAPODS: 1.10.1 diff --git a/package-lock.json b/package-lock.json index 91c8c59bdb3c..9f610e0d9d08 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.1.60-3", + "version": "1.1.70-3", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -6759,13 +6759,20 @@ } }, "@react-navigation/drawer": { - "version": "6.1.8", - "resolved": "https://registry.npmjs.org/@react-navigation/drawer/-/drawer-6.1.8.tgz", - "integrity": "sha512-kYE2EO5dianUuUcaYmAlYBcgtmvGm2fxWTQ5sn103cgPNidp4KBUR9ClkhF+btfRaHKq+8Ul5M6qvL0mBAv/Lg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@react-navigation/drawer/-/drawer-6.3.0.tgz", + "integrity": "sha512-rbIpJCMeRVler6JI8eiHdvFEXbF8j8ii4cD42HeN9DqjpEJRfuz134ObM3O6Qd7h0k9U69exshbAUQ+7QaWesA==", "requires": { - "@react-navigation/elements": "^1.2.1", + "@react-navigation/elements": "^1.3.1", "color": "^3.1.3", "warn-once": "^0.1.0" + }, + "dependencies": { + "@react-navigation/elements": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.3.tgz", + "integrity": "sha512-Lv2lR7si5gNME8dRsqz57d54m4FJtrwHRjNQLOyQO546ZxO+g864cSvoLC6hQedQU0+IJnPTsZiEI2hHqfpEpw==" + } } }, "@react-navigation/elements": { @@ -23779,8 +23786,8 @@ } }, "expensify-common": { - "version": "git+https://github.com/Expensify/expensify-common.git#427295da130a4eacc184d38693664280d020dffd", - "from": "git+https://github.com/Expensify/expensify-common.git#427295da130a4eacc184d38693664280d020dffd", + "version": "git+https://github.com/Expensify/expensify-common.git#e989d858aa2ab8191284ae106acf9cd323ab879d", + "from": "git+https://github.com/Expensify/expensify-common.git#e989d858aa2ab8191284ae106acf9cd323ab879d", "requires": { "classnames": "2.3.1", "clipboard": "2.0.4", @@ -23792,6 +23799,7 @@ "react-dom": "16.12.0", "semver": "^7.3.5", "simply-deferred": "git+https://github.com/Expensify/simply-deferred.git#77a08a95754660c7bd6e0b6979fdf84e8e831bf5", + "string.prototype.replaceall": "^1.0.6", "underscore": "1.13.1" }, "dependencies": { @@ -24755,7 +24763,6 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -24767,7 +24774,6 @@ "version": "1.19.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dev": true, "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", @@ -24794,14 +24800,12 @@ "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==" }, "internal-slot": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, "requires": { "get-intrinsic": "^1.1.0", "has": "^1.0.3", @@ -24811,20 +24815,17 @@ "is-callable": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" }, "is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -24834,7 +24835,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, "requires": { "has-tostringtag": "^1.0.0" } @@ -24842,14 +24842,12 @@ "object-inspect": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", - "dev": true + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==" }, "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==", - "dev": true, "requires": { "call-bind": "^1.0.0", "define-properties": "^1.1.3", @@ -24861,7 +24859,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, "requires": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -24872,7 +24869,6 @@ "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==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -24882,7 +24878,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -24899,8 +24894,7 @@ "functions-have-names": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.2.tgz", - "integrity": "sha512-bLgc3asbWdwPbx2mNk2S49kmJCuQeu0nfmaOgbs8WIyzzkw3r4htszdIi9Q9EMezDPTYuJx2wvjZ/EwgAthpnA==", - "dev": true + "integrity": "sha512-bLgc3asbWdwPbx2mNk2S49kmJCuQeu0nfmaOgbs8WIyzzkw3r4htszdIi9Q9EMezDPTYuJx2wvjZ/EwgAthpnA==" }, "fuse.js": { "version": "3.6.1", @@ -25205,7 +25199,7 @@ "good-listener": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", - "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", + "integrity": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==", "requires": { "delegate": "^3.1.2" } @@ -25366,6 +25360,14 @@ } } }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "requires": { + "get-intrinsic": "^1.1.1" + } + }, "has-symbols": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", @@ -36520,65 +36522,12 @@ } }, "react-native-onyx": { - "version": "git+https://github.com/Expensify/react-native-onyx.git#7ab6aed5ce9158f7017ee1c9fd8b5d725d57db73", - "from": "git+https://github.com/Expensify/react-native-onyx.git#7ab6aed5ce9158f7017ee1c9fd8b5d725d57db73", + "version": "git+https://github.com/Expensify/react-native-onyx.git#4cc46d1ad70312d2e10adf7cdd7065ab9b472113", + "from": "git+https://github.com/Expensify/react-native-onyx.git#4cc46d1ad70312d2e10adf7cdd7065ab9b472113", "requires": { "ascii-table": "0.0.9", - "expensify-common": "git+https://github.com/Expensify/expensify-common.git#2e5cff552cf132da90a3fb9756e6b4fb6ae7b40c", - "lodash": "4.17.21", + "lodash": "^4.17.21", "underscore": "^1.13.1" - }, - "dependencies": { - "expensify-common": { - "version": "git+https://github.com/Expensify/expensify-common.git#2e5cff552cf132da90a3fb9756e6b4fb6ae7b40c", - "from": "git+https://github.com/Expensify/expensify-common.git#2e5cff552cf132da90a3fb9756e6b4fb6ae7b40c", - "requires": { - "classnames": "2.2.5", - "clipboard": "2.0.4", - "html-entities": "^1.3.1", - "jquery": "3.3.1", - "lodash": "4.17.21", - "prop-types": "15.7.2", - "react": "16.12.0", - "react-dom": "16.12.0", - "semver": "^7.3.4", - "simply-deferred": "git+https://github.com/Expensify/simply-deferred.git#77a08a95754660c7bd6e0b6979fdf84e8e831bf5", - "underscore": "1.9.1" - }, - "dependencies": { - "underscore": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", - "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" - } - } - }, - "jquery": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz", - "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==" - }, - "react": { - "version": "16.12.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.12.0.tgz", - "integrity": "sha512-fglqy3k5E+81pA8s+7K0/T3DBCF0ZDOher1elBFzF7O6arXJgzyu/FW+COxFvAWXJoJN9KIZbT2LXlukwphYTA==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" - } - }, - "react-dom": { - "version": "16.12.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.12.0.tgz", - "integrity": "sha512-LMxFfAGrcS3kETtQaCkTKjMiifahaMySFDn71fZUNpPHZQEzmk/GiAeIT8JSOrHB23fnuCOMruL2a8NYlw+8Gw==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.18.0" - } - } } }, "react-native-pdf": { @@ -38422,6 +38371,7 @@ "version": "7.3.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, "requires": { "lru-cache": "^6.0.0" }, @@ -38430,6 +38380,7 @@ "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": { "yallist": "^4.0.0" } @@ -38437,7 +38388,8 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } } }, @@ -39681,6 +39633,203 @@ } } }, + "string.prototype.replaceall": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.replaceall/-/string.prototype.replaceall-1.0.6.tgz", + "integrity": "sha512-OA8VDhE7ssNFlyoDXUHxw6V5cjgPrtosyJKqJX5i1P5tV9eUynsbhx1yz0g+Ye4fjFwAxhKLxt8GSRx2Aqc+Sw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.2", + "is-regex": "^1.1.4" + }, + "dependencies": { + "es-abstract": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", + "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "regexp.prototype.flags": "^1.4.3", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "requires": { + "call-bind": "^1.0.2" + } + }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" + }, + "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" + } + }, + "regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + } + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "dependencies": { + "define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + } + } + }, + "string.prototype.trimstart": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "dependencies": { + "define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + } + } + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + } + } + }, "string.prototype.trim": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.5.tgz", diff --git a/package.json b/package.json index 4096beb17bfb..073e8d811ed9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.1.60-3", + "version": "1.1.70-3", "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.", @@ -55,14 +55,14 @@ "@react-native-masked-view/masked-view": "^0.2.4", "@react-native-picker/picker": "^2.3.1", "@react-navigation/compat": "^5.3.20", - "@react-navigation/drawer": "6.1.8", + "@react-navigation/drawer": "6.3.0", "@react-navigation/native": "6.0.8", "@react-navigation/stack": "6.0.11", "babel-plugin-transform-remove-console": "^6.9.4", "dom-serializer": "^0.2.2", "domhandler": "^4.3.0", "dotenv": "^8.2.0", - "expensify-common": "git+https://github.com/Expensify/expensify-common.git#427295da130a4eacc184d38693664280d020dffd", + "expensify-common": "git+https://github.com/Expensify/expensify-common.git#e989d858aa2ab8191284ae106acf9cd323ab879d", "fbjs": "^3.0.2", "file-loader": "^6.0.0", "html-entities": "^1.3.1", @@ -91,7 +91,7 @@ "react-native-image-size": "^1.1.3", "react-native-keyboard-spacer": "^0.4.1", "react-native-modal": "^13.0.0", - "react-native-onyx": "git+https://github.com/Expensify/react-native-onyx.git#7ab6aed5ce9158f7017ee1c9fd8b5d725d57db73", + "react-native-onyx": "git+https://github.com/Expensify/react-native-onyx.git#4cc46d1ad70312d2e10adf7cdd7065ab9b472113", "react-native-pdf": "^6.2.2", "react-native-performance": "^2.0.0", "react-native-permissions": "^3.0.1", diff --git a/src/CONST.js b/src/CONST.js index e3a88d48cd7e..c0e26e78fca7 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -387,6 +387,8 @@ const CONST = { EMOJI_FREQUENT_ROW_COUNT: 3, + EMOJI_INVISIBLE_CODEPOINT: 'fe0f', + TOOLTIP_MAX_LINES: 3, LOGIN_TYPE: { diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index 39d1a8f9dd09..73fb51e1a929 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -118,6 +118,7 @@ class AddPlaidBankAccount extends React.Component { this.clearError = inputKey => ReimbursementAccountUtils.clearError(this.props, inputKey); this.getErrorText = inputKey => ReimbursementAccountUtils.getErrorText(this.props, { password: 'passwordForm.error.incorrectPassword', + selectedBank: 'bankAccount.error.noBankAccountSelected', }, inputKey); } @@ -253,7 +254,7 @@ class AddPlaidBankAccount extends React.Component { label: this.props.translate('bankAccount.chooseAnAccount'), } : {}} value={this.state.selectedIndex} - hasError={this.getErrors().selectedBank} + errorText={this.getErrorText('selectedBank')} /> {!_.isUndefined(this.state.selectedIndex) && this.props.isPasswordRequired && ( diff --git a/src/components/AddressSearch.js b/src/components/AddressSearch.js index 9458a85361f4..7ad5474ae06b 100644 --- a/src/components/AddressSearch.js +++ b/src/components/AddressSearch.js @@ -106,7 +106,11 @@ const AddressSearch = (props) => { if (_.size(values) === 0) { return; } - props.onInputChange(values); + if (props.inputID) { + _.each(values, (value, key) => props.onInputChange(value, key)); + } else { + props.onInputChange(values); + } }; return ( @@ -161,7 +165,7 @@ const AddressSearch = (props) => { label: props.label, containerStyles: props.containerStyles, errorText: props.errorText, - hint: props.hint, + hint: displayListViewBorder ? undefined : props.hint, value: props.value, defaultValue: props.defaultValue, inputID: props.inputID, diff --git a/src/components/ArchivedReportFooter.js b/src/components/ArchivedReportFooter.js index bcb204c98369..af5be5de4d1a 100644 --- a/src/components/ArchivedReportFooter.js +++ b/src/components/ArchivedReportFooter.js @@ -1,37 +1,24 @@ -import lodashGet from 'lodash/get'; import React from 'react'; import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; -import CONST from '../CONST'; import Banner from './Banner'; import withLocalize, {withLocalizePropTypes} from './withLocalize'; import compose from '../libs/compose'; import personalDetailsPropType from '../pages/personalDetailsPropType'; import ONYXKEYS from '../ONYXKEYS'; import * as ReportUtils from '../libs/ReportUtils'; +import reportActionPropTypes from '../pages/home/report/reportActionPropTypes'; const propTypes = { - /** The reason this report was archived */ - reportClosedAction: PropTypes.shape({ - /** Message attached to the report closed action */ - originalMessage: PropTypes.shape({ - /** The reason the report was closed */ - reason: PropTypes.string.isRequired, - - /** (For accountMerged reason only), the email of the previous owner of this report. */ - oldLogin: PropTypes.string, - - /** (For accountMerged reason only), the email of the account the previous owner was merged into */ - newLogin: PropTypes.string, - }).isRequired, - }), - /** The archived report */ report: PropTypes.shape({ - /** The policy this report is attached to */ - policyID: PropTypes.string, + /** The email of the owner of the report */ + ownerEmail: PropTypes.string, }).isRequired, + /** Array of report actions for this report */ + reportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)).isRequired, + /** Personal details of all users */ personalDetails: PropTypes.objectOf(personalDetailsPropType).isRequired, @@ -44,40 +31,14 @@ const propTypes = { ...withLocalizePropTypes, }; -const defaultProps = { - reportClosedAction: { - originalMessage: { - reason: CONST.REPORT.ARCHIVE_REASON.DEFAULT, - }, - }, -}; - const ArchivedReportFooter = (props) => { - const archiveReason = lodashGet(props.reportClosedAction, 'originalMessage.reason', CONST.REPORT.ARCHIVE_REASON.DEFAULT); - let displayName = lodashGet(props.personalDetails, `${props.report.ownerEmail}.displayName`, props.report.ownerEmail); - - let oldDisplayName; - if (archiveReason === CONST.REPORT.ARCHIVE_REASON.ACCOUNT_MERGED) { - const newLogin = props.reportClosedAction.originalMessage.newLogin; - const oldLogin = props.reportClosedAction.originalMessage.oldLogin; - displayName = lodashGet(props.personalDetails, `${newLogin}.displayName`, newLogin); - oldDisplayName = lodashGet(props.personalDetails, `${oldLogin}.displayName`, oldLogin); - } - + const archivedText = ReportUtils.getArchivedText(props.report, props.reportActions, props.personalDetails, props.policies); return ( - ${displayName}`, - oldDisplayName: `${oldDisplayName}`, - policyName: `${ReportUtils.getPolicyName(props.report, props.policies)}`, - })} - shouldRenderHTML={archiveReason !== CONST.REPORT.ARCHIVE_REASON.DEFAULT} - /> + ); }; ArchivedReportFooter.propTypes = propTypes; -ArchivedReportFooter.defaultProps = defaultProps; ArchivedReportFooter.displayName = 'ArchivedReportFooter'; export default compose( diff --git a/src/components/Avatar.js b/src/components/Avatar.js index 71ecd130ed9d..ff51d2c427b8 100644 --- a/src/components/Avatar.js +++ b/src/components/Avatar.js @@ -7,6 +7,7 @@ import Icon from './Icon'; import themeColors from '../styles/themes/default'; import CONST from '../CONST'; import * as StyleUtils from '../styles/StyleUtils'; +import * as Expensicons from './Icon/Expensicons'; const propTypes = { /** Source for the avatar. Can be a URL or an icon. */ @@ -23,6 +24,9 @@ const propTypes = { /** The fill color for the icon. Can be hex, rgb, rgba, or valid react-native named color such as 'red' or 'blue' */ fill: PropTypes.string, + + /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */ + fallbackIcon: PropTypes.func, }; const defaultProps = { @@ -31,9 +35,17 @@ const defaultProps = { containerStyles: [], size: CONST.AVATAR_SIZE.DEFAULT, fill: themeColors.icon, + fallbackIcon: Expensicons.FallbackAvatar, }; class Avatar extends PureComponent { + constructor(props) { + super(props); + this.state = { + imageError: false, + }; + } + render() { if (!this.props.source) { return null; @@ -45,13 +57,21 @@ class Avatar extends PureComponent { ]; const iconSize = StyleUtils.getAvatarSize(this.props.size); + return ( - { - _.isFunction(this.props.source) - ? - : - } + {_.isFunction(this.props.source) || this.state.imageError + ? ( + + ) + : ( + this.setState({imageError: true})} /> + )} ); } diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index 02644c75fec2..2e0d4f3c8792 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -53,6 +53,9 @@ const propTypes = { /** Size of Indicator */ size: PropTypes.oneOf([CONST.AVATAR_SIZE.LARGE, CONST.AVATAR_SIZE.DEFAULT]), + /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */ + fallbackIcon: PropTypes.func, + ...withLocalizePropTypes, }; @@ -65,6 +68,7 @@ const defaultProps = { isUsingDefaultAvatar: false, isUploading: false, size: CONST.AVATAR_SIZE.DEFAULT, + fallbackIcon: Expensicons.FallbackAvatar, }; class AvatarWithImagePicker extends React.Component { @@ -181,6 +185,8 @@ class AvatarWithImagePicker extends React.Component { containerStyles={styles.avatarLarge} imageStyles={[styles.avatarLarge, styles.alignSelfCenter]} source={this.props.avatarURL} + fallbackIcon={this.props.fallbackIcon} + size={this.props.size} /> ) : ( diff --git a/src/components/AvatarWithIndicator.js b/src/components/AvatarWithIndicator.js index 0db3ff1253ef..aa37769156e3 100644 --- a/src/components/AvatarWithIndicator.js +++ b/src/components/AvatarWithIndicator.js @@ -101,6 +101,7 @@ class AvatarWithIndicator extends PureComponent { diff --git a/src/components/Banner.js b/src/components/Banner.js index 9c67174f0386..a4ea17eec2c8 100644 --- a/src/components/Banner.js +++ b/src/components/Banner.js @@ -5,21 +5,13 @@ import Hoverable from './Hoverable'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; import RenderHTML from './RenderHTML'; -import Text from './Text'; import styles from '../styles/styles'; import * as StyleUtils from '../styles/StyleUtils'; import getButtonState from '../libs/getButtonState'; const propTypes = { - /** Text to display in the banner. */ - text: PropTypes.string.isRequired, - - /** Should this component render the text as HTML? */ - shouldRenderHTML: PropTypes.bool, -}; - -const defaultProps = { - shouldRenderHTML: false, + /** HTML to display in the banner. */ + html: PropTypes.string.isRequired, }; const Banner = props => ( @@ -31,6 +23,7 @@ const Banner = props => ( styles.p5, styles.borderRadiusNormal, isHovered ? styles.activeComponentBG : styles.hoveredComponentBG, + styles.breakAll, ]} > @@ -39,18 +32,13 @@ const Banner = props => ( fill={StyleUtils.getIconFillColor(getButtonState(isHovered))} /> - { - props.shouldRenderHTML - ? - : {props.text} - } + )} ); Banner.propTypes = propTypes; -Banner.defaultProps = defaultProps; Banner.displayName = 'Banner'; export default memo(Banner); diff --git a/src/components/Button.js b/src/components/Button.js index 85254d4c1e75..4fcc046e0f7c 100644 --- a/src/components/Button.js +++ b/src/components/Button.js @@ -173,14 +173,11 @@ class Button extends Component { return ; } - if (this.props.isLoading) { - return ; - } - const textComponent = ( @@ -273,6 +270,12 @@ class Button extends Component { ]} > {this.renderContent()} + {this.props.isLoading && ( + + )} )} diff --git a/src/components/ConfirmContent.js b/src/components/ConfirmContent.js index 78e01b756a61..164a21ce9a8e 100644 --- a/src/components/ConfirmContent.js +++ b/src/components/ConfirmContent.js @@ -76,7 +76,7 @@ const ConfirmContent = props => ( /> {props.shouldShowCancelButton && (