diff --git a/src/components/Search/SearchList/ListItem/TransactionListItem.tsx b/src/components/Search/SearchList/ListItem/TransactionListItem.tsx index 34f06bcd0231..f30b58b25ac8 100644 --- a/src/components/Search/SearchList/ListItem/TransactionListItem.tsx +++ b/src/components/Search/SearchList/ListItem/TransactionListItem.tsx @@ -252,6 +252,7 @@ function TransactionListItem({ exportedColumnSize={exportedColumnSize} amountColumnSize={amountColumnSize} taxAmountColumnSize={taxAmountColumnSize} + isActionColumnWide={transactionItem.isActionColumnWide} shouldShowCheckbox={!!canSelectMultiple} checkboxSentryLabel={CONST.SENTRY_LABEL.SEARCH.TRANSACTION_LIST_ITEM_CHECKBOX} style={[styles.p3, styles.pv2, shouldUseNarrowLayout ? styles.pt2 : isLargeScreenWidth && styles.noBorderRadius]} diff --git a/src/components/Search/SearchList/ListItem/types.ts b/src/components/Search/SearchList/ListItem/types.ts index 4de4bc9adbbc..3792f70b022f 100644 --- a/src/components/Search/SearchList/ListItem/types.ts +++ b/src/components/Search/SearchList/ListItem/types.ts @@ -160,6 +160,11 @@ type TransactionListItemType = ListItem & isTaxAmountColumnWide: boolean; + /** Whether the action column should use its wider variant. + * This is true if at least one transaction in the dataset is deleted. + */ + isActionColumnWide: boolean; + /** Key used internally by React */ keyForList: string; diff --git a/src/components/Search/SearchList/index.tsx b/src/components/Search/SearchList/index.tsx index 6968b8647ddb..050b1968af88 100644 --- a/src/components/Search/SearchList/index.tsx +++ b/src/components/Search/SearchList/index.tsx @@ -134,6 +134,9 @@ type SearchListProps = Pick, 'onScroll' | 'conten /** Whether all transactions have been loaded from snapshots in group-by views */ hasLoadedAllTransactions?: boolean; + /** Whether the action column should use its wider variant (e.g. when there is at least one deleted transaction) */ + isActionColumnWide?: boolean; + /** Reference to the outer element */ ref?: ForwardedRef; }; @@ -218,6 +221,7 @@ function SearchList({ nonPersonalAndWorkspaceCards, selectedTransactions, hasLoadedAllTransactions, + isActionColumnWide, ref, }: SearchListProps) { const styles = useThemeStyles(); @@ -332,7 +336,7 @@ function SearchList({ }, [data, groupBy, newTransactions]); const {windowWidth} = useWindowDimensions(); - const minTableWidth = getTableMinWidth(columns, queryJSON.type); + const minTableWidth = getTableMinWidth(columns, queryJSON.type, isActionColumnWide); const shouldScrollHorizontally = !!SearchTableHeader && minTableWidth > windowWidth; const horizontalScrollViewRef = useRef(null); diff --git a/src/components/Search/SearchTableHeader.tsx b/src/components/Search/SearchTableHeader.tsx index 0cdffe589a17..10a0f9fe9239 100644 --- a/src/components/Search/SearchTableHeader.tsx +++ b/src/components/Search/SearchTableHeader.tsx @@ -448,6 +448,9 @@ type SearchTableHeaderProps = { /** True when we are inside an expense report view, false if we're in the Reports page. */ isExpenseReportView?: boolean; + + /** True when the action column should render in its wider variant (e.g. tasks, deleted expenses). */ + isActionColumnWide?: boolean; }; function SearchTableHeader({ @@ -468,6 +471,7 @@ function SearchTableHeader({ isTaxAmountColumnWide, groupBy, isExpenseReportView, + isActionColumnWide, }: SearchTableHeaderProps) { const styles = useThemeStyles(); // eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth @@ -540,7 +544,7 @@ function SearchTableHeader({ sortBy={sortBy} sortOrder={sortOrder} shouldRemoveTotalColumnFlex={!!groupBy !== !!isExpenseReportView} - isActionColumnWide={type === CONST.SEARCH.DATA_TYPES.TASK} + isActionColumnWide={isActionColumnWide ?? type === CONST.SEARCH.DATA_TYPES.TASK} // Don't butt up against the 'select all' checkbox if present containerStyles={canSelectMultiple && [styles.pl3]} onSortPress={(columnName, order) => { diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 748fbde53cc5..9499bb62b50e 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -43,6 +43,7 @@ import { getSortedSections, getValidGroupBy, getWideAmountIndicators, + hasDeletedTransactionInData, isGroupedItemArray, isReportActionListItemType, isSearchDataLoaded, @@ -1488,6 +1489,8 @@ function Search({ [searchResults?.data], ); + const hasDeletedTransaction = useMemo(() => (searchResults?.data ? hasDeletedTransactionInData(searchResults.data) : false), [searchResults?.data]); + const onSortPress = useCallback( (column: SearchColumnType, order: SortOrder) => { clearSelectedTransactions(); @@ -1652,6 +1655,7 @@ function Search({ shouldShowSorting groupBy={validGroupBy} isExpenseReportView={isExpenseReportType} + isActionColumnWide={isTask || hasDeletedTransaction} /> ) @@ -1683,6 +1687,7 @@ function Search({ newTransactions={newTransactions} hasLoadedAllTransactions={hasLoadedAllTransactions} nonPersonalAndWorkspaceCards={nonPersonalAndWorkspaceCards} + isActionColumnWide={isTask || hasDeletedTransaction} /> diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx index 27dbb04f162c..36e8f1d5957a 100644 --- a/src/components/TransactionItemRow/index.tsx +++ b/src/components/TransactionItemRow/index.tsx @@ -145,6 +145,7 @@ type TransactionItemRowProps = { checkboxSentryLabel?: string; isLargeScreenWidth?: boolean; nonPersonalAndWorkspaceCards?: CardList; + isActionColumnWide?: boolean; }; const EMPTY_ACTIVE_STYLE: StyleProp = []; @@ -198,6 +199,7 @@ function TransactionItemRow({ checkboxSentryLabel, nonPersonalAndWorkspaceCards = {}, isLargeScreenWidth: isLargeScreenWidthProp, + isActionColumnWide: isActionColumnWideProp, }: TransactionItemRowProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -412,7 +414,7 @@ function TransactionItemRow({ return ( {!!transactionItem.action && ( { + if (isTransactionGroupListItemType(item)) { + return item.transactions.some((transaction) => transaction.reportID === CONST.REPORT.TRASH_REPORT_ID); + } + if (isTransactionListItemType(item)) { + return item.reportID === CONST.REPORT.TRASH_REPORT_ID; + } + return false; + }); + } + + return Object.keys(data).some((key) => { + if (isTransactionEntry(key)) { + const item = data[key]; + return item?.reportID === CONST.REPORT.TRASH_REPORT_ID; + } + return false; + }); +} + type ShouldShowYearResult = { shouldShowYearCreated: boolean; shouldShowYearSubmitted: boolean; @@ -1729,6 +1751,7 @@ type PreprocessingContext = { shouldShowYearExportedReport: boolean; shouldShowAmountInWideColumn: boolean; shouldShowTaxAmountInWideColumn: boolean; + hasDeletedTransaction: boolean; currentYear: number; }; @@ -1754,6 +1777,7 @@ function createPreprocessingContext(): PreprocessingContext { shouldShowYearExportedReport: false, shouldShowAmountInWideColumn: false, shouldShowTaxAmountInWideColumn: false, + hasDeletedTransaction: false, currentYear: new Date().getFullYear(), }; } @@ -1837,6 +1861,9 @@ function processTransactionEntry(ctx: PreprocessingContext, transaction: OnyxTyp if (!ctx.shouldShowTaxAmountInWideColumn) { ctx.shouldShowTaxAmountInWideColumn = isTransactionTaxAmountTooLong(transaction); } + if (!ctx.hasDeletedTransaction) { + ctx.hasDeletedTransaction = transaction.reportID === CONST.REPORT.TRASH_REPORT_ID; + } if (!ctx.shouldShowYearCreated) { const transactionCreated = getTransactionCreatedDate(transaction); @@ -2038,6 +2065,7 @@ function getTransactionsSections({ shouldShowYearExported, shouldShowAmountInWideColumn, shouldShowTaxAmountInWideColumn, + hasDeletedTransaction, } = classifyAndPreprocess(data); const personalDetailsMap = new Map(Object.entries(data.personalDetailsList ?? {})); @@ -2122,6 +2150,7 @@ function getTransactionsSections({ shouldShowYearExported, isAmountColumnWide: shouldShowAmountInWideColumn, isTaxAmountColumnWide: shouldShowTaxAmountInWideColumn, + isActionColumnWide: hasDeletedTransaction, violations: transactionViolations, category: isIOUReport ? '' : transactionItem?.category, errors: undefined, @@ -2623,6 +2652,7 @@ function getReportSections({ shouldShowYearExportedReport, shouldShowAmountInWideColumn, shouldShowTaxAmountInWideColumn, + hasDeletedTransaction, } = classifyAndPreprocess(data); const currentQueryJSON = queryJSON ?? getCurrentSearchQueryJSON(); @@ -2721,6 +2751,7 @@ function getReportSections({ nonReimbursableSpend, reimbursableSpend, isAmountColumnWide: shouldShowAmountInWideColumn, + isActionColumnWide: hasDeletedTransaction, isAllScanning: false, ...avatarProps, }; @@ -2781,6 +2812,7 @@ function getReportSections({ violations: transactionViolations, isAmountColumnWide: shouldShowAmountInWideColumn, isTaxAmountColumnWide: shouldShowTaxAmountInWideColumn, + isActionColumnWide: hasDeletedTransaction, category: isIOUReport ? '' : transactionItem?.category, errors: undefined, }; @@ -5579,7 +5611,7 @@ function getTransactionFromTransactionListItem(item: TransactionListItemType): O return transaction as OnyxTypes.Transaction; } -function getTableMinWidth(columns: SearchColumnType[], type?: SearchDataTypes) { +function getTableMinWidth(columns: SearchColumnType[], type?: SearchDataTypes, isActionColumnWide?: boolean) { // Starts at 24px to account for the checkbox width let minWidth = 24; @@ -5593,7 +5625,7 @@ function getTableMinWidth(columns: SearchColumnType[], type?: SearchDataTypes) { } else if (column === CONST.SEARCH.TABLE_COLUMNS.STATUS) { minWidth += 80; } else if (column === CONST.SEARCH.TABLE_COLUMNS.ACTION) { - minWidth += type === CONST.SEARCH.DATA_TYPES.TASK ? 80 : 68; + minWidth += (isActionColumnWide ?? type === CONST.SEARCH.DATA_TYPES.TASK) ? 80 : 68; } else if (column === CONST.SEARCH.TABLE_COLUMNS.DATE) { minWidth += 48; } else if ( @@ -5826,6 +5858,7 @@ export { getCurrencyOptions, getFeedOptions, getWideAmountIndicators, + hasDeletedTransactionInData, isTransactionAmountTooLong, isTransactionTaxAmountTooLong, getDatePresets,