Skip to content

Avoid nested ScrollViews in landscape bottom-docked confirm modals - #102335

Merged
lakchote merged 4 commits into
mainfrom
claude-singleScrollInLandscapeConfirmModal
Sep 28, 2026
Merged

lakchote merged 4 commits into
mainfrom
claude-singleScrollInLandscapeConfirmModal

Conversation

@MelvinBot

@MelvinBot MelvinBot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Explanation of Change

On a phone in landscape, confirmation modals open as a bottom sheet capped at 75% of the screen height, and BaseModal wraps their content in a ScrollView so it can scroll. The bulk Submit and Export confirmations also put their list of report names in its own ScrollView. That left one scrolling area inside another, and iOS and Android disagree about which one gets the swipe:

  • iOS: the report list takes the swipe, so the sheet never scrolls. The confirm button and the last few report names stay cut off.
  • Android: the sheet takes the swipe, so the report list never scrolls. The button can be reached, but the last report names can't be seen.

This change makes sure there is only ever one scrolling area. BaseModal now passes down, through ModalContext, whether it has wrapped its content in a ScrollView. When it has, ConfirmContent doesn't add its own ScrollView around the report list.

  • Landscape: the whole sheet scrolls as one piece, so every report name and the buttons can be reached.
  • Portrait: nothing changes. The list still scrolls on its own between the title and the buttons.

Only the three confirmations that show a scrollable report list are affected: blocked bulk Submit, partial Export and Export again. Other confirmation modals, tablets and desktop are unchanged.

Fixed Issues

$ #101333
PROPOSAL: #101333 (comment)

Tests

Prerequisite:

  • Sign in as an admin of a regular workspace.
  • Create at least 15 separate expense reports on that workspace, each with one expense.
  • Go to Spend > Expenses, select all 15 expenses, choose Hold from the selected-items button at the top, enter any reason and confirm, so every expense is on hold.
  1. Go to Spend > Reports.
  2. Select the 15 reports.
  3. Turn the phone sideways (landscape).
  4. Tap the selected-items button at the top and choose Submit.
  5. Verify a panel titled Submit reports opens from the bottom and starts listing the report names.
  6. Put your finger directly on the list of report names and swipe up.
  7. Verify the whole panel scrolls together (title, list and button), not just the list.
  8. Keep swiping up until the panel stops.
  9. Verify the last report name on the list is fully visible and the Got it button is fully visible below it.
  10. Swipe down and verify the panel scrolls back up to the title.
  11. Tap Got it and verify the panel closes and none of the 15 reports were submitted.
  • Verify that no errors appear in the JS console

Offline tests

Same as tests

QA Steps

// TODO: These must be filled out, or the issue title must include "[No QA]."
Same as tests

  • Verify that no errors appear in the JS console

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 the expected offline behavior in the Offline steps 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 tested this PR with a High Traffic account against the staging or production API to ensure there are no regressions (e.g. long loading states that impact usability).
  • I included screenshots or videos for tests on all platforms
  • I ran the tests on all platforms & verified they passed on:
    • Android: Native
    • Android: mWeb Chrome
    • iOS: Native
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
    • 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 there are no new alerts related to the canBeMissing param for useOnyx
  • 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 is localized by adding it to src/languages/* files and using the translation method
      • If any non-english text was added/modified, I used JaimeGPT to get English > Spanish translation. I then posted it in #expensify-open-source and it was approved by an internal Expensify engineer. Link to Slack message:
    • I verified all numbers, amounts, dates and phone numbers shown in the product are using the localization methods
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue)
    • 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.ts or at the top of the file that uses the constant) are defined as such
  • I verified that if a function's arguments changed that all usages have also been updated correctly
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • 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(theme.componentBG))
  • If new assets were added or existing ones were modified, I verified that:
    • The assets are optimized and compressed (for SVG files, run npm run compress-svg)
    • The assets load correctly across all supported platforms.
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • 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.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label and/or tagged @Expensify/design so the design team can review the changes.
  • If a new page is added, I verified it's using the ScrollView component to make it scrollable when more elements are added to the page.
  • I added unit tests for any new feature or bug fix in this PR to help automatically prevent regressions in this user flow.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.

Screenshots/Videos

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

Co-authored-by: Lucien Akchoté <lakchote@users.noreply.github.com>
@MelvinBot

Copy link
Copy Markdown
Contributor Author

The failing checks are unrelated to this PR, so I didn't push a fix. main is currently broken, and these same failures will show up on any PR that runs against it.

Analysis: This PR changes only ConfirmContent.tsx, BaseModal.tsx, ModalContext.ts, and ConfirmContentTest.tsx. None of the failing files are in that diff, and each one is byte-identical to main (d291130). The failures appeared after the getReportTransactions refactor PRs merged today:

Evidence
Check Failure Cause
typecheck, test (job 5) tests/actions/ReportTest.ts:5239 and :5269: Property 'reportTransactions' is missing buildOptimisticChangePolicyData now requires reportTransactions (src/libs/actions/Report/index.ts:7928). The two delegateAccountID tests don't pass it.
test (job 6) useSearchBulkActionsDownloadPDFTest.ts: 3 all-matching tests useOnyxContext must be used within a OnyxListItemProvider [key: reportTransactionsAndViolations]
test (job 8) useSearchBulkActionsPayTest.ts: "excludes deselected reports from an all-matching bulk payment" Same OnyxListItemProvider error. useSearchBulkActions now reads reportTransactionsAndViolations, but these newer all-matching tests don't wrap it in the provider.

Check independent approval is a process check and doesn't need a code fix.

Next steps: Once someone fixes main, merge main into this branch or rerun the checks. They should pass after that. The main fix itself is small: add reportTransactions: [] to the two ReportTest calls, and wrap the two bulk-action hook tests in OnyxListItemProvider.


view run

…LandscapeConfirmModal

Co-authored-by: Lucien Akchoté <lakchote@users.noreply.github.com>
@MelvinBot

Copy link
Copy Markdown
Contributor Author

I merged main into this branch to pick up the fix for the failing checks (merge commit 90905f1d3b0). CI is running again.

The failures weren't caused by this PR. They came from a merge race on main with the getReportTransactions refactor, and [No QA] Fix tests broken by merge race with getReportTransactions refactor fixed them on main at 18:32 UTC. That fix touches exactly the failing files: ReportTest.ts, useSearchBulkActionsPayTest.ts, and useSearchBulkActionsDownloadPDFTest.ts.

The merge had no conflicts and doesn't change this PR's own files. I couldn't run Jest or typecheck in my environment, so the new CI run is the verification. Check independent approval still needs a reviewer approval, not a code change.


view run

@MelvinBot

MelvinBot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor Author

🤖 Android test steps verification results: ❌ fail

I couldn't verify the fix on Android. The PR's Tests section is still a TODO, so I used the steps from Landscape - Long scrollable confirmation modals can make content or actions unreachable. The tester signed in and created a workspace with 7 draft reports. The app then froze and stopped responding to touch before it could open the bulk Submit modal. The app was still frozen on a second check about 8 minutes later. The tester can't restart the app, so it ran none of the modal checks (portrait or landscape).
App frozen and unresponsive to touch

Step Status
At least 8 unsubmitted reports with expenses exist in a workspaceCreated a workspace and 7 of 8 draft reports (one expense each, $25–$60). The app froze while the tester was creating the 8th report. No expenses were held.
Report 8 in progress with action menu open, just before the app froze
❌
Bulk Submit from Search > Reports opens a confirmation modal listing report namesNot reached. The app was frozen.
❌
Portrait: report-name list scrolls inside the modal, and the buttons stay visibleNot reached.
❌
Landscape: the whole modal scrolls as one block, and the last report name is reachableNot reached.
❌
Landscape: the confirm button is reachableNot reached.
❌
Bulk Export opens a confirmation modal listing report namesNot reached. This step probably also needs an accounting integration.
❌
Landscape: the Export confirmation modal scrolls as one blockNot reached.
❌

To get a real result, rerun this on a fresh emulator session. It would also help to add test steps to the PR's Tests section.


view run · view recording

@MelvinBot

Copy link
Copy Markdown
Contributor Author

⏱️ Ran out of time before I could finish. This usually means the task was too complex or I got stuck exploring. Please try again with a more specific request or post in #melvinbot-ai.

Run details

@TaduJR

TaduJR commented Sep 26, 2026

Copy link
Copy Markdown
Contributor

@MelvinBot

Please merge main.

@MelvinBot

Copy link
Copy Markdown
Contributor Author

I didn't merge main into this branch. I can only push changes when the PR author, an assignee, or an existing co-author asks. TaduJR isn't one of those on this PR.

GitHub currently shows the branch as mergeable with no conflicts.

I can only make code changes when directed by the PR author, an assignee, or an existing co-author. To have me implement this, the PR assignee or author should reply with a request tagging me.


view run

@TaduJR

TaduJR commented Sep 26, 2026

Copy link
Copy Markdown
Contributor

@MelvinBot

Please assign me. I reviewed your Proposal from #101333 (comment) as the C+

@MelvinBot

Copy link
Copy Markdown
Contributor Author

Done. I assigned you to this PR and requested your review, since you're the C+ on Landscape - Long scrollable confirmation modals can make content or actions unreachable and you reviewed the proposal.

The PR's Tests and QA sections are still placeholders, so a human co-author needs to fill them in before review.


view run

@TaduJR

TaduJR commented Sep 26, 2026

Copy link
Copy Markdown
Contributor

@MelvinBot

Please merge main

…LandscapeConfirmModal

Co-authored-by: TaduJR <TaduJR@users.noreply.github.com>
@MelvinBot

Copy link
Copy Markdown
Contributor Author

I merged main into this branch in commit 043df0d. The branch was 33 commits behind, and the merge had no conflicts. None of those commits changed this PR's files.

I didn't run the Jest tests locally after the merge. CI will run them on the new commit.


view run

@TaduJR

This comment was marked as resolved.

@MelvinBot

Copy link
Copy Markdown
Contributor Author

🤖 I replaced the PR description with the one you provided. It includes the new Explanation of Change, the 15-report landscape Submit test steps, and your checklist. I left out the closing "Please replace the description with the above one." line.


view run

@TaduJR

TaduJR commented Sep 26, 2026

Copy link
Copy Markdown
Contributor

@MelvinBot The code looks good. It's the same change I tested on iOS in landscape. Two things on the tests:

  1. Nothing covers the BaseModal side. If BaseModal set isContentWrappedInScrollView from isBottomDockedModalInLandscapeMode instead of shouldWrapChildrenInScrollView (so it ignored the opt-out prop), all three new tests would still pass. Please add the BaseModal test below to tests/ui/BaseModalTest.tsx. It checks the flag is true only for a bottom-docked modal in landscape without the opt-out.

  2. tests/unit/ConfirmContentTest.tsx already exists. Please move these cases there instead of adding a second ConfirmContentTest.tsx under tests/ui. Mocking @components/ScrollView with a testID also removes the eslint-disable and the UNSAFE_queryAllByType call.

tests/ui/BaseModalTest.tsx
import type ModalContextType from '@components/Modal/ModalContext';

    it.each([
        [CONST.MODAL.MODAL_TYPE.BOTTOM_DOCKED, true, undefined, true],
        [CONST.MODAL.MODAL_TYPE.BOTTOM_DOCKED, true, false, false],
        [CONST.MODAL.MODAL_TYPE.BOTTOM_DOCKED, false, undefined, false],
        [CONST.MODAL.MODAL_TYPE.CENTERED, true, undefined, false],
    ])(
        'tells children whether a %s modal in landscape=%s with wrap override %s already scrolls them',
        (type, isInLandscapeMode, shouldWrapModalChildrenInScrollViewIfBottomDockedInLandscapeMode, expectedIsContentWrappedInScrollView) => {
            // Given the orientation is forced and the modal renders its children, so a child can read the context BaseModal provides
            jest.doMock('react', () => React);
            jest.doMock('@libs/isInLandscapeMode', () => ({
                __esModule: true,
                default: () => isInLandscapeMode,
            }));
            jest.doMock('@components/Modal/ReanimatedModal', () => ({
                __esModule: true,
                default: ({children}: ReanimatedModalProps) => children,
            }));
            const {default: BaseModal} = jest.requireActual<{default: typeof BaseModalComponent}>('@components/Modal/BaseModal');
            const {default: ModalContext} = jest.requireActual<{default: typeof ModalContextType}>('@components/Modal/ModalContext');
            let isContentWrappedInScrollView: boolean | undefined;
            function ContextReader() {
                isContentWrappedInScrollView = React.useContext(ModalContext).isContentWrappedInScrollView;
                return null;
            }

            // When the modal is shown
            render(
                <BaseModal
                    isVisible
                    type={type}
                    shouldWrapModalChildrenInScrollViewIfBottomDockedInLandscapeMode={shouldWrapModalChildrenInScrollViewIfBottomDockedInLandscapeMode}
                >
                    <ContextReader />
                </BaseModal>,
            );

            // Then children learn they are already inside a vertical scroller only when BaseModal actually adds its landscape ScrollView,
            // so they don't nest a second one that would fight it for the drag gesture
            expect(isContentWrappedInScrollView).toBe(expectedIsContentWrappedInScrollView);
        },
    );
tests/unit/ConfirmContentTest.tsx
import {render, screen, within} from '@testing-library/react-native';
import ModalContext from '@components/Modal/ModalContext';

jest.mock('@components/ScrollView', () => {
    const ReactLib = jest.requireActual<typeof React>('react');
    return {
        __esModule: true,
        default: ({children}: {children?: React.ReactNode}) => ReactLib.createElement('mock-scroll-view', {testID: 'prompt-scroll-view'}, children),
    };
});

    describe('scrollable prompt (shouldEnablePromptScroll=true)', () => {
        const prompt = '• Report 1\n• Report 2';

        it('puts the prompt in its own ScrollView when the modal does not already scroll its children', () => {
            // Given a modal that renders its children without a ScrollView, as a bottom-docked modal does in portrait
            // When a long prompt asks to be scrollable
            render(
                <ModalContext.Provider value={{isContentWrappedInScrollView: false, default: false}}>
                    <ConfirmContent
                        title="Test"
                        onConfirm={jest.fn()}
                        isVisible
                        prompt={prompt}
                        shouldEnablePromptScroll
                    />
                </ModalContext.Provider>,
            );

            // Then the prompt scrolls on its own, so the title and buttons stay pinned around the long list
            expect(within(screen.getByTestId('prompt-scroll-view')).getByText(prompt)).toBeOnTheScreen();
        });

        it('renders the prompt without its own ScrollView when the modal already scrolls its children', () => {
            // Given a modal that already wraps its children in a ScrollView, as a bottom-docked modal does in landscape
            // When a long prompt asks to be scrollable
            render(
                <ModalContext.Provider value={{isContentWrappedInScrollView: true, default: false}}>
                    <ConfirmContent
                        title="Test"
                        onConfirm={jest.fn()}
                        isVisible
                        prompt={prompt}
                        shouldEnablePromptScroll
                    />
                </ModalContext.Provider>,
            );

            // Then the prompt is not nested in a second vertical scroller: iOS would keep the drag in the inner one and Android would
            // give it to the outer one, leaving either the buttons or the end of the list unreachable
            expect(screen.queryByTestId('prompt-scroll-view')).toBeNull();
            expect(screen.getByText(prompt)).toBeOnTheScreen();
        });
    });

…sts to unit suite

Co-authored-by: TaduJR <TaduJR@users.noreply.github.com>
@MelvinBot

Copy link
Copy Markdown
Contributor Author

I made both test changes and pushed them in fe95be9.

  1. I added your BaseModal test to tests/ui/BaseModalTest.tsx:101.
  2. I moved the prompt cases into tests/unit/ConfirmContentTest.tsx:149 with the @components/ScrollView mock. I deleted tests/ui/ConfirmContentTest.tsx, which removes the eslint-disable and UNSAFE_queryAllByType.

I used your two cases as written, so the old "no provider" case is gone. Let me know if you want it back.

Checks
  • ✅ npm test on both files: 23 passed.
  • ✅ The new tests catch the regressions. I set isContentWrappedInScrollView from isBottomDockedModalInLandscapeMode, and the opt-out case failed. I dropped the !isContentWrappedInScrollView check in ConfirmContent, and the "already scrolls" case failed. I reverted both changes.
  • ✅ ESLint on both files, and npm run typecheck.
  • Not run: oxfmt --check and spell-changed. Both were blocked in this environment. The new code matches your snippets and the formatting around them.

view run

@TaduJR

TaduJR commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

Reviewer Checklist

  • 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 included screenshots or videos for tests on all platforms
  • I verified that the composer does not automatically focus or open the keyboard on mobile unless explicitly intended. This includes checking that returning the app from the background does not unexpectedly open the keyboard.
  • I verified tests pass on all platforms & I tested again on:
    • Android: HybridApp
    • Android: mWeb Chrome
    • iOS: HybridApp
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
  • If there are any errors in the console that are unrelated to this PR, I either fixed them (preferred) or linked to where I reported them in Slack
  • 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 that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue)
  • 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)
  • 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 */
    • 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 any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • 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(theme.componentBG)
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • 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.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label and/or tagged @Expensify/design so the design team can review the changes.
  • For any bug fix or new feature in this PR, I verified that sufficient unit tests are included to prevent regressions in this flow.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.
  • I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR.

Screenshots/Videos

Android: HybridApp
Android-Native.mov
Android: mWeb Chrome
Android-mWeb.mov
iOS: HybridApp
iOS-Native.mp4
iOS: mWeb Safari
iOS-Safari.mp4
MacOS: Chrome / Safari

@TaduJR TaduJR left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM!

@melvin-bot
melvin-bot Bot requested a review from lakchote September 26, 2026 12:23
@TaduJR

TaduJR commented Sep 26, 2026

Copy link
Copy Markdown
Contributor

@MelvinBot

Please make the PR ready for review.

@MelvinBot

Copy link
Copy Markdown
Contributor Author

I couldn't mark this PR ready for review. The command to change the draft status was blocked in my environment, so the PR is still a draft.

CI is green except Check independent approval, which needs a reviewer approval. lakchote can click Ready for review at the bottom of the PR.


view run

@TaduJR

TaduJR commented Sep 26, 2026

Copy link
Copy Markdown
Contributor

cc @lakchote

@TaduJR

TaduJR commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

I couldn't mark this PR ready for review. The command to change the draft status was blocked in my environment, so the PR is still a draft.
CI is green except Check independent approval, which needs a reviewer approval. lakchote can click Ready for review at the bottom of the PR.

@lakchote I think Melvin couldn't make the PR ready

@TaduJR

TaduJR commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

@MelvinBot

Please make the PR ready. I already approved the PR as C+

@MelvinBot

MelvinBot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor Author

I still can't mark this PR ready for review. My environment blocks the command that changes a PR's draft status, so the PR is still a draft. Retrying won't help until that permission changes.

lakchote can click Ready for review at the bottom of the PR.

All CI checks pass except Check independent approval. That check needs a second reviewer to approve.

@lakchote

Copy link
Copy Markdown
Contributor

@MelvinBot

Please make the PR ready.

@MelvinBot

Copy link
Copy Markdown
Contributor Author

I couldn't mark this PR ready for review. My environment still blocks the command that changes a PR's draft status. Retrying won't help until someone changes that permission.

lakchote, you can click Ready for review at the bottom of the PR.

All CI checks pass except Check independent approval. TaduJR approved as C+, and this check needs one more approval.


view run

@lakchote
lakchote marked this pull request as ready for review September 28, 2026 09:14
@lakchote
lakchote requested a review from a team as a code owner September 28, 2026 09:14
@melvin-bot
melvin-bot Bot requested review from TaduJR and dylanexpensify and removed request for a team September 28, 2026 09:14
@melvin-bot

melvin-bot Bot commented Sep 28, 2026

Copy link
Copy Markdown

@TaduJR Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button]

@melvin-bot
melvin-bot Bot removed the request for review from a team September 28, 2026 09:14
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-28T09:25:41.834610Z fe95be9 Draft marked ready
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@lakchote lakchote left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@TaduJR TaduJR left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM!

@melvin-bot
melvin-bot Bot requested a review from lakchote September 28, 2026 09:21
@lakchote

Copy link
Copy Markdown
Contributor

@dylanexpensify everything looks good from a product perspective?

@dylanexpensify dylanexpensify left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good from a product perspective 👍

@lakchote
lakchote merged commit 3bd0106 into main Sep 28, 2026
40 of 45 checks passed
@lakchote
lakchote deleted the claude-singleScrollInLandscapeConfirmModal branch September 28, 2026 18:42
@OSBotify

Copy link
Copy Markdown
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.

@github-actions

Copy link
Copy Markdown
Contributor

🚧 lakchote has triggered a test Expensify/App build. You can view the workflow run here.

@OSBotify

Copy link
Copy Markdown
Contributor

🚀 Deployed to staging by https://github.com/lakchote in version: 9.4.95-0 🚀

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

@MelvinBot

Copy link
Copy Markdown
Contributor Author

No help site changes are needed for this PR, so I didn't create a docs PR.

This PR fixes how confirmation panels scroll on a phone held sideways (landscape). It changes no feature names, settings, buttons, or workflow steps. No article under App/docs/articles describes how confirmation panels scroll. The only related mention, "Submit reports" in Expense-and-Report-Actions.md, lists the action and stays accurate.


view run

@OSBotify

Copy link
Copy Markdown
Contributor

🚀 Deployed to production by https://github.com/Julesssss in version: 9.4.95-4 🚀

platform result
🕸 web 🕸 success ✅
🤖 android 🤖 failure ❌
🍎 iOS 🍎 failure ❌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Melvin-Test-Android Melvin-Test-Web Triggers Melvin to run the testing steps of the PR on web

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants