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

Remove unreadActionCount & Improve Global Indicators #10739

Merged
merged 17 commits into from
Sep 2, 2022

Conversation

marcaaron
Copy link
Contributor

@marcaaron marcaaron commented Sep 1, 2022

Details

Removes unreadActionCount in favor of boolean unread status

Fixed Issues

$ https://github.com/Expensify/Expensify/issues/226118
$ #10768

Tests

Testing Global Unread Indicator

  1. Start a chat between User A and User B.
  2. Ensure User A is not looking at the chat.
  3. Leave a comment on the chat as User B.
  4. Verify the global indicator (app icon or browser page title) has increased by 1
  5. Leave another comment
  6. Verify the global indicator has not changed
  7. As User C add another comment to a chat that User A is not looking at
  8. Verify the global indicator increases by 1
  9. As User A visit the chat with User B
  10. Verify the global indicator decreases by 1
  11. As user A visit the chat with User C
  12. Verify the global indicator decreases by 1

Testing Unread LHN Status, “New Messages” badge, and New Line Indicator

  1. Start a chat between User A and User B.
  2. Ensure User A is not looking at the chat.
  3. Send a message as User B
  4. Verify the LHN row shows in bold for User A to indicate unread messages
  5. Visit the chat as User A and verify the LHN row no longer shows in bold
  6. Verify there is a “----- New” line above the message sent by User B
  7. Scroll up and verify that the “New Messages” button appears floating above the content.
  8. Verify that tapping this button will scroll you to the bottom of the chat but not clear the “---- New” line marker.
  9. Mark a comment as “unread”
  10. Verify the “---- New” line marker changes to the place above the comment marked as unread
  11. Mark as unread comments above and below the existing new marker
  12. Verify the marker appears in the correct position each time
  13. While the new marker is active leave a comment as User A
  14. Verify the new marker and new messages badge both disappear
  15. Mark another comment as unread.
  16. Navigate away from the chat
  17. Navigate back to the chat
  18. Verify the chat in the LHN shows as read
  19. Verify the New Line marker and new messages badge is still present
  20. Navigate away one more time and back
  21. Verify the new marker and new messages badge both disappear
  22. Mark another comment as unread.
  23. Navigate away from the chat
  24. Navigate back to the chat
  25. Minimize the app and reopen it
  26. Verify the new marker and new message badge both disappear
  27. Switch to a mobile view (small screen) and mark a message as unread
  28. Tap the header to reveal the LHN
  29. Verify the chat in the LHN shows as “unread”
  30. Tap the chat
  31. Verify the new marker and badge are present
  32. Tap the header to reveal the LHN
  33. Verify the chat in the LHN shows as “read”
  34. Tap the chat
  35. Verify the new marker and badge are no longer present.
  36. Scroll up in the chat so that last comment is out of view
  37. Leave a comment as User B
  38. Verify the “new messages badge” shows for User A
  39. Scroll down and verify the “new line marker” shows for User A in the correct position.
  40. Scroll back up and leave another comment as User B
  41. Scroll down as User A
  42. Verify the new marker is in the same position as it was before
  • Verify that no errors appear in the JS console

PR Review Checklist

Contributor (PR Author) Checklist

  • I linked the correct issue in the ### Fixed Issues section above
  • I wrote clear testing steps that cover the changes made in this PR
    • I added steps for local testing in the Tests section
    • I added steps for Staging and/or Production testing in the QA steps section
    • I added steps to cover failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
  • I included screenshots or videos for tests on all platforms
  • I ran the tests on all platforms & verified they passed on:
    • iOS / native
    • Android / native
    • iOS / Safari
    • Android / Chrome
    • MacOS / Chrome
    • MacOS / Desktop
  • I verified there are no console errors (if there's a console error not related to the PR, report it or open an issue for it to be fixed)
  • I followed proper code patterns (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick)
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text shown in the product was added in all src/languages/* files
    • I verified any copy / text that was added to the app is correct English and approved by marketing by tagging the marketing team on the original GH to get the correct copy.
    • I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I followed the guidelines as stated in the Review Guidelines
  • I tested other components that can be impacted by my changes (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar are working as expected)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.js or at the top of the file that uses the constant) are defined as such
  • If a new component is created I verified that:
    • A similar component doesn't exist in the codebase
    • All props are defined accurately and each prop has a /** comment above it */
    • Any functional components have the displayName property
    • The file is named correctly
    • The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone
    • The only data being stored in the state is data necessary for rendering and nothing else
    • For Class Components, any internal methods passed to components event handlers are bound to this properly so there are no scoping issues (i.e. for onClick={this.submit} the method this.submit should be bound to this in the constructor)
    • Any internal methods bound to this are necessary to be bound (i.e. avoid this.submit = this.submit.bind(this); if this.submit is never passed to a component event handler like onClick)
    • All JSX used for rendering exists in the render method
    • The component has the minimum amount of code necessary for its purpose, and it is broken down into smaller components in order to separate concerns and functions
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • I have checked off every checkbox in the PR author checklist, including those that don't apply to this PR.

PR Reviewer Checklist

The Contributor+ will copy/paste it into a new comment and complete it after the author checklist is completed

  • I have verified the author checklist is complete (all boxes are checked off).
  • I verified the correct issue is linked in the ### Fixed Issues section above
  • I verified testing steps are clear and they cover the changes made in this PR
    • I verified the steps for local testing are in the Tests section
    • I verified the steps for Staging and/or Production testing are in the QA steps section
    • I verified the steps cover any possible failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
  • I checked that screenshots or videos are included for tests on all platforms
  • I verified tests pass on all platforms & I tested again on:
    • iOS / native
    • Android / native
    • iOS / Safari
    • Android / Chrome
    • MacOS / Chrome
    • MacOS / Desktop
  • I verified there are no console errors (if there's a console error not related to the PR, report it or open an issue for it to be fixed)
  • I verified proper code patterns were followed (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick).
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text shown in the product was added in all src/languages/* files
    • I verified any copy / text that was added to the app is correct English and approved by marketing by tagging the marketing team on the original GH to get the correct copy.
    • I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I verified that this PR follows the guidelines as stated in the Review Guidelines
  • I verified other components that can be impacted by these changes have been tested, and I retested again (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar have been tested & I retested again)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.js or at the top of the file that uses the constant) are defined as such
  • If a new component is created I verified that:
    • A similar component doesn't exist in the codebase
    • All props are defined accurately and each prop has a /** comment above it */
    • Any functional components have the displayName property
    • The file is named correctly
    • The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone
    • The only data being stored in the state is data necessary for rendering and nothing else
    • For Class Components, any internal methods passed to components event handlers are bound to this properly so there are no scoping issues (i.e. for onClick={this.submit} the method this.submit should be bound to this in the constructor)
    • Any internal methods bound to this are necessary to be bound (i.e. avoid this.submit = this.submit.bind(this); if this.submit is never passed to a component event handler like onClick)
    • All JSX used for rendering exists in the render method
    • The component has the minimum amount of code necessary for its purpose, and it is broken down into smaller components in order to separate concerns and functions
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR.

QA Steps

  • Verify that no errors appear in the JS console

Screenshots

Web

Mobile Web

Desktop

iOS

Android

@marcaaron marcaaron self-assigned this Sep 1, 2022
@marcaaron marcaaron marked this pull request as ready for review September 2, 2022 07:33
@marcaaron marcaaron requested a review from a team as a code owner September 2, 2022 07:33
@melvin-bot melvin-bot bot requested review from danieldoglas and removed request for a team September 2, 2022 07:33
@marcaaron
Copy link
Contributor Author

Okaiee this is ready for reviews now :D

Copy link
Contributor

@mountiny mountiny left a comment

Choose a reason for hiding this comment

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

code looks clean, great job, going to test now!

cead22
cead22 previously approved these changes Sep 2, 2022

// Stash the unread action counts for each report
const unreadActionCounts = {};
// Stash the reports
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// Stash the reports

updateUnread(totalCount);
}, 1000, {leading: false});
}, 300, {leading: false});
Copy link
Contributor

Choose a reason for hiding this comment

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

Curious why this changed from 1000 to 300

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh no particular reason - this is leftover from testing and I think not needed.

return;
}

const totalCount = _.reduce(reports, (total, report) => total + (ReportUtils.isUnread(report) ? 1 : 0), 0);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
const totalCount = _.reduce(reports, (total, report) => total + (ReportUtils.isUnread(report) ? 1 : 0), 0);
const totalCount = _.filter(reports, ReportUtils.isUnread).length

NAB, just a suggestion

@@ -214,6 +212,9 @@ class ReportActionsView extends React.Component {
} else if (this.state.newMarkerSequenceNumber === 0) {
this.setState({newMarkerSequenceNumber: currentLastSequenceNumber});
}
} else if (this.state.newMarkerSequenceNumber === 0) {
// The report is not in view so we will update the newMarkerSequenceNumber
Copy link
Contributor

Choose a reason for hiding this comment

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

Update to the last one so nothing shows as unread?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah so, the condition here is:

  • report isn't in view
  • a new message appeared from someone besides the current user
  • no previous marker is set

So we will update the new marker with this sequenceNumber. This basically fixes a bug found by QA here: #10768

@mountiny
Copy link
Contributor

mountiny commented Sep 2, 2022

@marcaaron Tests well 🎉

But a bit confused about these steps:

  • Verify that tapping this button will scroll you to the bottom of the chat but not clear the “---- New” line marker.
  • Mark a comment as “unread”
  • Verify the “---- New” line marker appears
  • Mark as unread comments above and below the existing new marker
  • Verify the marker appears in the correct position each time
  • While the new marker is active leave a comment as User A

So click the New Message, scorll down, dont errase the ---- New line marker. Mark comment as unread and the marker should appear? Did you mean the marker should change to the place above the comment marked as unread.

What is a bit unintuitive for me is that I mark old comment as unread and then I mark newer comment as unread but the New marker is moved to the newer comment. Should the marker not stay with the older comment marked as unread as it is technically the oldest comment "I did not read"?

cead22
cead22 previously approved these changes Sep 2, 2022
@@ -214,6 +212,10 @@ class ReportActionsView extends React.Component {
} else if (this.state.newMarkerSequenceNumber === 0) {
this.setState({newMarkerSequenceNumber: currentLastSequenceNumber});
}
} else if (this.state.newMarkerSequenceNumber === 0) {
// The report is not in view and we received a comment from another user while the new marker is not set
// so we wil set the new marker now.
Copy link
Contributor

Choose a reason for hiding this comment

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

<3

mountiny
mountiny previously approved these changes Sep 2, 2022
Copy link
Contributor

@mountiny mountiny left a comment

Choose a reason for hiding this comment

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

NAB: Typo

src/pages/home/report/ReportActionsView.js Outdated Show resolved Hide resolved
@marcaaron
Copy link
Contributor Author

Mark comment as unread and the marker should appear? Did you mean the marker should change to the place above the comment marked as unread.

yes exactly this! I updated the steps to make it clearer, thanks!

What is a bit unintuitive for me is that I mark old comment as unread and then I mark newer comment as unread but the New marker is moved to the newer comment. Should the marker not stay with the older comment marked as unread as it is technically the oldest comment "I did not read"?

No, in the case of manually marking a comment as unread the user is telling us they want to manually override the unread position.

@marcaaron marcaaron dismissed stale reviews from mountiny and cead22 via e92d5c1 September 2, 2022 10:26
@marcaaron
Copy link
Contributor Author

Updated thanks for the reviews! 🙇‍♂️

Copy link
Contributor

@danieldoglas danieldoglas left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@thienlnam thienlnam left a comment

Choose a reason for hiding this comment

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

This has been simplified quite a bit, thanks for these changes!

Copy link
Contributor

@mountiny mountiny left a comment

Choose a reason for hiding this comment

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

No, in the case of manually marking a comment as unread the user is telling us they want to manually override the unread position.

Coolio! Thanks

@marcaaron marcaaron merged commit 8ce2774 into main Sep 2, 2022
@marcaaron marcaaron deleted the marcaaron-removeUnreadActionCount branch September 2, 2022 11:13
@melvin-bot melvin-bot bot added the Emergency label Sep 2, 2022
@melvin-bot
Copy link

melvin-bot bot commented Sep 2, 2022

@marcaaron looks like this was merged without passing tests. Please add a note explaining why this was done and remove the Emergency label if this is not an emergency.

@OSBotify
Copy link
Contributor

OSBotify commented Sep 2, 2022

✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release.

@marcaaron
Copy link
Contributor Author

Did pass the tests.

@OSBotify
Copy link
Contributor

OSBotify commented Sep 5, 2022

🚀 Deployed to staging by @marcaaron in version: 1.1.97-0 🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 failure ❌
🕸 web 🕸 success ✅

@Julesssss
Copy link
Contributor

Tested flawlessly for me on staging. Nice work.
Screenshot 2022-09-08 at 00 39 55
Screenshot 2022-09-08 at 00 36 24
Screenshot 2022-09-08 at 00 34 57
Screenshot 2022-09-08 at 00 24 48
Screenshot_20220908-004142

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

Successfully merging this pull request may close these issues.

7 participants