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

[HOLD for payment 2022-12-20] [$250] Offline default avatar doesn't update after connecting to the internet reported by @thesahindia #12712

Closed
kavimuru opened this issue Nov 14, 2022 · 39 comments
Assignees
Labels
Bug Something is broken. Auto assigns a BugZero manager. External Added to denote the issue can be worked on by a contributor Reviewing Has a PR in review Weekly KSv2

Comments

@kavimuru
Copy link

kavimuru commented Nov 14, 2022

If you haven’t already, check out our contributing guidelines for onboarding and email [email protected] to request to join our Slack channel!


Action Performed:

  1. Login to an account which has more than 20 chats
  2. Disconnect the internet connection
  3. Navigate to search page
  4. Scroll and select a chat with offline default avatar
  5. Enable the internet connection

Expected Result:

The avatar should update and you should see the default colour avatar or custom image if the profile has one

Actual Result:

It doesn't update, you have to refresh the page

Workaround:

unknown

Platform:

Where is this issue occurring?

  • Web
  • iOS
  • Android
  • Desktop App
  • Mobile Web

Version Number: 1.2.27-3
Reproducible in staging?: y
Reproducible in production?: y
Email or phone of affected tester (no customers):
Logs: https://stackoverflow.com/c/expensify/questions/4856
Notes/Photos/Videos:

video_20221114_035336_edit.mp4
Recording.925.mp4

Expensify/Expensify Issue URL:
Issue reported by: @thesahindia
Slack conversation: https://expensify.slack.com/archives/C049HHMV9SM/p1668379245649689

View all open jobs on GitHub

Upwork Automation - Do Not Edit

@kavimuru kavimuru added Daily KSv2 Bug Something is broken. Auto assigns a BugZero manager. labels Nov 14, 2022
@melvin-bot
Copy link

melvin-bot bot commented Nov 14, 2022

Triggered auto assignment to @laurenreidexpensify (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details.

@laurenreidexpensify
Copy link
Contributor

@laurenreidexpensify laurenreidexpensify added the External Added to denote the issue can be worked on by a contributor label Nov 15, 2022
@melvin-bot
Copy link

melvin-bot bot commented Nov 15, 2022

Current assignee @laurenreidexpensify is eligible for the External assigner, not assigning anyone new.

@melvin-bot
Copy link

melvin-bot bot commented Nov 15, 2022

Triggered auto assignment to Contributor-plus team member for initial proposal review - @parasharrajat (External)

@melvin-bot melvin-bot bot added the Help Wanted Apply this label when an issue is open to proposals by contributors label Nov 15, 2022
@melvin-bot
Copy link

melvin-bot bot commented Nov 15, 2022

Triggered auto assignment to @yuwenmemon (External), see https://stackoverflow.com/c/expensify/questions/7972 for more details.

@melvin-bot melvin-bot bot changed the title Offline default avatar doesn't update after connecting to the internet reported by @thesahindia [$250] Offline default avatar doesn't update after connecting to the internet reported by @thesahindia Nov 15, 2022
@hungvu193
Copy link
Contributor

hungvu193 commented Nov 15, 2022

Proposal
In Avatar.js component when internet connection is disconnected, the function onError is called and set the state imageError to true, but when the internet is online again, there was no function to make this state to false, that's why the avatar didn't update.

{_.isFunction(this.props.source) || this.state.imageError
? (
<Icon
src={this.state.imageError ? this.props.fallbackIcon : this.props.source}
height={iconSize}
width={iconSize}
fill={this.state.imageError ? themeColors.offline : this.props.fill}
/>
)
: (
<Image
source={{uri: this.props.source}}
defaultSource={getAvatarDefaultSource(this.props.source)}
style={imageStyle}
onError={() => this.setState({imageError: true})}
/>
)}

Solution
We need to add componentDidUpdate and check when ever the internet connection is back and decide to reload the avatar.

From 3e223e2e2e78ece0109bbe2c8826083c21300b6c Mon Sep 17 00:00:00 2001
From: Hans <[email protected]>
Date: Tue, 15 Nov 2022 19:05:55 +0700
Subject: [PATCH] make avatar update

---
 src/components/Avatar.js | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/src/components/Avatar.js b/src/components/Avatar.js
index aa4f6dbf9..eec70dd11 100644
--- a/src/components/Avatar.js
+++ b/src/components/Avatar.js
 import {Image, View} from 'react-native';
 import PropTypes from 'prop-types';
 import _ from 'underscore';
+import lodashGet from 'lodash/get';
 import stylePropTypes from '../styles/stylePropTypes';
 import Icon from './Icon';
 import themeColors from '../styles/themes/default';
@@ -9,6 +10,8 @@ import CONST from '../CONST';
 import * as StyleUtils from '../styles/StyleUtils';
 import * as Expensicons from './Icon/Expensicons';
 import getAvatarDefaultSource from '../libs/getAvatarDefaultSource';
+import {withNetwork} from './OnyxProvider';
+import networkPropTypes from './networkPropTypes';
 
 const propTypes = {
     /** Source for the avatar. Can be a URL or an icon. */
@@ -29,6 +32,9 @@ const propTypes = {
 
     /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */
     fallbackIcon: PropTypes.func,
+
+    /** Props to detect online status */
+    network: networkPropTypes.isRequired,
 };
 
 const defaultProps = {
@@ -48,6 +54,14 @@ class Avatar extends PureComponent {
         };
     }
 
+    componentDidUpdate(prevProps) {
+        if (
+            lodashGet(prevProps.network, 'isOffline') === true && lodashGet(this.props.network, 'isOffline') === false
+        ) {
+            this.setState({imageError: false});
+        }
+    }
+
     render() {
         if (!this.props.source) {
             return null;
@@ -86,4 +100,4 @@ class Avatar extends PureComponent {
 
 Avatar.defaultProps = defaultProps;
 Avatar.propTypes = propTypes;
-export default Avatar;
+export default withNetwork()(Avatar);
-- 
2.31.0

Result:

Screen.Recording.2022-11-15.at.19.08.07.mov

@yuwenmemon
Copy link
Contributor

Hmmm... @hungvu193 I don't think that's the behavior we're looking for here. The image avatars should still stay even if you go offline. We shouldn't remove data that we already have if that makes sense.

In other words, we should only be recovering from the avatar "error state" - not purposefully sending it to an error state when we go offline. The error state should only come up if we've failed to grab the original avatar - does that make sense?

@hungvu193
Copy link
Contributor

Hmmm... @hungvu193 I don't think that's the behavior we're looking for here. The image avatars should still stay even if you go offline. We shouldn't remove data that we already have if that makes sense.

In other words, we should only be recovering from the avatar "error state" - not purposefully sending it to an error state when we go offline. The error state should only come up if we've failed to grab the original avatar - does that make sense?

Makes sense, I think I need to implement shouldComponentUpdate to check that.

@hungvu193
Copy link
Contributor

@yuwenmemon
Updated proposal
I updated the shouldComponentUpdate and componentDidUpdate to avoid redundant render.

From fa505d1945c9dd1bf79b57488dd2639a9228d8c1 Mon Sep 17 00:00:00 2001
From: Hans <[email protected]>
Date: Tue, 15 Nov 2022 19:05:55 +0700
Subject: [PATCH] make avatar update

---
 src/components/Avatar.js | 41 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 38 insertions(+), 3 deletions(-)

diff --git a/src/components/Avatar.js b/src/components/Avatar.js
index aa4f6dbf9..2967fd454 100644
--- a/src/components/Avatar.js
+++ b/src/components/Avatar.js
@@ -1,7 +1,8 @@
-import React, {PureComponent} from 'react';
+import React, {Component, PureComponent} from 'react';
 import {Image, View} from 'react-native';
 import PropTypes from 'prop-types';
 import _ from 'underscore';
+import lodashGet from 'lodash/get';
 import stylePropTypes from '../styles/stylePropTypes';
 import Icon from './Icon';
 import themeColors from '../styles/themes/default';
@@ -9,6 +10,8 @@ import CONST from '../CONST';
 import * as StyleUtils from '../styles/StyleUtils';
 import * as Expensicons from './Icon/Expensicons';
 import getAvatarDefaultSource from '../libs/getAvatarDefaultSource';
+import {withNetwork} from './OnyxProvider';
+import networkPropTypes from './networkPropTypes';
 
 const propTypes = {
     /** Source for the avatar. Can be a URL or an icon. */
@@ -29,6 +32,9 @@ const propTypes = {
 
     /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */
     fallbackIcon: PropTypes.func,
+
+    /** Props to detect online status */
+    network: networkPropTypes.isRequired,
 };
 
 const defaultProps = {
@@ -40,7 +46,7 @@ const defaultProps = {
     fallbackIcon: Expensicons.FallbackAvatar,
 };
 
-class Avatar extends PureComponent {
+class Avatar extends Component {
     constructor(props) {
         super(props);
         this.state = {
@@ -48,6 +54,35 @@ class Avatar extends PureComponent {
         };
     }
 
+    shouldComponentUpdate(nextProps, nextState) {
+        if (
+            lodashGet(this.props.network, 'isOffline')
+                  && !lodashGet(nextProps.network, 'isOffline')
+        ) {
+            return true;
+        }
+        if (this.props.source !== nextProps.source) {
+            return true;
+        }
+        if (this.state.imageError !== nextState.imageError) {
+            return true;
+        }
+
+        return false;
+    }
+
+    componentDidUpdate(prevProps) {
+        if (!this.state.imageError) {
+            return;
+        }
+        if (
+            lodashGet(prevProps.network, 'isOffline') === true
+            && lodashGet(this.props.network, 'isOffline') === false
+        ) {
+            this.setState({imageError: false});
+        }
+    }
+
     render() {
         if (!this.props.source) {
             return null;
@@ -86,4 +121,4 @@ class Avatar extends PureComponent {
 
 Avatar.defaultProps = defaultProps;
 Avatar.propTypes = propTypes;
-export default Avatar;
+export default withNetwork()(Avatar);
-- 
2.31.0

Result:
https://user-images.githubusercontent.com/16502320/202076907-9e4b5e03-be16-4f11-bb51-01cd896e33a6.mov

@Emz27
Copy link

Emz27 commented Nov 16, 2022

Proposal

  • initially render both placeholder and user image. User avatar on top of the placeholder that acts as an overlay with transparent background so that the placeholder can be seen while the user avatar is still loading .Set userAvatarLoaded state on load of user avatar and this state will determine if we need to unmount the placeholder.

I suggest that we dont unmount the user avatar or use any offline handlers because it might be inaccurate at times and it just prevent the image native handler that resumes image loading when user restored the connection

@parasharrajat
Copy link
Member

I think @hungvu193 's approach is correct. We can handle the clean up in the PR.

cc: @yuwenmemon

🎀 👀 🎀 C+ reviewed

@yuwenmemon
Copy link
Contributor

Thanks, @parasharrajat - Agreed. Assigning @hungvu193

@melvin-bot melvin-bot bot removed the Help Wanted Apply this label when an issue is open to proposals by contributors label Nov 16, 2022
@melvin-bot
Copy link

melvin-bot bot commented Nov 16, 2022

📣 @hungvu193 You have been assigned to this job by @yuwenmemon!
Please apply to this job in Upwork and leave a comment on the Github issue letting us know when we can expect a PR to be ready for review 🧑‍💻
Keep in mind: Code of Conduct | Contributing 📖

@Emz27
Copy link

Emz27 commented Nov 16, 2022

@hungvu193 's updated proposal might cause a regression on <SubscriptAvatar because he used shouldComponentUpdate with just 3 condition returning true and default to false.

check the components that uses the SubscriptAvatar because I assume that SubscriptAvatar have dynamic props
https://github.com/Expensify/App/blob/ef0df807dd60c5cddea86e704a70ba7e27f98b5c/src/components/OptionRow.js#L184#L192

I suggest to add the rest of the property of avatar returning true (risky) or just dont use shouldComponentUpdate at all

@parasharrajat
Copy link
Member

I think we will not need shouldComponentUpdate. This will be cleared in the PR.

@hungvu193
Copy link
Contributor

Cool. I will create a PR and test it carefully

@yuwenmemon
Copy link
Contributor

Thanks, @hungvu193 and @parasharrajat - just a heads up that I'm going OOO until the 28th so hopefully @laurenreidexpensify will be able to help find another engineer to sign off and merge your PR when it's ready.

@hungvu193
Copy link
Contributor

#12808 is ready for review.
Since we need to use the withNetwork() to reload the image, I still think we need the shouldComponentUpdate to control the render, I added more condition to prevent the redundant render.

@laurenreidexpensify laurenreidexpensify added Weekly KSv2 and removed Daily KSv2 labels Nov 23, 2022
@laurenreidexpensify
Copy link
Contributor

PR Is merged

@parasharrajat
Copy link
Member

Not yet merged. Still discussing some changes on the PR.

@parasharrajat
Copy link
Member

@hungvu193 Can you please answer my questions so that I can wrap up the discussion and merge this PR asap?

@hungvu193
Copy link
Contributor

@parasharrajat sure, I'll get back to you shortly

@laurenreidexpensify
Copy link
Contributor

@parasharrajat @hungvu193 are we still waiting on anything further here?

@yuwenmemon
Copy link
Contributor

@laurenreidexpensify We're in the process of reviewing the PR here: #12808

@parasharrajat
Copy link
Member

parasharrajat commented Dec 9, 2022

We hurried in merging the PR and a check got missed. I still have something to confirm.

Please hold the payment for this task until #12808 (comment) is done.

@parasharrajat
Copy link
Member

There is no need to block the payment further. Thanks.

@melvin-bot melvin-bot bot added Weekly KSv2 Awaiting Payment Auto-added when associated PR is deployed to production and removed Weekly KSv2 labels Dec 13, 2022
@melvin-bot melvin-bot bot changed the title [$250] Offline default avatar doesn't update after connecting to the internet reported by @thesahindia [HOLD for payment 2022-12-20] [$250] Offline default avatar doesn't update after connecting to the internet reported by @thesahindia Dec 13, 2022
@melvin-bot
Copy link

melvin-bot bot commented Dec 13, 2022

The solution for this issue has been 🚀 deployed to production 🚀 in version 1.2.38-6 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:

If no regressions arise, payment will be issued on 2022-12-20. 🎊

After the hold period, please check if any of the following need payment for this issue, and if so check them off after paying:

  • External issue reporter
  • Contributor that fixed the issue
  • Contributor+ that helped on the issue and/or PR

As a reminder, here are the bonuses/penalties that should be applied for any External issue:

  • Merged PR within 3 business days of assignment - 50% bonus
  • Merged PR more than 9 business days after assignment - 50% penalty

@melvin-bot
Copy link

melvin-bot bot commented Dec 13, 2022

BugZero Checklist: The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed:

  • [@parasharrajat / @nkuoch] The PR that introduced the bug has been identified. Link to the PR:
  • [@parasharrajat / @nkuoch] The offending PR has been commented on, pointing out the bug it caused and why, so the author and reviewers can learn from the mistake. Link to comment:
  • [@parasharrajat / @nkuoch] A discussion in #expensify-bugs has been started about whether any other steps should be taken (e.g. updating the PR review checklist) in order to catch this type of bug sooner. Link to discussion:
  • [@laurenreidexpensify] A regression test has been added or updated so that the same bug will not reach production again. Link to the GH issue for creating the test here:

@laurenreidexpensify
Copy link
Contributor

@hungvu193 @parasharrajat @thesahindia apols, I thought I had hired everyone in Upwork already 🤦🏽‍♀️, have sent offers now and will issue payment as soon as accepted.

@hungvu193
Copy link
Contributor

@laurenreidexpensify I've accepted the offer

@melvin-bot melvin-bot bot added Daily KSv2 and removed Weekly KSv2 labels Dec 20, 2022
@laurenreidexpensify laurenreidexpensify added Weekly KSv2 and removed Awaiting Payment Auto-added when associated PR is deployed to production Daily KSv2 labels Dec 22, 2022
@laurenreidexpensify
Copy link
Contributor

Everyone has been paid, I'm downgrading this to weekly over the holidays so we can complete the outstanding steps in the new year when everyone is back online

@laurenreidexpensify
Copy link
Contributor

@nkuoch @parasharrajat bump here on completing these tasks

@parasharrajat
Copy link
Member

[@parasharrajat / @nkuoch] The PR that introduced the bug has been identified. Link to the PR:

#8852

[@parasharrajat / @nkuoch] The offending PR has been commented on, pointing out the bug it caused and why, so the author and reviewers can learn from the mistake. Link to comment:

#8852 (comment)

[@parasharrajat / @nkuoch] A discussion in #expensify-bugs has been started about whether any other steps should be taken (e.g. updating the PR review checklist) in order to catch this type of bug sooner. Link to discussion:

I think no discussion is needed as we have started to add Offline tests to the PRs as well.

@nkuoch Could you please edit the checklist #12712 and update it. Thanks.

@laurenreidexpensify
Copy link
Contributor

laurenreidexpensify commented Jan 11, 2023

Regression Test convo here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Something is broken. Auto assigns a BugZero manager. External Added to denote the issue can be worked on by a contributor Reviewing Has a PR in review Weekly KSv2
Projects
None yet
Development

No branches or pull requests

8 participants