Skip to content

Commit

Permalink
Merge branch 'main' into edu/17548_personal_details_push_to_page
Browse files Browse the repository at this point in the history
* main: (306 commits)
  Use correct consts and functions for expensify emails
  More cleanup & adding consts
  A bit of code cleanup
  Update version to 1.3.28-4
  Update version to 1.3.28-3
  fix: use accountIDs as numbers in react methods
  fix: rename props
  A few accountID updates
  fix: remove unnecessary spread
  fix: setContactMethodAsDefault use accountID
  fix: remove setIsReportScreenIsReady
  Update version to 1.3.28-2
  Update version to 1.3.28-1
  Revert pod cache
  Update version to 1.3.28-0
  Update version to 1.3.27-7
  Fix lint
  update expensify-common to avoid parsing underscores of mention email
  fix: use of UserUtils.getAvatar
  remove unused code
  ...
  • Loading branch information
gedu committed Jun 15, 2023
2 parents 6b11127 + 9ea7b45 commit b2e31bd
Show file tree
Hide file tree
Showing 164 changed files with 2,588 additions and 1,881 deletions.
17 changes: 17 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,20 @@ USE_WEB_PROXY=false
USE_WDYR=false
CAPTURE_METRICS=false
ONYX_METRICS=false

EXPENSIFY_ACCOUNT_ID_ACCOUNTING=-1
EXPENSIFY_ACCOUNT_ID_ADMIN=-1
EXPENSIFY_ACCOUNT_ID_BILLS=-1
EXPENSIFY_ACCOUNT_ID_CHRONOS=-1
EXPENSIFY_ACCOUNT_ID_CONCIERGE=-1
EXPENSIFY_ACCOUNT_ID_CONTRIBUTORS=-1
EXPENSIFY_ACCOUNT_ID_FIRST_RESPONDER=-1
EXPENSIFY_ACCOUNT_ID_HELP=-1
EXPENSIFY_ACCOUNT_ID_INTEGRATION_TESTING_CREDS=-1
EXPENSIFY_ACCOUNT_ID_PAYROLL=-1
EXPENSIFY_ACCOUNT_ID_QA=-1
EXPENSIFY_ACCOUNT_ID_QA_TRAVIS=-1
EXPENSIFY_ACCOUNT_ID_RECEIPTS=-1
EXPENSIFY_ACCOUNT_ID_REWARDS=-1
EXPENSIFY_ACCOUNT_ID_STUDENT_AMBASSADOR=-1
EXPENSIFY_ACCOUNT_ID_SVFG=-1
7 changes: 0 additions & 7 deletions .github/workflows/platformDeploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -157,14 +157,7 @@ jobs:
ruby-version: '2.7'
bundler-cache: true

- uses: actions/cache@v3
id: cache-pods
with:
path: ios/Pods
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}

- name: Install cocoapods
if: steps.cache-pods.outputs.cache-hit != 'true'
uses: nick-invision/retry@0711ba3d7808574133d713a0d92d2941be03a350
with:
timeout_minutes: 10
Expand Down
7 changes: 0 additions & 7 deletions .github/workflows/testBuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,7 @@ jobs:
ruby-version: '2.7'
bundler-cache: true

- uses: actions/cache@v3
id: cache-pods
with:
path: ios/Pods
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}

- name: Install cocoapods
if: steps.cache-pods.outputs.cache-hit != 'true'
uses: nick-invision/retry@0711ba3d7808574133d713a0d92d2941be03a350
with:
timeout_minutes: 10
Expand Down
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1001032706
versionName "1.3.27-6"
versionCode 1001032804
versionName "1.3.28-4"
}

splits {
Expand Down
10 changes: 5 additions & 5 deletions contributingGuides/FORMS.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,10 @@ Here's an example for a form that has two inputs, `routingNumber` and `accountNu
function validate(values) {
const errors = {};
if (!values.routingNumber) {
errors.routingNumber = props.translate(CONST.ERRORS.ROUTING_NUMBER);
errors.routingNumber = CONST.ERRORS.ROUTING_NUMBER;
}
if (!values.accountNumber) {
errors.accountNumber = props.translate(CONST.ERRORS.ACCOUNT_NUMBER);
errors.accountNumber = CONST.ERRORS.ACCOUNT_NUMBER;
}
return errors;
}
Expand All @@ -130,15 +130,15 @@ function validate(values) {
let errors = {};

if (!ValidationUtils.isValidDisplayName(values.firstName)) {
errors = ErrorUtils.addErrorMessage(errors, 'firstName', props.translate('personalDetails.error.hasInvalidCharacter'));
errors = ErrorUtils.addErrorMessage(errors, 'firstName', 'personalDetails.error.hasInvalidCharacter');
}

if (ValidationUtils.doesContainReservedWord(values.firstName, CONST.DISPLAY_NAME.RESERVED_FIRST_NAMES)) {
errors = ErrorUtils.addErrorMessage(errors, 'firstName', props.translate('personalDetails.error.containsReservedWord'));
errors = ErrorUtils.addErrorMessage(errors, 'firstName', 'personalDetails.error.containsReservedWord');
}

if (!ValidationUtils.isValidDisplayName(values.lastName)) {
errors.lastName = props.translate('personalDetails.error.hasInvalidCharacter');
errors.lastName = 'personalDetails.error.hasInvalidCharacter';
}

return errors;
Expand Down
73 changes: 72 additions & 1 deletion contributingGuides/NAVIGATION.md
Original file line number Diff line number Diff line change
@@ -1 +1,72 @@
This is a placeholder for the documentation of how navigation is implemented in the App.
# Overview

The navigation in the App consists of a top-level Stack Navigator (called `RootStack`) with each of its `Screen` components handling different high-level flow. All those flows can be seen in `AuthScreens.js` file.

## Terminology

`RHP` - Right hand panel that shows content inside a dismissible modal that takes up a partial portion of the screen on large format devices e.g. desktop/web/tablets. On smaller screens the content shown in the RHP fills the entire screen.

Navigation Actions - User actions correspond to resulting navigation actions that we will define now. The navigation actions are: `Back`, `Up`, `Dismiss`, `Forward` and `Push`.

- `Back` - Moves the user “back” in the history stack by popping the screen or stack of screens. Note: This can potentially make the user exit the app itself (native) or display a previous app (not Expensify), or just the empty state of the browser.

- `Up` - Pops the current screen off the current stack. This action is very easy to confuse with `Back`. Unless you’ve navigated from one screen to a nested screen in a stack of screens these actions will almost always be the same. Unlike a “back” action, “up” should never result in the user exiting the app and should only be an option if there is somewhere to go “up” to.

- `Dismiss` - Closes any modals (outside the navigation hierarchy) or pops a nested stack of screens off returning the user to the previous screen in the main stack.

- `Forward` - This will take you forward in the history stack. Can only be invoked after you have gone `Back` at least once. Note: Only possible on web.

- `Push` - Either adds a new individual screen to the main stack or a nested stack of screens to the main stack with the user pointed at the last index of the pushed stack.

## Adding RHP flows

Most of the time, if you want to add some of the flows concerning one of your reports, e.g. `Money Request` from a user, you will most probably use `RightModalNavigator.js` and `ModalStackNavigators.js` file:

- Since each of those flows is kind of a modal stack, if you want to add a page to the existing flow, you should just add a page to the correct stack in `ModalStackNavigators.js`.

- If you want to create new flow, add a `Screen` in `RightModalNavigator.js` and make new modal in `ModalStackNavigators.js` with chosen pages.

When creating RHP flows, you have to remember a couple things:

- Since you can deeplink to different pages inside the RHP navigator, it is important to provide the possibility for the user to properly navigate back from any page with UP press (`HeaderWithBackButton` component).

- An example can be deeplinking to `/settings/profile/personal-details`. From there, when pressing the UP button, you should navigate to `/settings/profile`, so in order for it to work, you should provide the correct route in `onBackButtonPress` prop of `HeaderWithBackButton` (`Navigation.goBack(ROUTES.SETTINGS_PROFILE)` in this example).

- We use a custom `goBack` function to handle the browser and the `react-navigation` history stack. Under the hood, it resolves to either replacing the current screen with the one we navigate to (deeplinking scenario) or just going back if we reached the current page by navigating in App (pops the screen). It ensures the requested behaviors on web, which is navigating back to the place from where you deeplinked when going into the RHP flow by it.

- If you want to navigate to a certain report after completing a flow related to it, e.g. `RequestMoney` flow with a certain group/user, you should use `Navigation.dismissModal` with this `reportID` as an argument. If, in the future, we would like to navigate to something different than the report after such flows, the API should be rather easy to change. We do it like that in order to replace the RHP flow with the new report instead of pushing it, so pressing the back button does not navigate back to the ending page of the flow. If we were to navigate to the same report, we just pop the RHP modal.

### Example of usage

An example of adding `Settings_Workspaces` page:

1. Add path to `ROUTES.js`: https://github.com/Expensify/App/blob/3531af22dcadaa94ed11eccf370517dca0b8c305/src/ROUTES.js#L36

2. Add `Settings_Workspaces` page to proper RHP flow in `linkingConfig.js`: https://github.com/Expensify/App/blob/3531af22dcadaa94ed11eccf370517dca0b8c305/src/libs/Navigation/linkingConfig.js#L40-L42

3. Add your page to proper navigator (it should be aligned with where you've put it in the previous step) https://github.com/Expensify/App/blob/3531af22dcadaa94ed11eccf370517dca0b8c305/src/libs/Navigation/AppNavigator/ModalStackNavigators.js#L334-L338

4. Make sure `HeaderWithBackButton` leads to the previous page in navigation flow of your page: https://github.com/Expensify/App/blob/3531af22dcadaa94ed11eccf370517dca0b8c305/src/pages/workspace/WorkspacesListPage.js#L186

## Performance solutions

Using [react-freeze](https://github.com/software-mansion/react-freeze) allows us to increase performance by avoiding unnecessary re-renders of screens that aren’t visible to the user anyway.

- To ensure that the user doesn't ever see frozen report content, we are freezing the screens from 2 levels down the `RootStack` (which contains a `Screen` for each report), so when dismissing with a swipe, the user always sees the content of the previous report.

- We want to freeze as high in the view hierarchy as we can, so we do it in a `Screen` of `RootStack`, being `CentralPaneNavigator` and `SidebarScreen`.

- We want the report content visible as fast as possible, and at the same time we want the navigation animation to trigger instantly. To do so, we do a hack with `firstRenderRef` which renders `ReportActionsSkeletonView` instead of the messages at the first render, and the proper content afterward. It works since there are always more renders of `ReportScreen` before the content shows up (hopefully).

## Handling wide and narrow layouts

- The wide and narrow layouts are conditionally rendered with different components in `createResponsiveNavigator` depending on screen size (`isSmallScreen` prop from the `withWindowDimension.js`).

- The wide layout is rendered with our custom `ThreePaneView.js` and the narrow layout is rendered with `StackView` from `@react-navigation/stack`

- To make sure that we have the correct navigation state after changing the layout we need to force react to create new instance of the `NavigationContainer`. Without this, the navigation state could be broken after changing the type of layout.

- We are getting the new instance by changing the `key` prop of `NavigationContainer` that depends on the `isSmallScreenWidth`.

- To keep the navigation state that was present before changing the layout, we save the state on every change and use it for the `initialState` prop.
Changing the layout means that every component inside `NavigationContainer` is mounted anew.
4 changes: 2 additions & 2 deletions ios/NewExpensify/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.3.27</string>
<string>1.3.28</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
Expand All @@ -32,7 +32,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>1.3.27.6</string>
<string>1.3.28.4</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationQueriesSchemes</key>
Expand Down
4 changes: 2 additions & 2 deletions ios/NewExpensifyTests/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.3.27</string>
<string>1.3.28</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.3.27.6</string>
<string>1.3.28.4</string>
</dict>
</plist>
6 changes: 6 additions & 0 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,8 @@ PODS:
- Firebase/Performance (= 8.8.0)
- React-Core
- RNFBApp
- RNFS (2.20.0):
- React-Core
- RNGestureHandler (2.9.0):
- React-Core
- RNLocalize (2.2.6):
Expand Down Expand Up @@ -809,6 +811,7 @@ DEPENDENCIES:
- "RNFBApp (from `../node_modules/@react-native-firebase/app`)"
- "RNFBCrashlytics (from `../node_modules/@react-native-firebase/crashlytics`)"
- "RNFBPerf (from `../node_modules/@react-native-firebase/perf`)"
- RNFS (from `../node_modules/react-native-fs`)
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- RNLocalize (from `../node_modules/react-native-localize`)
- RNPermissions (from `../node_modules/react-native-permissions`)
Expand Down Expand Up @@ -999,6 +1002,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-firebase/crashlytics"
RNFBPerf:
:path: "../node_modules/@react-native-firebase/perf"
RNFS:
:path: "../node_modules/react-native-fs"
RNGestureHandler:
:path: "../node_modules/react-native-gesture-handler"
RNLocalize:
Expand Down Expand Up @@ -1120,6 +1125,7 @@ SPEC CHECKSUMS:
RNFBApp: 729c0666395b1953198dc4a1ec6deb8fbe1c302e
RNFBCrashlytics: 2061ca863e8e2fa1aae9b12477d7dfa8e88ca0f9
RNFBPerf: 389914cda4000fe0d996a752532a591132cbf3f9
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
RNGestureHandler: 071d7a9ad81e8b83fe7663b303d132406a7d8f39
RNLocalize: d4b8af4e442d4bcca54e68fc687a2129b4d71a81
RNPermissions: dcdb7b99796bbeda6975a6e79ad519c41b251b1c
Expand Down
6 changes: 6 additions & 0 deletions jest/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,9 @@ jest.spyOn(console, 'debug').mockImplementation((...params) => {
// eslint-disable-next-line no-console
console.log('DEBUG', ...params);
});

// This mock is required for mocking file systems when running tests
jest.mock('react-native-fs', () => ({
unlink: jest.fn(() => new Promise((res) => res())),
CachesDirectoryPath: jest.fn(),
}));
Loading

0 comments on commit b2e31bd

Please sign in to comment.