diff --git a/src/components/ReportActionItem/MoneyReportView.tsx b/src/components/ReportActionItem/MoneyReportView.tsx index a1a9c6c747a1..bef9a6c4bb3c 100644 --- a/src/components/ReportActionItem/MoneyReportView.tsx +++ b/src/components/ReportActionItem/MoneyReportView.tsx @@ -19,6 +19,7 @@ import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import AnimatedEmptyStateBackground from '@pages/home/report/AnimatedEmptyStateBackground'; import variables from '@styles/variables'; +import * as reportActions from '@src/libs/actions/Report'; import ROUTES from '@src/ROUTES'; import type {Policy, PolicyReportField, Report} from '@src/types/onyx'; @@ -81,6 +82,7 @@ function MoneyReportView({report, policy, shouldShowHorizontalRule}: MoneyReport errors={report.errorFields?.[fieldKey]} errorRowStyles={styles.ph5} key={`menuItem-${fieldKey}`} + onClose={() => reportActions.clearReportFieldErrors(report.reportID, reportField)} > = { onDismissError?: (item: TItem) => void; /** Component to display on the right side */ - rightHandSideComponent?: ((item: TItem) => ReactElement) | ReactElement | null; + rightHandSideComponent?: ((item: TItem) => ReactElement | null) | ReactElement | null; /** Styles for the pressable component */ pressableStyle?: StyleProp; @@ -278,7 +278,7 @@ type BaseSelectionListProps = Partial & { isKeyboardShown?: boolean; /** Component to display on the right side of each child */ - rightHandSideComponent?: ((item: ListItem) => ReactElement) | ReactElement | null; + rightHandSideComponent?: ((item: ListItem) => ReactElement | null) | ReactElement | null; /** Whether to show the loading indicator for new options */ isLoadingNewOptions?: boolean; diff --git a/src/languages/en.ts b/src/languages/en.ts index 041c90146ec0..ab1a53a55da9 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1919,6 +1919,10 @@ export default { subtitle: 'Sync your chart of accounts and more.', }, }, + reportFields: { + delete: 'Delete field', + deleteConfirmation: 'Are you sure that you want to delete this field?', + }, tags: { tagName: 'Tag name', requiresTag: 'Members must tag all spend', diff --git a/src/languages/es.ts b/src/languages/es.ts index ef6ab4a66759..6330ade811ca 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1946,6 +1946,10 @@ export default { subtitle: 'Sincroniza tu plan de cuentas y otras opciones.', }, }, + reportFields: { + delete: 'Eliminar campos', + deleteConfirmation: '¿Estás seguro de que quieres eliminar esta campos?', + }, tags: { tagName: 'Nombre de etiqueta', requiresTag: 'Los miembros deben etiquetar todos los gastos', diff --git a/src/libs/API/parameters/DeleteReportFieldParams.ts b/src/libs/API/parameters/DeleteReportFieldParams.ts new file mode 100644 index 000000000000..f64659512f6b --- /dev/null +++ b/src/libs/API/parameters/DeleteReportFieldParams.ts @@ -0,0 +1,5 @@ +type DeleteReportFieldParams = { + fieldID: string; +}; + +export default DeleteReportFieldParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 1bc80e4c08c4..8ef3f255184e 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -128,6 +128,7 @@ export type {default as CompleteEngagementModalParams} from './CompleteEngagemen export type {default as SetNameValuePairParams} from './SetNameValuePairParams'; export type {default as SetReportFieldParams} from './SetReportFieldParams'; export type {default as SetReportNameParams} from './SetReportNameParams'; +export type {default as DeleteReportFieldParams} from './DeleteReportFieldParams'; export type {default as CompleteSplitBillParams} from './CompleteSplitBillParams'; export type {default as UpdateMoneyRequestParams} from './UpdateMoneyRequestParams'; export type {default as RequestMoneyParams} from './RequestMoneyParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 3cff726a530c..aa4e57561ba0 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -136,6 +136,7 @@ const WRITE_COMMANDS = { COMPLETE_ENGAGEMENT_MODAL: 'CompleteEngagementModal', SET_NAME_VALUE_PAIR: 'SetNameValuePair', SET_REPORT_FIELD: 'Report_SetFields', + DELETE_REPORT_FIELD: 'RemoveReportField', SET_REPORT_NAME: 'RenameReport', COMPLETE_SPLIT_BILL: 'CompleteSplitBill', UPDATE_MONEY_REQUEST_DATE: 'UpdateMoneyRequestDate', @@ -324,6 +325,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.SET_NAME_VALUE_PAIR]: Parameters.SetNameValuePairParams; [WRITE_COMMANDS.SET_REPORT_FIELD]: Parameters.SetReportFieldParams; [WRITE_COMMANDS.SET_REPORT_NAME]: Parameters.SetReportNameParams; + [WRITE_COMMANDS.DELETE_REPORT_FIELD]: Parameters.DeleteReportFieldParams; [WRITE_COMMANDS.COMPLETE_SPLIT_BILL]: Parameters.CompleteSplitBillParams; [WRITE_COMMANDS.UPDATE_MONEY_REQUEST_DATE]: Parameters.UpdateMoneyRequestParams; [WRITE_COMMANDS.UPDATE_MONEY_REQUEST_MERCHANT]: Parameters.UpdateMoneyRequestParams; diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index d2ed2ed7f5a6..6d0a1f2fc175 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -157,6 +157,9 @@ type GetOptionsConfig = { includeSelectedOptions?: boolean; includeTaxRates?: boolean; taxRates?: TaxRatesWithDefault; + includePolicyReportFieldOptions?: boolean; + policyReportFieldOptions?: string[]; + recentlyUsedPolicyReportFieldOptions?: string[]; transactionViolations?: OnyxCollection; }; @@ -184,6 +187,7 @@ type GetOptions = { categoryOptions: CategoryTreeSection[]; tagOptions: CategorySection[]; taxRatesOptions: CategorySection[]; + policyReportFieldOptions?: CategorySection[] | null; }; type PreviewConfig = {showChatPreviewLine?: boolean; forcePolicyNamePreview?: boolean; showPersonalDetails?: boolean}; @@ -1229,6 +1233,81 @@ function hasEnabledTags(policyTagList: Array return hasEnabledOptions(policyTagValueList); } +/** + * Transforms the provided report field options into option objects. + * + * @param reportFieldOptions - an initial report field options array + */ +function getReportFieldOptions(reportFieldOptions: string[]): Option[] { + return reportFieldOptions.map((name) => ({ + text: name, + keyForList: name, + searchText: name, + tooltipText: name, + isDisabled: false, + })); +} + +/** + * Build the section list for report field options + */ +function getReportFieldOptionsSection(options: string[], recentlyUsedOptions: string[], selectedOptions: Array>, searchInputValue: string) { + const reportFieldOptionsSections = []; + const selectedOptionKeys = selectedOptions.map(({text, keyForList, name}) => text ?? keyForList ?? name ?? '').filter((o) => !!o); + let indexOffset = 0; + + if (searchInputValue) { + const searchOptions = options.filter((option) => option.toLowerCase().includes(searchInputValue.toLowerCase())); + + reportFieldOptionsSections.push({ + // "Search" section + title: '', + shouldShow: true, + indexOffset, + data: getReportFieldOptions(searchOptions), + }); + + return reportFieldOptionsSections; + } + + const filteredRecentlyUsedOptions = recentlyUsedOptions.filter((recentlyUsedOption) => !selectedOptionKeys.includes(recentlyUsedOption)); + const filteredOptions = options.filter((option) => !selectedOptionKeys.includes(option)); + + if (selectedOptionKeys.length) { + reportFieldOptionsSections.push({ + // "Selected" section + title: '', + shouldShow: true, + indexOffset, + data: getReportFieldOptions(selectedOptionKeys), + }); + + indexOffset += selectedOptionKeys.length; + } + + if (filteredRecentlyUsedOptions.length > 0) { + reportFieldOptionsSections.push({ + // "Recent" section + title: Localize.translateLocal('common.recent'), + shouldShow: true, + indexOffset, + data: getReportFieldOptions(filteredRecentlyUsedOptions), + }); + + indexOffset += filteredRecentlyUsedOptions.length; + } + + reportFieldOptionsSections.push({ + // "All" section when items amount more than the threshold + title: Localize.translateLocal('common.all'), + shouldShow: true, + indexOffset, + data: getReportFieldOptions(filteredOptions), + }); + + return reportFieldOptionsSections; +} + /** * Transforms tax rates to a new object format - to add codes and new name with concatenated name and value. * @@ -1454,6 +1533,9 @@ function getOptions( includeTaxRates, taxRates, includeSelfDM = false, + includePolicyReportFieldOptions = false, + policyReportFieldOptions = [], + recentlyUsedPolicyReportFieldOptions = [], }: GetOptionsConfig, ): GetOptions { if (includeCategories) { @@ -1498,6 +1580,20 @@ function getOptions( }; } + if (includePolicyReportFieldOptions) { + const transformedPolicyReportFieldOptions = getReportFieldOptionsSection(policyReportFieldOptions, recentlyUsedPolicyReportFieldOptions, selectedOptions, searchInputValue); + return { + recentReports: [], + personalDetails: [], + userToInvite: null, + currentUserOption: null, + categoryOptions: [], + tagOptions: [], + taxRatesOptions: [], + policyReportFieldOptions: transformedPolicyReportFieldOptions, + }; + } + const parsedPhoneNumber = PhoneNumber.parsePhoneNumber(LoginUtils.appendCountryCode(Str.removeSMSDomain(searchInputValue))); const searchValue = parsedPhoneNumber.possible ? parsedPhoneNumber.number?.e164 : searchInputValue.toLowerCase(); const topmostReportId = Navigation.getTopmostReportId() ?? ''; @@ -1881,6 +1977,9 @@ function getFilteredOptions( includeTaxRates = false, taxRates: TaxRatesWithDefault = {} as TaxRatesWithDefault, includeSelfDM = false, + includePolicyReportFieldOptions = false, + policyReportFieldOptions: string[] = [], + recentlyUsedPolicyReportFieldOptions: string[] = [], ) { return getOptions( {reports, personalDetails}, @@ -1905,6 +2004,9 @@ function getFilteredOptions( includeTaxRates, taxRates, includeSelfDM, + includePolicyReportFieldOptions, + policyReportFieldOptions, + recentlyUsedPolicyReportFieldOptions, }, ); } diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index f3fefa4850a7..91128ac89178 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -1598,6 +1598,18 @@ function updateReportName(reportID: string, value: string, previousValue: string API.write(WRITE_COMMANDS.SET_REPORT_NAME, parameters, {optimisticData, failureData, successData}); } +function clearReportFieldErrors(reportID: string, reportField: PolicyReportField) { + const fieldKey = ReportUtils.getReportFieldKey(reportField.fieldID); + Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, { + pendingFields: { + [fieldKey]: null, + }, + errorFields: { + [fieldKey]: null, + }, + }); +} + function updateReportField(reportID: string, reportField: PolicyReportField, previousReportField: PolicyReportField) { const fieldKey = ReportUtils.getReportFieldKey(reportField.fieldID); const recentlyUsedValues = allRecentlyUsedReportFields?.[fieldKey] ?? []; @@ -1678,6 +1690,65 @@ function updateReportField(reportID: string, reportField: PolicyReportField, pre API.write(WRITE_COMMANDS.SET_REPORT_FIELD, parameters, {optimisticData, failureData, successData}); } +function deleteReportField(reportID: string, reportField: PolicyReportField) { + const fieldKey = ReportUtils.getReportFieldKey(reportField.fieldID); + + const optimisticData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: { + fieldList: { + [fieldKey]: null, + }, + pendingFields: { + [fieldKey]: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }, + }, + }, + ]; + + const failureData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: { + fieldList: { + [fieldKey]: reportField, + }, + pendingFields: { + [fieldKey]: null, + }, + errorFields: { + [fieldKey]: ErrorUtils.getMicroSecondOnyxError('report.genericUpdateReportFieldFailureMessage'), + }, + }, + }, + ]; + + const successData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: { + pendingFields: { + [fieldKey]: null, + }, + errorFields: { + [fieldKey]: null, + }, + }, + }, + ]; + + const parameters = { + reportID, + fieldID: fieldKey, + }; + + API.write(WRITE_COMMANDS.DELETE_REPORT_FIELD, parameters, {optimisticData, failureData, successData}); +} + function updateDescription(reportID: string, previousValue: string, newValue: string) { // No change needed, navigate back if (previousValue === newValue) { @@ -3010,6 +3081,8 @@ export { clearNewRoomFormError, updateReportField, updateReportName, + deleteReportField, + clearReportFieldErrors, resolveActionableMentionWhisper, updateRoomVisibility, setGroupDraft, diff --git a/src/pages/EditReportFieldDatePage.tsx b/src/pages/EditReportFieldDate.tsx similarity index 53% rename from src/pages/EditReportFieldDatePage.tsx rename to src/pages/EditReportFieldDate.tsx index 3d60884d3cfc..e7021f9123d6 100644 --- a/src/pages/EditReportFieldDatePage.tsx +++ b/src/pages/EditReportFieldDate.tsx @@ -4,9 +4,7 @@ import DatePicker from '@components/DatePicker'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; import type {FormInputErrors, FormOnyxValues} from '@components/Form/types'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; import type {AnimatedTextInputRef} from '@components/RNTextInput'; -import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import CONST from '@src/CONST'; @@ -46,40 +44,29 @@ function EditReportFieldDatePage({fieldName, isRequired, onSubmit, fieldValue, f ); return ( - { - inputRef.current?.focus(); - }} - testID={EditReportFieldDatePage.displayName} + - - - - {/* @ts-expect-error TODO: Remove this once DatePicker (https://github.com/Expensify/App/issues/25148) is migrated to TypeScript. */} - - InputComponent={DatePicker} - inputID={fieldKey} - name={fieldKey} - defaultValue={fieldValue} - label={fieldName} - accessibilityLabel={fieldName} - role={CONST.ROLE.PRESENTATION} - maxDate={CONST.CALENDAR_PICKER.MAX_DATE} - minDate={CONST.CALENDAR_PICKER.MIN_DATE} - ref={inputRef} - /> - - - + + + + ); } diff --git a/src/pages/EditReportFieldDropdown.tsx b/src/pages/EditReportFieldDropdown.tsx new file mode 100644 index 000000000000..225051238e2b --- /dev/null +++ b/src/pages/EditReportFieldDropdown.tsx @@ -0,0 +1,125 @@ +import React, {useCallback, useMemo} from 'react'; +import {withOnyx} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; +import Icon from '@components/Icon'; +import * as Expensicons from '@components/Icon/Expensicons'; +import SelectionList from '@components/SelectionList'; +import RadioListItem from '@components/SelectionList/RadioListItem'; +import type {ListItem} from '@components/SelectionList/types'; +import useDebouncedState from '@hooks/useDebouncedState'; +import useLocalize from '@hooks/useLocalize'; +import useTheme from '@hooks/useTheme'; +import * as OptionsListUtils from '@libs/OptionsListUtils'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {RecentlyUsedReportFields} from '@src/types/onyx'; + +type EditReportFieldDropdownPageComponentProps = { + /** Value of the policy report field */ + fieldValue: string; + + /** Key of the policy report field */ + fieldKey: string; + + /** ID of the policy this report field belongs to */ + // eslint-disable-next-line react/no-unused-prop-types + policyID: string; + + /** Options of the policy report field */ + fieldOptions: string[]; + + /** Callback to fire when the Save button is pressed */ + onSubmit: (form: Record) => void; +}; + +type EditReportFieldDropdownPageOnyxProps = { + recentlyUsedReportFields: OnyxEntry; +}; + +type EditReportFieldDropdownPageProps = EditReportFieldDropdownPageComponentProps & EditReportFieldDropdownPageOnyxProps; + +function EditReportFieldDropdownPage({onSubmit, fieldKey, fieldValue, fieldOptions, recentlyUsedReportFields}: EditReportFieldDropdownPageProps) { + const [searchValue, debouncedSearchValue, setSearchValue] = useDebouncedState(''); + const theme = useTheme(); + const {translate} = useLocalize(); + const recentlyUsedOptions = useMemo(() => recentlyUsedReportFields?.[fieldKey] ?? [], [recentlyUsedReportFields, fieldKey]); + + const itemRightSideComponent = useCallback( + (item: ListItem) => { + if (item.text === fieldValue) { + return ( + + ); + } + + return null; + }, + [theme.iconSuccessFill, fieldValue], + ); + + const [sections, headerMessage] = useMemo(() => { + const validFieldOptions = fieldOptions?.filter((option) => !!option); + + const {policyReportFieldOptions} = OptionsListUtils.getFilteredOptions( + [], + [], + [], + debouncedSearchValue, + [ + { + keyForList: fieldValue, + searchText: fieldValue, + text: fieldValue, + }, + ], + [], + false, + false, + false, + {}, + [], + false, + {}, + [], + false, + false, + undefined, + undefined, + undefined, + true, + validFieldOptions, + recentlyUsedOptions, + ); + + const policyReportFieldData = policyReportFieldOptions?.[0]?.data ?? []; + const header = OptionsListUtils.getHeaderMessageForNonUserList(policyReportFieldData.length > 0, debouncedSearchValue); + + return [policyReportFieldOptions, header]; + }, [recentlyUsedOptions, debouncedSearchValue, fieldValue, fieldOptions]); + + const selectedOptionKey = useMemo(() => (sections?.[0]?.data ?? []).filter((option) => option.searchText === fieldValue)?.[0]?.keyForList, [sections, fieldValue]); + return ( + onSubmit({[fieldKey]: !option?.text || fieldValue === option.text ? '' : option.text})} + initiallyFocusedOptionKey={selectedOptionKey ?? undefined} + onChangeText={setSearchValue} + headerMessage={headerMessage} + ListItem={RadioListItem} + isRowMultilineSupported + rightHandSideComponent={itemRightSideComponent} + /> + ); +} + +EditReportFieldDropdownPage.displayName = 'EditReportFieldDropdownPage'; + +export default withOnyx({ + recentlyUsedReportFields: { + key: () => ONYXKEYS.RECENTLY_USED_REPORT_FIELDS, + }, +})(EditReportFieldDropdownPage); diff --git a/src/pages/EditReportFieldDropdownPage.tsx b/src/pages/EditReportFieldDropdownPage.tsx deleted file mode 100644 index e887860ae155..000000000000 --- a/src/pages/EditReportFieldDropdownPage.tsx +++ /dev/null @@ -1,167 +0,0 @@ -import React, {useMemo, useState} from 'react'; -import {withOnyx} from 'react-native-onyx'; -import type {OnyxEntry} from 'react-native-onyx'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import OptionsSelector from '@components/OptionsSelector'; -import ScreenWrapper from '@components/ScreenWrapper'; -import useLocalize from '@hooks/useLocalize'; -import useStyleUtils from '@hooks/useStyleUtils'; -import useThemeStyles from '@hooks/useThemeStyles'; -import ONYXKEYS from '@src/ONYXKEYS'; -import type {RecentlyUsedReportFields} from '@src/types/onyx'; - -type EditReportFieldDropdownPageComponentProps = { - /** Value of the policy report field */ - fieldValue: string; - - /** Name of the policy report field */ - fieldName: string; - - /** Key of the policy report field */ - fieldKey: string; - - /** ID of the policy this report field belongs to */ - // eslint-disable-next-line react/no-unused-prop-types - policyID: string; - - /** Options of the policy report field */ - fieldOptions: string[]; - - /** Callback to fire when the Save button is pressed */ - onSubmit: (form: Record) => void; -}; - -type EditReportFieldDropdownPageOnyxProps = { - recentlyUsedReportFields: OnyxEntry; -}; - -type EditReportFieldDropdownPageProps = EditReportFieldDropdownPageComponentProps & EditReportFieldDropdownPageOnyxProps; - -type ReportFieldDropdownData = { - text: string; - keyForList: string; - searchText: string; - tooltipText: string; -}; - -type ReportFieldDropdownSectionItem = { - data: ReportFieldDropdownData[]; - shouldShow: boolean; - title?: string; -}; - -function EditReportFieldDropdownPage({fieldName, onSubmit, fieldKey, fieldValue, fieldOptions, recentlyUsedReportFields}: EditReportFieldDropdownPageProps) { - const [searchValue, setSearchValue] = useState(''); - const styles = useThemeStyles(); - const {getSafeAreaMargins} = useStyleUtils(); - const {translate} = useLocalize(); - const recentlyUsedOptions = useMemo(() => recentlyUsedReportFields?.[fieldKey] ?? [], [recentlyUsedReportFields, fieldKey]); - - const {sections, headerMessage} = useMemo(() => { - let newHeaderMessage = ''; - const newSections: ReportFieldDropdownSectionItem[] = []; - - if (searchValue) { - const filteredOptions = fieldOptions.filter((option) => option.toLowerCase().includes(searchValue.toLowerCase())); - newHeaderMessage = !filteredOptions.length ? translate('common.noResultsFound') : ''; - newSections.push({ - shouldShow: false, - data: filteredOptions.map((option) => ({ - text: option, - keyForList: option, - searchText: option, - tooltipText: option, - })), - }); - } else { - const selectedValue = fieldValue; - if (selectedValue) { - newSections.push({ - shouldShow: false, - data: [ - { - text: selectedValue, - keyForList: selectedValue, - searchText: selectedValue, - tooltipText: selectedValue, - }, - ], - }); - } - - const filteredRecentlyUsedOptions = recentlyUsedOptions.filter((option) => option !== selectedValue && fieldOptions.includes(option)); - if (filteredRecentlyUsedOptions.length > 0) { - newSections.push({ - title: translate('common.recents'), - shouldShow: true, - data: filteredRecentlyUsedOptions.map((option) => ({ - text: option, - keyForList: option, - searchText: option, - tooltipText: option, - })), - }); - } - - const filteredFieldOptions = fieldOptions.filter((option) => option !== selectedValue); - if (filteredFieldOptions.length > 0) { - newSections.push({ - title: translate('common.all'), - shouldShow: true, - data: filteredFieldOptions.map((option) => ({ - text: option, - keyForList: option, - searchText: option, - tooltipText: option, - })), - }); - } - } - - return {sections: newSections, headerMessage: newHeaderMessage}; - }, [fieldValue, fieldOptions, recentlyUsedOptions, searchValue, translate]); - - return ( - - {({insets}) => ( - <> - - ) => - onSubmit({ - [fieldKey]: fieldValue === option.text ? '' : option.text, - }) - } - onChangeText={setSearchValue} - highlightSelectedOptions - isRowMultilineSupported - headerMessage={headerMessage} - /> - - )} - - ); -} - -EditReportFieldDropdownPage.displayName = 'EditReportFieldDropdownPage'; - -export default withOnyx({ - recentlyUsedReportFields: { - key: () => ONYXKEYS.RECENTLY_USED_REPORT_FIELDS, - }, -})(EditReportFieldDropdownPage); diff --git a/src/pages/EditReportFieldPage.tsx b/src/pages/EditReportFieldPage.tsx index 72a472db3da0..6cc93d05ebbc 100644 --- a/src/pages/EditReportFieldPage.tsx +++ b/src/pages/EditReportFieldPage.tsx @@ -1,18 +1,25 @@ import Str from 'expensify-common/lib/str'; -import React from 'react'; +import React, {useState} from 'react'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; +import ConfirmModal from '@components/ConfirmModal'; import type {FormOnyxValues} from '@components/Form/types'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import type {ThreeDotsMenuItem} from '@components/HeaderWithBackButton/types'; +import * as Expensicons from '@components/Icon/Expensicons'; import ScreenWrapper from '@components/ScreenWrapper'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import useWindowDimensions from '@hooks/useWindowDimensions'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import * as ReportActions from '@src/libs/actions/Report'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Policy, Report} from '@src/types/onyx'; -import EditReportFieldDatePage from './EditReportFieldDatePage'; -import EditReportFieldDropdownPage from './EditReportFieldDropdownPage'; -import EditReportFieldTextPage from './EditReportFieldTextPage'; +import EditReportFieldDate from './EditReportFieldDate'; +import EditReportFieldDropdown from './EditReportFieldDropdown'; +import EditReportFieldText from './EditReportFieldText'; type EditReportFieldPageOnyxProps = { /** The report object for the expense report */ @@ -40,9 +47,13 @@ type EditReportFieldPageProps = EditReportFieldPageOnyxProps & { }; function EditReportFieldPage({route, policy, report}: EditReportFieldPageProps) { + const {windowWidth} = useWindowDimensions(); + const styles = useThemeStyles(); const fieldKey = ReportUtils.getReportFieldKey(route.params.fieldID); const reportField = report?.fieldList?.[fieldKey] ?? policy?.fieldList?.[fieldKey]; const isDisabled = ReportUtils.isReportFieldDisabled(report, reportField ?? null, policy); + const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false); + const {translate} = useLocalize(); if (!reportField || !report || isDisabled) { return ( @@ -73,44 +84,78 @@ function EditReportFieldPage({route, policy, report}: EditReportFieldPageProps) Navigation.dismissModal(report?.reportID); }; + const handleReportFieldDelete = () => { + ReportActions.deleteReportField(report.reportID, reportField); + Navigation.dismissModal(report?.reportID); + }; + const fieldValue = isReportFieldTitle ? report.reportName ?? '' : reportField.value ?? reportField.defaultValue; - if (reportField.type === 'text' || isReportFieldTitle) { - return ( - - ); + const menuItems: ThreeDotsMenuItem[] = []; + + const isReportFieldDeletable = reportField.deletable && !isReportFieldTitle; + + if (isReportFieldDeletable) { + menuItems.push({icon: Expensicons.Trashcan, text: translate('common.delete'), onSelected: () => setIsDeleteModalVisible(true)}); } - if (reportField.type === 'date') { - return ( - + - ); - } - if (reportField.type === 'dropdown') { - return ( - !reportField.disabledOptions[index])} - onSubmit={handleReportFieldChange} + setIsDeleteModalVisible(false)} + prompt={translate('workspace.reportFields.deleteConfirmation')} + confirmText={translate('common.delete')} + cancelText={translate('common.cancel')} + danger /> - ); - } + + {(reportField.type === 'text' || isReportFieldTitle) && ( + + )} + + {reportField.type === 'date' && ( + + )} + + {reportField.type === 'dropdown' && ( + !reportField.disabledOptions[index])} + onSubmit={handleReportFieldChange} + /> + )} + + ); } EditReportFieldPage.displayName = 'EditReportFieldPage'; diff --git a/src/pages/EditReportFieldTextPage.tsx b/src/pages/EditReportFieldText.tsx similarity index 58% rename from src/pages/EditReportFieldTextPage.tsx rename to src/pages/EditReportFieldText.tsx index 1a6cf96fb37a..d89724f0228b 100644 --- a/src/pages/EditReportFieldTextPage.tsx +++ b/src/pages/EditReportFieldText.tsx @@ -3,9 +3,7 @@ import {View} from 'react-native'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; import type {FormInputErrors, FormOnyxValues} from '@components/Form/types'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; import type {AnimatedTextInputRef} from '@components/RNTextInput'; -import ScreenWrapper from '@components/ScreenWrapper'; import TextInput from '@components/TextInput'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -46,37 +44,27 @@ function EditReportFieldTextPage({fieldName, onSubmit, fieldValue, isRequired, f ); return ( - { - inputRef.current?.focus(); - }} - testID={EditReportFieldTextPage.displayName} + - - - - - - - + + + + ); }