diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 66fdf3e56e2..3e004a024dc 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -33,7 +33,7 @@ jobs: with: path-to-signatures: '${{ github.repository }}/cla.json' path-to-document: 'https://github.com/${{ github.repository }}/blob/main/CLA.md' - branch: 'master' + branch: 'main' remote-organization-name: 'Expensify' remote-repository-name: 'CLA' lock-pullrequest-aftermerge: false diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 519deb5b1aa..55d4bc3ce22 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -70,6 +70,7 @@ In this scenario, it’s possible that you found a bug or enhancement that we ha #### Propose a solution for the job 4. After you reproduce the issue, make a proposal for your solution and post it as a comment in the corresponding GitHub issue (linked in the Upwork job). Your solution proposal should include a brief technical explanation of the changes you will make. - Note: If you post a proposed solution in an issue that has not been tagged with the `External` label, Expensify has the right to use your proposal to fix said issue, without providing compensation for your solution. + - Note: Before submitting a proposal on an issue, be sure to read any other existing proposals. Any new proposal should be substantively different from existing proposals. 5. Pause at this step until Expensify provides feedback on your proposal (do not begin coding or creating a pull request yet). 6. If your solution proposal is accepted, Expensify will hire you on Upwork and assign the GitHub issue to you. diff --git a/README.md b/README.md index 48a9fb9828a..8a0f4725d14 100644 --- a/README.md +++ b/README.md @@ -55,10 +55,37 @@ You can use any IDE or code editing tool for developing on any platform. Use you ## Troubleshooting 1. If you are having issues with **_Getting Started_**, please reference [React Native's Documentation](https://reactnative.dev/docs/environment-setup) -2. If you are running into issues communicating with the API please verify your `.env` file is [set up correctly](#getting-started) for the platform you are trying to run. +2. If you are running into CORS errors like (in the browser dev console) + ```sh + Access to fetch at 'https://www.expensify.com/api?command=GetAccountStatus' from origin 'http://localhost:8080' has been blocked by CORS policy + ``` + You probably have a misconfigured `.env` file - remove it (`rm .env`) and try again **Note:** Expensify engineers that will be testing with the API in your local dev environment please refer to [these additional instructions](https://stackoverflow.com/c/expensify/questions/7699/7700). +## Environment variables +Creating an `.env` file is not necessary. We advise external contributors against it. It can lead to errors when +variables referenced here get updated since your local `.env` file is ignored. + +- `EXPENSIFY_URL_CASH` - The root URL used for the website +- `EXPENSIFY_URL_SECURE` - The URL used to hit the Expensify secure API +- `EXPENSIFY_URL_COM` - The URL used to hit the Expensify API +- `EXPENSIFY_PARTNER_NAME` - Constant used for the app when authenticating. +- `EXPENSIFY_PARTNER_PASSWORD` - Another constant used for the app when authenticating. (This is OK to be public) +- `PUSHER_APP_KEY` - Key used to authenticate with Pusher.com +- `SECURE_NGROK_URL` - Secure URL used for `ngrok` when testing +- `NGROK_URL` - URL used for `ngrok` when testing +- `USE_NGROK` - Flag to turn `ngrok` testing on or off +- `USE_WDYR` - Flag to turn [`Why Did You Render`](https://github.com/welldone-software/why-did-you-render) testing on or off +- `USE_WEB_PROXY`⚠️- Used in web/desktop development, it starts a server along the local development server to proxy + requests to the backend. External contributors should set this to `true` otherwise they'll have CORS errors. + If you don't want to start the proxy server set this explicitly to `false` +- `CAPTURE_METRICS` (optional) - Set this to `true` to capture performance metrics and see them in Flipper + see [PERFORMANCE.md](PERFORMANCE.md#performance-metrics-opt-in-on-local-release-builds) for more information +- `ONYX_METRICS` (optional) - Set this to `true` to capture even more performance metrics and see them in Flipper + see [React-Native-Onyx#benchmarks](https://github.com/Expensify/react-native-onyx#benchmarks) for more information + + ---- # Running the tests diff --git a/android/app/build.gradle b/android/app/build.gradle index 8a1c353d6b3..574b44a8b7f 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -150,8 +150,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001010001 - versionName "1.1.0-1" + versionCode 1001010800 + versionName "1.1.8-0" } splits { abi { diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml index c612507bd64..187c1ee179b 100644 --- a/android/app/src/main/res/values/colors.xml +++ b/android/app/src/main/res/values/colors.xml @@ -1,3 +1,6 @@ #FFFFFF + #0185ff + #0b1b34 + #7D8B8F diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index cf62d64ac8a..5b0ebadd121 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -3,14 +3,13 @@ - diff --git a/assets/images/bill.svg b/assets/images/bill.svg new file mode 100644 index 00000000000..b27e6776b0f --- /dev/null +++ b/assets/images/bill.svg @@ -0,0 +1,11 @@ + + + + + + diff --git a/assets/images/briefcase.svg b/assets/images/briefcase.svg new file mode 100644 index 00000000000..f73854bbb36 --- /dev/null +++ b/assets/images/briefcase.svg @@ -0,0 +1,8 @@ + + + + + + + diff --git a/assets/images/circle-hourglass.svg b/assets/images/circle-hourglass.svg new file mode 100644 index 00000000000..1bba8b47410 --- /dev/null +++ b/assets/images/circle-hourglass.svg @@ -0,0 +1,10 @@ + + + + + + + diff --git a/assets/images/concierge.svg b/assets/images/concierge.svg new file mode 100644 index 00000000000..4b22f626a0e --- /dev/null +++ b/assets/images/concierge.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/assets/images/confetti-pop.gif b/assets/images/confetti-pop.gif new file mode 100644 index 00000000000..a4137b6e9dd Binary files /dev/null and b/assets/images/confetti-pop.gif differ diff --git a/assets/images/invoice.svg b/assets/images/invoice.svg new file mode 100644 index 00000000000..91391b0f9bc --- /dev/null +++ b/assets/images/invoice.svg @@ -0,0 +1,11 @@ + + + + + + diff --git a/assets/images/lets-chat.svg b/assets/images/lets-chat.svg new file mode 100644 index 00000000000..b083891413a --- /dev/null +++ b/assets/images/lets-chat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/luggage.svg b/assets/images/luggage.svg new file mode 100644 index 00000000000..b7f8dc7fe93 --- /dev/null +++ b/assets/images/luggage.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/assets/images/paycheck.svg b/assets/images/paycheck.svg index 228faf7cee7..f81a5a9a86a 100644 --- a/assets/images/paycheck.svg +++ b/assets/images/paycheck.svg @@ -1,20 +1,17 @@ - + - - - - - + + + diff --git a/assets/images/paypal.svg b/assets/images/paypal.svg index 752dac9dac9..370a55b4128 100644 --- a/assets/images/paypal.svg +++ b/assets/images/paypal.svg @@ -2,12 +2,8 @@ - - - - + + diff --git a/assets/images/product-illustrations/bank-arrow--pink.svg b/assets/images/product-illustrations/bank-arrow--pink.svg new file mode 100644 index 00000000000..c561bfd2790 --- /dev/null +++ b/assets/images/product-illustrations/bank-arrow--pink.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/product-illustrations/bank-mouse--green.svg b/assets/images/product-illustrations/bank-mouse--green.svg new file mode 100644 index 00000000000..99dfd1718c1 --- /dev/null +++ b/assets/images/product-illustrations/bank-mouse--green.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/product-illustrations/bank-user--green.svg b/assets/images/product-illustrations/bank-user--green.svg new file mode 100644 index 00000000000..676d05c3bc0 --- /dev/null +++ b/assets/images/product-illustrations/bank-user--green.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/product-illustrations/concierge--blue.svg b/assets/images/product-illustrations/concierge--blue.svg new file mode 100644 index 00000000000..d1d3fede1f6 --- /dev/null +++ b/assets/images/product-illustrations/concierge--blue.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + diff --git a/assets/images/product-illustrations/credit-cards--blue.svg b/assets/images/product-illustrations/credit-cards--blue.svg new file mode 100644 index 00000000000..008dbd20be3 --- /dev/null +++ b/assets/images/product-illustrations/credit-cards--blue.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + diff --git a/assets/images/product-illustrations/invoice--orange.svg b/assets/images/product-illustrations/invoice--orange.svg new file mode 100644 index 00000000000..aebd5066066 --- /dev/null +++ b/assets/images/product-illustrations/invoice--orange.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + diff --git a/assets/images/product-illustrations/jewel-box--blue.svg b/assets/images/product-illustrations/jewel-box--blue.svg new file mode 100644 index 00000000000..b9d6a084bcb --- /dev/null +++ b/assets/images/product-illustrations/jewel-box--blue.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/product-illustrations/jewel-box--green.svg b/assets/images/product-illustrations/jewel-box--green.svg new file mode 100644 index 00000000000..ba1cade3dcc --- /dev/null +++ b/assets/images/product-illustrations/jewel-box--green.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/product-illustrations/jewel-box--pink.svg b/assets/images/product-illustrations/jewel-box--pink.svg new file mode 100644 index 00000000000..dd58151c913 --- /dev/null +++ b/assets/images/product-illustrations/jewel-box--pink.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/product-illustrations/jewel-box--yellow.svg b/assets/images/product-illustrations/jewel-box--yellow.svg new file mode 100644 index 00000000000..858d5b66688 --- /dev/null +++ b/assets/images/product-illustrations/jewel-box--yellow.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/product-illustrations/money-envelope--blue.svg b/assets/images/product-illustrations/money-envelope--blue.svg new file mode 100644 index 00000000000..199489af882 --- /dev/null +++ b/assets/images/product-illustrations/money-envelope--blue.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + diff --git a/assets/images/product-illustrations/money-mouse--pink.svg b/assets/images/product-illustrations/money-mouse--pink.svg new file mode 100644 index 00000000000..72c21fc4675 --- /dev/null +++ b/assets/images/product-illustrations/money-mouse--pink.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + diff --git a/assets/images/product-illustrations/receipt--yellow.svg b/assets/images/product-illustrations/receipt--yellow.svg new file mode 100644 index 00000000000..f40f3e0a5aa --- /dev/null +++ b/assets/images/product-illustrations/receipt--yellow.svg @@ -0,0 +1,20 @@ + + + + + + + + + + diff --git a/assets/images/product-illustrations/rocket--orange.svg b/assets/images/product-illustrations/rocket--orange.svg new file mode 100644 index 00000000000..a3bb9a67fb7 --- /dev/null +++ b/assets/images/product-illustrations/rocket--orange.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/product-illustrations/tada--yellow.svg b/assets/images/product-illustrations/tada--yellow.svg new file mode 100644 index 00000000000..037baef7def --- /dev/null +++ b/assets/images/product-illustrations/tada--yellow.svg @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/receipt-search.svg b/assets/images/receipt-search.svg new file mode 100644 index 00000000000..6272cfea321 --- /dev/null +++ b/assets/images/receipt-search.svg @@ -0,0 +1,15 @@ + + + + + + + diff --git a/assets/images/request-call.svg b/assets/images/request-call.svg new file mode 100644 index 00000000000..ed4b8fd3f53 --- /dev/null +++ b/assets/images/request-call.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + diff --git a/assets/images/users.svg b/assets/images/users.svg index e74a77d7f4c..948998d2c35 100644 --- a/assets/images/users.svg +++ b/assets/images/users.svg @@ -13,12 +13,13 @@ - - - - - + + + + diff --git a/colors.json b/colors.json new file mode 100644 index 00000000000..3bd147e531d --- /dev/null +++ b/colors.json @@ -0,0 +1,6 @@ +{ + "onfidoPrimaryColor": "#03d47c", + "onfidoPrimaryButtonTextColor": "#ffffff", + "onfidoPrimaryButtonColorPressed": "#03c775", + "onfidoAndroidStatusBarColor": "#FAFAFA" +} diff --git a/config/webpack/webpack.common.js b/config/webpack/webpack.common.js index 97f9eb94826..45a2e6b73be 100644 --- a/config/webpack/webpack.common.js +++ b/config/webpack/webpack.common.js @@ -21,6 +21,7 @@ const includeModules = [ 'react-native-onyx', 'react-native-gesture-handler', 'react-native-flipper', + 'react-native-google-places-autocomplete', ].join('|'); const webpackConfig = { diff --git a/fastlane/Fastfile b/fastlane/Fastfile index fd43e45ccbc..e3157fbd214 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -108,27 +108,38 @@ platform :ios do build_app( workspace: "./ios/NewExpensify.xcworkspace", - scheme: "NewExpensify" - ) - - upload_to_testflight( - api_key_path: "./ios/ios-fastlane-json-key.json", - distribute_external: true, - notify_external_testers: true, - changelog: "Thank you for beta testing New Expensify, this version includes bug fixes and improvements.", - groups: ["Beta"], - demo_account_required: true, - beta_app_review_info: { - contact_email: ENV["APPLE_CONTACT_EMAIL"], - contact_first_name: "Andrew", - contact_last_name: "Gable", - contact_phone: ENV["APPLE_CONTACT_PHONE"], - demo_account_name: ENV["APPLE_DEMO_EMAIL"], - demo_account_password: ENV["APPLE_DEMO_PASSWORD"], - notes: "Use the account provided. Thank you for the review." + scheme: "NewExpensify", + export_options: { + manageAppVersionAndBuildNumber: false } ) + begin + upload_to_testflight( + api_key_path: "./ios/ios-fastlane-json-key.json", + distribute_external: true, + notify_external_testers: true, + changelog: "Thank you for beta testing New Expensify, this version includes bug fixes and improvements.", + groups: ["Beta"], + demo_account_required: true, + beta_app_review_info: { + contact_email: ENV["APPLE_CONTACT_EMAIL"], + contact_first_name: "Andrew", + contact_last_name: "Gable", + contact_phone: ENV["APPLE_CONTACT_PHONE"], + demo_account_name: ENV["APPLE_DEMO_EMAIL"], + demo_account_password: ENV["APPLE_DEMO_PASSWORD"], + notes: "Use the account provided. Thank you for the review." + } + ) + rescue Exception => e + if e.message.include? "Another build is in review" + UI.important("Another build is already in external beta review. Skipping external beta review submission") + else + raise + end + end + upload_symbols_to_crashlytics( dsym_path: lane_context[SharedValues::DSYM_OUTPUT_PATH], gsp_path: "./ios/GoogleService-Info.plist", @@ -142,7 +153,7 @@ platform :ios do api_key_path: "./ios/ios-fastlane-json-key.json", # Skip HTMl report verification - force: true, + force: true, # VERSION will be set to the full build_number e.g. '1.0.92.0' build_number: ENV["VERSION"], diff --git a/ios/NewExpensify.xcodeproj/project.pbxproj b/ios/NewExpensify.xcodeproj/project.pbxproj index 0102b9f060b..b5c08101945 100644 --- a/ios/NewExpensify.xcodeproj/project.pbxproj +++ b/ios/NewExpensify.xcodeproj/project.pbxproj @@ -33,6 +33,7 @@ DB77016704074197AB6633BB /* GTAmericaExpMono-RgIt.otf in Resources */ = {isa = PBXBuildFile; fileRef = 5150E5D0D7F74DBA8D7C1914 /* GTAmericaExpMono-RgIt.otf */; }; E9DF872D2525201700607FDC /* AirshipConfig.plist in Resources */ = {isa = PBXBuildFile; fileRef = E9DF872C2525201700607FDC /* AirshipConfig.plist */; }; ED814D34526B415CAFA0451E /* GTAmericaExpMono-BdIt.otf in Resources */ = {isa = PBXBuildFile; fileRef = 3981452A2C7340EBBA2B9BD1 /* GTAmericaExpMono-BdIt.otf */; }; + F0C450EA2705020500FD2970 /* colors.json in Resources */ = {isa = PBXBuildFile; fileRef = F0C450E92705020500FD2970 /* colors.json */; }; F2C9290F276DB05EEF04D160 /* libPods-NewExpensify-NewExpensifyTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 820334EEB8DDED5217A15684 /* libPods-NewExpensify-NewExpensifyTests.a */; }; /* End PBXBuildFile section */ @@ -86,6 +87,7 @@ EB3C4841B1DB1490EA09A324 /* Pods-NewExpensify.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.release.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.release.xcconfig"; sourceTree = ""; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; ED2971642150620600B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/JavaScriptCore.framework; sourceTree = DEVELOPER_DIR; }; + F0C450E92705020500FD2970 /* colors.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = colors.json; path = ../colors.json; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -165,6 +167,7 @@ 83CBB9F61A601CBA00E9B192 = { isa = PBXGroup; children = ( + F0C450E92705020500FD2970 /* colors.json */, 7041848326A8E40900E09F4D /* RCTStartupTimer.h */, 7041848426A8E47D00E09F4D /* RCTStartupTimer.m */, 18D050DF262400AF000D658B /* BridgingFile.swift */, @@ -328,6 +331,7 @@ 1E76D5222522316A005A268F /* GTAmericaExp-Light.otf in Resources */, 1E76D5232522316A005A268F /* GTAmericaExp-Medium.otf in Resources */, 1E76D5242522316A005A268F /* GTAmericaExp-Regular.otf in Resources */, + F0C450EA2705020500FD2970 /* colors.json in Resources */, 1E76D5252522316A005A268F /* GTAmericaExp-Thin.otf in Resources */, 425866037F4C482AAB46CB8B /* GTAmericaExp-BdIt.otf in Resources */, 6856B78873B64C44A92E51DB /* GTAmericaExp-MdIt.otf in Resources */, diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 7afb072bd77..9e53fa08b5f 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.1.0 + 1.1.8 CFBundleSignature ???? CFBundleURLTypes @@ -31,7 +31,7 @@ CFBundleVersion - 1.1.0.1 + 1.1.8.0 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 3532a7c43a1..4608af77a07 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.1.0 + 1.1.8 CFBundleSignature ???? CFBundleVersion - 1.1.0.1 + 1.1.8.0 diff --git a/ios/Podfile.lock b/ios/Podfile.lock index c6f92137584..e78bb9605b5 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -509,6 +509,8 @@ PODS: - React-Core - RNCPicker (1.9.11): - React-Core + - RNDateTimePicker (3.5.2): + - React-Core - RNFBAnalytics (12.3.0): - Firebase/Analytics (= 8.4.0) - React-Core @@ -666,6 +668,7 @@ DEPENDENCIES: - "RNCClipboard (from `../node_modules/@react-native-community/clipboard`)" - "RNCMaskedView (from `../node_modules/@react-native-masked-view/masked-view`)" - "RNCPicker (from `../node_modules/@react-native-picker/picker`)" + - "RNDateTimePicker (from `../node_modules/@react-native-community/datetimepicker`)" - "RNFBAnalytics (from `../node_modules/@react-native-firebase/analytics`)" - "RNFBApp (from `../node_modules/@react-native-firebase/app`)" - "RNFBCrashlytics (from `../node_modules/@react-native-firebase/crashlytics`)" @@ -826,6 +829,8 @@ EXTERNAL SOURCES: :path: "../node_modules/@react-native-masked-view/masked-view" RNCPicker: :path: "../node_modules/@react-native-picker/picker" + RNDateTimePicker: + :path: "../node_modules/@react-native-community/datetimepicker" RNFBAnalytics: :path: "../node_modules/@react-native-firebase/analytics" RNFBApp: @@ -956,6 +961,7 @@ SPEC CHECKSUMS: RNCClipboard: 5e299c6df8e0c98f3d7416b86ae563d3a9f768a3 RNCMaskedView: 138134c4d8a9421b4f2bf39055a79aa05c2d47b1 RNCPicker: 6780c753e9e674065db90d9c965920516402579d + RNDateTimePicker: c9911be59b1f8670b9f244b85af3a7c295e175ed RNFBAnalytics: 8ba84c2d31c64374d054c8621b998f25145ffddc RNFBApp: 64c90ab78b6010ed5c3ade026dfe5ff6442c21fd RNFBCrashlytics: 1de18b8cc36d9bcf86407c4a354399228cc84a61 diff --git a/package-lock.json b/package-lock.json index e1521dc08c0..0d51c2a927d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.1.0-1", + "version": "1.1.8-0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -8190,6 +8190,14 @@ "resolved": "https://registry.npmjs.org/@react-native-community/clipboard/-/clipboard-1.5.1.tgz", "integrity": "sha512-AHAmrkLEH5UtPaDiRqoULERHh3oNv7Dgs0bTC0hO5Z2GdNokAMPT5w8ci8aMcRemcwbtdHjxChgtjbeA38GBdA==" }, + "@react-native-community/datetimepicker": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@react-native-community/datetimepicker/-/datetimepicker-3.5.2.tgz", + "integrity": "sha512-TWRuAtr/DnrEcRewqvXMLea2oB+YF+SbtuYLHguALLxNJQLl/RFB7aTNZeF+OoH75zKFqtXECXV1/uxQUpA+sg==", + "requires": { + "invariant": "^2.2.4" + } + }, "@react-native-community/eslint-config": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@react-native-community/eslint-config/-/eslint-config-2.0.0.tgz", @@ -8298,13 +8306,13 @@ "integrity": "sha512-Gh5O6Ng3z0/qSBhuuWuPSi24+RrkgNy5hzvEke8qjS+kbrPfSFLD6aq9B2Fdfndp/dAyfxgTi6aULUsnv847Hw==" }, "@react-navigation/core": { - "version": "6.0.0-next.13", - "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-6.0.0-next.13.tgz", - "integrity": "sha512-4UrxUfpvV5cZOEuuLhJiU5CRlyUUV5/v5ed4GsBHB/SCSu6QpINyI2zFn2FKcHfbVayzry0FEUIcvIduhYSTgg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-6.0.1.tgz", + "integrity": "sha512-mVdvBDYdz8uzLQHokmVdX/xC4rS7NIkD1FN/yaGdovVzYApAhM+UGd3w1zskjyCSyXaVHHOwV59ZGVew+84xfQ==", "requires": { - "@react-navigation/routers": "^6.0.0-next.4", + "@react-navigation/routers": "^6.0.1", "escape-string-regexp": "^4.0.0", - "nanoid": "^3.1.22", + "nanoid": "^3.1.23", "query-string": "^7.0.0", "react-is": "^16.13.0" }, @@ -8317,35 +8325,28 @@ } }, "@react-navigation/drawer": { - "version": "6.0.0-next.17", - "resolved": "https://registry.npmjs.org/@react-navigation/drawer/-/drawer-6.0.0-next.17.tgz", - "integrity": "sha512-iEkusYpdLnt0KQBU1iUhIk+Bo8iRNKb6JuD1gdJ4brWRohECeY9LRdpPlG3GN/yMXYdHDXZiRjnUBjjyT9ywow==", + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@react-navigation/drawer/-/drawer-6.1.4.tgz", + "integrity": "sha512-lmWV/Hxd60LFLsHESOXkDXZmzqpXHoRhBdaxk5FvQHXSBYm+ZB0bP9vq5nTCzUby513wTyM381GBujdgYWCGRA==", "requires": { - "@react-navigation/elements": "^1.0.0-next.17", + "@react-navigation/elements": "^1.1.0", "color": "^3.1.3", "warn-once": "^0.1.0" - }, - "dependencies": { - "@react-navigation/elements": { - "version": "1.0.0-next.17", - "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.0.0-next.17.tgz", - "integrity": "sha512-7Uc99uMfECTH/giKWQjKq/J3kHnML6fniOoD4LTkoqgCxpWJ9WPWNDmft/a7Kijz6uTkYiFnAgH+yXIfm7gAgg==" - } } }, "@react-navigation/elements": { - "version": "1.0.0-next.17", - "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.0.0-next.17.tgz", - "integrity": "sha512-7Uc99uMfECTH/giKWQjKq/J3kHnML6fniOoD4LTkoqgCxpWJ9WPWNDmft/a7Kijz6uTkYiFnAgH+yXIfm7gAgg==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.1.0.tgz", + "integrity": "sha512-jZncciZPGuoP6B6f+Wpf6MYSSYy86B2HJDbFTCtT5xZV0w6V9GgCeqvSTOEAxifZrmKl8uDxsr0GrIxgQE8NxA==" }, "@react-navigation/native": { - "version": "6.0.0-next.13", - "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-6.0.0-next.13.tgz", - "integrity": "sha512-NCGw4ZuD7gK0cAHcBr+VwBEs/EKDk3dmK+CHGJ+BJ4f2NR9uZZPZ38I6A3JlDVXPmx1woXdDb+MgZevJkIjWng==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-6.0.2.tgz", + "integrity": "sha512-HDqEwgvQ4Cu16vz8jQ55lfyNK9CGbECI1wM9cPOcUa+gkOQEDZ/95VFfFjGGflXZs3ybPvGXlMC4ZAyh1CcO6w==", "requires": { - "@react-navigation/core": "^6.0.0-next.13", + "@react-navigation/core": "^6.0.1", "escape-string-regexp": "^4.0.0", - "nanoid": "^3.1.22" + "nanoid": "^3.1.23" }, "dependencies": { "escape-string-regexp": { @@ -8356,21 +8357,20 @@ } }, "@react-navigation/routers": { - "version": "6.0.0-next.4", - "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-6.0.0-next.4.tgz", - "integrity": "sha512-Jpc5FTaz8eL6eGarYttNfE37++QmHYpyIifxtCJVmTi99WWNz8NmT80p4nLKPGU0R0ZdVcq+bPTGN3oqCUa1Iw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-6.0.1.tgz", + "integrity": "sha512-5ctB49rmtTRQuTSBVgqMsEzBUjPP2ByUzBjNivA7jmvk+PDCl4oZsiR8KAm/twhxe215GYThfi2vUWXKAg6EEQ==", "requires": { - "nanoid": "^3.1.22" + "nanoid": "^3.1.23" } }, "@react-navigation/stack": { - "version": "6.0.0-next.25", - "resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-6.0.0-next.25.tgz", - "integrity": "sha512-EBNa1M+U3qyr+AqC7IuXa6aLI+cngCDkrclq7ltaTTNfqVX+yOKXrVq5kOK4VyiFfhf0Hwe8hIl6aDlEpwi3wQ==", + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-6.0.7.tgz", + "integrity": "sha512-hxwhRZbn6zD2rInhItBeHTCPYzmurz+/8/MhtRevBEdLG0+61dik8Y+evg/mu6AsOU0WrDakTsLcHdf/9zkXzw==", "requires": { - "@react-navigation/elements": "^1.0.0-next.17", + "@react-navigation/elements": "^1.1.0", "color": "^3.1.3", - "react-native-iphone-x-helper": "^1.3.0", "warn-once": "^0.1.0" } }, @@ -20585,12 +20585,12 @@ } }, "color": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/color/-/color-3.1.3.tgz", - "integrity": "sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", "requires": { - "color-convert": "^1.9.1", - "color-string": "^1.5.4" + "color-convert": "^1.9.3", + "color-string": "^1.6.0" }, "dependencies": { "color-convert": { @@ -20605,6 +20605,15 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-string": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.6.0.tgz", + "integrity": "sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } } } }, @@ -32503,8 +32512,7 @@ "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", - "dev": true + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" }, "lodash.isequal": { "version": "4.5.0", @@ -34985,9 +34993,9 @@ "optional": true }, "nanoid": { - "version": "3.1.23", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", - "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==" + "version": "3.1.25", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", + "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==" }, "nanomatch": { "version": "1.2.13", @@ -37142,9 +37150,9 @@ "dev": true }, "query-string": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.0.0.tgz", - "integrity": "sha512-Iy7moLybliR5ZgrK/1R3vjrXq03S13Vz4Rbm5Jg3EFq1LUmQppto0qtXz4vqZ386MSRjZgnTSZ9QC+NZOSd/XA==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.0.1.tgz", + "integrity": "sha512-uIw3iRvHnk9to1blJCG3BTc+Ro56CBowJXKmNNAm3RulvPBzWLRqKSiiDk+IplJhsydwtuNMHi8UGQFcCLVfkA==", "requires": { "decode-uri-component": "^0.2.0", "filter-obj": "^1.1.0", @@ -38516,6 +38524,23 @@ } } }, + "react-native-google-places-autocomplete": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/react-native-google-places-autocomplete/-/react-native-google-places-autocomplete-2.4.1.tgz", + "integrity": "sha512-NJrzZ5zsguhTqe0C5tIW9PfxOn2wkWDiGYIBFksHzFOIIURxFPUlO0cJmfOjs5CBIDtMampgNXBdgADExBen5w==", + "requires": { + "lodash.debounce": "^4.0.8", + "prop-types": "^15.7.2", + "qs": "~6.9.1" + }, + "dependencies": { + "qs": { + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==" + } + } + }, "react-native-image-pan-zoom": { "version": "2.1.12", "resolved": "https://registry.npmjs.org/react-native-image-pan-zoom/-/react-native-image-pan-zoom-2.1.12.tgz", @@ -38526,11 +38551,6 @@ "resolved": "https://registry.npmjs.org/react-native-image-picker/-/react-native-image-picker-4.0.3.tgz", "integrity": "sha512-S4a1jE4fAPDzmah/7OVTEAXGz1/wlGyClU+spygmek5rVLERR5BgwnkX3tLP/UvMQbfdPZNUbnH0hEe7su2AZg==" }, - "react-native-iphone-x-helper": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz", - "integrity": "sha512-HOf0jzRnq2/aFUcdCJ9w9JGzN3gdEg0zFE4FyYlp4jtidqU03D5X7ZegGKfT1EWteR0gPBGp9ye5T5FvSWi9Yg==" - }, "react-native-keyboard-spacer": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/react-native-keyboard-spacer/-/react-native-keyboard-spacer-0.4.1.tgz", diff --git a/package.json b/package.json index eed88eee4a8..524e08017ca 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.1.0-1", + "version": "1.1.8-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.", @@ -41,6 +41,7 @@ "@react-native-async-storage/async-storage": "^1.15.5", "@react-native-community/cli": "4.13.1", "@react-native-community/clipboard": "^1.5.1", + "@react-native-community/datetimepicker": "^3.5.2", "@react-native-community/netinfo": "^5.9.10", "@react-native-community/progress-bar-android": "^1.0.4", "@react-native-community/progress-view": "^1.2.3", @@ -51,9 +52,9 @@ "@react-native-masked-view/masked-view": "^0.2.4", "@react-native-picker/picker": "^1.9.11", "@react-navigation/compat": "^5.3.15", - "@react-navigation/drawer": "^6.0.0-next.17", - "@react-navigation/native": "^6.0.0-next.13", - "@react-navigation/stack": "^6.0.0-next.25", + "@react-navigation/drawer": "6.1.4", + "@react-navigation/native": "6.0.2", + "@react-navigation/stack": "6.0.7", "babel-plugin-transform-remove-console": "^6.9.4", "dotenv": "^8.2.0", "electron-context-menu": "^2.3.0", @@ -80,6 +81,7 @@ "react-native-config": "^1.4.0", "react-native-document-picker": "^5.1.0", "react-native-gesture-handler": "1.9.0", + "react-native-google-places-autocomplete": "^2.4.1", "react-native-image-pan-zoom": "^2.1.12", "react-native-image-picker": "^4.0.3", "react-native-keyboard-spacer": "^0.4.1", @@ -208,7 +210,7 @@ "runnerConfig": "tests/e2e/config.json", "configurations": { "ios.sim.debug": { - "binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/expensify.cash.app", + "binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/new expensify.app", "build": "xcodebuild -workspace ios/NewExpensify.xcworkspace -scheme NewExpensify -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build | xcpretty", "type": "ios.simulator", "name": "iPhone 11" diff --git a/src/CONST.js b/src/CONST.js index 206ac649f5e..5b12ef437ef 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -28,6 +28,7 @@ const CONST = { MISSING_INCORPORATION_STATE: '402 Missing incorporationState in additionalData', MISSING_INCORPORATION_TYPE: '402 Missing incorporationType in additionalData', MAX_VALIDATION_ATTEMPTS_REACHED: 'Validation for this bank account has been disabled due to too many incorrect attempts. Please contact us.', + INCORRECT_VALIDATION_AMOUNTS: 'The validate code you entered is incorrect, please try again.', }, STEP: { // In the order they appear in the VBA flow @@ -72,6 +73,11 @@ const CONST = { VERIFYING: 'VERIFYING', PENDING: 'PENDING', }, + MAX_LENGTH: { + TAX_ID_NUMBER: 9, + SSN: 4, + ZIP_CODE: 5, + }, }, INCORPORATION_TYPES: { LLC: 'LLC', @@ -90,6 +96,7 @@ const CONST = { DEFAULT_ROOMS: 'defaultRooms', BETA_EXPENSIFY_WALLET: 'expensifyWallet', INTERNATIONALIZATION: 'internationalization', + IOU_SEND: 'sendMoney', }, BUTTON_STATES: { DEFAULT: 'default', @@ -127,8 +134,8 @@ const CONST = { PRIVACY_URL: 'https://use.expensify.com/privacy', LICENSES_URL: 'https://use.expensify.com/licenses', PLAY_STORE_URL: 'https://play.google.com/store/apps/details?id=com.expensify.chat&hl=en', - ADD_SECONDARY_LOGIN_URL: '/settings?param={%22section%22:%22account%22}', - MANAGE_CARDS_URL: '/domain_companycards', + ADD_SECONDARY_LOGIN_URL: 'settings?param={%22section%22:%22account%22}', + MANAGE_CARDS_URL: 'domain_companycards', FEES_URL: 'https://use.expensify.com/fees', CFPB_PREPAID_URL: 'https://cfpb.gov/prepaid', STAGING_SECURE_URL: 'https://staging-secure.expensify.com/', @@ -213,6 +220,7 @@ const CONST = { }, ERROR: { API_OFFLINE: 'session.offlineMessageRetry', + UNKNOWN_ERROR: 'Unknown error', }, NETWORK: { METHOD: { @@ -244,6 +252,13 @@ const CONST = { // at least 8 characters, 1 capital letter, 1 lowercase number, 1 number PASSWORD_COMPLEXITY_REGEX_STRING: '^(?=.*[A-Z])(?=.*[0-9])(?=.*[a-z]).{8,}$', + PASSWORD_PAGE: { + ERROR: { + ALREADY_VALIDATED: 'Account already validated', + VALIDATE_CODE_FAILED: 'Validate code failed', + }, + }, + EMOJI_SPACER: 'SPACER', LOGIN_TYPE: { @@ -336,6 +351,7 @@ const CONST = { SMS_NUMBER_COUNTRY_CODE: 'US', ERROR: { USER_CANCELLED: 'User canceled flow', + USER_TAPPED_BACK: 'User exited by clicking the back button.', }, }, @@ -367,6 +383,11 @@ const CONST = { PAYPAL_ME: 'PayPal.me', VENMO: 'Venmo', }, + IOU_TYPE: { + SEND: 'send', + SPLIT: 'split', + REQUEST: 'request', + }, AMOUNT_MAX_LENGTH: 10, }, @@ -404,11 +425,12 @@ const CONST = { LARGE: 'large', DEFAULT: 'default', }, - + PHONE_MAX_LENGTH: 15, REGEX: { US_PHONE: /^\+1\d{10}$/, DIGITS_AND_PLUS: /^\+?[0-9]*$/, PHONE_E164_PLUS: /^\+?[1-9]\d{1,14}$/, + PHONE_WITH_SPECIAL_CHARS: /^[+]*[(]{0,1}[0-9]{1,3}[)]{0,1}[-\s\\./0-9]{0,12}$/, NON_ALPHA_NUMERIC: /[^A-Za-z0-9+]/g, PO_BOX: /\b[P|p]?(OST|ost)?\.?\s*[O|o|0]?(ffice|FFICE)?\.?\s*[B|b][O|o|0]?[X|x]?\.?\s+[#]?(\d+)\b/, ANY_VALUE: /^.+$/, @@ -416,6 +438,14 @@ const CONST = { INDUSTRY_CODE: /^[0-9]{6}$/, SSN_LAST_FOUR: /[0-9]{4}/, NUMBER: /^[0-9]+$/, + CARD_NUMBER: /^[0-9]{15,16}$/, + CARD_SECURITY_CODE: /^[0-9]{3,4}$/, + CARD_EXPIRATION_DATE: /(0[1-9]|10|11|12)\/20[0-9]{2}$/, + + // Adapted from: https://gist.github.com/dperini/729294 + // eslint-disable-next-line max-len + HYPERLINK: /^(?:(?:(?:https?|ftp):\/\/)?)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)+(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?$/i, + // eslint-disable-next-line max-len, no-misleading-character-class EMOJIS: /(?:\uD83D(?:\uDC41\u200D\uD83D\uDDE8|\uDC68\u200D\uD83D[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|\uDC69\u200D\uD83D\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?))|[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|[\ud83c\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|[\ud83c\ude32-\ude3a]|[\ud83c\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])/g, }, diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index 2290eb69c3f..4317a9ac6be 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -131,4 +131,10 @@ export default { // Stores Workspace ID that will be tied to reimbursement account during setup REIMBURSEMENT_ACCOUNT_WORKSPACE_ID: 'reimbursementAccountWorkspaceID', + + // Notifies all tabs that they should sign out and clear storage. + SHOULD_SIGN_OUT: 'shouldSignOut', + + // Set when we are loading payment methods + IS_LOADING_PAYMENT_METHODS: 'isLoadingPaymentMethods', }; diff --git a/src/ROUTES.js b/src/ROUTES.js index 520f6f06417..71206888801 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -27,6 +27,7 @@ export default { SETTINGS_APP_DOWNLOAD_LINKS: 'settings/about/app-download-links', SETTINGS_PAYMENTS: 'settings/payments', SETTINGS_ADD_PAYPAL_ME: 'settings/payments/add-paypal-me', + SETTINGS_ADD_DEBIT_CARD: 'settings/payments/add-debit-card', SETTINGS_ADD_LOGIN: 'settings/addlogin/:type', getSettingsAddLoginRoute: type => `settings/addlogin/${type}`, NEW_GROUP: 'new/group', @@ -67,6 +68,7 @@ export default { getReportDetailsRoute: reportID => `r/${reportID}/details`, VALIDATE_LOGIN: 'v', VALIDATE_LOGIN_WITH_VALIDATE_CODE: 'v/:accountID/:validateCode', + LOGIN_WITH_SHORT_LIVED_TOKEN: 'transition', // This is a special validation URL that will take the user to /workspace/new after validation. This is used // when linking users from e.com in order to share a session in this app. @@ -75,17 +77,29 @@ export default { LOGIN_WITH_VALIDATE_CODE_WORKSPACE_CARD: 'v/:accountID/:validateCode/workspace/:policyID/card', LOGIN_WITH_VALIDATE_CODE_2FA_WORKSPACE_CARD: 'v/:accountID/:validateCode/2fa/workspace/:policyID/card', ENABLE_PAYMENTS: 'enable-payments', - WORKSPACE: 'workspace', - WORKSPACE_CARD: ':policyID/card', - WORKSPACE_PEOPLE: ':policyID/people', - getWorkspaceCardRoute: policyID => `workspace/${policyID}/card`, - getWorkspacePeopleRoute: policyID => `workspace/${policyID}/people`, - getWorkspaceInviteRoute: policyID => `workspace/${policyID}/invite`, + WORKSPACE_NEW: 'workspace/new', + WORKSPACE_INITIAL: 'workspace/:policyID', WORKSPACE_INVITE: 'workspace/:policyID/invite', + WORKSPACE_SETTINGS: 'workspace/:policyID/settings', + WORKSPACE_CARD: 'workspace/:policyID/card', + WORKSPACE_REIMBURSE: 'workspace/:policyID/reimburse', + WORKSPACE_BILLS: 'workspace/:policyID/bills', + WORKSPACE_INVOICES: 'workspace/:policyID/invoices', + WORKSPACE_TRAVEL: 'workspace/:policyID/travel', + WORKSPACE_MEMBERS: 'workspace/:policyID/members', + WORKSPACE_BANK_ACCOUNT: 'workspace/:policyID/bank-account', + getWorkspaceInitialRoute: policyID => `workspace/${policyID}`, + getWorkspaceInviteRoute: policyID => `workspace/${policyID}/invite`, + getWorkspaceSettingsRoute: policyID => `workspace/${policyID}/settings`, + getWorkspaceCardRoute: policyID => `workspace/${policyID}/card`, + getWorkspaceReimburseRoute: policyID => `workspace/${policyID}/reimburse`, + getWorkspaceBillsRoute: policyID => `workspace/${policyID}/bills`, + getWorkspaceInvoicesRoute: policyID => `workspace/${policyID}/invoices`, + getWorkspaceTravelRoute: policyID => `workspace/${policyID}/travel`, + getWorkspaceMembersRoute: policyID => `workspace/${policyID}/members`, + getWorkspaceBankAccountRoute: policyID => `workspace/${policyID}/bank-account`, getRequestCallRoute: taskID => `request-call/${taskID}`, REQUEST_CALL: 'request-call/:taskID', - getWorkspaceEditorRoute: policyID => `workspace/${policyID}/edit`, - WORKSPACE_EDITOR: 'workspace/:policyID/edit', /** * @param {String} route diff --git a/src/SCREENS.js b/src/SCREENS.js index 764965e7335..3a9754a1ee7 100644 --- a/src/SCREENS.js +++ b/src/SCREENS.js @@ -6,6 +6,7 @@ export default { HOME: 'Home', LOADING: 'Loading', REPORT: 'Report', + LOG_IN_WITH_SHORT_LIVED_TOKEN: 'LogInWithShortLivedToken', LOGIN_WITH_VALIDATE_CODE_NEW_WORKSPACE: 'LoginWithValidateCodeNewWorkspace', LOGIN_WITH_VALIDATE_CODE_2FA_NEW_WORKSPACE: 'LoginWithValidateCode2FANewWorkspace', LOGIN_WITH_VALIDATE_CODE_WORKSPACE_CARD: 'LoginWithValidateCodeWorkspaceCard', diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index fa10e5c0f19..b88e2d58b09 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -24,6 +24,9 @@ import ExpensiPicker from './ExpensiPicker'; import Text from './Text'; import * as ReimbursementAccountUtils from '../libs/ReimbursementAccountUtils'; import ReimbursementAccountForm from '../pages/ReimbursementAccount/ReimbursementAccountForm'; +import getBankIcon from './Icon/BankIcons'; +import Icon from './Icon'; +import variables from '../styles/variables'; const propTypes = { ...withLocalizePropTypes, @@ -135,8 +138,11 @@ class AddPlaidBankAccount extends React.Component { } const account = this.getAccounts()[this.state.selectedIndex]; + const bankName = lodashGet(this.props.plaidBankAccounts, 'bankName'); this.props.onSubmit({ - account, plaidLinkToken: this.props.plaidLinkToken, + bankName, + account, + plaidLinkToken: this.props.plaidLinkToken, }); } @@ -177,9 +183,14 @@ class AddPlaidBankAccount extends React.Component { {!_.isEmpty(this.props.text) && ( {this.props.text} )} - {/* @TODO there are a bunch of logos to incorporate here to replace this name - https://d2k5nsl2zxldvw.cloudfront.net/images/plaid/bg_plaidLogos_12@2x.png */} - {this.state.institution.name} + + + {this.state.institution.name} + { + const googlePlacesRef = useRef(); + useEffect(() => { + googlePlacesRef.current?.setAddressText(props.value); + }, []); + + // eslint-disable-next-line + const getAddressComponent = (object, field, nameType) => { + return _.chain(object.address_components) + .find(component => _.contains(component.types, field)) + .get(nameType) + .value(); + }; + + const validateAddressComponents = (addressComponents) => { + if (!addressComponents) { + return false; + } + if (!_.some(addressComponents, component => _.includes(component.types, 'street_number'))) { + // Missing Street number + return false; + } + if (_.some(addressComponents, component => _.includes(component.types, 'post_box'))) { + // Reject PO box + return false; + } + return true; + }; + + const saveLocationDetails = (details) => { + if (validateAddressComponents(details.address_components)) { + // Gather the values from the Google details + const streetNumber = getAddressComponent(details, 'street_number', 'long_name'); + const streetName = getAddressComponent(details, 'route', 'long_name'); + const city = getAddressComponent(details, 'locality', 'long_name'); + const state = getAddressComponent(details, 'administrative_area_level_1', 'short_name'); + const zipCode = getAddressComponent(details, 'postal_code', 'long_name'); + + // Trigger text change events for each of the individual fields being saved on the server + props.onChangeText('addressStreet', `${streetNumber} ${streetName}`); + props.onChangeText('addressCity', city); + props.onChangeText('addressState', state); + props.onChangeText('addressZipCode', zipCode); + } else { + // Clear the values associated to the address, so our validations catch the problem + props.onChangeText('addressStreet', null); + props.onChangeText('addressCity', null); + props.onChangeText('addressState', null); + props.onChangeText('addressZipCode', null); + } + }; + + return ( + saveLocationDetails(details)} + query={{ + key: 'AIzaSyC4axhhXtpiS-WozJEsmlL3Kg3kXucbZus', + language: props.preferredLocale, + types: 'address', + components: 'country:us', + }} + requestUrl={{ + useOnPlatform: 'web', + url: `${CONFIG.EXPENSIFY.URL_EXPENSIFY_COM}api?command=Proxy_GooglePlaces&proxyUrl=`, + }} + textInputProps={{ + InputComp: ExpensiTextInput, + label: props.label, + containerStyles: props.containerStyles, + errorText: props.errorText, + }} + styles={{ + textInputContainer: [styles.flexColumn], + listView: [ + styles.borderTopRounded, + styles.borderBottomRounded, + styles.mt1, + styles.overflowAuto, + styles.borderLeft, + styles.borderRight, + ], + row: [ + styles.pv4, + styles.ph3, + styles.overflowAuto, + ], + description: [styles.googleSearchText], + separator: [styles.googleSearchSeparator], + }} + /> + ); +}; + +AddressSearch.propTypes = propTypes; +AddressSearch.defaultProps = defaultProps; + +export default withLocalize(AddressSearch); diff --git a/src/components/AttachmentModal.js b/src/components/AttachmentModal.js index 508a62baf88..92ab48c199a 100755 --- a/src/components/AttachmentModal.js +++ b/src/components/AttachmentModal.js @@ -158,6 +158,7 @@ class AttachmentModal extends PureComponent { + this.setState({isMenuVisible: true})} + disabled={this.props.isUploading} + > + + {this.props.avatarURL + ? ( + + ) + : ( + + )} + + {({openPicker}) => ( + <> + { + this.props.isUploading + ? ( + - - {this.props.avatarURL - ? ( - - ) - : ( - - )} - - {({openPicker}) => ( - <> - { - this.props.isUploading - ? ( - - - - - ) - : ( - <> - this.setState({isMenuVisible: true})} - > - - this.setState({isMenuVisible: false})} - onItemSelected={() => this.setState({isMenuVisible: false})} - menuItems={this.createMenuItems(openPicker)} - anchorPosition={this.props.anchorPosition} - animationIn="fadeInDown" - animationOut="fadeOutUp" - /> - - ) - } - - )} - - + + ) + : ( + <> + + + + this.setState({isMenuVisible: false})} + onItemSelected={() => this.setState({isMenuVisible: false})} + menuItems={this.createMenuItems(openPicker)} + anchorPosition={this.props.anchorPosition} + animationIn="fadeInDown" + animationOut="fadeOutUp" + /> + + ) + } + + )} + + + ); } diff --git a/src/components/ButtonWithMenu.js b/src/components/ButtonWithMenu.js new file mode 100644 index 00000000000..a71d0c196da --- /dev/null +++ b/src/components/ButtonWithMenu.js @@ -0,0 +1,109 @@ +import React, {PureComponent} from 'react'; +import PropTypes from 'prop-types'; +import {View} from 'react-native'; +import _ from 'underscore'; +import styles from '../styles/styles'; +import Button from './Button'; +import ButtonWithDropdown from './ButtonWithDropdown'; +import PopoverMenu from './PopoverMenu'; + +const propTypes = { + /** Text to display for the menu header */ + menuHeaderText: PropTypes.string, + + /** Callback to execute when the main button is pressed */ + onPress: PropTypes.func.isRequired, + + /** Callback to execute when a menu item is selected */ + onChange: PropTypes.func, + + /** Whether we should show a loading state for the main button */ + isLoading: PropTypes.bool, + + /** Should the confirmation button be disabled? */ + isDisabled: PropTypes.bool, + + /** Menu options to display */ + /** [{text: 'Pay with Expensify', icon: Wallet}, {text: 'PayPal', icon: PayPal}, {text: 'Venmo', icon: Venmo}] */ + options: PropTypes.arrayOf(PropTypes.shape({ + text: PropTypes.string.isRequired, + icon: PropTypes.elementType, + iconWidth: PropTypes.number, + iconHeight: PropTypes.number, + iconDescription: PropTypes.string, + })).isRequired, +}; + +const defaultProps = { + onChange: () => {}, + isLoading: false, + isDisabled: false, + menuHeaderText: '', +}; + +class ButtonWithMenu extends PureComponent { + constructor(props) { + super(props); + + this.state = { + selectedItem: props.options[0], + isMenuVisible: false, + }; + } + + setMenuVisibility(isMenuVisible) { + this.setState({isMenuVisible}); + } + + render() { + const selectedItemText = this.state.selectedItem.text; + return ( + + {this.props.options.length > 1 ? ( + { + this.setMenuVisibility(true); + }} + /> + ) : ( +