Open m-natarajan opened 1 week ago
Triggered auto assignment to @lschurr (Bug
), see https://stackoverflow.com/c/expensify/questions/14418 for more details. Please add this bug to a GH project, as outlined in the SO.
I would like to curate this so assigning myself
Do you need BugZero on this @MonilBhavsar or will it be all internal?
We need BugZero and C+ on this. Going to export it
Job added to Upwork: https://www.upwork.com/jobs/~021844272500597248585
Triggered auto assignment to Contributor-plus team member for initial proposal review - @ikevin127 (External
)
Edited by proposal-police: This proposal was edited at 2024-10-10 08:56:49 UTC.
The "New messages" pill appears;
unreadMarkerReportActionID returns the new action when users add new comment, the reason is because we don't have the logic to exclude the message that comes from current user
In
when checking hasUnreadReportAction
we exclude the current user's message so we should do the same in
const shouldDisplay = isCurrentMessageUnread && isNextMessageRead && !ReportActionsUtils.shouldHideNewMarker(reportAction) && (
(ReportActionsUtils.isReportPreviewAction(reportAction) ? reportAction.childLastActorAccountID : reportAction.actorAccountID) !== Report.getCurrentUserAccountID()
);
isMessageUnread
function to exclude the current user's messageEdited by proposal-police: This proposal was edited at 2024-10-15 14:10:25 UTC.
An unread marker shows every time we add a message.
This happens after https://github.com/Expensify/App/pull/49367. Previously, we ignore any message that the current user sends, unless the user mark it as unread manually.
The unread marker shows because the scroll offset is out of the threshold (250) and isMessageUnread
for the new message is true.
https://github.com/Expensify/App/blob/285bde8073f84dad0ca6d63ef6ec251b10e52882/src/pages/home/report/ReportActionsList.tsx#L224-L226
isMessageUnread
will be true if the report action created
value is bigger than the unreadMarkerTime
.
https://github.com/Expensify/App/blob/285bde8073f84dad0ca6d63ef6ec251b10e52882/src/pages/home/report/ReportActionsList.tsx#L125-L131
The unreadMarkerTime
is updated in 3 cases as written on the comment below.
https://github.com/Expensify/App/blob/285bde8073f84dad0ca6d63ef6ec251b10e52882/src/pages/home/report/ReportActionsList.tsx#L202-L214
For the 3rd case, we have this useEffect
that updates the unreadMarkerTime
, but only if unreadMarkerReportActionID
doesn't exist, which exist in our case because we are out of the scroll threshold.
We will have a new useEffect
that is similar to the 3rd case, but in this case, we will only update the unreadMarkerTime
if there is a new last action created
value from the current user and there is previously no unread marker.
When user adds a new message and there is currently an unread marker, the prevUnreadMarkerReportActionID
will always have a value.
For example, the current user mark A as unread: prevUnreadMarkerReportActionID: undefined unreadMarkerReportActionID: A
then, the current user sends a message. prevUnreadMarkerReportActionID will now contain A.
const prevUnreadMarkerReportActionID = usePrevious(unreadMarkerReportActionID);
const lastAction = sortedVisibleReportActions.at(0);
useEffect(() => {
if (prevUnreadMarkerReportActionID || !lastAction) {
return;
}
const isFromCurrentUser = accountID === (ReportActionsUtils.isReportPreviewAction(lastAction) ? !lastAction.childLastActorAccountID : lastAction.actorAccountID);
if (!isFromCurrentUser || lastAction.created <= unreadMarkerTime) {
return;
}
setUnreadMarkerTime(lastAction.created);
}, [prevUnreadMarkerReportActionID, lastAction?.created]);
We need to add a new case for updating unreadMarkerTime
if a new message is added by the current user, even when the user scroll offset is out of threshold.
Luckily, we already have an observer to detect a new message from the current user. https://github.com/Expensify/App/blob/285bde8073f84dad0ca6d63ef6ec251b10e52882/src/pages/home/report/ReportActionsList.tsx#L371 https://github.com/Expensify/App/blob/285bde8073f84dad0ca6d63ef6ec251b10e52882/src/pages/home/report/ReportActionsList.tsx#L341-L353
We can update the unreadMarkerTime
inside the callback, scrollToBottomForCurrentUserAction
, but that only covers for optimistic case. After the AddComment API success, the BE will send us a new action created
which is bigger from the optimistic created
, so we still need to update the unreadMarkerTime
when receiving the API response.
To do that, we can have a new ref called lastActionAddedByCurrentUser
. We set the ref every time we send a message. reportActionID
is from the 2nd parameter of the callback (scrollToBottomForCurrentUserAction
).
if (!unreadMarkerReportActionID) {
lastActionAddedByCurrentUser.current = reportActionID;
}
It's important to check for existing unread marker to not remove it when adding a new message, which is the current behavior. If we want to remove the marker when adding a new message, then we can remove the if
. Make sure to add unreadMarkerReportActionID
to the useCallback
deps and add scrollToBottomForCurrentUserAction
to this useEffect
where it's being registered.
https://github.com/Expensify/App/blob/285bde8073f84dad0ca6d63ef6ec251b10e52882/src/pages/home/report/ReportActionsList.tsx#L371-L385
Next, adds a useEffect
that updates unreadMarkerTime
whenever the last action is updated. If the last action from props is the same as the last action saved to the ref, then we update the unreadMarkerTime
to that last action created, so unreadMarkerTime
will equal to the last action created
.
const lastAction = sortedVisibleReportActions.at(0);
useEffect(() => {
if (!lastActionAddedByCurrentUser.current || lastAction?.reportActionID !== lastActionAddedByCurrentUser.current) {
return;
}
setUnreadMarkerTime(lastAction.created);
if (lastAction.isOptimisticAction) {
return;
}
lastActionAddedByCurrentUser.current = undefined;
}, [lastAction]);
lastActionAddedByCurrentUser
should be cleared after being used, but we only want to clear that if the last action is not an optimistic action anymore because we still want to update the unreadMarkerTime
when receiving the new action from the API response.
Next, return false here if the report action is the same as the last action added by user. https://github.com/Expensify/App/blob/285bde8073f84dad0ca6d63ef6ec251b10e52882/src/pages/home/report/ReportActionsList.tsx#L220-L227
return shouldDisplay && isWithinVisibleThreshold && reportAction.reportActionID !== lastActionAddedByCurrentUser.current;
Last, we need to clear lastActionAddedByCurrentUser
when mark as unread/read manually.
https://github.com/Expensify/App/blob/285bde8073f84dad0ca6d63ef6ec251b10e52882/src/pages/home/report/ReportActionsList.tsx#L245-L251
♻️ Reviewing proposals...
From my experience with the ReportActionsList.tsx
unread marker functionality I know that there's always more to consider and whenever a straight-forward fix was suggested in the past, we always had regressions because there's a lot of functionality which can be disrupted even with small changes.
Given this I'm inclined to go with bernhardoj's proposal since it mentioned the offending PR which caused the issue and also both RCA and solution proposed are more detailed and consider multiple aspects of the current functionality - hence it shows better understanding of the issue at hand.
However, before moving on with assignment here I want test the proposed solution thoroughly and because I don't want to miss any part of the solution, @bernhardoj can you please share a test branch with the complete solution so I can test it ?
♻️ Will get back on this once I get the chance to test the proposed solution.
@ikevin127 here is the test branch
@bernhardoj Thanks for putting together the test branch, I got to test the fix implementation and while it does seem to work compared to staging:
⚠️ However I found an edge case in which the fix doen't work, allow me to explain the steps and show you a video demonstrating the issue:
[!tip]
Steps to reproduce
- Login into the same account on 2 separate browser windows, one on local dev (with testing branch) and one on current staging (https://staging.new.expensify.com).
- On local dev (with testing branch), verify that you can NOT reproduce the issue by following the steps in issue's description.
- On local dev (with testing branch), make sure there is no new message marker or pill showing and scroll up such that you cannot see the last message.
- On the same account / report on Staging, verify that you CAN reproduce the issue by following the steps in issue's description.
- Now returning to the local dev test branc, observe that the new message marker and pill are showing even though you posted them with the same user account from Staging.
- On local dev (with testing branch), mark as read to ensure there is no new message marker or pill showing then repeat step (2.) and notice that the fix does not work anymore after doing the Staging / Dev back n' forth.
[!note] The same thing happens if the steps are followed on 2 different sessions of the local dev (with testing branch) for example if logging in with the same account and following the above steps on 2 different browsers.
Here's a video for better visualisation:
Given this, from my side I see two issues here:
I updated my proposal with a different solution to cover that (and moved the previous main solution as the alternative).
Thanks for the update, I'll review again today.
I reviewed @bernhardoj's updated proposal's main solution again and this time it passed the tests. Given this I think we're good to go with their proposal as they show a deep understanding of the issue / functionality, the RCA is valid and the updated solution fixes the issue as per the expected result, without altering current working functionality.
For reference, here's how I implemented the solution locally:
[!tip]
Notes for PR
- Make sure to comment the new
useEffect
in detail for others to understand why we need it and what it does.- Ensure thorough testing on narrow layout devices (native / mweb) since on these devices the unread marker / pill can work slightly different because of the DeviceEventEmitter listeners and LHN / Central Pane not being mounted both at the same time.
🎀👀🎀 C+ reviewed
Current assignee @MonilBhavsar is eligible for the choreEngineerContributorManagement assigner, not assigning anyone new.
If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!
Version Number: 9.0.46-2 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: @paultsimura Slack conversation: https://expensify.slack.com/archives/C049HHMV9SM/p1728390912425749
Action Performed:
Expected Result:
Since the user is the author of the message:
Actual Result:
The "New messages" pill appears;
Workaround:
unknown
Platforms:
Which of our officially supported platforms is this issue occurring on?
Screenshots/Videos
https://github.com/user-attachments/assets/2b7ab579-9309-4ff1-adca-f8a60e3edf04
https://github.com/user-attachments/assets/ae7a35e5-fe3e-48c9-8959-d9382135a1dc
Add any screenshot/video evidence
View all open jobs on GitHub
Upwork Automation - Do Not Edit
Issue Owner
Current Issue Owner: @ikevin127