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

Simplify new line indicator and message badge #10582

Merged
merged 7 commits into from
Aug 31, 2022

Conversation

marcaaron
Copy link
Contributor

@marcaaron marcaaron commented Aug 25, 2022

Details

Fixed Issues

$ https://github.com/Expensify/Expensify/issues/224876

Tests

  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 appears
  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

Same as Test Steps

  • Verify that no errors appear in the JS console

Screenshots

Web

Mobile Web

Desktop

iOS

Android

@marcaaron marcaaron self-assigned this Aug 25, 2022
@marcaaron marcaaron changed the title [WIP] Simplify new line indicator and message badge [HOLD Web-Expensify/pull/34696] Simplify new line indicator and message badge Aug 26, 2022
@marcaaron marcaaron changed the title [HOLD Web-Expensify/pull/34696] Simplify new line indicator and message badge [HOLD Web-Expensify 34696] Simplify new line indicator and message badge Aug 26, 2022
@marcaaron
Copy link
Contributor Author

This PR is required to test atm as I discovered a regression caused by the OpenReport changes.

@marcaaron
Copy link
Contributor Author

This is still on HOLD but testing well so marking it as ready.

@marcaaron marcaaron marked this pull request as ready for review August 29, 2022 09:37
@marcaaron marcaaron requested a review from a team as a code owner August 29, 2022 09:37
@melvin-bot melvin-bot bot requested review from amyevans and removed request for a team August 29, 2022 09:38
@@ -11,14 +11,8 @@ import withLocalize, {withLocalizePropTypes} from '../../../../components/withLo
import FloatingMessageCounterContainer from './FloatingMessageCounterContainer';

const propTypes = {
/** Count of new messages to show in the badge */
count: PropTypes.number,

/** Whether the marker is active */
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
/** Whether the marker is active */
/** Whether the New Messages indicator is active */

Should we rename this file since it's no longer showing counts?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Missed the comment below this but going to raise a separate PR to clean up the file naming


/** Callback to be called when user closes the badge */
onClose: PropTypes.func,
isActive: PropTypes.bool,

/** Callback to be called when user clicks the marker */
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
/** Callback to be called when user clicks the marker */
/** Callback to be called when user clicks the New Messages indicator */

Not sure if these comments were copy paste from the new messages marker, or if we're calling both things a marker, but I think it's good to differentiate for clarity

</Text>
</View>
)}
shouldRemoveRightBorderRadius
/>
<Button
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this mean the new messages indicator can't be closed with an X? Why the change? Just curious

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Largely just a matter of simplification and nobody fought to keep it. In the new design, the visibility of the component is enabled based on these conditions alone:

  • The new marker is set
  • The user is scrolled up past a certain distance

Doc here -> https://docs.google.com/document/d/1gvPDhGTxdcu-0lQxvruQnQJfJBrAmSjHieKciucV8eo/edit#bookmark=id.v1smzjvcr8ra

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you think it's something we'll miss? Should be relatively easy to add it back in if so. I kinda found it just made the code harder to understand and not really all that useful of a feature.

Copy link
Contributor

Choose a reason for hiding this comment

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

No I like this change actually, this was just my first time looking at this code, and this is a change I "picked up" that I wasn't expecting, and I wanted to make sure I understood it correctly, since I'm still kind of a noob when it comes to reviews in App

@@ -134,8 +134,8 @@ class ReportActionsList extends React.Component {
item,
index,
}) {
const shouldDisplayNewIndicator = this.props.report.newMarkerSequenceNumber > 0
&& item.action.sequenceNumber === this.props.report.newMarkerSequenceNumber;
const shouldDisplayNewIndicator = this.props.newMarkerSequenceNumber > 0
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the first condition needed here? can both sequenceNumber and newMarkerSequenceNumber be equal to zero simultaneously?

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 we explicitly set this to zero, could we set to null to indicate the lack of a value here instead? NAB but since zero could be a valid sequence number (just based on the data type), null could be a little cleaner

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure if I understand the question. But the newMarkerSequenceNumber can be equal to zero and the created action has a sequenceNumber of 0. So we do this to avoid showing the marker for the "created" action. We don't want to show the marker when the last read sequenceNumber is 0.

As for using null instead, I don't have strong feelings on it, but maybe we can add a comment here at least to explain what I just mentioned.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Let me know if this comment helps. Or if you feel strongly that we should use null. I'm inclined to leave it since everything is working well for me.

Copy link
Contributor

Choose a reason for hiding this comment

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

The comment makes sense to me, so I agree it's 👌 to leave it using 0

@@ -174,53 +176,79 @@ class ReportActionsView extends React.Component {
}

componentDidUpdate(prevProps) {
const isReportFullyVisible = this.getIsReportFullyVisible();

// NETWORK CHANGE DETECTED
Copy link
Contributor

Choose a reason for hiding this comment

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

Not a fan of these capitalized comments, can we make them lowercase and keep consistency with all other comments, or use variable to communicate this? Eg,

const bool wasNetworkChangeDetected = lodashGet(prevProps.network, 'isOffline') && !lodashGet(this.props.network, 'isOffline');
...
if (wasNetworkChangeDetected) {
...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

With the comments I wanted to create a sense that these are discrete "events" or "situations" we might encounter.

I had a draft where each of these was moved to a method like checkIfNetworkChangedAndRefetch(), but that felt like something Uncle Bob would do and maybe overkill. I eventually just decided to do something obvious and ugly. Will try the variable thing! Thanks!

Copy link
Contributor

Choose a reason for hiding this comment

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

Making these comments not be all uppercase already solves my concern. I think we should follow our guidelines, so others can as well. If we break consistency for our comments, contributors may start doing the same

Copy link
Contributor

Choose a reason for hiding this comment

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

And to be clear, I did appreciate the comments that are in this code, as it would've been much harder to follow without them

Comment on lines 224 to 225
// REPORT PREVIOUSLY HIDDEN BY SIDEBAR/LHN OR VIEW EXPANDED FROM MOBILE TO DESKTOP LAYOUT
// We update the new marker position, mark the report as read, and fetch new report actions
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
// REPORT PREVIOUSLY HIDDEN BY SIDEBAR/LHN OR VIEW EXPANDED FROM MOBILE TO DESKTOP LAYOUT
// We update the new marker position, mark the report as read, and fetch new report actions
// If the report was previously hidden by the side bar, or the view is expanded from mobile to desktop layout
// we update the new marker position, mark the report as read, and fetch new report actions

Report.openReport(this.props.report.reportID);
}

// REPORT PREVIOUSLY OPEN BUT USER NAVIGATED TO SIDEBAR/LHN
// When the user swipes back on the report or navigates to the LHN the ReportActionsView doesn’t unmount and just remains hidden.
Copy link
Contributor

Choose a reason for hiding this comment

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

How's "swipes back on the report" different from "navigates to the LHN"?

Suggested change
// When the user swipes back on the report or navigates to the LHN the ReportActionsView doesnt unmount and just remains hidden.
// When the user swipes back on the report or navigates to the LHN the ReportActionsView doesn't unmount and just remains hidden.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll be more general here. I meant swipe or tap the back button. Both would be ways of navigating to the LHN.

Report.openReport(this.props.report.reportID);
}

// REPORT PREVIOUSLY OPEN BUT USER NAVIGATED TO SIDEBAR/LHN
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
// REPORT PREVIOUSLY OPEN BUT USER NAVIGATED TO SIDEBAR/LHN

}

// REPORT COMMENT MANUALLY MARKED AS UNREAD
// Checks to see if a report comment has been manually "marked as read". All other times when the lastReadSequenceNumber
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
// Checks to see if a report comment has been manually "marked as read". All other times when the lastReadSequenceNumber
// Checks to see if a report comment has been manually "marked as unread". All other times when the lastReadSequenceNumber

this.setState({newMarkerSequenceNumber: 0});
}

// REPORT COMMENT MANUALLY MARKED AS UNREAD
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
// REPORT COMMENT MANUALLY MARKED AS UNREAD

Copy link
Contributor

@amyevans amyevans left a comment

Choose a reason for hiding this comment

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

I don't have a lot of context for these changes, but they test well for me locally, and the logic and comments make sense to me

@@ -134,8 +134,8 @@ class ReportActionsList extends React.Component {
item,
index,
}) {
const shouldDisplayNewIndicator = this.props.report.newMarkerSequenceNumber > 0
&& item.action.sequenceNumber === this.props.report.newMarkerSequenceNumber;
const shouldDisplayNewIndicator = this.props.newMarkerSequenceNumber > 0
Copy link
Contributor

Choose a reason for hiding this comment

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

The comment makes sense to me, so I agree it's 👌 to leave it using 0

@marcaaron marcaaron changed the title [HOLD Web-Expensify 34696] Simplify new line indicator and message badge Simplify new line indicator and message badge Aug 31, 2022
@marcaaron marcaaron merged commit bc57fff into main Aug 31, 2022
@marcaaron marcaaron deleted the marcaaron-simplifyNewLineAndCounter branch August 31, 2022 13:20
@OSBotify
Copy link
Contributor

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

@OSBotify
Copy link
Contributor

OSBotify commented Sep 1, 2022

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

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

@roryabraham
Copy link
Contributor

Going to try reverting this to see if it's the cause for #10751

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.

5 participants