Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type {PolicyReportField} from '@src/types/onyx';

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

import React, {useRef} from 'react';
import React, {useRef, useState} from 'react';

type ReportFieldFilterContentProps = {
values: Partial<SearchAdvancedFiltersForm> | undefined;
Expand All @@ -26,6 +26,8 @@ function ReportFieldFilterContent({values, selectedField, largeButton, style, on
const styles = useThemeStyles();
const reportFieldRef = useRef<ReportFieldHandle>(null);

const [error, setError] = useState<string>();

return (
<>
<ReportFieldBase
Expand All @@ -34,6 +36,7 @@ function ReportFieldFilterContent({values, selectedField, largeButton, style, on
hasFeed={!!values?.feed}
selectedField={selectedField}
onFieldSelected={onFieldSelected}
onError={setError}
style={style}
/>
{!!selectedField && (
Expand All @@ -44,6 +47,10 @@ function ReportFieldFilterContent({values, selectedField, largeButton, style, on
text={translate('common.apply')}
pressOnEnter
onPress={() => {
if (error) {
return;
}

const value = reportFieldRef.current?.applySelectedFieldAndGoBack();
if (!value) {
return;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {isAmountFilterKey, isDateFilterKey} from '@libs/SearchUIUtils';
import {isAmountFilterKey, isDateFilterKey, isTextFilterKey} from '@libs/SearchUIUtils';
import type {SearchFilter} from '@libs/SearchUIUtils';

import CONST from '@src/CONST';
Expand Down Expand Up @@ -42,14 +42,7 @@ function getFilterFormValue<K extends FilterComponentsProps['filterKey']>(filter
function SearchAdvancedFiltersContent({filterKey, values, policyIDQuery, ready, components, onChange}: SearchAdvancedFiltersContentProps) {
const {Text: TextFilter, Amount: AmountFilter, Date: DateFilter, ReportField: ReportFieldFilter, Common: CommonFilter} = components;

if (
filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.MERCHANT ||
filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.DESCRIPTION ||
filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.REPORT_ID ||
filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.KEYWORD ||
filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.TITLE ||
filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.WITHDRAWAL_ID
) {
if (isTextFilterKey(filterKey)) {
return (
<TextFilter
key={filterKey}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import Button from '@components/Button';
import useTextFilterValidation from '@components/Search/hooks/useTextFilterValidation';
import TextInput from '@components/TextInput';
import type {BaseTextInputRef} from '@components/TextInput/BaseTextInput/types';

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

import type CONST from '@src/CONST';
import {FILTER_VIEW_MAP} from '@libs/SearchUIUtils';

import type {StyleProp, ViewStyle} from 'react-native';
import CONST from '@src/CONST';

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

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

import FilterComponents from '..';

type TextInputFilterContentProps = {
filterKey:
| typeof CONST.SEARCH.SYNTAX_FILTER_KEYS.MERCHANT
Expand All @@ -27,28 +31,49 @@ type TextInputFilterContentProps = {
onChange: (value: string | undefined) => void;
};

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

function TextInputFilterContent({filterKey, value: initialValue, autoFocus, largeButton, style, onChange}: TextInputFilterContentProps) {
const {translate} = useLocalize();
const styles = useThemeStyles();
const [value, setValue] = useState(initialValue);

const label = translate(FILTER_VIEW_MAP[filterKey].labelKey);
const {inputCallbackRef} = useAutoFocusInput();
const error = useTextFilterValidation(filterKey, value);

return (
<View style={[styles.flex1, styles.justifyContentBetween, style]}>
<FilterComponents
<TextInput
ref={(ref) => {
if (!autoFocus || !isTextInput(ref)) {
return;
}
inputCallbackRef(ref);
}}
placeholder={label}
value={value}
policyIDs={undefined}
filterKey={filterKey}
policyIDQuery={undefined}
autoFocus={autoFocus}
onChange={(v) => setValue(typeof v === 'string' ? v : undefined)}
errorText={error}
hasError={!!error}
onChangeText={setValue}
accessibilityLabel={label}
role={CONST.ROLE.PRESENTATION}
containerStyles={[styles.ph5]}
/>
<Button
style={[styles.ph5, styles.pb5]}
success
large={largeButton}
text={translate('common.confirm')}
pressOnEnter
onPress={() => onChange(value)}
onPress={() => {
if (error) {
return;
}
onChange(value);
}}
/>
</View>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import useTextFilterValidation from '@components/Search/hooks/useTextFilterValidation';
import type {ReportFieldTextKey} from '@components/Search/types';
import TextInput from '@components/TextInput';

import useThemeStyles from '@hooks/useThemeStyles';
Expand All @@ -8,18 +10,23 @@ import type {PolicyReportField} from '@src/types/onyx';
import React from 'react';

type ReportFieldTextProps = {
filterKey: ReportFieldTextKey;
field: PolicyReportField;
value: string | undefined;
onChange: (newValue: string) => void;
onError: (error: string | undefined) => void;
};

function ReportFieldText({field, value, onChange}: ReportFieldTextProps) {
function ReportFieldText({filterKey, field, value, onChange, onError}: ReportFieldTextProps) {
const styles = useThemeStyles();
const error = useTextFilterValidation(filterKey, value, onError);

return (
<TextInput
placeholder={field.name}
value={value}
errorText={error}
hasError={!!error}
onChangeText={onChange}
accessibilityLabel={field.name}
role={CONST.ROLE.PRESENTATION}
Expand Down
16 changes: 10 additions & 6 deletions src/components/Search/FilterComponents/ReportField/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,14 @@ type ReportFieldBaseProps = {
hasFeed: boolean;
style?: StyleProp<ViewStyle>;
onFieldSelected: (field: PolicyReportField | null) => void;
onError: (error: string | undefined) => void;
};

type SelectedReportFieldProps = {
ref: React.Ref<ReportFieldHandle>;
field: PolicyReportField;
value: string | undefined;
onError: (error: string | undefined) => void;
};

type SelectedDateReportFieldProps = {
Expand All @@ -69,9 +71,10 @@ function getFilterKey(fieldName: string) {
return `${CONST.SEARCH.REPORT_FIELD.DEFAULT_PREFIX}${suffix}` as const;
}

function SelectedReportField({ref, field, value: initialValue}: SelectedReportFieldProps) {
function SelectedReportField({ref, field, value: initialValue, onError}: SelectedReportFieldProps) {
const [value, setValue] = useState(initialValue);
const fieldType = field.type as Exclude<ValueOf<typeof CONST.REPORT_FIELD_TYPES>, typeof CONST.REPORT_FIELD_TYPES.FORMULA | typeof CONST.REPORT_FIELD_TYPES.DATE>;
const filterKey = getFilterKey(field.name);

const UpdateReportFieldComponent = {
[CONST.REPORT_FIELD_TYPES.LIST]: ReportFieldList,
Expand All @@ -80,22 +83,22 @@ function SelectedReportField({ref, field, value: initialValue}: SelectedReportFi

useImperativeHandle(ref, () => ({
getValue: () => {
const key = getFilterKey(field.name);
return {[key]: value};
return {[filterKey]: value};
},
getEmptyValue: () => {
const key = getFilterKey(field.name);
return {[key]: ''};
return {[filterKey]: ''};
},
isDateModifierSelected: () => false,
applySelectedFieldAndGoBack: () => {},
}));

return (
<UpdateReportFieldComponent
filterKey={filterKey}
field={field}
value={value}
onChange={setValue}
onError={onError}
/>
);
}
Expand Down Expand Up @@ -164,7 +167,7 @@ function SelectedDateReportField({ref, field, value: initialValue, selectedDateM
);
}

function ReportFieldBase({ref, values: initialValues = {}, selectedField, hasFeed, style, onFieldSelected}: ReportFieldBaseProps) {
function ReportFieldBase({ref, values: initialValues = {}, selectedField, hasFeed, style, onFieldSelected, onError}: ReportFieldBaseProps) {
const {translate, localeCompare} = useLocalize();
const styles = useThemeStyles();
const policyReportFieldsSelector = (policies: OnyxCollection<Policy>) => createAllPolicyReportFieldsSelector(policies, localeCompare);
Expand Down Expand Up @@ -255,6 +258,7 @@ function ReportFieldBase({ref, values: initialValues = {}, selectedField, hasFee
ref={selectedFieldRef}
field={selectedField}
value={getValue(selectedField.name)}
onError={onError}
/>
)}
</>
Expand Down
55 changes: 1 addition & 54 deletions src/components/Search/FilterComponents/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import type {SearchAmountFilterKeys, SearchDateFilterKeys, SearchFilterCommonProps} from '@components/Search/types';
import TextInput from '@components/TextInput';
import type {BaseTextInputRef} from '@components/TextInput/BaseTextInput/types';

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

import {FILTER_VIEW_MAP, getMultiSelectFilterOptions, getSingleSelectFilterOptions} from '@libs/SearchUIUtils';
import {getMultiSelectFilterOptions, getSingleSelectFilterOptions} from '@libs/SearchUIUtils';
import type {SearchFilter} from '@libs/SearchUIUtils';

import CONST from '@src/CONST';
Expand Down Expand Up @@ -38,19 +34,6 @@ type FilterComponentsProps = SearchFilterCommonProps<SearchAdvancedFiltersForm[F
policyIDQuery: string[] | undefined;
};

type TextInputFilterComponentsProps = {
filterKey:
| typeof CONST.SEARCH.SYNTAX_FILTER_KEYS.MERCHANT
| typeof CONST.SEARCH.SYNTAX_FILTER_KEYS.DESCRIPTION
| typeof CONST.SEARCH.SYNTAX_FILTER_KEYS.REPORT_ID
| typeof CONST.SEARCH.SYNTAX_FILTER_KEYS.KEYWORD
| typeof CONST.SEARCH.SYNTAX_FILTER_KEYS.TITLE
| typeof CONST.SEARCH.SYNTAX_FILTER_KEYS.WITHDRAWAL_ID;
value: string | undefined;
autoFocus?: boolean;
onChange: (value: string) => void;
};

type SingleSelectFilterKeys = typeof CONST.SEARCH.SYNTAX_FILTER_KEYS.BILLABLE | typeof CONST.SEARCH.SYNTAX_FILTER_KEYS.REIMBURSABLE | typeof CONST.SEARCH.SYNTAX_FILTER_KEYS.WITHDRAWAL_TYPE;
type SingleSelectFilterComponentsProps = SearchFilterCommonProps<SearchAdvancedFiltersForm[SingleSelectFilterKeys] | undefined> & {
filterKey: SingleSelectFilterKeys;
Expand All @@ -69,26 +52,6 @@ type MultiSelectFilterComponentsProps = SearchFilterCommonProps<SearchAdvancedFi
type: SearchDataTypes | undefined;
};

function TextInputFilterComponents({filterKey, value, autoFocus, onChange}: TextInputFilterComponentsProps) {
const {translate} = useLocalize();
const styles = useThemeStyles();

const label = translate(FILTER_VIEW_MAP[filterKey].labelKey);
const {inputCallbackRef} = useAutoFocusInput();

return (
<TextInput
ref={autoFocus ? (inputCallbackRef as (ref: BaseTextInputRef | null) => void) : undefined}
placeholder={label}
value={value}
onChangeText={onChange}
accessibilityLabel={label}
role={CONST.ROLE.PRESENTATION}
containerStyles={[styles.ph5]}
/>
);
}

function SingleSelectFilterComponents({filterKey, value, selectionListTextInputStyle, selectionListStyle, footer, onChange}: SingleSelectFilterComponentsProps) {
const {translate} = useLocalize();
const items = getSingleSelectFilterOptions(filterKey, translate);
Expand Down Expand Up @@ -172,22 +135,6 @@ function FilterComponents({filterKey, value, type, policyIDs, policyIDQuery, sel
/>
);
}
case CONST.SEARCH.SYNTAX_FILTER_KEYS.MERCHANT:
case CONST.SEARCH.SYNTAX_FILTER_KEYS.DESCRIPTION:
case CONST.SEARCH.SYNTAX_FILTER_KEYS.REPORT_ID:
case CONST.SEARCH.SYNTAX_FILTER_KEYS.KEYWORD:
case CONST.SEARCH.SYNTAX_FILTER_KEYS.TITLE:
case CONST.SEARCH.SYNTAX_FILTER_KEYS.WITHDRAWAL_ID: {
return (
<TextInputFilterComponents
key={filterKey}
filterKey={filterKey}
value={typeof value === 'string' ? value : undefined}
autoFocus={autoFocus}
onChange={onChange}
/>
);
}
case CONST.SEARCH.SYNTAX_FILTER_KEYS.CURRENCY:
case CONST.SEARCH.SYNTAX_FILTER_KEYS.PURCHASE_CURRENCY: {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ function ReportFieldPopup({values, closeOverlay, updateFilterForm}: ReportFieldP
const [selectedField, setSelectedField] = useState<PolicyReportField | null>(null);
const reportFieldRef = useRef<ReportFieldHandle>(null);

const [error, setError] = useState<string>();

const applyChanges = () => {
if (!reportFieldRef.current) {
if (!reportFieldRef.current || error) {
Comment thread
bernhardoj marked this conversation as resolved.
return;
}

Expand All @@ -55,6 +57,7 @@ function ReportFieldPopup({values, closeOverlay, updateFilterForm}: ReportFieldP
hasFeed={!!values.feed}
selectedField={selectedField}
onFieldSelected={setSelectedField}
onError={setError}
/>
</BasePopup>
);
Expand Down
Loading
Loading