Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement React Navigation #1559

Merged
merged 49 commits into from
Mar 12, 2021
Merged

Implement React Navigation #1559

merged 49 commits into from
Mar 12, 2021

Conversation

marcaaron
Copy link
Contributor

@marcaaron marcaaron commented Feb 25, 2021

cc @AndrewGable @Julesssss

Details

  • This PR implements react-navigation and removes react-router from Expensify.cash.
  • It's HOLDing on this issue since we are still not redirecting unknown paths back to index.html and this is a requirement for deep linking to work (although routing in general will work fine) DONE!
  • There are a ton of moving pieces so I'm pretty open to suggestions on how to break this into smaller PRs if necessary, but it's size is due to the unavoidable complexity involved in replacing our existing navigation system.

There are a few known issues that I'm still working on resolving:

  1. On mWeb URLs are not showing up accurately when tapping on a chat. This has no ill effects on desktop or native and isn't a huge blocker for me right now.
  2. Animations are a little bit off on web. This is also not a huge blocker and could be improved in the future.

Fixed Issues

Fixes https://github.com/Expensify/Expensify/issues/154512

Tests

Will be adding some more tests, but here's what I have so far...

mWeb

  1. Create a new test account on e.com and validate it
  2. Log into this account on mobileWeb
  3. Verify that the chat list displays their chat with concierge
  4. Tap on the chat and verify you are brought to the chat screen
  5. Press the left arrow to go back
  6. Test each modal and close them by pressing the x
  7. Each time the x is press we should return to the chat list
  8. Take note of the reportID for the concierge chat and visit /r/<reportID> in a new mobile web window.
  9. Verify you are brought to the chat and not the chat list
  10. Repeat the same process with each modal link /new/chat /new/group /settings /search
  11. Verify each time the x is pressed on a modal view that we return to the chat list

Web/Desktop wide screen

  1. Create a new test account on e.com and validate it
  2. Log into this account on mobileWeb
  3. Verify that the chat list displays their chat with concierge
  4. Tap on the chat and verify you are brought to the chat screen
  5. Press the left arrow to go back
  6. Test each modal and close them by pressing the x
  7. Each time the x is press we should return to the chat list
  8. Take note of the reportID for the concierge chat and visit /r/<reportID> in a new mobile web window.
  9. Verify you are brought to the chat and not the chat list
  10. Repeat the same process with each modal link /new/chat /new/group /settings /search
  11. Verify each time the x is pressed on a modal view that we return to the chat list

iOS / Android

  1. Create a new test account on e.com and validate it
  2. Log into this account on native mobile
  3. Verify that the chat list displays chat with concierge
  4. Tap on the chat and verify you are brought to the chat screen
  5. Press the left arrow to go back
  6. Test each modal (New Chat, New Group, Search, etc) and close them by pressing the x
  7. Each time the x is press we should return to the chat list

Extra steps:

  1. Make sure the "subroutes" are working OK for the settings pages e.g. /settings/profile, /settings/password, etc
  2. Test that the back button and close button behavior is as expected when inside these views

Tested On

  • Web
  • Mobile Web
  • Desktop
  • iOS
  • Android

Screenshots

Web

2021-02-24_14-50-00
2021-02-24_14-50-08

Mobile Web

2021-02-24_14-49-00
2021-02-24_14-49-16
2021-02-24_14-49-27

Desktop

2021-02-24_16-01-11

iOS

2021-02-24_15-23-35
2021-02-24_15-23-41
2021-02-24_15-23-47

Android

2021-02-24_15-17-58
2021-02-24_15-19-20
2021-02-24_15-19-35

@marcaaron marcaaron requested a review from a team as a code owner February 25, 2021 02:37
@marcaaron marcaaron self-assigned this Feb 25, 2021
@botify
Copy link

botify commented Feb 25, 2021

Hey, I noticed you changed some webpack configuration files. This can break production builds. Did you remember to run a production build locally to verify they still work?

@botify botify requested review from Dal-Papa and removed request for a team February 25, 2021 02:38
Do a lot

Fix up routing issues on web by using Linking.getInitialUrl()

Make sure root route displays correctly

fix favicons

fix background issue for native modals

Fix report not loading on init

remove isSidebarShown code

move header gaps

fix weird window width issue
@marcaaron marcaaron removed the request for review from Dal-Papa February 25, 2021 02:39
@marcaaron marcaaron marked this pull request as draft February 25, 2021 02:39
@marcaaron
Copy link
Contributor Author

@Dal-Papa sorry mean to make this a draft 🙃

@botify
Copy link

botify commented Feb 26, 2021

Hey, I noticed you changed some webpack configuration files. This can break production builds. Did you remember to run a production build locally to verify they still work?

4 similar comments
@botify
Copy link

botify commented Feb 26, 2021

Hey, I noticed you changed some webpack configuration files. This can break production builds. Did you remember to run a production build locally to verify they still work?

@botify
Copy link

botify commented Feb 26, 2021

Hey, I noticed you changed some webpack configuration files. This can break production builds. Did you remember to run a production build locally to verify they still work?

@botify
Copy link

botify commented Feb 26, 2021

Hey, I noticed you changed some webpack configuration files. This can break production builds. Did you remember to run a production build locally to verify they still work?

@botify
Copy link

botify commented Feb 26, 2021

Hey, I noticed you changed some webpack configuration files. This can break production builds. Did you remember to run a production build locally to verify they still work?

@marcaaron
Copy link
Contributor Author

@shawnborton lmk if you are up for taking this for a spin and bringing back any notes before we go into a full review. I tried to keep everything largely the same, but might have missed some small details here and there.

@shawnborton
Copy link
Contributor

Just took this for a quick spin on iOS and it feels pretty smooth to me! I think this might currently exist, but I do think it's weird that on mobile devices, we use an active state for the chat row when in reality you aren't really viewing an active chat:
image

Only other thing I ran into was that I am unable to create new group chats - not sure if that is a result of this PR or not. Otherwise this is feeling awesome, such a great improvement!

@marcaaron
Copy link
Contributor Author

we use an active state for the chat row when in reality you aren't really viewing an active chat

Oh yeah, that's a great catch. Will look into this.

@marcaaron
Copy link
Contributor Author

Updated

@marcaaron
Copy link
Contributor Author

Ok, ended up responding to most of the comments! Removing redirect() touched quite a few more files so I'm hoping we can get a quick merge tomorrow.

src/Expensify.js Outdated Show resolved Hide resolved
src/Expensify.js Outdated Show resolved Hide resolved
Copy link
Contributor

@Julesssss Julesssss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good.

Totally agree with getting this merged soon and building upon it. But do we have a plan to document the remaining work in issues?

@marcaaron
Copy link
Contributor Author

Thanks @Julesssss! I've gone ahead and created some follow up issues for the things we've discussed, but didn't want to tackle yet. They can be found in the project column here. Let me know if there's anything I missed that needs an issue.

@marcaaron
Copy link
Contributor Author

unclear about when react-navigation requires a component's children to be a function and why we need all the arrow functions in the render functions, and if there's a way to clean that up that makes it clearer when/why it's necessary

@roryabraham managed to remove all of those cases and re-organize a bit definitely looks tidier

@Expensify Expensify deleted a comment from botify Mar 12, 2021
@Expensify Expensify deleted a comment from botify Mar 12, 2021
@Expensify Expensify deleted a comment from botify Mar 12, 2021
Julesssss
Julesssss previously approved these changes Mar 12, 2021
Copy link
Contributor

@Julesssss Julesssss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All good 👍

Noticed a couple of minor things during a final run-through, but no need to view these as blockers:

  • [Web]: the modal-close animation seems to have gone, but the modal-open animation still works
  • [Android] (Physical device): when you open the settings page the first back button press is ignored (as if an extra invisible page was added to the page stack), but the second and third back button press work as expected

@marcaaron
Copy link
Contributor Author

Created issues for those as well, thanks.

roryabraham
roryabraham previously approved these changes Mar 12, 2021
Copy link
Contributor

@roryabraham roryabraham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't have time for another thorough review and test, but it seems like most of my comments from the last review were well-resolved.

NikkiWines
NikkiWines previously approved these changes Mar 12, 2021
Copy link
Contributor

@NikkiWines NikkiWines left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, amazing job @marcaaron 🎉 Tested on desktop + android sim and works well.

Couple things to note:

[Android] (Physical device): when you open the settings page the first back button press is ignored (as if an extra invisible page was added to the page stack), but the second and third back button press work as expected

I didn't experience this same thing on the android sim, all buttons worked immediately on the first press.

Secondly, I was getting some delay with the chat switcher on android sim only (so I'm not sure this is a real issue but figured I'd call it out just in case) where the old chat was momentarily displayed before the new chat

sim-chatswitcher.mov

AndrewGable
AndrewGable previously approved these changes Mar 12, 2021
Copy link
Contributor

@AndrewGable AndrewGable left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks amazing on mobile, super excited to continuing building on this!

@marcaaron marcaaron dismissed stale reviews from AndrewGable, NikkiWines, and roryabraham via 2b5e557 March 12, 2021 19:43
@marcaaron
Copy link
Contributor Author

So close, but got just one more conflict 😝 updated

@marcaaron marcaaron merged commit ca735fb into master Mar 12, 2021
@marcaaron marcaaron deleted the marcaaron-reactnav branch March 12, 2021 20:11
@github-actions github-actions bot locked and limited conversation to collaborators Mar 12, 2021
Copy link
Contributor

@tgolen tgolen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've got some reading up to do about react-navigation, but just noticed a few things that I wanted to comment on.


const IOURequestModalStackNavigator = () => (
<IOURequestModalStack.Navigator
path="/iou/request"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be OK to change these to reference ROUTES.js?

import themeColors from '../../styles/themes/default';

const propTypes = {
authenticated: PropTypes.bool.isRequired,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are missing inline docs

throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?");
}

const state = linkingConfig?.getStateFromPath
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we officially adopting the ?. pattern now?

root.reset(state);
}
} else {
throw new Error('Failed to parse the path to a navigation state.');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our standard style is to fail quickly and early, so this should be moved up to an if (!state) piece of logic

}
}

Onyx.merge(ONYXKEYS.CURRENT_URL, path);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move all Onyx calls into an action (discussed on Slack briefly)

redirectTo: PropTypes.string,
// Session info for the currently logged in user.
session: PropTypes.shape({
authToken: PropTypes.string,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of sub-props in this PR are missing inline comments

getReportRoute: reportID => `/r/${reportID}`,
ROOT: '/',
SEARCH: '/search',
SET_PASSWORD: '/setpassword/:validateCode',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like some of these route definitions are no longer used. Can these be cleaned up?

const propTypes = {
// Internal react-navigation stuff used to determine which view we should display
state: PropTypes.shape({
index: PropTypes.number,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More inline comments missing



class ResponsiveView extends React.Component {
getCurrentViewDescriptor() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing method docs

</Text>
</Pressable>
<ScreenWrapper>
{() => (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was seeing all of these, and wondering if there is a way to clean these up a little. I might not have all the context behind this, but I looked through the docs for the safe area context: https://github.com/th3rdwave/react-native-safe-area-context

It appears to me that the only reason the {() => ()} pattern is used is because ScreenWrapper is using SafeAreaInsetsContext.Consumer to get access to the insets. The insets are only used in a single component (sidebar).

I'm curious if all the other views could be much more simple that don't need access to the insets. Maybe something like this:

// Normal screenwrapper defaults to not providing insets
<ScreenWrapper>
    <View />
</ScreenWrapper>

Then for the one that needs insets:

<ScreenWrapperWithInsets>
    {(insets) => (...)}
</ScreenWrapperWithInsets>

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants