-
Notifications
You must be signed in to change notification settings - Fork 3k
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: Leave thread chat when has no comment #27849
Conversation
@dukenv0307 you have conflicts here |
@roryabraham @dukenv0307 I would like to point out that this solution will not fix the previous thread that you opened without commenting , it will just prevent the bug from occurring in the future. The user should re-open all these threads again to fix the unread count completely. However there is a challenge as these reports are not visible in the LHN, making it difficult for the user to locate them. |
@fedirjh Not sure if any actions should I take from my side based on your comment? Or should we wait for the internal team to confirm |
Hi! Can we fix conflicts on this and get it merged? At least for me, I think it's fine that it won't fix old threads, they won't be super active (and if people follow the other methods to get to them) it'll be either a non-issue or fixed eventually. |
Reviewing shortly. |
src/pages/home/ReportScreen.js
Outdated
return; | ||
} | ||
|
||
if (ReportUtils.isThread(report) && report.notificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) { |
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.
Let's add a comment explaining this hook.
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.
Added
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.
should prefer early return here:
if (!ReportUtils.isThread(report) || report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) {
return;
}
Report.leaveRoom(report.reportID, false);
src/pages/home/ReportScreen.js
Outdated
Report.leaveRoom(report.reportID, false); | ||
} | ||
|
||
// eslint-disable-next-line react-hooks/exhaustive-deps |
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.
Why didn’t we pass all deps , basically the report
?
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 we should trigger this useEffect once the report loses focus
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.
Agree we don't want to run this whenever any property on the report changes. However, I think we probably want to make sure that the correct report data is used and want to avoid suppressing the lint rule.
So maybe we can workaround the lint rule with something like this:
const isThread = ReportUtils.isThread(report);
const isNotificationPreferenceHidden = report.notificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN;
const reportID = report.reportID;
// When the report screen is unmounted or no longer in focus, and the user has no comments on that thread, call LeaveRoom
useEffect(() => {
if (isFocused || !isThread || !isNotificationPreferenceHidden) {
return;
}
Report.leaveRoom(reportID, false);
}, [isFocused, isThread, isNotificationPreferenceHidden, reportID]);
@@ -350,6 +351,18 @@ function ReportScreen({ | |||
[report, isLoading, shouldHideReport, isDefaultReport, isOptimisticDelete, userLeavingStatus], | |||
); | |||
|
|||
useEffect(() => { |
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.
Will this hook runs when component unmounts ?
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.
Yes, it will
src/libs/actions/Report.js
Outdated
if (report.parentReportID) { | ||
Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(report.parentReportID), CONST.NAVIGATION.TYPE.FORCED_UP); | ||
return; | ||
if (shouldNavigate) { |
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.
Let's early return before dismissing the modal and keep the other part as it is .
if (!shouldNavigate) {
return
}
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.
Updated
Excited to review this one as soon as it's ready |
src/pages/home/ReportScreen.js
Outdated
return; | ||
} | ||
|
||
if (ReportUtils.isThread(report) && report.notificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) { |
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.
should prefer early return here:
if (!ReportUtils.isThread(report) || report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) {
return;
}
Report.leaveRoom(report.reportID, false);
src/pages/home/ReportScreen.js
Outdated
Report.leaveRoom(report.reportID, false); | ||
} | ||
|
||
// eslint-disable-next-line react-hooks/exhaustive-deps |
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.
Agree we don't want to run this whenever any property on the report changes. However, I think we probably want to make sure that the correct report data is used and want to avoid suppressing the lint rule.
So maybe we can workaround the lint rule with something like this:
const isThread = ReportUtils.isThread(report);
const isNotificationPreferenceHidden = report.notificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN;
const reportID = report.reportID;
// When the report screen is unmounted or no longer in focus, and the user has no comments on that thread, call LeaveRoom
useEffect(() => {
if (isFocused || !isThread || !isNotificationPreferenceHidden) {
return;
}
Report.leaveRoom(reportID, false);
}, [isFocused, isThread, isNotificationPreferenceHidden, reportID]);
@roryabraham Just updated the code. Please help review again. |
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.
Nice, LGTM 👍🏼
if (!shouldNavigate) { | ||
return; | ||
} |
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.
Let's move this line above the modal dismissal .
Bug: User is navigated to concierge after leaving the thread
- Open report
- Navigate to thread
- Click back button
- User should go back to main report
- User is navigate to concierge
CleanShot.2023-09-26.at.16.07.37.mp4
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.
@fedirjh I see the problem, this PR changed the logic
so I don't think just moving that IF condition will work since when we call LeaveRoom, we set the optimistic data of that report statusNum to CLOSED
App/src/libs/actions/Report.js
Line 1868 in fff2dd4
statusNum: CONST.REPORT.STATUS.CLOSED, |
In ReportScreen, we have a logic to navigate to Concierge once statusNum is CLOSED
App/src/pages/home/ReportScreen.js
Lines 312 to 321 in fff2dd4
if ( | |
// non-optimistic case | |
(!prevUserLeavingStatus && userLeavingStatus) || | |
// optimistic case | |
(prevOnyxReportID && prevOnyxReportID === routeReportID && !onyxReportID && prevReport.statusNum === CONST.REPORT.STATUS.OPEN && report.statusNum === CONST.REPORT.STATUS.CLOSED) | |
) { | |
Navigation.goBack(); | |
Report.navigateToConciergeChat(); | |
return; | |
} |
Working on this to find a solution
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 one simple solution for this bug is that we add an optimistic prop let's say shouldNavigate
and use it to prevent redirection inside ReportScreen
.
optimisticData: [
{
onyxMethod: Onyx.METHOD.SET,
key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
value: {
stateNum: CONST.REPORT.STATE_NUM.SUBMITTED,
statusNum: CONST.REPORT.STATUS.CLOSED,
shouldNavigate, // Add this prop
},
},
],
// Update the condition to
if (
// non-optimistic case
(!prevUserLeavingStatus && userLeavingStatus) ||
// optimistic case
(... && report.shouldNavigate)
) {
@dukenv0307 any update ? |
@fedirjh The bug
will be successfully resolved using your suggestion However, I just encountered a new bug.
Screen.Recording.2023-09-28.at.15.21.58.movThe reason is that isFocused now will be false, therefore LeaveRoom will be triggered. I need a little bit more time to find a better alternative solution. Will ping back if any update |
@dukenv0307 Why do we prefer leaving the room when the component loses focus, why we didn’t just leave the room when the component unmounts? That way LeaveRoom will be called once. useEffect(() => () => {
if (!isThread || !isNotificationPreferenceHidden) {
return;
}
Report.leaveRoom(reportID, false);
}, [isThread, isNotificationPreferenceHidden, reportID]); |
@fedirjh |
@roryabraham / @fedirjh can you take a look at the failed checks on this one? |
Looks like we have conflicts here, and the last failing check is just the reviewer checklist. Currently awaiting approval + checklist from @fedirjh |
@fedirjh @roryabraham After implementing the proposal, I found out that many regressions are likely to happen if the LeaveRoom solution is applied
I would suggest applying a new solution to update the logic here App/src/libs/UnreadIndicatorUpdater/index.js Lines 11 to 12 in 6c7ee53
to leave out all the report that notificationPreference is hidden. |
Those are very bad regressions, worse than having wrong indicator 😕 .
@dukenv0307 Do you suggest we exclude the hidden notificationPreference in the count, But we will still have data in Onyx for those reports. The solution looks better than having wrong count, but doesn’t seems ideal. Curious about your thoughts @roryabraham |
@roryabraham Friendly bump. Any thoughts on this #27849 (comment) |
My thoughts are that the solution we are working on here is still logically sound, but we need to add some additional logic to correctly handle edge cases. psuedocode like this:
In plain English, if you navigate away from a thread that you have not commented on, and are not navigating to a child thread, then leave the thread and recursively do the same thing for all parent threads. thoughts? |
@roryabraham Actually, these are not really few edge cases; the report screen will lose focus in different ways, Opening any RHN modal including deeplink will make the report screen lose focus (and trigger the leave action). I am not sure if we can cover all of them with the suggested approach. |
@roryabraham @dukenv0307 We have this PR #30013 merged, It addresses the same issue we are fixing. What is our next plan of action for this PR? Should we proceed with closing it? |
Yes, I suppose we should close this now |
Details
New messages on the threads that I can't see on my LHN are not counting toward the unread counter on the app icon
Fixed Issues
$ #27512
PROPOSAL: #27512 (comment)
Tests
Offline tests
QA Steps
PR Author Checklist
### Fixed Issues
section aboveTests
sectionOffline steps
sectionQA steps
sectiontoggleReport
and notonIconClick
)myBool && <MyComponent />
.src/languages/*
files and using the translation methodWaiting for Copy
label for a copy review on the original GH to get the correct copy.STYLE.md
) were followedAvatar
, I verified the components usingAvatar
are working as expected)/** comment above it */
this
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)ScrollView
component to make it scrollable when more elements are added to the page.main
branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTest
steps.Screenshots/Videos
Web
web.7.mp4
Mobile Web - Chrome
chrome.3.mp4
Mobile Web - Safari
safari.1.mp4
Desktop
desktop.5.mp4
iOS
ios.3.mp4
Android
android.6.mp4