diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportGroupHeader.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportGroupHeader.tsx index 756b7f4330b0..d0cb8db184b3 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportGroupHeader.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportGroupHeader.tsx @@ -1,4 +1,4 @@ -import React, {useCallback, useMemo} from 'react'; +import React from 'react'; import {View} from 'react-native'; import Checkbox from '@components/Checkbox'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; @@ -6,6 +6,7 @@ import Text from '@components/Text'; import {useCurrencyListActions} from '@hooks/useCurrencyList'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayoutOnWideRHP from '@hooks/useResponsiveLayoutOnWideRHP'; +import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import {getCommaSeparatedTagNameWithSanitizedColons} from '@libs/PolicyUtils'; import variables from '@styles/variables'; @@ -13,8 +14,6 @@ import CONST from '@src/CONST'; import type {GroupedTransactions} from '@src/types/onyx'; import type {PendingAction} from '@src/types/onyx/OnyxCommon'; -const DESKTOP_HEIGHT = 28; - type MoneyRequestReportGroupHeaderProps = { /** The grouped transaction data */ group: GroupedTransactions; @@ -65,6 +64,7 @@ function MoneyRequestReportGroupHeader({ }: MoneyRequestReportGroupHeaderProps) { const {convertToDisplayString} = useCurrencyListActions(); const styles = useThemeStyles(); + const theme = useTheme(); const {translate} = useLocalize(); const {shouldUseNarrowLayout: shouldUseNarrowLayoutHook} = useResponsiveLayoutOnWideRHP(); const shouldUseNarrowLayout = shouldUseNarrowLayoutProp ?? shouldUseNarrowLayoutHook; @@ -75,18 +75,27 @@ function MoneyRequestReportGroupHeader({ const shouldShowCheckbox = isSelectionModeEnabled || !shouldUseNarrowLayout; - const textStyle = useMemo( - () => (shouldUseNarrowLayout ? {fontSize: variables.fontSizeLabel, lineHeight: 16} : {fontSize: variables.fontSizeNormal, lineHeight: DESKTOP_HEIGHT}), - [shouldUseNarrowLayout], - ); + const textStyle = shouldUseNarrowLayout ? {fontSize: variables.fontSizeLabel, lineHeight: 16} : [styles.labelStrong]; - const handleToggleSelection = useCallback(() => { + const handleToggleSelection = () => { onToggleSelection?.(groupKey); - }, [onToggleSelection, groupKey]); + }; + + const groupHeaderStyle = !shouldUseNarrowLayout + ? [ + {minHeight: variables.tableGroupRowHeight}, + styles.justifyContentCenter, + styles.highlightBG, + styles.pv2, + styles.ph3, + styles.borderBottom, + isSelected && {borderColor: theme.buttonHoveredBG}, + ] + : [styles.ph4, styles.pv3, styles.borderBottom]; return ( - + {shouldShowCheckbox && ( )} {displayName} diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportTableHeader.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportTableHeader.tsx index 53dc2cd5be3c..6c5c82aac0c1 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportTableHeader.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportTableHeader.tsx @@ -16,8 +16,19 @@ type SearchTableHeaderProps = { taxAmountColumnSize: TableColumnSize; shouldShowSorting: boolean; columns: SearchColumnType[]; + shouldRemoveTotalColumnFlex?: boolean; }; -function MoneyRequestReportTableHeader({sortBy, sortOrder, onSortPress, dateColumnSize, shouldShowSorting, columns, amountColumnSize, taxAmountColumnSize}: SearchTableHeaderProps) { +function MoneyRequestReportTableHeader({ + sortBy, + sortOrder, + onSortPress, + dateColumnSize, + shouldShowSorting, + columns, + amountColumnSize, + taxAmountColumnSize, + shouldRemoveTotalColumnFlex, +}: SearchTableHeaderProps) { const styles = useThemeStyles(); const columnConfig = useMemo( @@ -77,6 +88,7 @@ function MoneyRequestReportTableHeader({sortBy, sortOrder, onSortPress, dateColu sortBy={sortBy} sortOrder={sortOrder} onSortPress={onSortPress} + shouldRemoveTotalColumnFlex={shouldRemoveTotalColumnFlex} /> ); diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionItem.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionItem.tsx index 858ffba9006a..04c00b51e9b6 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionItem.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionItem.tsx @@ -10,6 +10,7 @@ import useAnimatedHighlightStyle from '@hooks/useAnimatedHighlightStyle'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useResponsiveLayoutOnWideRHP from '@hooks/useResponsiveLayoutOnWideRHP'; +import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useTransactionViolations from '@hooks/useTransactionViolations'; @@ -70,8 +71,11 @@ type MoneyRequestReportTransactionItemProps = { /** List of cards for the user */ nonPersonalAndWorkspaceCards: CardList; - /** Whether this is the last item in the list (used to skip border-bottom on narrow) */ + /** Whether this is the last item in the list */ isLastItem?: boolean; + + /** Whether the list is horizontally scrollable */ + shouldScrollHorizontally?: boolean; }; function MoneyRequestReportTransactionItem({ @@ -92,9 +96,11 @@ function MoneyRequestReportTransactionItem({ shouldBeHighlighted, nonPersonalAndWorkspaceCards, isLastItem = false, + shouldScrollHorizontally = false, }: MoneyRequestReportTransactionItemProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); + const StyleUtils = useStyleUtils(); // eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth const {isSmallScreenWidth, isMediumScreenWidth} = useResponsiveLayout(); const {shouldUseNarrowLayout} = useResponsiveLayoutOnWideRHP(); @@ -117,7 +123,7 @@ function MoneyRequestReportTransactionItem({ }, [scrollToNewTransaction, shouldBeHighlighted]); const animatedHighlightStyle = useAnimatedHighlightStyle({ - borderRadius: shouldUseNarrowLayout ? 0 : variables.componentBorderRadius, + borderRadius: shouldUseNarrowLayout ? variables.componentBorderRadius : 0, shouldHighlight: shouldBeHighlighted, highlightColor: theme.messageHighlightBG, backgroundColor: theme.highlightBG, @@ -125,7 +131,10 @@ function MoneyRequestReportTransactionItem({ }); return ( - + { @@ -136,7 +145,7 @@ function MoneyRequestReportTransactionItem({ role={getButtonRole(true)} isNested id={transaction.transactionID} - style={[styles.transactionListItemStyle, shouldUseNarrowLayout && styles.noBorderRadius]} + style={[styles.transactionListItemStyle, !shouldUseNarrowLayout ? StyleUtils.getSearchTableRowPressableStyle(isLastItem, isSelected) : styles.noBorderRadius]} hoverStyle={[!isPendingDelete && styles.hoveredComponentBG, isSelected && styles.activeComponentBG]} dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}} onPressIn={() => canUseTouchScreen() && ControlSelection.block()} @@ -146,7 +155,7 @@ function MoneyRequestReportTransactionItem({ }} disabled={isTransactionPendingDelete(transaction)} ref={viewRef} - wrapperStyle={[animatedHighlightStyle, styles.userSelectNone, shouldUseNarrowLayout && !isLastItem && styles.borderBottom]} + wrapperStyle={[animatedHighlightStyle, styles.userSelectNone, shouldUseNarrowLayout && !isLastItem && StyleUtils.getSelectedBorderBottomStyle(isSelected)]} > {({hovered}) => ( { handleOnPress(transaction.transactionID); }} onArrowRightPress={() => onArrowRightPress?.(transaction.transactionID)} isHover={hovered} nonPersonalAndWorkspaceCards={nonPersonalAndWorkspaceCards} + shouldRemoveTotalColumnFlex /> )} diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx index 6827aa7a3d13..8dfc916928d6 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx @@ -28,6 +28,7 @@ import useHandleSelectionMode from '@hooks/useHandleSelectionMode'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useMobileSelectionMode from '@hooks/useMobileSelectionMode'; +import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; import useReportIsArchived from '@hooks/useReportIsArchived'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; @@ -154,6 +155,7 @@ function MoneyRequestReportTransactionList({ const [isModalVisible, setIsModalVisible] = useState(false); const [selectedTransactionID, setSelectedTransactionID] = useState(''); const {reportPendingAction} = getReportOfflinePendingActionAndErrors(report); + const {isOffline} = useNetwork(); const isTaxEnabled = isPolicyTaxEnabled(policy); const {totalDisplaySpend, nonReimbursableSpend, reimbursableSpend} = getMoneyRequestSpendBreakdown(report); @@ -563,11 +565,37 @@ function MoneyRequestReportTransactionList({ [groupByOptions, reportLayoutGroupBy, styles, windowHeight, isInLandscapeMode], ); + const isDesktopTableLayout = !shouldUseNarrowLayout; + const lastTransactionID = useMemo(() => { const allTransactions = shouldShowGroupedTransactions ? groupedTransactions.flatMap((group) => group.transactions) : resolvedTransactions; - const nonDeletedTransactions = allTransactions.filter((t) => !isTransactionPendingDelete(t)); - return nonDeletedTransactions.at(-1)?.transactionID; - }, [shouldShowGroupedTransactions, groupedTransactions, resolvedTransactions]); + const visibleTransactions = allTransactions.filter((t) => isOffline || !isTransactionPendingDelete(t)); + return visibleTransactions.at(-1)?.transactionID; + }, [shouldShowGroupedTransactions, groupedTransactions, resolvedTransactions, isOffline]); + + const renderTransactionItem = (transaction: TransactionWithOptionalHighlight) => ( + + ); const transactionItems = shouldShowGroupedTransactions ? groupedTransactions.map((group) => { @@ -577,12 +605,8 @@ function MoneyRequestReportTransactionList({ isDisabled: false, pendingAction: undefined, }; - return ( - + - {group.transactions.map((transaction) => { - const isLastItem = transaction.transactionID === lastTransactionID; - return ( - - ); - })} + {group.transactions.map((transaction) => renderTransactionItem(transaction))} ); }) - : resolvedTransactions.map((transaction) => { - const isLastItem = transaction.transactionID === lastTransactionID; - return ( - - ); - }); + : resolvedTransactions.map((transaction) => renderTransactionItem(transaction)); const narrowListWrapper = shouldUseNarrowLayout ? [styles.highlightBG, styles.searchTableTopRadius, styles.searchTableBottomRadius, styles.overflowHidden] : undefined; const transactionListContent = ( {narrowListWrapper ? {transactionItems} : transactionItems} @@ -673,8 +649,28 @@ function MoneyRequestReportTransactionList({ const tableHeaderContent = ( - - + 0), + ]} + > + { if (selectedTransactionIDs.length !== 0) { @@ -686,14 +682,17 @@ function MoneyRequestReportTransactionList({ accessibilityLabel={translate('accessibilityHints.selectAllTransactions')} isIndeterminate={selectedTransactionIDs.length > 0 && selectedTransactionIDs.length !== transactionsWithoutPendingDelete.length} isChecked={selectedTransactionIDs.length > 0 && selectedTransactionIDs.length === transactionsWithoutPendingDelete.length} + containerStyle={isDesktopTableLayout && styles.m0} + style={isDesktopTableLayout && styles.mr3} /> - {isMediumScreenWidth && !shouldScrollHorizontally && {translate('workspace.people.selectAll')}} + {isMediumScreenWidth && !shouldScrollHorizontally && {translate('workspace.people.selectAll')}} {(!isMediumScreenWidth || shouldScrollHorizontally) && ( ({ borderRadius: 0, shouldHighlight: item?.shouldAnimateInHighlight ?? false, highlightColor: theme.messageHighlightBG, - backgroundColor: theme.highlightBG, + backgroundColor: item.isSelected ? theme.activeComponentBG : theme.highlightBG, shouldApplyOtherStyles: !isLargeScreenWidth, }); @@ -283,7 +283,7 @@ function ExpenseReportListItem({ isLargeScreenWidth && isLastItem && [styles.searchTableBottomRadius, styles.overflowHidden], !isLargeScreenWidth && isFirstItem && styles.searchTableTopRadius, !isLargeScreenWidth && isLastItem && styles.searchTableBottomRadius, - !isLargeScreenWidth && !isLastItem && styles.borderBottom, + !isLargeScreenWidth && !isLastItem && StyleUtils.getSelectedBorderBottomStyle(item.isSelected), ]} accessible={false} shouldShowRightCaret={false} diff --git a/src/components/Search/SearchList/ListItem/TransactionGroupListExpanded.tsx b/src/components/Search/SearchList/ListItem/TransactionGroupListExpanded.tsx index 087288f8149b..90d0f6d8d7c3 100644 --- a/src/components/Search/SearchList/ListItem/TransactionGroupListExpanded.tsx +++ b/src/components/Search/SearchList/ListItem/TransactionGroupListExpanded.tsx @@ -14,6 +14,7 @@ import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails' import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; @@ -92,6 +93,7 @@ function TransactionGroupListExpanded({ const shouldShowLoadingOnSearch = !!(!transactions?.length && transactionsSnapshotMetadata?.isLoading) || currentOffset > 0; const shouldDisplayLoadingIndicator = !isExpenseReportType && !!transactionsSnapshotMetadata?.isLoading && shouldShowLoadingOnSearch; const {isLargeScreenWidth} = useResponsiveLayout(); + const StyleUtils = useStyleUtils(); const isAmountColumnWide = transactions.some((transaction) => transaction.isAmountColumnWide); const isTaxAmountColumnWide = transactions.some((transaction) => transaction.isTaxAmountColumnWide); @@ -224,7 +226,7 @@ function TransactionGroupListExpanded({ isActionColumnWide={isActionColumnWide} /> - + )} {visibleTransactions.map((transaction, index) => { diff --git a/src/components/Search/SearchList/ListItem/TransactionGroupListItem.tsx b/src/components/Search/SearchList/ListItem/TransactionGroupListItem.tsx index 79fc9bd20ee5..9d86c8b992c7 100644 --- a/src/components/Search/SearchList/ListItem/TransactionGroupListItem.tsx +++ b/src/components/Search/SearchList/ListItem/TransactionGroupListItem.tsx @@ -198,16 +198,15 @@ function TransactionGroupListItem({ }; const StyleUtils = useStyleUtils(); + const isItemSelected = isSelectAllChecked || item?.isSelected; const animatedHighlightStyle = useAnimatedHighlightStyle({ shouldHighlight: item?.shouldAnimateInHighlight ?? false, highlightColor: theme.messageHighlightBG, - backgroundColor: theme.highlightBG, + backgroundColor: isItemSelected ? theme.activeComponentBG : theme.highlightBG, shouldApplyOtherStyles: false, }); - const isItemSelected = isSelectAllChecked || item?.isSelected; - const pressableStyle = [ styles.transactionGroupListItemStyle, isLargeScreenWidth && { @@ -544,9 +543,9 @@ function TransactionGroupListItem({ isLargeScreenWidth ? [StyleUtils.getSearchTableGroupRowBorderStyle(isFirstItem, isLastItem, isItemSelected), isLastItem && styles.overflowHidden] : [ - !isFirstItem && styles.borderTop, isFirstItem && [styles.searchTableTopRadius, styles.overflowHidden], isLastItem && [styles.searchTableBottomRadius, styles.overflowHidden], + !isLastItem && StyleUtils.getSelectedBorderBottomStyle(isItemSelected), ], ]} > @@ -558,7 +557,7 @@ function TransactionGroupListItem({ onPress={onExpandIconPress} expandButtonStyle={isLargeScreenWidth ? styles.pv2 : styles.pv4Half} shouldShowToggleButton={isLargeScreenWidth} - borderBottomStyle={isLargeScreenWidth && styles.borderNone} + borderBottomStyle={isLargeScreenWidth ? styles.borderNone : isItemSelected && {borderColor: theme.buttonHoveredBG}} sentryLabel={CONST.SENTRY_LABEL.SEARCH.GROUP_EXPAND_TOGGLE} > ({ const theme = useTheme(); const StyleUtils = useStyleUtils(); - const {isLargeScreenWidth, shouldUseNarrowLayout} = useResponsiveLayout(); + const {isLargeScreenWidth} = useResponsiveLayout(); const {currentSearchHash, currentSearchKey, currentSearchResults} = useSearchStateContext(); const snapshotReport = (currentSearchResults?.data?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionItem.reportID}`] ?? {}) as Report; @@ -130,7 +130,7 @@ function TransactionListItem({ borderRadius: 0, shouldHighlight: item?.shouldAnimateInHighlight ?? false, highlightColor: theme.messageHighlightBG, - backgroundColor: theme.highlightBG, + backgroundColor: item.isSelected ? theme.activeComponentBG : theme.highlightBG, shouldApplyOtherStyles: !isLargeScreenWidth, }); @@ -226,7 +226,7 @@ function TransactionListItem({ isLargeScreenWidth && isLastItem && styles.searchTableBottomRadius, !isLargeScreenWidth && isFirstItem && styles.searchTableTopRadius, !isLargeScreenWidth && isLastItem && styles.searchTableBottomRadius, - !isLargeScreenWidth && !isLastItem && styles.borderBottom, + !isLargeScreenWidth && !isLastItem && StyleUtils.getSelectedBorderBottomStyle(item.isSelected), ]} > {({hovered}) => ( @@ -262,7 +262,12 @@ function TransactionListItem({ isActionColumnWide={transactionItem.isActionColumnWide} shouldShowCheckbox={!!canSelectMultiple} checkboxSentryLabel={CONST.SENTRY_LABEL.SEARCH.TRANSACTION_LIST_ITEM_CHECKBOX} - style={[styles.p3, styles.pv2, shouldUseNarrowLayout ? [styles.p0, styles.pt3, styles.noBorderRadius] : isLargeScreenWidth && styles.noBorderRadius]} + style={[ + styles.p3, + styles.pv2, + !isLargeScreenWidth && [styles.p0, styles.pt3, isLastItem ? styles.searchTableBottomRadius : styles.noBorderRadius], + isLargeScreenWidth && (isLastItem ? styles.searchTableBottomRadius : styles.noBorderRadius), + ]} violations={transactionViolations} onArrowRightPress={isDeletedTransaction ? undefined : () => onSelectRow(item, transactionPreviewData)} isHover={hovered} diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx index 43c9e1553ce7..c63c12b6f78d 100644 --- a/src/components/TransactionItemRow/index.tsx +++ b/src/components/TransactionItemRow/index.tsx @@ -148,6 +148,7 @@ type TransactionItemRowProps = { policyForMovingExpenses?: Policy; nonPersonalAndWorkspaceCards?: CardList; isActionColumnWide?: boolean; + shouldRemoveTotalColumnFlex?: boolean; }; const EMPTY_ACTIVE_STYLE: StyleProp = []; @@ -203,6 +204,7 @@ function TransactionItemRow({ isLargeScreenWidth: isLargeScreenWidthProp, policyForMovingExpenses, isActionColumnWide: isActionColumnWideProp, + shouldRemoveTotalColumnFlex, }: TransactionItemRowProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -548,7 +550,7 @@ function TransactionItemRow({ return ( {shouldShowAttendees && ( - + )} @@ -889,7 +891,7 @@ function TransactionItemRow({ {!!shouldShowBottomBorder && ( - + )} diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts index 71410b3531d9..c0415bb95f69 100644 --- a/src/styles/utils/index.ts +++ b/src/styles/utils/index.ts @@ -1834,7 +1834,10 @@ const createStyleUtils = (theme: ThemeColors, styles: ThemeStyles) => ({ getSearchTableRowPressableStyle: (isLastItem?: boolean, isSelected?: boolean, padding?: {vertical?: number; horizontal?: number}): ViewStyle => ({ minHeight: variables.tableRowHeight, - borderRadius: 0, + borderTopLeftRadius: 0, + borderTopRightRadius: 0, + borderBottomLeftRadius: 0, + borderBottomRightRadius: 0, borderBottomWidth: isLastItem ? 0 : 1, borderColor: isSelected ? theme.buttonHoveredBG : theme.border, ...(isLastItem ? styles.searchTableBottomRadius : {}), @@ -1842,6 +1845,11 @@ const createStyleUtils = (theme: ThemeColors, styles: ThemeStyles) => ({ ...(padding?.horizontal !== undefined && {paddingHorizontal: padding.horizontal}), }), + getSelectedBorderBottomStyle: (isSelected?: boolean): ViewStyle => ({ + ...styles.borderBottom, + borderColor: isSelected ? theme.buttonHoveredBG : theme.border, + }), + getSearchTableHighlightBorderRadius: (isLargeScreenWidth: boolean): number => (isLargeScreenWidth ? 0 : variables.componentBorderRadius), getReportTableColumnStyles: (columnName: string, options: GetReportTableColumnStylesParams = {}): ViewStyle => { diff --git a/src/styles/variables.ts b/src/styles/variables.ts index 1671512a426e..07fb408ace49 100644 --- a/src/styles/variables.ts +++ b/src/styles/variables.ts @@ -124,6 +124,7 @@ export default { tableRowPaddingVertical: 8, tableRowPaddingHorizontal: 12, tableGroupRowPaddingVertical: 4, + tableGroupRowHeight: 36, sectionMenuItemHeight: 52, sectionMenuItemHeightCompact: 44, optionsListSectionHeaderHeight: getValueUsingPixelRatio(32, 38),