Repository navigation
fix: preserve cached chat scroll position on reconnect - #106687
chrispader wants to merge 4 commits into
Conversation
Keep displayed offline actions ready while queued app and report loads finish. This prevents loading skeletons and the first successful response from recreating the list and resetting its viewport. Co-authored-by: Codex <noreply@openai.com>
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dc9fcd5490
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // Before the first successful load, a missing loading-state entry means ReportFetchHandler has not | ||
| // enqueued OpenReport yet. Once a terminal failure writes false, the stored state releases the gate. | ||
| const shouldKeepInitialReportLoadGated = isReportLoadPending || (!hasOnceLoadedReportActions && isLoadingInitialReportActions !== false); | ||
| const shouldKeepInitialReportLoadGated = !hasOnceLoadedReportActions && (isReportLoadPending || isLoadingInitialReportActions !== false); |
There was a problem hiding this comment.
Preserve the pending gate on a fresh online report mount
When an unread report is reopened online after an earlier successful visit in the same session, hasOnceLoadedReportActions is already true even though this is a new list mount. If only the newest action is cached—for example, after report-action cache eviction—this change skips the pending OpenReport gate and initializes the list before the older unread messages arrive. useReportActionsListScroll also omits the unread anchor from listID while this flag is true, so the response cannot remount the list to apply its first-unread scroll position; the viewport remains at the newest cached message instead. Suppress the pending gate only when the current list has actually been displayed, rather than using the session-wide successful-load flag as that indication.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Chris's AI understudy stepping in. 🤖
Good catch, fixed in 1460697. The guard now tracks whether it has already displayed the list since it mounted, and only that skips the pending OpenReport gate and the app-load skeleton. A new mount of an unread report waits for OpenReport again, like on main, even if the report loaded earlier in the session. A list that is already on screen still stays mounted when queued loads resume after reconnecting.
Reconnecting removed the skeleton that holds the space of unloaded history before the older actions arrived. The list shrank, the browser clamped the scroll position, and the messages being read jumped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The reconnect fix skipped the OpenReport and app-load gates whenever the report had loaded earlier in the session. A new mount of an unread report with only its newest action cached then opened at that action instead of the first unread one. Only a list this guard has already displayed now skips those gates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When a cached chat opens offline, reconnecting can replace its messages with a loading skeleton and reset its scroll position. I keep the displayed list mounted while app and report refreshes finish. This fix works with the existing FlashList and is independent of the LegendList migration.
Explanation of Change
Once cached messages have been shown, I keep their list mounted while app and report refreshes finish. Initial online loads still wait for the data they need.
Fixed Issues
$ #98994
PROPOSAL: N/A
Tests
Use a chat with enough history to scroll.
Offline tests
QA Steps
Repeat Tests and Offline tests.
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectionAvatar, I verified the components usingAvatarare working as expected)npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari
Return online while reading older cached messages.
Before:
Screen.Recording.2026-11-13.at.12.44.07.mov
After:
Screen.Recording.2026-11-13.at.12.29.45.mov
🤖 Generated with Codex