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

[$500] mWeb - Chat - Tapping on new messages after marking a message unread leads to a blank page #31591

Closed
1 of 6 tasks
kbecciv opened this issue Nov 20, 2023 · 39 comments
Closed
1 of 6 tasks
Assignees
Labels
Bug Something is broken. Auto assigns a BugZero manager. External Added to denote the issue can be worked on by a contributor Monthly KSv2 Not a priority Reviewing Has a PR in review

Comments

@kbecciv
Copy link

kbecciv commented Nov 20, 2023

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


Version Number: 1.4.1.5
Reproducible in staging?: y
Reproducible in production?: y
If this was caught during regression testing, add the test name, ID and link from TestRail:
Email or phone of affected tester (no customers):
Logs: https://stackoverflow.com/c/expensify/questions/4856
Expensify/Expensify Issue URL:
Issue reported by: Applause - Internal Team
Slack conversation:

Action Performed:

  1. Navigate to https://staging.new.expensify.com/
  2. Log in
  3. Open a group conversation with a lot of messages
  4. Swipe to the middle of the page and mark any message as unread
  5. Swipe to the top of the page
  6. Tap on the "New messages" button

Expected Result:

User should be redirected to the unread message.

Actual Result:

Tapping on new messages after marking a message unread leads to a blank page

Workaround:

Unknown

Platforms:

Which of our officially supported platforms is this issue occurring on?

  • Android: Native
  • Android: mWeb Chrome
  • iOS: Native
  • iOS: mWeb Safari
  • MacOS: Chrome / Safari
  • MacOS: Desktop

Screenshots/Videos

Add any screenshot/video evidence

Bug6284625_1700519015921.Group_disappears.mp4

View all open jobs on GitHub

Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~017b6f62003e67ff2c
  • Upwork Job ID: 1726728849329471488
  • Last Price Increase: 2023-11-27
  • Automatic offers:
    • wlegolas | Contributor | 27951745
@kbecciv kbecciv added External Added to denote the issue can be worked on by a contributor Daily KSv2 Bug Something is broken. Auto assigns a BugZero manager. labels Nov 20, 2023
@melvin-bot melvin-bot bot changed the title mWeb - Chat - Tapping on new messages after marking a message unread leads to a blank page [$500] mWeb - Chat - Tapping on new messages after marking a message unread leads to a blank page Nov 20, 2023
Copy link

melvin-bot bot commented Nov 20, 2023

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

Copy link

melvin-bot bot commented Nov 20, 2023

Job added to Upwork: https://www.upwork.com/jobs/~017b6f62003e67ff2c

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

melvin-bot bot commented Nov 20, 2023

Bug0 Triage Checklist (Main S/O)

  • This "bug" occurs on a supported platform (ensure Platforms in OP are ✅)
  • This bug is not a duplicate report (check E/App issues and #expensify-bugs)
    • If it is, comment with a link to the original report, close the issue and add any novel details to the original issue instead
  • This bug is reproducible using the reproduction steps in the OP. S/O
    • If the reproduction steps are clear and you're unable to reproduce the bug, check with the reporter and QA first, then close the issue.
    • If the reproduction steps aren't clear and you determine the correct steps, please update the OP.
  • This issue is filled out as thoroughly and clearly as possible
    • Pay special attention to the title, results, platforms where the bug occurs, and if the bug happens on staging/production.
  • I have reviewed and subscribed to the linked Slack conversation to ensure Slack/Github stay in sync

Copy link

melvin-bot bot commented Nov 20, 2023

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

@wlegolas
Copy link
Contributor

wlegolas commented Nov 21, 2023

Proposal

Please re-state the problem that we are trying to solve in this issue.

mWeb - Chat - Tapping on new messages after marking a message unread leads to a blank page

What is the root cause of that problem?

There are two problems:

1- Showing a blank screen when clicking on the New Message button

The problem is related to the InvertedFlatList component because when the user scrolls and this action is not finished, when the user clicks on the "New messages" button, the action will scroll to the Report view bottom, but the scroll action is still occurring, that way the InvertedFlatList is not ready to show the information and show a blank screen.

Here's the code in the InvertedFlatList that handles the scrolls, you can see there is a delay of 250ms to finish the scroll action and this code was created to deal with a scroll for Web application because the react-native-web doesn't support the controlled props for the scroll.

const handleScroll = (event) => {
onScroll(event);
const timestamp = Date.now();
if (scrollEndTimeout.current) {
clearTimeout(scrollEndTimeout.current);
}
if (lastScrollEvent.current) {
scrollEndTimeout.current = setTimeout(() => {
if (lastScrollEvent.current !== timestamp) {
return;
}
// Scroll has ended
lastScrollEvent.current = null;
onScrollEnd();
}, 250);
}
lastScrollEvent.current = timestamp;
};

In the InvertedFlatList component there is the internal method onScroll that is called when the scroll starts here, that's the root cause to see a blank screen.

If you scroll and wait for this action to finish and click on the "New messages" button, this behavior won't occur.

2- When clicking on the "New Message" button the scroll goes to the view bottom

The FloatingMessageCounter component receives in the property onClick the action to be executed when clicking on the floating message element, the ReportActionsList component uses the FloatingMessageCounter and passes to the onClick property the method scrollToBottomAndMarkReportAsRead, this method will always scrolls to the bottom:

const scrollToBottomAndMarkReportAsRead = () => {
reportScrollManager.scrollToBottom();
readActionSkipped.current = false;
Report.readNewestAction(report.reportID);
};

What changes do you think we should make in order to solve the problem?

1- Showing a blank screen when clicking on the New Message button

We should call the props.onScroll inside the InvertedFlatList component only when the scroll action ends. To call the props.onScroll when finishing the scroll we should make three changes:

1. Change the method onScrollEnd to receive one parameter event with the scroll event, and call the props.onScroll(event);

For example:

/**
 * Emits when the scrolling has ended.
 * 
 * @param {Event} event - The onScroll event from the FlatList
 */
const onScrollEnd = (event) => {
    props.onScroll(event);

    eventHandler.current = DeviceEventEmitter.emit(CONST.EVENTS.SCROLLING, false);
    updateInProgress.current = false;
};

2. Change the method onScroll to not receive the parameter event and not call the props.onScroll(event);

For example:

/**
 * Emits when the scrolling is in progress. Also,
 * invokes the onScroll callback function from props.
 */
const onScroll = () => {
    if (updateInProgress.current) {
        return;
    }

    updateInProgress.current = true;
    eventHandler.current = DeviceEventEmitter.emit(CONST.EVENTS.SCROLLING, true);
};

3. Change the method handleScroll to pass the event object when calling the onScrollEnd method.

For example:

const handleScroll = (event) => {
    onScroll(); // <- Here we can remove the event from the parameter
    const timestamp = Date.now();

    if (scrollEndTimeout.current) {
        clearTimeout(scrollEndTimeout.current);
    }

    if (lastScrollEvent.current) {
        scrollEndTimeout.current = setTimeout(() => {
            if (lastScrollEvent.current !== timestamp) {
                return;
            }
            // Scroll has ended
            lastScrollEvent.current = null;
            onScrollEnd(event); // <- Here we need to change
        }, 250);
    }

    lastScrollEvent.current = timestamp;
};

2- When clicking on the New Message button the scroll goes to the view bottom

We should improve the method scrollToBottomAndMarkReportAsRead to find the index of the first unread message and use the scrollToIndex method from the reportScrollManager to set the scrolls to the first unread message using the found index.

For example,

const getScrollIndex = () => {
    const bottomIndex = 0;
    const firstUnreadMessageIndex = _.findIndex(sortedReportActions, shouldDisplayNewMarker);

    return firstUnreadMessageIndex > -1 ? firstUnreadMessageIndex : bottomIndex;
};

const scrollToBottomAndMarkReportAsRead = () => {
    const scrollIndex = getScrollIndex();

    reportScrollManager.scrollToIndex(scrollIndex, false);
    readActionSkipped.current = false;
    Report.readNewestAction(report.reportID);
};

Note: maybe we should rename the method name from scrollToBottomAndMarkReportAsRead to scrollToNextUnreadMessageAndMarkReportAsRead

What alternative solutions did you explore? (Optional)

1- Showing a blank screen when clicking on the "New Message" button

Besides my proposal above, we can also solve this issue with one of these approaches:

Approach 1: Creating a mechanism to delay the onClick in the FloatingMessageCounter component

We should change the FloatingMessageCounter component to have a mechanism to call the onClick property when the scroll is not occurring.

We can use almost the same approach that the Hoverable component does, adding an event listener to the scrolling event and setting the value if the scroll is occurring or not into a memoized value, this memoized value will be used to handle the onClick, if there is an active scroll we can delay the click.

useEffect(() => {
if (!shouldHandleScroll) {
return;
}
const scrollingListener = DeviceEventEmitter.addListener(CONST.EVENTS.SCROLLING, (scrolling) => {
isScrolling.current = scrolling;
if (!scrolling) {
setIsHovered(isHoveredRef.current);
}
});
return () => scrollingListener.remove();
}, [shouldHandleScroll]);

Approach 2: Adding a delay to call the onClick method

Changing FloatingMessageCounter component to have a mechanism for delaying the onClick using the value from CONST.ANIMATED_TRANSITION that is greater than 250 that is used here

POC

poc-issue-31591.mp4

@parasharrajat
Copy link
Member

@wlegolas Please explain how the posted root cause caused this issue.

@wlegolas
Copy link
Contributor

Hi @parasharrajat

Sorry, I focused only on the solution to scroll to the first unread message.

I updated my proposal with this root cause and the changes that we need to make to fix it.

If you have any questions, please feel free to contact me

@wlegolas
Copy link
Contributor

Proposal

Updated

Copy link

melvin-bot bot commented Nov 24, 2023

@JmillsExpensify, @parasharrajat Whoops! This issue is 2 days overdue. Let's get this updated quick!

@melvin-bot melvin-bot bot added the Overdue label Nov 24, 2023
@JmillsExpensify
Copy link

Still working through proposals

@melvin-bot melvin-bot bot added Overdue and removed Overdue labels Nov 24, 2023
Copy link

melvin-bot bot commented Nov 27, 2023

📣 It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? 💸

Copy link

melvin-bot bot commented Nov 28, 2023

@JmillsExpensify, @parasharrajat Whoops! This issue is 2 days overdue. Let's get this updated quick!

@parasharrajat
Copy link
Member

Going to review it soon.

@melvin-bot melvin-bot bot removed the Overdue label Nov 28, 2023
@JmillsExpensify
Copy link

Waiting on proposal review

@parasharrajat
Copy link
Member

parasharrajat commented Nov 30, 2023

Good explanation @wlegolas. Let's use your primary solution.

Suggestion:

  1. Instead of changing onScroll prop to be called at scrollEnd, create a new prop callback called onScrollEnd and call it in the scrollEnd handler.
  2. We might be able to use currentUnreadMarker to get the unread marker location instead of recalculating.

🎀 👀 🎀 C+ reviewed

Copy link

melvin-bot bot commented Nov 30, 2023

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

@melvin-bot melvin-bot bot removed the Overdue label Dec 4, 2023
Copy link

melvin-bot bot commented Dec 4, 2023

@wlegolas @JmillsExpensify @MariaHCD @parasharrajat this issue was created 2 weeks ago. Are we close to approving a proposal? If not, what's blocking us from getting this issue assigned? Don't hesitate to create a thread in #expensify-open-source to align faster in real time. Thanks!

@wlegolas
Copy link
Contributor

wlegolas commented Dec 5, 2023

Hi Melvin, I've just started to change the code. In the next days, I will send the PR with the changes.

@wlegolas
Copy link
Contributor

wlegolas commented Dec 5, 2023

  1. We might be able to use currentUnreadMarker to get the unread marker location instead of recalculating.

Hi, @parasharrajat regarding your suggestion above, the currentUnreadMarker has the value for the reportActionID, only with this information I didn't see a way to get the position to go back the scroll to the index.

Using the currentUnreadMarker I think we need to calculate the position using the sortedReportActions method.

Could you please, give a direction on how to use the currentUnreadMarker to get the unread index?

@parasharrajat
Copy link
Member

I see. You need the index... In that case, I would just replace the predicate in findIndex function of your sample to find the item whose id matches with currentUnreadMarker. It should still be a little faster.

@wlegolas
Copy link
Contributor

wlegolas commented Dec 6, 2023

Hi, @parasharrajat

I finished my changes but before I send the PR, I need to check the "New messages" button behaviors.

  • When there is an unread message, the "New messages" button is displayed, and when the user clicks on this button, we should scroll to the unread message in the view.
  • When the user clicks on the "New messages" button and scrolls to the unread message in the view, the "New messages" button continues showing because there is a logic in the handleUnreadFloatingButton to just hide this button if the scroll is close to the Flatlist bottom. (code below)
  • When the user goes to the Flatlist bottom the "New messages" button is hidden

const handleUnreadFloatingButton = () => {
if (scrollingVerticalOffset.current > VERTICAL_OFFSET_THRESHOLD && !isFloatingMessageCounterVisible && !!currentUnreadMarker) {
setIsFloatingMessageCounterVisible(true);
}
if (scrollingVerticalOffset.current < VERTICAL_OFFSET_THRESHOLD && isFloatingMessageCounterVisible) {
if (readActionSkipped.current) {
readActionSkipped.current = false;
Report.readNewestAction(report.reportID);
}
setIsFloatingMessageCounterVisible(false);
}
};

The video below shows all these behaviors.

Just to confirm, are these the expected behaviors?

behavior-new-message-button.mp4

@parasharrajat
Copy link
Member

When the user clicks on the "New messages" button and scrolls to the unread message in the view, the "New messages" button continues showing because there is a logic in the handleUnreadFloatingButton to just hide this button if the scroll is close to the Flatlist bottom. (code below)

This should change now when you are changing the click behaviour.

@parasharrajat
Copy link
Member

parasharrajat commented Dec 6, 2023

I am unsure of whether the scroll to unread logic will work as expected. We should test it with the pagination of chat messages.

Test Scenario:

  • Let's say you go to the history of messages, mark a message as unread, and then directly open that report from an uncached environment(where the report is not cached to Onyx/storage yet).

@wlegolas
Copy link
Contributor

wlegolas commented Dec 6, 2023

When the user clicks on the "New messages" button and scrolls to the unread message in the view, the "New messages" button continues showing because there is a logic in the handleUnreadFloatingButton to just hide this button if the scroll is close to the Flatlist bottom. (code below)

This should change now when you are changing the click behaviour.

In this case, should I hide the button when scrolling to the unread message or is there another behavior that you thought?

@wlegolas
Copy link
Contributor

wlegolas commented Dec 6, 2023

I am unsure of whether the scroll to unread logic will work as expected. We should test it with the pagination of chat messages.

Test Scenario:

  • Let's say you go to the history of messages, mark a message as unread, and then directly open that report from an uncached environment(where the report is not cached to Onyx/storage yet).

I'll do this test, thank you for helping me.

@parasharrajat
Copy link
Member

Behaviour should be same to what happens currently when we scroll to bottom. Only change we are doing is instead of scrolling to the bottom, we scroll to first unread chat.

@wlegolas
Copy link
Contributor

wlegolas commented Dec 7, 2023

Hi, @parasharrajat I created the PR with the changes to fix the issue. I need to add the evidence for Android Native, I've been having some problems running the simulator.

If you have any suggestions or questions, feel free to add a comment in the PR.

PR: #32630

@wlegolas
Copy link
Contributor

wlegolas commented Dec 8, 2023

Behaviour should be same to what happens currently when we scroll to bottom. Only change we are doing is instead of scrolling to the bottom, we scroll to first unread chat.

Hi, @parasharrajat I finished the implementation, just to let you know how the implementation went, I changed the handleUnreadFloatingButton method to not hide the new floating message when the user scrolls to the end of the list (the first if) the new behavior will show the "New messages" when the user is doing the scroll even they are at the end of the list, this new behavior is almost the same as Slack's new message button.

const handleUnreadFloatingButton = () => {
if (scrollingVerticalOffset.current > VERTICAL_OFFSET_THRESHOLD && !isFloatingMessageCounterVisible && !!currentUnreadMarker) {
setIsFloatingMessageCounterVisible(true);
}
if (scrollingVerticalOffset.current < VERTICAL_OFFSET_THRESHOLD && isFloatingMessageCounterVisible) {
if (readActionSkipped.current) {
readActionSkipped.current = false;
Report.readNewestAction(report.reportID);
}
setIsFloatingMessageCounterVisible(false);
}
};

I updated my PR with these changes.

You can see this behavior in the following evidence:

iOS: Native
new-behavior-IOS-Native.mp4
MacOS: Chrome
new-behavior-Mac-chrome.mp4

@JmillsExpensify
Copy link

Still discussing

@wlegolas
Copy link
Contributor

Hi @parasharrajat I don't know if you saw my last commit, but I think I finished the fix and the implementations.

If you have any questions or suggestions, please let me know.

@wlegolas
Copy link
Contributor

Hi @JmillsExpensify and @MariaHCD, I finished the PR and I don't know if @parasharrajat reviewed it, the last message was two weeks ago.

Do you know how we can check with @parasharrajat if this PR is good to merge or not?

@parasharrajat
Copy link
Member

I was busy the last few days. I plan to wrap up soon.

@wlegolas
Copy link
Contributor

I was busy the last few days. I plan to wrap up soon.

No problem @parasharrajat, I just asked to know if we should do anything else to close this PR.

If you have any questions or suggestions, please let me know.

@melvin-bot melvin-bot bot added Monthly KSv2 and removed Weekly KSv2 labels Jan 15, 2024
Copy link

melvin-bot bot commented Jan 15, 2024

This issue has not been updated in over 15 days. @wlegolas, @JmillsExpensify, @MariaHCD, @parasharrajat eroding to Monthly issue.

P.S. Is everyone reading this sure this is really a near-term priority? Be brave: if you disagree, go ahead and close it out. If someone disagrees, they'll reopen it, and if they don't: one less thing to do!

@wlegolas
Copy link
Contributor

Hi Melvin, we're having a discussion on the PR.

I think we are going to have the final changes soon after some tests from @parasharrajat

@parasharrajat
Copy link
Member

BacK from vacation. Will be checking it.

@melvin-bot melvin-bot bot closed this as completed Mar 13, 2024
Copy link

melvin-bot bot commented Mar 13, 2024

@wlegolas, @JmillsExpensify, @MariaHCD, @parasharrajat, this Monthly task hasn't been acted upon in 6 weeks; closing.

If you disagree, feel encouraged to reopen it -- but pick your least important issue to close instead.

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 Monthly KSv2 Not a priority Reviewing Has a PR in review
Projects
None yet
Development

No branches or pull requests

5 participants