Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
21cac2d
fix: Use contains operator for merchant filter in advanced search
HiepPP Feb 27, 2026
167132a
fix: Use contains operator for merchant filter in advanced search
HiepPP Mar 10, 2026
5263040
Merge branch 'main' into fix/80823-merchant-contains-operator
HiepPP Mar 15, 2026
e869214
Merge branch 'main' into fix/80823-merchant-contains-operator
HiepPP Mar 19, 2026
390eed1
Regenerate parser files with Peggy 4.0.3 to match package.json
HiepPP Mar 19, 2026
fda8c05
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Mar 24, 2026
62cf077
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Mar 26, 2026
9d6ff9c
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Mar 28, 2026
fb5f7ad
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Mar 30, 2026
15482e4
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Apr 29, 2026
4219ec5
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP May 11, 2026
556ffab
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP May 18, 2026
a7097b8
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP May 19, 2026
c033992
chore(search): fix parser CI checks
HiepPP May 21, 2026
b28ded0
Merge branch 'main' of github.com:Expensify/App into fix/80823-mercha…
HiepPP May 21, 2026
db675eb
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP May 27, 2026
c74520d
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Jun 3, 2026
6922311
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Jun 17, 2026
234ff70
feat(search): add merchant match type selector
HiepPP Jun 26, 2026
f5b6713
chore(i18n): generate locale translations for merchant match type keys
HiepPP Jun 26, 2026
c532a99
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Jun 26, 2026
5e91743
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Jun 29, 2026
b2042f8
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Jun 30, 2026
24cc2e1
fix: use SingleSelectListItem for merchant match type selector
HiepPP Jun 30, 2026
3e69172
fix: inline merchant filter input under match type option
HiepPP Jun 30, 2026
d7ae22f
fix: match Amount filter spacing for merchant input (mv2)
HiepPP Jun 30, 2026
f4dca8e
refactor: align merchant filter input with Amount via containerStyles
HiepPP Jun 30, 2026
917b615
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Jul 3, 2026
c8393b9
style: apply oxfmt to merge-resolved search filter files
HiepPP Jul 3, 2026
2a54c3b
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Jul 6, 2026
b6d73ba
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Jul 7, 2026
30b6796
fix(search): escape contains operator in keyword queries
HiepPP Jul 14, 2026
5dcf473
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Jul 14, 2026
95d9396
fix(search): reject negated contains filters
HiepPP Jul 17, 2026
1387f0c
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Jul 31, 2026
e1d2f61
Fix merchant operator rows overlapping the value input on native
HiepPP Aug 3, 2026
d6d4084
Merge remote-tracking branch 'fork/fix/80823-merchant-contains-operat…
HiepPP Aug 3, 2026
8f6b401
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Aug 3, 2026
d3bf79e
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Aug 6, 2026
d1fa1cd
Add missing merchant filter translation to Greek (el)
HiepPP Aug 6, 2026
2a353ed
fix(search): hide merchant match types when negated
HiepPP Aug 7, 2026
0164d54
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Aug 13, 2026
81247ea
fix(search): align merchant filter with rules layout
HiepPP Aug 14, 2026
b9cb8dc
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Aug 14, 2026
d664814
fix(search): address review feedback on merchant contains operator
HiepPP Aug 18, 2026
dd4a4fc
fix(search): show merchant match type on filter chip and chip popup
HiepPP Aug 20, 2026
e1cf8c7
fix(search): preserve legacy merchant contains semantics
HiepPP Aug 26, 2026
7164be0
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Aug 26, 2026
bfe6153
fix(search): consolidate merchant popup imports
HiepPP Aug 26, 2026
e3b753b
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Aug 26, 2026
e98d311
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Aug 26, 2026
eb3f0cb
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Aug 27, 2026
b214d46
refactor(search): use search-scoped merchant translations
HiepPP Aug 27, 2026
a76d328
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Aug 27, 2026
a677f33
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Aug 27, 2026
bc389b2
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Aug 28, 2026
f56eaac
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Aug 28, 2026
5895f50
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Aug 28, 2026
2d7e2e8
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Aug 28, 2026
2d7013b
Merge origin/main into fix/80823-merchant-contains-operator
HiepPP Aug 28, 2026
6c98d84
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Aug 28, 2026
e636a74
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Aug 28, 2026
c3130bc
Merge origin/main into fix/80823-merchant-contains-operator
HiepPP Aug 28, 2026
f30c813
fix(search): default merchant filters to contains
HiepPP Sep 4, 2026
98667e4
Merge remote-tracking branch 'myfork/fix/80823-merchant-contains-oper…
HiepPP Sep 4, 2026
15d41eb
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Sep 4, 2026
83bd615
fix(search): preserve merchant lists and isolate filter UI
HiepPP Sep 7, 2026
268f398
chore: merge Expensify main into merchant filter branch
HiepPP Sep 7, 2026
7fb75a9
refactor(search): isolate merchant filter chip popup
HiepPP Sep 7, 2026
631a35d
refactor(search): remove redundant text filter wrapper
HiepPP Sep 7, 2026
23b9ecc
fix(search): preserve mixed merchant predicates in filter updates
HiepPP Sep 8, 2026
4b7c234
fix(search): preserve merchant lists through filter updates
HiepPP Sep 8, 2026
7b33baf
fix(search): retain merchant lists when changing match type
HiepPP Sep 8, 2026
d16816d
chore: merge main into merchant filter branch
HiepPP Sep 11, 2026
0154b5e
fix(search): apply merchant conditions to all clauses
HiepPP Sep 25, 2026
2f84247
chore(search): merge main into merchant filter branch
HiepPP Sep 25, 2026
31630f8
fix(search): address merchant filter review feedback
HiepPP Sep 26, 2026
0e01cb9
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Sep 30, 2026
b3272ae
test(search): expect contains for merchant filter in compare parser test
HiepPP Sep 30, 2026
4fbb097
Merge fix/80823-merchant-contains-operator into latest main
HiepPP Oct 7, 2026
45ff0ef
Drop the unrelated ReceiptTypeValues export
HiepPP Oct 7, 2026
cfc6130
Remove the dead exactMatchFilterKeys code path
HiepPP Oct 7, 2026
380f75d
Extract buildMerchantFilterQuery from the filter query builder
HiepPP Oct 7, 2026
afdf370
Reuse TextInputFilterContent for the Merchant filter
HiepPP Oct 7, 2026
93596d7
Load the English locale in SearchSavePageTest
HiepPP Oct 7, 2026
58f320b
Render SearchColumnsPage inside OnyxListItemProvider in its test
HiepPP Oct 8, 2026
8b1ff74
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Oct 8, 2026
b179aab
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Oct 10, 2026
71e3304
Merge commit '97f79f1c31713fc55f27d0e522da391c0cfa465f' into fix/8082…
HiepPP Oct 12, 2026
33151be
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Oct 14, 2026
125ca02
Update main's Spend footer tests for the merchant contains operator
HiepPP Oct 14, 2026
37fd19d
Merge remote-tracking branch 'origin/main' into fix/80823-merchant-co…
HiepPP Oct 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

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.

This is TextInputFilterContent plus the match-type selector, but without its ScrollView and shouldButtonBeInScrollView handling.

Should we add an optional slot to TextInputFilterContent instead of forking it?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done in c2a4c59, added a generic renderBelowInput slot to TextInputFilterContent.

Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/**
* Renders the advanced Merchant filter input, match type, and negation controls.
*/
import MerchantMatchTypeSelector from '@components/Search/FilterComponents/MerchantMatchTypeSelector';

import useThemeStyles from '@hooks/useThemeStyles';

import CONST from '@src/CONST';
import FILTER_KEYS from '@src/types/form/SearchAdvancedFiltersForm';
import type {MerchantMatchType, SearchAdvancedFiltersForm} from '@src/types/form/SearchAdvancedFiltersForm';

import type {StyleProp, ViewStyle} from 'react-native';
import type {ValueOf} from 'type-fest';

import React, {useState} from 'react';
import {View} from 'react-native';

import TextInputFilterContent from './TextInputFilterContent';

type MerchantFilterContentProps = {
/** The Merchant filter key. */
baseFilterKey: typeof CONST.SEARCH.SYNTAX_FILTER_KEYS.MERCHANT;

/** The current Merchant value. */
value: string | undefined;

/** Whether the filter currently uses the negated value. */
isNegated: boolean;

/** The current Merchant match type. */
merchantOperator?: MerchantMatchType;

/** The button size used for confirmation. */
buttonSize?: Exclude<ValueOf<typeof CONST.BUTTON_SIZE>, typeof CONST.BUTTON_SIZE.SMALL>;

/** The label used when the filter applies immediately. */
buttonText?: string;

/** The Sentry label for the confirmation button. */
sentryLabel?: string;

/** Whether the input should receive focus automatically. */
autoFocus?: boolean;

/** Additional styles for the filter content. */
style?: StyleProp<ViewStyle>;

/** Additional styles for the confirmation button. */
buttonStyles?: StyleProp<ViewStyle>;

/** Called with the updated Merchant filter form values. */
onChange: (values: Partial<SearchAdvancedFiltersForm>) => void;
};

function MerchantFilterContent({
baseFilterKey,
value,
isNegated,
merchantOperator: initialMerchantOperator,
buttonSize,
buttonText,
sentryLabel,
autoFocus,
style,
buttonStyles,
onChange,
}: MerchantFilterContentProps) {
const styles = useThemeStyles();
const [merchantOperator, setMerchantOperator] = useState<MerchantMatchType>(initialMerchantOperator ?? CONST.SEARCH.SYNTAX_OPERATORS.CONTAINS);

const updateMerchantFilter = (newValue: string | undefined, newIsNegated: boolean) => {
onChange({
[FILTER_KEYS.MERCHANT]: newIsNegated ? undefined : newValue,
[FILTER_KEYS.MERCHANT_NOT]: newIsNegated ? newValue : undefined,
[FILTER_KEYS.MERCHANT_OPERATOR]: newIsNegated ? undefined : merchantOperator,
});
};

// A negated Merchant filter always uses the not-equal operator, so the match type is hidden.
const renderMatchTypeSelector = (isFilterNegated: boolean) =>
isFilterNegated ? null : (
<View style={[styles.flex1, styles.mt2]}>
<MerchantMatchTypeSelector
value={merchantOperator}
onChange={setMerchantOperator}
/>
</View>
);

return (
<TextInputFilterContent
baseFilterKey={baseFilterKey}
value={value}
isNegated={isNegated}
size={buttonSize}
autoFocus={autoFocus}
style={style}
buttonText={buttonText}
buttonStyles={buttonStyles}
sentryLabel={sentryLabel}
renderBelowInput={renderMatchTypeSelector}
onChange={updateMerchantFilter}
/>
);
}

export default MerchantFilterContent;
export type {MerchantFilterContentProps};
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,21 @@ import type {SearchFilter} from '@libs/SearchUIUtils';

import CONST from '@src/CONST';
import type {SearchAdvancedFiltersForm} from '@src/types/form';
import FILTER_KEYS from '@src/types/form/SearchAdvancedFiltersForm';

import React from 'react';

import type {AmountFilterContentProps} from './AmountFilterContent';
import type {DateFilterContentProps} from './DateFilterContent';
import type {MerchantFilterContentProps} from './MerchantFilterContent';
import type {ReportFieldFilterContentProps} from './ReportFieldFilterContent';
import type {TextInputFilterContentProps} from './TextInputFilterContent';

type TextInputFilterContentWrapperProps = Pick<TextInputFilterContentProps, 'baseFilterKey' | 'value' | 'isNegated' | 'onChange' | 'buttonText'>;
type AmountFilterContentWrapperProps = Pick<AmountFilterContentProps, 'baseFilterKey' | 'value' | 'onChange' | 'buttonText'>;
type DateFilterContentWrapperProps = Pick<DateFilterContentProps, 'baseFilterKey' | 'value' | 'hasFeed' | 'onChange'> & {buttonText?: string};
type ReportFieldFilterContentWrapperProps = Pick<ReportFieldFilterContentProps, 'values' | 'onChange'> & {buttonText?: string};
type MerchantFilterContentWrapperProps = Pick<MerchantFilterContentProps, 'baseFilterKey' | 'value' | 'isNegated' | 'merchantOperator' | 'onChange' | 'buttonText'>;
type ListFilterContentWrapperProps = Omit<ListFilterContentProps, 'onChange' | 'onNegationChange' | 'selectionListTextInputStyle' | 'selectionListStyle' | 'autoFocus' | 'footer'> & {
onChange: (value: ListFilterContentProps['value'], isNegated: boolean) => void;
buttonText?: string;
Expand All @@ -29,6 +32,7 @@ type SearchAdvancedFiltersContentProps = {
ready?: boolean;
buttonText?: string;
components: {
Merchant: React.ComponentType<MerchantFilterContentWrapperProps>;
Text: React.ComponentType<TextInputFilterContentWrapperProps>;
Amount: React.ComponentType<AmountFilterContentWrapperProps>;
Date: React.ComponentType<DateFilterContentWrapperProps>;
Expand Down Expand Up @@ -98,6 +102,22 @@ function SearchAdvancedFiltersContent({baseFilterKey, values, ready, components,
);
}

if (baseFilterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.MERCHANT) {
const {isNegated, value} = getFilterNegatableValue(baseFilterKey, values);
const MerchantFilter = components.Merchant;
return (
<MerchantFilter
key={baseFilterKey}
baseFilterKey={baseFilterKey}
value={value}
isNegated={isNegated}
merchantOperator={values?.[FILTER_KEYS.MERCHANT_OPERATOR]}
buttonText={buttonText}
onChange={onChange}
/>
);
}

if (isTextFilterKey(baseFilterKey)) {
const {isNegated, value} = getFilterNegatableValue(baseFilterKey, values);
const TextFilter = components.Text;
Expand Down Expand Up @@ -131,4 +151,11 @@ function SearchAdvancedFiltersContent({baseFilterKey, values, ready, components,
}

export default SearchAdvancedFiltersContent;
export type {TextInputFilterContentWrapperProps, AmountFilterContentWrapperProps, DateFilterContentWrapperProps, ReportFieldFilterContentWrapperProps, ListFilterContentWrapperProps};
export type {
TextInputFilterContentWrapperProps,
MerchantFilterContentWrapperProps,
AmountFilterContentWrapperProps,
DateFilterContentWrapperProps,
ReportFieldFilterContentWrapperProps,
ListFilterContentWrapperProps,
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {FILTER_VIEW_MAP} from '@libs/SearchUIUtils';

import CONST from '@src/CONST';

import type {ComponentRef} from 'react';
import type {ComponentRef, ReactNode} from 'react';
import type {TextInput as RNTextInput, StyleProp, ViewStyle} from 'react-native';
import type {ValueOf} from 'type-fest';

Expand All @@ -30,14 +30,32 @@ type TextInputFilterContentProps = {
autoFocus?: boolean;
style?: StyleProp<ViewStyle>;
buttonText?: string;
buttonStyles?: StyleProp<ViewStyle>;
sentryLabel?: string;

/** Renders extra controls under the input, inside the scrollable area. Receives the current negation state, so the content can change when the user negates the filter. */
renderBelowInput?: (isNegated: boolean) => ReactNode;

onChange: (value: string | undefined, isNegated: boolean) => void;
};

function isTextInput(element: BaseTextInputRef | ComponentRef<typeof RNTextInput> | null): element is ComponentRef<typeof RNTextInput> {
return !!element && 'isFocused' in element;
}

function TextInputFilterContent({baseFilterKey, value: initialValue, isNegated: initialIsNegated, autoFocus, size, style, buttonText, onChange}: TextInputFilterContentProps) {
function TextInputFilterContent({
baseFilterKey,
value: initialValue,
isNegated: initialIsNegated,
autoFocus,
size,
style,
buttonText,
buttonStyles,
sentryLabel,
renderBelowInput,
onChange,
}: TextInputFilterContentProps) {
const {translate} = useLocalize();
const styles = useThemeStyles();
const [value, setValue] = useState(initialValue);
Expand All @@ -50,7 +68,7 @@ function TextInputFilterContent({baseFilterKey, value: initialValue, isNegated:

const button = (
<Button
style={[styles.ph5, styles.pb5]}
style={[styles.ph5, styles.pb5, buttonStyles]}
variant={CONST.BUTTON_VARIANT.SUCCESS}
size={size}
onPress={() => {
Expand All @@ -59,6 +77,7 @@ function TextInputFilterContent({baseFilterKey, value: initialValue, isNegated:
}
onChange(value, isNegated);
}}
sentryLabel={sentryLabel}
>
<Button.KeyboardShortcut />
<Button.Text>{buttonText ?? translate('common.confirm')}</Button.Text>
Expand Down Expand Up @@ -93,6 +112,7 @@ function TextInputFilterContent({baseFilterKey, value: initialValue, isNegated:
containerStyles={[styles.ph5]}
/>
</NegatableFilter>
{renderBelowInput?.(isNegated)}
{shouldButtonBeInScrollView && button}
</ScrollView>
{!shouldButtonBeInScrollView && button}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* Shared Merchant match type selector for search filter surfaces.
*/
import SelectionList from '@components/SelectionList';
import SingleSelectListItem from '@components/SelectionList/ListItem/SingleSelectListItem';
import type {ListItem} from '@components/SelectionList/ListItem/types';
import Text from '@components/Text';

import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';

import variables from '@styles/variables';

import CONST from '@src/CONST';
import type {MerchantMatchType} from '@src/types/form/SearchAdvancedFiltersForm';

import React from 'react';
import {View} from 'react-native';

type MerchantMatchTypeSelectorProps = {
/** Currently selected Merchant match type. */
value: MerchantMatchType;

/** Updates the selected Merchant match type. */
onChange: (value: MerchantMatchType) => void;
};

function MerchantMatchTypeSelector({value, onChange}: MerchantMatchTypeSelectorProps) {
const {translate} = useLocalize();
const styles = useThemeStyles();
const items: Array<ListItem<MerchantMatchType>> = [
{
keyForList: CONST.SEARCH.SYNTAX_OPERATORS.CONTAINS,
text: translate('search.filters.merchant.contains'),
isSelected: value === CONST.SEARCH.SYNTAX_OPERATORS.CONTAINS,
},
{
keyForList: CONST.SEARCH.SYNTAX_OPERATORS.EQUAL_TO,
text: translate('search.filters.merchant.equalTo'),
isSelected: value === CONST.SEARCH.SYNTAX_OPERATORS.EQUAL_TO,
},
];

return (
<>
<View style={[styles.pb2, styles.ph5]}>
<Text style={[styles.textLabelSupporting]}>{translate('search.filters.merchant.matchType')}</Text>
</View>
{/* Inside a ScrollView a flex list can shrink to zero height when the keyboard is open, so reserve room for every row */}
<View style={[styles.flex1, {minHeight: items.length * variables.optionRowHeight}]}>
<SelectionList
data={items}
ListItem={SingleSelectListItem}
onSelectRow={(item) => onChange(item.keyForList)}
shouldSingleExecuteRowSelect
/>
</View>
</>
);
}

export default MerchantMatchTypeSelector;
68 changes: 68 additions & 0 deletions src/components/Search/FilterDropdowns/MerchantFilterPopup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* Edits the Merchant filter value and match type from its search filter chip.
*/
import MerchantFilterContent from '@components/Search/FilterComponents/AdvancedFilters/MerchantFilterContent';

import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';

import {getFilterNegatableValue} from '@libs/SearchUIUtils';

import type CONST from '@src/CONST';
import FILTER_KEYS from '@src/types/form/SearchAdvancedFiltersForm';
import type {SearchAdvancedFiltersForm} from '@src/types/form/SearchAdvancedFiltersForm';

import React from 'react';

import type {PopoverComponentProps} from './FilterPopupButton';

import BasePopup from './BasePopup';

type MerchantFilterPopupProps = {
/** The Merchant filter key. */
baseFilterKey: typeof CONST.SEARCH.SYNTAX_FILTER_KEYS.MERCHANT;
/** The current search filter form values. */
values: Partial<SearchAdvancedFiltersForm> | undefined;
/** The translated filter label. */
label: string;
/** Closes the filter popup. */
closeOverlay: PopoverComponentProps['closeOverlay'];
/** Applies the updated Merchant filter values. */
updateFilterForm: (value: Partial<SearchAdvancedFiltersForm>) => void;
};

function MerchantFilterPopup({baseFilterKey, values, label, updateFilterForm, closeOverlay}: MerchantFilterPopupProps) {
const {translate} = useLocalize();
const styles = useThemeStyles();
const {isNegated, value} = getFilterNegatableValue(baseFilterKey, values);
const applySentryLabel = `Search-FilterPopupApply-${baseFilterKey}`;

const applyChanges = (newValues: Partial<SearchAdvancedFiltersForm>) => {
updateFilterForm(newValues);
closeOverlay();
};

// The content renders its own padded Apply button, so the popup only provides the label and the spacing ActionButtons would add.
return (
<BasePopup
label={label}
shouldShowActionButtons={false}
style={styles.pb0}
onApply={closeOverlay}
applySentryLabel={applySentryLabel}
>
<MerchantFilterContent
baseFilterKey={baseFilterKey}
value={value}
isNegated={isNegated}
merchantOperator={values?.[FILTER_KEYS.MERCHANT_OPERATOR]}
buttonText={translate('common.apply')}
sentryLabel={applySentryLabel}
buttonStyles={styles.mt2}
onChange={applyChanges}
/>
</BasePopup>
);
}

export default MerchantFilterPopup;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import MerchantFilterContent from '@components/Search/FilterComponents/AdvancedFilters/MerchantFilterContent';
import type {MerchantFilterContentWrapperProps} from '@components/Search/FilterComponents/AdvancedFilters/SearchAdvancedFiltersContent';

import useThemeStyles from '@hooks/useThemeStyles';

import React from 'react';

function MerchantFilterContentPopupWrapper({baseFilterKey, value, isNegated, merchantOperator, buttonText, onChange}: MerchantFilterContentWrapperProps) {
const styles = useThemeStyles();

return (
<MerchantFilterContent
baseFilterKey={baseFilterKey}
value={value}
isNegated={isNegated}
merchantOperator={merchantOperator}
buttonText={buttonText}
style={[styles.pt6]}
onChange={onChange}
/>
);
}

export default MerchantFilterContentPopupWrapper;
Loading
Loading