You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Due for payment 2026-10-23] [$175] Android - Spend - Merchant filter modal only shows Merchant title and Apply button #104133
Version Number: 9.5.10-0 Reproducible in staging?: Yes Reproducible in production?: No If this was caught during regression testing, add the test name, ID and link from BrowserStack:#83733 Email or phone of affected tester (no customers):[email protected] Issue reported by: Applause Internal Team Bug source: Exploratory - Significant User Experience Deterioration Device used: Samsung Galaxy S25 FE / Android 16 App Component: Search
Action Performed:
Launch Expensify app.
Go to Spend > Expenses.
Tap Filters.
Tap Merchant.
Enter anything > Confirm > Apply filters.
Open merchant quick filter.
Expected Result:
Merchant filter modal will be shown completely.
Actual Result:
Merchant filter modal only shows Merchant title and Apply button.
👋 Friendly reminder that deploy blockers are time-sensitive ⏱ issues! Check out the open `StagingDeployCash` deploy checklist to see the list of PRs included in this release, then work quickly to do one of the following:
Identify the pull request that introduced this issue and revert it.
Root cause: The Merchant quick-filter chip now renders MerchantFilterPopup, which reuses TextInputFilterContent. That component was built for the full-height advanced-filters page. Its root uses flex1 and puts the input and match-type list inside a ScrollView. The chip popover is sized by its content, so on native the ScrollView gets 0 height. Only the "Merchant" label and the Apply button (outside the ScrollView) remain visible.
Recommendation: fix forward. The PR changes 48 files, and later PRs in the same checklist build on it, so a revert would likely conflict. Either:
give TextInputFilterContent a popover mode with no root flex1, no ScrollView, and an inline button, or
build MerchantFilterPopup like TextFilterPopup, with NegatableFilter, TextInput, and MerchantMatchTypeSelector placed directly in BasePopup.
If a fix isn't ready quickly, revert the PR and resolve the conflicts.
Investigation details
Before: The chip used TextFilterPopup, which puts a plain TextInput in BasePopup with no ScrollView or flex1. The popup grows to fit its content: TextFilterPopup.tsx#L46-L68.
That content assumes a parent with height: the root is flex1 (L88), the input and the renderBelowInput match-type list sit in a ScrollView (L89-L117), and the Apply button renders outside it (L118): TextInputFilterContent.tsx#L87-L119.
Why only native: On web, ScrollView is a div that sizes to its content. The advanced-filters page works because it is a full-height screen. iOS native likely has the same bug.
Other candidates ruled out: Only Make report, expense, and member values copyable touches the filter-popup area, and it changes only DisplayPopup.tsx and list items, not the Merchant chip path.
Assignees: The PR author HiepPP and reviewers truph01 and neil-marcellini are already assigned, which matches this finding.
I did not reproduce this on a device. This run only had a web tester, and the bug is native-only.
TextInputFilterContent has a flex1 root. It puts the input and the match-type list inside a ScrollView, and it renders the Apply button outside that ScrollView. The chip popover has no height of its own because it sizes to its content. On native, a flex1 child of a content-sized parent gets 0 height, so the ScrollView collapses. Only the "Merchant" label and the Apply button stay visible. Web is not affected because a web ScrollView grows to fit its content.
What changes do you think we should make in order to solve the problem?
Build MerchantFilterPopup the same way as TextFilterPopup, so it sizes to its content. Leave the advanced-filters page unchanged.
In MerchantFilterPopup, keep local state for value, isNegated, and merchantOperator. Seed them from getFilterNegatableValue and values[MERCHANT_OPERATOR].
Render BasePopup with its default action buttons, onApply, and shouldSubmitOnEnter. Remove shouldShowActionButtons={false}.
Inside BasePopup, render NegatableFilter with a TextInput, the same as TextFilterPopup. Below it, render MerchantMatchTypeSelector only when the filter is not negated. The selector already reserves a minHeight for its rows.
On apply, validate with useTextFilterValidation. Then build the form values the same way MerchantFilterContent.updateMerchantFilter does. Move that mapping into a small shared helper so both surfaces use it.
Stop using MerchantFilterContent in the chip popup.
What alternative solutions did you explore? (Optional)
Add a popover mode to TextInputFilterContent. It would drop the root flex1 and the ScrollView and render the button inline. MerchantFilterContent would also drop the flex1 around the selector. This keeps one component but adds layout branches to a shared component that other text filters use.
Reverting the PR is possible but risky. It changes 48 files, and later PRs in the same checklist build on it.
I haven't tested this on a device because the bug only happens on native.
Next Steps for Contributor+ team: To accept:@MelvinBot implement [this](https://github.com/Expensify/App/issues/104133) to create a draft PR. To refine:@MelvinBot <your feedback> To reject: Explain why you are rejecting Melvin's proposal.
changed the title [-]Android - Spend - Merchant filter modal only shows Merchant title and Apply button[/-][+][$175] Android - Spend - Merchant filter modal only shows Merchant title and Apply button[/+]on Oct 15, 2026
changed the title [-][$175] Android - Spend - Merchant filter modal only shows Merchant title and Apply button[/-][+][Due for payment 2026-10-23] [$175] Android - Spend - Merchant filter modal only shows Merchant title and Apply button[/+]on Oct 16, 2026
The solution for this issue has been 🚀 deployed to production 🚀 in version 9.5.12-1 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:
If no regressions arise, payment will be issued on 2026-10-23. 🎊
The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the Contributor+ Checklist from here into a new comment on this GH and complete it. If you have the K2 extension, you can simply click: [this button]. If no checklist is needed for this issue, you can click: [no checklist button]
Activity
applause-bot commentedon Oct 15, 2026
While Applause doesn't embed attachments for this bug, here are the links for quick view:
https://platform.applause.com/services/links/v1/external/5b87e07e057f771fe0add33b09709246eb6b19851b27cc62193c5a987d611c38
melvin-bot commentedon Oct 15, 2026
You have been assigned to this deploy blocker because you recently merged this PR: #83733
melvin-bot commentedon Oct 15, 2026
@neil-marcellini @truph01 you have been assigned to this deploy blocker because you reviewed the offending PR: #83733
melvin-bot commentedon Oct 15, 2026
💬 A slack conversation has been started in #expensify-open-source
github-actions commentedon Oct 15, 2026
👋 Friendly reminder that deploy blockers are time-sensitive ⏱ issues! Check out the open `StagingDeployCash` deploy checklist to see the list of PRs included in this release, then work quickly to do one of the following:
truph01 commentedon Oct 15, 2026
@MelvinBot Post proposal
MelvinBot commentedon Oct 15, 2026
Deploy Blocker Investigation
Causing PR: [Payment due @truph01] fix: Add Contains / Equal to match type for the Merchant filter [80823] (high confidence). It merged on 2026-10-14 and is in the 9.5.10-0 checklist. It is a frontend bug.
Root cause: The Merchant quick-filter chip now renders
MerchantFilterPopup, which reusesTextInputFilterContent. That component was built for the full-height advanced-filters page. Its root usesflex1and puts the input and match-type list inside aScrollView. The chip popover is sized by its content, so on native theScrollViewgets 0 height. Only the "Merchant" label and the Apply button (outside theScrollView) remain visible.Recommendation: fix forward. The PR changes 48 files, and later PRs in the same checklist build on it, so a revert would likely conflict. Either:
TextInputFilterContenta popover mode with no rootflex1, noScrollView, and an inline button, orMerchantFilterPopuplikeTextFilterPopup, withNegatableFilter,TextInput, andMerchantMatchTypeSelectorplaced directly inBasePopup.If a fix isn't ready quickly, revert the PR and resolve the conflicts.
Investigation details
TextFilterPopup, which puts a plainTextInputinBasePopupwith noScrollVieworflex1. The popup grows to fit its content: TextFilterPopup.tsx#L46-L68.MerchantFilterPopup: useSearchFiltersBar.tsx#L123-L133.MerchantFilterContent→TextInputFilterContent): MerchantFilterPopup.tsx#L47-L64, MerchantFilterContent.tsx#L91-L103.flex1(L88), the input and therenderBelowInputmatch-type list sit in aScrollView(L89-L117), and the Apply button renders outside it (L118): TextInputFilterContent.tsx#L87-L119.BasePopupis also content-sized: BasePopup.tsx#L47-L58.ScrollViewis a div that sizes to its content. The advanced-filters page works because it is a full-height screen. iOS native likely has the same bug.Other candidates ruled out: Only Make report, expense, and member values copyable touches the filter-popup area, and it changes only
DisplayPopup.tsxand list items, not the Merchant chip path.Assignees: The PR author
HiepPPand reviewerstruph01andneil-marcelliniare already assigned, which matches this finding.I did not reproduce this on a device. This run only had a web tester, and the bug is native-only.
view run
MelvinBot commentedon Oct 15, 2026
Proposal
What is the root cause of that problem?
fix: Add Contains / Equal to match type for the Merchant filter [80823] switched the Merchant chip from
TextFilterPopupto the newMerchantFilterPopup. The new popup reusesMerchantFilterContent→TextInputFilterContent, which was built for the full-height advanced-filters page.TextInputFilterContenthas aflex1root. It puts the input and the match-type list inside aScrollView, and it renders the Apply button outside thatScrollView. The chip popover has no height of its own because it sizes to its content. On native, aflex1child of a content-sized parent gets 0 height, so theScrollViewcollapses. Only the "Merchant" label and the Apply button stay visible. Web is not affected because a webScrollViewgrows to fit its content.Code references
MerchantFilterPopup: useSearchFiltersBar.tsx#L123-L133flex1root,ScrollView, and Apply button outside it: TextInputFilterContent.tsx#L87-L119flex1: MerchantFilterContent.tsx#L80-L88ScrollVieworflex1, so it grows to fit: TextFilterPopup.tsx#L45-L69What changes do you think we should make in order to solve the problem?
Build
MerchantFilterPopupthe same way asTextFilterPopup, so it sizes to its content. Leave the advanced-filters page unchanged.MerchantFilterPopup, keep local state forvalue,isNegated, andmerchantOperator. Seed them fromgetFilterNegatableValueandvalues[MERCHANT_OPERATOR].BasePopupwith its default action buttons,onApply, andshouldSubmitOnEnter. RemoveshouldShowActionButtons={false}.BasePopup, renderNegatableFilterwith aTextInput, the same asTextFilterPopup. Below it, renderMerchantMatchTypeSelectoronly when the filter is not negated. The selector already reserves aminHeightfor its rows.useTextFilterValidation. Then build the form values the same wayMerchantFilterContent.updateMerchantFilterdoes. Move that mapping into a small shared helper so both surfaces use it.MerchantFilterContentin the chip popup.What alternative solutions did you explore? (Optional)
Add a popover mode to
TextInputFilterContent. It would drop the rootflex1and theScrollViewand render the button inline.MerchantFilterContentwould also drop theflex1around the selector. This keeps one component but adds layout branches to a shared component that other text filters use.Reverting the PR is possible but risky. It changes 48 files, and later PRs in the same checklist build on it.
I haven't tested this on a device because the bug only happens on native.
Next Steps for Contributor+ team:
To accept:
@MelvinBot implement [this](https://github.com/Expensify/App/issues/104133)to create a draft PR.To refine:
@MelvinBot <your feedback>To reject: Explain why you are rejecting Melvin's proposal.
view run
3 remaining items
[-]Android - Spend - Merchant filter modal only shows Merchant title and Apply button[/-][+][$175] Android - Spend - Merchant filter modal only shows Merchant title and Apply button[/+]melvin-bot commentedon Oct 15, 2026
Job added to Upwork: https://www.upwork.com/jobs/~022110839950867453127
neil-marcellini commentedon Oct 15, 2026
Fix was CPed to staging and it's being retested as requested here.
izarutskaya commentedon Oct 16, 2026
Issue is still reproducible
Build 9.5.12-0
Samsung Galaxy A40/Android 11 and Android 13
MicrosoftTeams-video.15.mp4
Screen.Recording.20261016.111244.Expensify.mp4
izarutskaya commentedon Oct 16, 2026
It's passed with the build #104141 (comment)
Xiaomi Redmi Note 10 / Android 12
Screenrecorder-2026-10-16-11-46-05-390.mp4
Screen_Recording_20261016_120237_Expensify.Adhoc.mp4
cristipaval commentedon Oct 16, 2026
CP'd the fix into staging
m-natarajan commentedon Oct 16, 2026
Not repro on Samsung Galaxy A40/Android 11/App/Build 9.5.12-1
MicrosoftTeams-video.16.mp4
[-][$175] Android - Spend - Merchant filter modal only shows Merchant title and Apply button[/-][+][Due for payment 2026-10-23] [$175] Android - Spend - Merchant filter modal only shows Merchant title and Apply button[/+]melvin-bot commentedon Oct 16, 2026
@truph01
The solution for this issue has been 🚀 deployed to production 🚀 in version 9.5.12-1 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:
If no regressions arise, payment will be issued on 2026-10-23. 🎊
The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the Contributor+ Checklist from here into a new comment on this GH and complete it. If you have the K2 extension, you can simply click: [this button]. If no checklist is needed for this issue, you can click: [no checklist button]