-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
Fix crashes when personal details are not available #9385
Conversation
…p into aldo_fix-crash-missing-personal-details
I just added myself as a "code owner" (kind of hate this name as I don't own anything) as it's the easiest way to subscribe to changes on some specific files that I'm interested in. Usually removing myself if I have nothing to add. |
I see! good to know :) |
// Waiting until ONYX variables are loaded before displaying the component | ||
if (_.isEmpty(this.props.personalDetails)) { | ||
return null; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hum, I think this may cause a white screen to show for a few moments. Maybe I should have put a spinner. I'll try that if the whole approach makes sense.
@@ -403,6 +407,11 @@ class ReportActionsView extends React.Component { | |||
return null; | |||
} | |||
|
|||
// Waiting until ONYX variables are loaded before displaying the component |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably we are not waiting for Onyx, but the API response to set these expected details?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would also maybe consider moving this to the ReportScreen
... seems we have a few "loading" type interactions there and instead of returning null
we can show the loading state?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I retested this and I didn't find any case where _.isEmpty(this.props.personalDetails)
is true
. At this point I'm not sure why I added it.
I just removed it, I don't think it makes sense because:
- if
this.props.personalDetails
is an empty object, we won't crash when we open the DetailsPage because of the new spinner - ReportActionsView doesn't really use the personal details, so it is wrong to hold it from rendering because PersonalDetails are not ready
- if
this.props.personalDetails
isnull
orundefined
, it would crash earlier here
Update: removed useless check |
@@ -127,7 +131,7 @@ class ReportActionsView extends React.Component { | |||
|
|||
// If the reportID is not found then we have either not loaded this chat or the user is unable to access it. | |||
// We will attempt to fetch it and redirect if still not accessible. | |||
if (!this.props.report.reportID) { | |||
if (!this.props.report.reportID || !this.props.personalDetails[this.props.report.reportID]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The personalDetails
object has a key that is a reportID
? IIRC personalDetails
are keyed by logins.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are totally right about that... investigating more...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the long wait. I think I found a better way to handle this stuff:
Just like Report.fetchChatReportsByIDs
chains a call to PersonalDetails.getFromReportParticipants
here, I chained a PersonalDetails.getFromReportParticipants
call here when we call Reports.fetchOrCreateChatReport
. This way we don't depend on Report.fetchChatReportsByIDs
being called (which happens inconsistently depending on the platform as explained here)
I know the new API refactor avoids chaining, but this is an easy fix, consistent with the old chaining approach and fixes the crash for IOS/Android, so I think it is fine as a temporary solution until all this gets refactored.
src/pages/DetailsPage.js
Outdated
<View style={[styles.flex1, styles.alignItemsCenter, styles.justifyContentCenter]}> | ||
<ActivityIndicator color={themeColors.spinner} size="large" /> | ||
</View> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NAB, but you could use the <FullscreenLoadingIndicator />
component here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll give it a try, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, that works. Because of the name, I assumed it would block the whole screen and not just the sidebar.
Friendly bump @marcaaron |
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
@@ -66,6 +67,10 @@ const getPhoneNumber = (details) => { | |||
|
|||
const DetailsPage = (props) => { | |||
const details = props.personalDetails[props.route.params.login]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that this line is probably what is causing this crash: #9545
It doesn't seem like a very safe way to access properties. It appears like there can be cases where props.route.params
is undefined
. Is that a valid case? Should this use lodashGet
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you are right. If you just open https://new.expensify.com/details
without the param login
, it crashes. I'll spin a small PR to fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, this feels low priority, I don't know how a user ended up with the URL without the parameter.
🚀 Deployed to staging by @marcaaron in version: 1.1.81-0 🚀
|
🚀 Deployed to production by @roryabraham in version: 1.1.82-5 🚀
|
Details
This is fixing two cases where we can end up with a crash after tapping a user's avatar to see the personal details:
Problem 1: Only Android/IOS - tapping the avatar after opening a conversation with an account that doesn't exist
Bug and solution described here: #9182 (comment)
Problem 2: You tapped too fast and the request
PersonalDetails_GetForEmails
has not finished yetWhen we select a new contact from the search panel, the following API requests happen:
CreateChatReport
to create the chatPersonalDetails_GetForEmails
to get the personal detailsIf the user clicks the avatar in the conversation that opens the personal details panels before
PersonalDetails_GetForEmails
finishes, the app crashes.Note on offline behaviour: You cannot create a new chat while offline, so I think there is nothing to test when offline
Fixed Issues
$ #9182
#9182 (comment)
Tests
Problem 1: Only Android/IOS
PersonalDetails_GetForEmails
has not finished yet)Problem 2: You tapped too fast and the request
PersonalDetails_GetForEmails
has not finished yetIf you have the PHP Api running locally, it is very easy to reproduce by just adding a
sleep(10);
in the part of the API handling the commandPersonalDetails_GetForEmails
Another way of making it easier to reproduce is using
chrome tools > network > throttle
QA
Same steps as Tests, and you can try using
chrome tools > network > throttle
to make it easier to click the avatar before the request has finished.PR Review Checklist
Contributor (PR Author) Checklist
### Fixed Issues
section aboveTests
sectionQA steps
sectiontoggleReport
and notonIconClick
)src/languages/*
filesSTYLE.md
) were followedAvatar
, I verified the components usingAvatar
are working as expected)/** comment above it */
displayName
propertythis
properly so there are no scoping issues (i.e. foronClick={this.submit}
the methodthis.submit
should be bound tothis
in the constructor)this
are necessary to be bound (i.e. avoidthis.submit = this.submit.bind(this);
ifthis.submit
is never passed to a component event handler likeonClick
)StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG
)Avatar
is modified, I verified thatAvatar
is working as expected in all cases)PR Reviewer Checklist
### Fixed Issues
section aboveTests
sectionQA steps
sectiontoggleReport
and notonIconClick
).src/languages/*
filesSTYLE.md
) were followed/** comment above it */
displayName
propertythis
properly so there are no scoping issues (i.e. foronClick={this.submit}
the methodthis.submit
should be bound tothis
in the constructor)this
are necessary to be bound (i.e. avoidthis.submit = this.submit.bind(this);
ifthis.submit
is never passed to a component event handler likeonClick
)StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG
)Avatar
is modified, I verified thatAvatar
is working as expected in all cases)QA Steps
Screenshots
Web
Mobile Web
Simulator.Screen.Recording.-.iPhone.13.-.2022-06-10.at.11.02.39.mp4
Desktop
Screen.Recording.2022-06-10.at.11.00.09.AM.mov
iOS
Simulator.Screen.Recording.-.iPhone.13.-.2022-06-10.at.10.51.28.mp4
Android
XRecorder_10062022_103832.mp4