-
Notifications
You must be signed in to change notification settings - Fork 3.9k
perf: Split TransactionItemRow into narrow and wide versions #89120
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
87efc50
6bb3918
500f134
6e0a385
7d8ee4f
6dc07ff
11b6e5f
82aaf30
d674ba2
81571af
1a177fb
f451903
4da0f5d
f02178c
a7cba6e
082cbab
e05d79b
c8fe540
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| import React, {useDeferredValue} from 'react'; | ||
| import {View} from 'react-native'; | ||
| import PulsingView from '@components/PulsingView'; | ||
| import useTheme from '@hooks/useTheme'; | ||
| import useThemeStyles from '@hooks/useThemeStyles'; | ||
| import ActionCell from '.'; | ||
| import type {ActionCellProps} from '.'; | ||
|
|
||
| function DeferredActionCell(actionCellProps: ActionCellProps) { | ||
| const styles = useThemeStyles(); | ||
| const theme = useTheme(); | ||
| const shouldRender = useDeferredValue(true, false); | ||
|
|
||
| if (!shouldRender) { | ||
| const sizeStyle = actionCellProps.extraSmall ? styles.buttonExtraSmall : styles.buttonSmall; | ||
| return ( | ||
| <PulsingView | ||
| shouldPulse | ||
| style={styles.w100} | ||
| > | ||
| <View style={[styles.w100, sizeStyle, {backgroundColor: theme.skeletonLHNIn}]} /> | ||
| </PulsingView> | ||
| ); | ||
| } | ||
|
|
||
| // eslint-disable-next-line react/jsx-props-no-spreading | ||
| return <ActionCell {...actionCellProps} />; | ||
| } | ||
|
|
||
| export default DeferredActionCell; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,138 @@ | ||
| import React, {useRef} from 'react'; | ||
| import type {View} from 'react-native'; | ||
| import {getButtonRole} from '@components/Button/utils'; | ||
| import OfflineWithFeedback from '@components/OfflineWithFeedback'; | ||
| import PressableWithFeedback from '@components/Pressable/PressableWithFeedback'; | ||
| import UserInfoAndActionButtonRow from '@components/Search/SearchList/ListItem/UserInfoAndActionButtonRow'; | ||
| import type {ListItem} from '@components/SelectionList/types'; | ||
| import TransactionItemRow from '@components/TransactionItemRow'; | ||
| import useAnimatedHighlightStyle from '@hooks/useAnimatedHighlightStyle'; | ||
| import useResponsiveLayout from '@hooks/useResponsiveLayout'; | ||
| import useStyleUtils from '@hooks/useStyleUtils'; | ||
| import useSyncFocus from '@hooks/useSyncFocus'; | ||
| import useTheme from '@hooks/useTheme'; | ||
| import useThemeStyles from '@hooks/useThemeStyles'; | ||
| import CONST from '@src/CONST'; | ||
| import type {TransactionListItemNarrowProps} from './types'; | ||
|
|
||
| function TransactionListItemNarrow<TItem extends ListItem>({ | ||
| item, | ||
| transactionItem, | ||
| isDeletedTransaction, | ||
| isFocused, | ||
| showTooltip, | ||
| isDisabled, | ||
| canSelectMultiple, | ||
| onSelectRow, | ||
| onCheckboxPress, | ||
| onFocus, | ||
| onLongPressRow, | ||
| shouldSyncFocus, | ||
| columns, | ||
| isLoading, | ||
| isActionLoading, | ||
| isLastItem, | ||
| isFirstItem, | ||
| transactionViolations, | ||
| handleActionButtonPress, | ||
| transactionPreviewData, | ||
| exportedReportActions, | ||
| nonPersonalAndWorkspaceCards, | ||
| policyForMovingExpenses, | ||
| }: TransactionListItemNarrowProps<TItem>) { | ||
| const styles = useThemeStyles(); | ||
| const theme = useTheme(); | ||
| const StyleUtils = useStyleUtils(); | ||
| const {shouldUseNarrowLayout} = useResponsiveLayout(); | ||
| const pressableRef = useRef<View>(null); | ||
| useSyncFocus(pressableRef, !!isFocused, shouldSyncFocus); | ||
|
|
||
| const pressableStyle = [ | ||
| styles.transactionListItemStyle, | ||
| styles.p4, | ||
| styles.noBorderRadius, | ||
| item.isSelected && styles.activeComponentBG, | ||
| {...styles.flexColumn, ...styles.alignItemsStretch}, | ||
| ]; | ||
|
|
||
| const animatedHighlightStyle = useAnimatedHighlightStyle({ | ||
| borderRadius: 0, | ||
| shouldHighlight: item?.shouldAnimateInHighlight ?? false, | ||
| highlightColor: theme.messageHighlightBG, | ||
| backgroundColor: theme.highlightBG, | ||
| shouldApplyOtherStyles: true, | ||
| }); | ||
|
|
||
| return ( | ||
| <OfflineWithFeedback pendingAction={item.pendingAction}> | ||
| <PressableWithFeedback | ||
| ref={pressableRef} | ||
| onLongPress={() => onLongPressRow?.(item)} | ||
| onPress={isDeletedTransaction && !canSelectMultiple ? undefined : () => onSelectRow(item, transactionPreviewData)} | ||
| disabled={isDisabled && !item.isSelected} | ||
| accessibilityLabel={item.text ?? ''} | ||
| role={!isDeletedTransaction ? getButtonRole(true) : 'none'} | ||
| isNested | ||
| onMouseDown={(e) => e.preventDefault()} | ||
| hoverStyle={[!item.isDisabled && styles.hoveredComponentBG, item.isSelected && styles.activeComponentBG]} | ||
| dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true, [CONST.INNER_BOX_SHADOW_ELEMENT]: false}} | ||
| id={item.keyForList ?? ''} | ||
| sentryLabel={CONST.SENTRY_LABEL.SEARCH.TRANSACTION_LIST_ITEM} | ||
| style={[ | ||
| pressableStyle, | ||
| isFocused && StyleUtils.getItemBackgroundColorStyle(!!item.isSelected, !!isFocused, !!item.isDisabled, theme.activeComponentBG, theme.hoverComponentBG), | ||
| isDeletedTransaction && styles.cursorDefault, | ||
| ]} | ||
| onFocus={onFocus} | ||
| wrapperStyle={[ | ||
| styles.mh5, | ||
| styles.flex1, | ||
| animatedHighlightStyle, | ||
| styles.userSelectNone, | ||
| isFirstItem && [styles.searchTableTopRadius, styles.overflowHidden, styles.searchTableTopRadius], | ||
| isLastItem && [styles.searchTableBottomRadius, styles.overflowHidden, styles.searchTableBottomRadius], | ||
| !isLastItem && styles.borderBottom, | ||
| ]} | ||
| > | ||
| {() => ( | ||
| <> | ||
| <UserInfoAndActionButtonRow | ||
| item={transactionItem} | ||
| shouldShowUserInfo={!isDeletedTransaction && !!transactionItem?.from} | ||
| stateNum={transactionItem.report?.stateNum} | ||
| statusNum={transactionItem.report?.statusNum} | ||
| /> | ||
| <TransactionItemRow | ||
| transactionItem={transactionItem} | ||
| report={transactionItem.report} | ||
| policy={transactionItem.policy} | ||
| shouldShowTooltip={showTooltip} | ||
| onButtonPress={handleActionButtonPress} | ||
| onCheckboxPress={() => onCheckboxPress?.(item)} | ||
| shouldUseNarrowLayout | ||
| isLargeScreenWidth={false} | ||
| columns={columns} | ||
| isActionLoading={isLoading ?? isActionLoading} | ||
| isSelected={!!transactionItem.isSelected} | ||
| isDisabled={!!isDisabled} | ||
| dateColumnSize={CONST.SEARCH.TABLE_COLUMN_SIZES.NORMAL} | ||
| amountColumnSize={CONST.SEARCH.TABLE_COLUMN_SIZES.NORMAL} | ||
| taxAmountColumnSize={CONST.SEARCH.TABLE_COLUMN_SIZES.NORMAL} | ||
| shouldShowCheckbox={!!canSelectMultiple} | ||
| checkboxSentryLabel={CONST.SENTRY_LABEL.SEARCH.TRANSACTION_LIST_ITEM_CHECKBOX} | ||
| style={[styles.p3, styles.pv2, shouldUseNarrowLayout ? [styles.p0, styles.pt3] : [styles.noBorderRadius]]} | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The narrow list path no longer includes Useful? React with 👍 / 👎.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not valid. No shape jump occurs in practice. The radius would only become visible on a selected row, which isn't the scenario (inner |
||
| violations={transactionViolations} | ||
| onArrowRightPress={isDeletedTransaction ? undefined : () => onSelectRow(item, transactionPreviewData)} | ||
| isHover={false} | ||
| nonPersonalAndWorkspaceCards={nonPersonalAndWorkspaceCards} | ||
| reportActions={exportedReportActions} | ||
| policyForMovingExpenses={policyForMovingExpenses} | ||
| /> | ||
| </> | ||
| )} | ||
| </PressableWithFeedback> | ||
| </OfflineWithFeedback> | ||
| ); | ||
| } | ||
|
|
||
| export default TransactionListItemNarrow; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,140 @@ | ||
| import React, {useRef} from 'react'; | ||
| import type {View} from 'react-native'; | ||
| import {getButtonRole} from '@components/Button/utils'; | ||
| import OfflineWithFeedback from '@components/OfflineWithFeedback'; | ||
| import PressableWithFeedback from '@components/Pressable/PressableWithFeedback'; | ||
| import type {ListItem} from '@components/SelectionList/types'; | ||
| import TransactionItemRow from '@components/TransactionItemRow'; | ||
| import useAnimatedHighlightStyle from '@hooks/useAnimatedHighlightStyle'; | ||
| import useStyleUtils from '@hooks/useStyleUtils'; | ||
| import useSyncFocus from '@hooks/useSyncFocus'; | ||
| import useTheme from '@hooks/useTheme'; | ||
| import useThemeStyles from '@hooks/useThemeStyles'; | ||
| import CONST from '@src/CONST'; | ||
| import type {TransactionListItemWideProps} from './types'; | ||
|
|
||
| function TransactionListItemWide<TItem extends ListItem>({ | ||
| item, | ||
| transactionItem, | ||
| isDeletedTransaction, | ||
| isFocused, | ||
| showTooltip, | ||
| isDisabled, | ||
| canSelectMultiple, | ||
| onSelectRow, | ||
| onCheckboxPress, | ||
| onFocus, | ||
| onLongPressRow, | ||
| shouldSyncFocus, | ||
| columns, | ||
| isLoading, | ||
| isActionLoading, | ||
| isLastItem, | ||
| transactionViolations, | ||
| handleActionButtonPress, | ||
| transactionPreviewData, | ||
| exportedReportActions, | ||
| nonPersonalAndWorkspaceCards, | ||
| policyForMovingExpenses, | ||
| }: TransactionListItemWideProps<TItem>) { | ||
| const styles = useThemeStyles(); | ||
| const theme = useTheme(); | ||
| const StyleUtils = useStyleUtils(); | ||
| const pressableRef = useRef<View>(null); | ||
| useSyncFocus(pressableRef, !!isFocused, shouldSyncFocus); | ||
|
|
||
| const amountColumnSize = transactionItem.isAmountColumnWide ? CONST.SEARCH.TABLE_COLUMN_SIZES.WIDE : CONST.SEARCH.TABLE_COLUMN_SIZES.NORMAL; | ||
| const taxAmountColumnSize = transactionItem.isTaxAmountColumnWide ? CONST.SEARCH.TABLE_COLUMN_SIZES.WIDE : CONST.SEARCH.TABLE_COLUMN_SIZES.NORMAL; | ||
| const dateColumnSize = transactionItem.shouldShowYear ? CONST.SEARCH.TABLE_COLUMN_SIZES.WIDE : CONST.SEARCH.TABLE_COLUMN_SIZES.NORMAL; | ||
| const submittedColumnSize = transactionItem.shouldShowYearSubmitted ? CONST.SEARCH.TABLE_COLUMN_SIZES.WIDE : CONST.SEARCH.TABLE_COLUMN_SIZES.NORMAL; | ||
| const approvedColumnSize = transactionItem.shouldShowYearApproved ? CONST.SEARCH.TABLE_COLUMN_SIZES.WIDE : CONST.SEARCH.TABLE_COLUMN_SIZES.NORMAL; | ||
| const postedColumnSize = transactionItem.shouldShowYearPosted ? CONST.SEARCH.TABLE_COLUMN_SIZES.WIDE : CONST.SEARCH.TABLE_COLUMN_SIZES.NORMAL; | ||
| const exportedColumnSize = transactionItem.shouldShowYearExported ? CONST.SEARCH.TABLE_COLUMN_SIZES.WIDE : CONST.SEARCH.TABLE_COLUMN_SIZES.NORMAL; | ||
|
|
||
| const pressableStyle = [ | ||
| styles.transactionListItemStyle, | ||
| item.isSelected && styles.activeComponentBG, | ||
| { | ||
| ...styles.flexRow, | ||
| ...styles.justifyContentBetween, | ||
| ...styles.alignItemsCenter, | ||
| ...StyleUtils.getSearchTableRowPressableStyle(!!isLastItem, item.isSelected), | ||
| }, | ||
| ]; | ||
|
|
||
| const animatedHighlightStyle = useAnimatedHighlightStyle({ | ||
| borderRadius: 0, | ||
| shouldHighlight: item?.shouldAnimateInHighlight ?? false, | ||
| highlightColor: theme.messageHighlightBG, | ||
| backgroundColor: theme.highlightBG, | ||
| shouldApplyOtherStyles: false, | ||
| }); | ||
|
|
||
| return ( | ||
| <OfflineWithFeedback pendingAction={item.pendingAction}> | ||
| <PressableWithFeedback | ||
| ref={pressableRef} | ||
| onLongPress={() => onLongPressRow?.(item)} | ||
| onPress={isDeletedTransaction && !canSelectMultiple ? undefined : () => onSelectRow(item, transactionPreviewData)} | ||
| disabled={isDisabled && !item.isSelected} | ||
| accessibilityLabel={item.text ?? ''} | ||
| role={!isDeletedTransaction ? getButtonRole(true) : 'none'} | ||
| isNested | ||
| onMouseDown={(e) => e.preventDefault()} | ||
| hoverStyle={[!item.isDisabled && styles.hoveredComponentBG, item.isSelected && styles.activeComponentBG]} | ||
| dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true, [CONST.INNER_BOX_SHADOW_ELEMENT]: false}} | ||
| id={item.keyForList ?? ''} | ||
| sentryLabel={CONST.SENTRY_LABEL.SEARCH.TRANSACTION_LIST_ITEM} | ||
| style={[ | ||
| pressableStyle, | ||
| isFocused && StyleUtils.getItemBackgroundColorStyle(!!item.isSelected, !!isFocused, !!item.isDisabled, theme.activeComponentBG, theme.hoverComponentBG), | ||
| isDeletedTransaction && styles.cursorDefault, | ||
| ]} | ||
| onFocus={onFocus} | ||
| wrapperStyle={[ | ||
| styles.mh5, | ||
| styles.flex1, | ||
| animatedHighlightStyle, | ||
| styles.userSelectNone, | ||
| isLastItem && [styles.searchTableBottomRadius, styles.overflowHidden, styles.searchTableBottomRadius], | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Valid suggestion.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed duplicate |
||
| ]} | ||
| > | ||
| {({hovered}) => ( | ||
| <TransactionItemRow | ||
| transactionItem={transactionItem} | ||
| report={transactionItem.report} | ||
| policy={transactionItem.policy} | ||
| shouldShowTooltip={showTooltip} | ||
| onButtonPress={handleActionButtonPress} | ||
| onCheckboxPress={() => onCheckboxPress?.(item)} | ||
| shouldUseNarrowLayout={false} | ||
| isLargeScreenWidth | ||
| columns={columns} | ||
| isActionLoading={isLoading ?? isActionLoading} | ||
| isSelected={!!transactionItem.isSelected} | ||
| isDisabled={!!isDisabled} | ||
| dateColumnSize={dateColumnSize} | ||
| submittedColumnSize={submittedColumnSize} | ||
| approvedColumnSize={approvedColumnSize} | ||
| postedColumnSize={postedColumnSize} | ||
| 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, styles.noBorderRadius]} | ||
| violations={transactionViolations} | ||
| onArrowRightPress={isDeletedTransaction ? undefined : () => onSelectRow(item, transactionPreviewData)} | ||
| isHover={hovered} | ||
| nonPersonalAndWorkspaceCards={nonPersonalAndWorkspaceCards} | ||
| reportActions={exportedReportActions} | ||
| policyForMovingExpenses={policyForMovingExpenses} | ||
| /> | ||
| )} | ||
| </PressableWithFeedback> | ||
| </OfflineWithFeedback> | ||
| ); | ||
| } | ||
|
|
||
| export default TransactionListItemWide; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed duplicate