diff --git a/assets/images/columns.svg b/assets/images/columns.svg new file mode 100644 index 000000000000..6921bb4895dd --- /dev/null +++ b/assets/images/columns.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/CONST/index.ts b/src/CONST/index.ts index 5fa77b994f63..7f2b5f5767a3 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -6699,6 +6699,21 @@ const CONST = { CARD: 'card', WITHDRAWAL_ID: 'withdrawal-id', }, + get CUSTOM_COLUMNS() { + return { + DATE: this.TABLE_COLUMNS.DATE, + STATUS: this.TABLE_COLUMNS.STATUS, + TITLE: this.TABLE_COLUMNS.TITLE, + FROM: this.TABLE_COLUMNS.FROM, + TO: this.TABLE_COLUMNS.TO, + ACTION: this.TABLE_COLUMNS.ACTION, + }; + }, + get DEFAULT_COLUMNS() { + return { + EXPENSE_REPORT: [this.TABLE_COLUMNS.DATE, this.TABLE_COLUMNS.STATUS, this.TABLE_COLUMNS.TITLE, this.TABLE_COLUMNS.FROM, this.TABLE_COLUMNS.TO, this.TABLE_COLUMNS.ACTION], + }; + }, BOOLEAN: { YES: 'yes', NO: 'no', @@ -6781,6 +6796,7 @@ const CONST = { SORT_BY: 'sortBy', SORT_ORDER: 'sortOrder', GROUP_BY: 'groupBy', + COLUMNS: 'columns', }, SYNTAX_FILTER_KEYS: { TYPE: 'type', @@ -6889,6 +6905,7 @@ const CONST = { ATTENDEE: 'attendee', IS: 'is', REPORT_FIELD: 'report-field', + COLUMNS: 'columns', }, get SEARCH_USER_FRIENDLY_VALUES_MAP() { return { diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 3b7d7253be31..9cbc13be2f56 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -66,6 +66,7 @@ const ROUTES = { route: 'search/saved-search/rename', getRoute: ({name, jsonQuery}: {name: string; jsonQuery: SearchQueryString}) => `search/saved-search/rename?name=${name}&q=${jsonQuery}` as const, }, + SEARCH_COLUMNS: 'search/columns', SEARCH_ADVANCED_FILTERS: { route: 'search/filters/:filterKey?', getRoute: (filterKey?: SearchFilterKey | UserFriendlyKey) => { diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 8ac4f48c7614..da77476dd62b 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -48,6 +48,7 @@ const SCREENS = { MONEY_REQUEST_REPORT_HOLD_TRANSACTIONS: 'Search_Money_Request_Report_Hold_Transactions', MONEY_REQUEST_REPORT_REJECT_TRANSACTIONS: 'Search_Money_Request_Report_Reject_Transactions', REPORT_RHP: 'Search_Report_RHP', + COLUMNS_RHP: 'Search_Columns_RHP', REPORT_VERIFY_ACCOUNT: 'Search_Report_Verify_Account', ADVANCED_FILTERS_RHP: 'Search_Advanced_Filters_RHP', ADVANCED_FILTERS_TYPE_RHP: 'Search_Advanced_Filters_Type_RHP', @@ -253,6 +254,7 @@ const SCREENS = { EXPENSE_REPORT: 'ExpenseReport', SEARCH_MONEY_REQUEST_REPORT: 'SearchMoneyRequestReport', + SEARCH_COLUMNS: 'SearchColumns', SEARCH_ADVANCED_FILTERS: 'SearchAdvancedFilters', SEARCH_SAVED_SEARCH: 'SearchSavedSearch', SETTINGS_CATEGORIES: 'SettingsCategories', diff --git a/src/components/Icon/Expensicons.ts b/src/components/Icon/Expensicons.ts index b66b17b32bdc..aec8abbfecec 100644 --- a/src/components/Icon/Expensicons.ts +++ b/src/components/Icon/Expensicons.ts @@ -47,6 +47,7 @@ import Close from '@assets/images/close.svg'; import ClosedSign from '@assets/images/closed-sign.svg'; import Coins from '@assets/images/coins.svg'; import Collapse from '@assets/images/collapse.svg'; +import Columns from '@assets/images/columns.svg'; import CommentBubbles from '@assets/images/comment-bubbles.svg'; import Concierge from '@assets/images/concierge.svg'; import Connect from '@assets/images/connect.svg'; @@ -216,6 +217,7 @@ export { ConciergeAvatar, Connect, ConnectionComplete, + Columns, Copy, CreditCard, CreditCardHourglass, diff --git a/src/components/Icon/chunks/expensify-icons.chunk.ts b/src/components/Icon/chunks/expensify-icons.chunk.ts index 68d8253c0977..10a0c7fada65 100644 --- a/src/components/Icon/chunks/expensify-icons.chunk.ts +++ b/src/components/Icon/chunks/expensify-icons.chunk.ts @@ -54,6 +54,7 @@ import Close from '@assets/images/close.svg'; import ClosedSign from '@assets/images/closed-sign.svg'; import Coins from '@assets/images/coins.svg'; import Collapse from '@assets/images/collapse.svg'; +import Columns from '@assets/images/columns.svg'; import CommentBubbles from '@assets/images/comment-bubbles.svg'; import Concierge from '@assets/images/concierge.svg'; import Connect from '@assets/images/connect.svg'; @@ -266,6 +267,7 @@ const Expensicons = { Clock, ClosedSign, Collapse, + Columns, CommentBubbles, Concierge, ConciergeAvatar, diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx index 286103142f7e..01d3dc21d238 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx @@ -65,6 +65,7 @@ import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; +import {columnsSelector} from '@src/selectors/AdvancedSearchFiltersForm'; import type * as OnyxTypes from '@src/types/onyx'; import type {PendingAction} from '@src/types/onyx/OnyxCommon'; import MoneyRequestReportGroupHeader from './MoneyRequestReportGroupHeader'; @@ -183,6 +184,8 @@ function MoneyRequestReportTransactionList({ const shouldShowAddExpenseButton = canAddTransaction(report, isReportArchived) && isCurrentUserSubmitter(report); const [lastDistanceExpenseType] = useOnyx(ONYXKEYS.NVP_LAST_DISTANCE_EXPENSE_TYPE, {canBeMissing: true}); const [reportLayoutGroupBy] = useOnyx(ONYXKEYS.NVP_REPORT_LAYOUT_GROUP_BY, {canBeMissing: true}); + const [visibleColumns] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM, {canBeMissing: true, selector: columnsSelector}); + const shouldShowGroupedTransactions = isExpenseReport(report) && !isIOUReport(report); const addExpenseDropdownOptions = useMemo( @@ -265,9 +268,9 @@ function MoneyRequestReportTransactionList({ }, [newTransactions, sortBy, sortOrder, transactions, localeCompare, report]); const columnsToShow = useMemo(() => { - const columns = getColumnsToShow(currentUserDetails?.accountID, transactions, true); + const columns = getColumnsToShow(currentUserDetails?.accountID, transactions, visibleColumns, true); return (Object.keys(columns) as SearchColumnType[]).filter((column) => columns[column]); - }, [transactions, currentUserDetails?.accountID]); + }, [transactions, currentUserDetails?.accountID, visibleColumns]); const currentGroupBy = getReportLayoutGroupBy(reportLayoutGroupBy); diff --git a/src/components/Search/SearchPageHeader/SearchFiltersBar.tsx b/src/components/Search/SearchPageHeader/SearchFiltersBar.tsx index 2b820f11c3ce..04d602e9e8d6 100644 --- a/src/components/Search/SearchPageHeader/SearchFiltersBar.tsx +++ b/src/components/Search/SearchPageHeader/SearchFiltersBar.tsx @@ -99,7 +99,7 @@ function SearchFiltersBar({ const {isOffline} = useNetwork(); const personalDetails = usePersonalDetails(); - const {shouldUseNarrowLayout} = useResponsiveLayout(); + const {shouldUseNarrowLayout, isLargeScreenWidth} = useResponsiveLayout(); const {selectedTransactions, selectAllMatchingItems, areAllMatchingItemsSelected, showSelectAllMatchingItems, shouldShowFiltersBarLoading} = useSearchContext(); const [email] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true, selector: emailSelector}); @@ -113,7 +113,7 @@ function SearchFiltersBar({ const [allFeeds] = useOnyx(ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER, {canBeMissing: true}); const {isAccountLocked, showLockedAccountModal} = useContext(LockedAccountContext); const [searchResultsErrors] = useOnyx(`${ONYXKEYS.COLLECTION.SNAPSHOT}${hash}`, {canBeMissing: true, selector: searchResultsErrorSelector}); - const expensifyIcons = useMemoizedLazyExpensifyIcons(['Filter'] as const); + const expensifyIcons = useMemoizedLazyExpensifyIcons(['Filter', 'Columns'] as const); const taxRates = getAllTaxRates(allPolicies); @@ -324,6 +324,10 @@ function SearchFiltersBar({ Navigation.navigate(ROUTES.SEARCH_ADVANCED_FILTERS.getRoute()); }, [filterFormValues]); + const openSearchColumns = () => { + Navigation.navigate(ROUTES.SEARCH_COLUMNS); + }; + const isFormInitializedRef = useRef(false); useEffect(() => { @@ -777,6 +781,8 @@ function SearchFiltersBar({ [], ); + const shouldShowColumnsButton = isLargeScreenWidth && queryJSON.type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT; + const filterButtonText = useMemo( () => translate('search.filtersHeader') + (hiddenSelectedFilters.length > 0 ? ` (${hiddenSelectedFilters.length})` : ''), [translate, hiddenSelectedFilters.length], @@ -784,19 +790,46 @@ function SearchFiltersBar({ const renderListFooter = useCallback( () => ( -