Skip to content

Commit e51e6af

Browse files
authored
Merge pull request Expensify#96203 from emkhalid/fix/95564-reduce-expense-form-scrolling
Expense - Reduce confirmation form scrolling
2 parents 49ce089 + a32bfd1 commit e51e6af

5 files changed

Lines changed: 74 additions & 38 deletions

File tree

src/components/MoneyRequestConfirmationList.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ function MoneyRequestConfirmationList({
429429

430430
const sections = useConfirmationSections({
431431
isTypeSplit,
432+
isTypeInvoice,
432433
shouldHideToSection,
433434
shouldForceTopEmptySections,
434435
participantRowErrors,
@@ -509,7 +510,7 @@ function MoneyRequestConfirmationList({
509510
const selectionListStyle = {
510511
containerStyle: [styles.flexBasisAuto],
511512
contentContainerStyle: isCompactMode ? [styles.flexGrow1] : undefined,
512-
listFooterContentStyle: isCompactMode ? [styles.flex1, styles.mv3] : [styles.mv3],
513+
listFooterContentStyle: isCompactMode ? [styles.flex1, styles.mb3] : [styles.mb3],
513514
};
514515

515516
const footerContent = isReadOnly ? undefined : (

src/components/MoneyRequestConfirmationList/hooks/useConfirmationSections.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ type UseConfirmationSectionsParams = {
1818
/** Whether the current IOU type is split */
1919
isTypeSplit: boolean;
2020

21+
/** Whether the current IOU type is invoice (keeps the "To" header, which pairs with the invoice "Send from" field) */
22+
isTypeInvoice?: boolean;
23+
2124
/** Whether the "to" section should be hidden (used when adding directly to a report) */
2225
shouldHideToSection: boolean;
2326

@@ -55,6 +58,7 @@ type UseConfirmationSectionsParams = {
5558
*/
5659
function useConfirmationSections({
5760
isTypeSplit,
61+
isTypeInvoice = false,
5862
shouldHideToSection,
5963
shouldForceTopEmptySections = false,
6064
participantRowErrors,
@@ -104,7 +108,7 @@ function useConfirmationSections({
104108
];
105109

106110
options.push({
107-
title: selectedParticipants.length > 0 ? translate('common.to') : undefined,
111+
title: isTypeInvoice && selectedParticipants.length > 0 ? translate('common.to') : undefined,
108112
data: participantRows,
109113
sectionIndex: 0,
110114
});

src/components/MoneyRequestConfirmationListFooter/sections/ReceiptSection.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,8 @@ function ReceiptSection({
131131
}
132132
Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_SCAN.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID, Navigation.getActiveRoute()));
133133
}}
134-
style={[compact.isCompactMode ? undefined : styles.mv3, compact.isCompactMode && compact.compactReceiptStyle ? compact.compactReceiptStyle : styles.moneyRequestViewImage]}
134+
isCompact={!compact.isCompactMode}
135+
style={[compact.isCompactMode ? undefined : styles.mt2, compact.isCompactMode && compact.compactReceiptStyle ? compact.compactReceiptStyle : undefined]}
135136
/>
136137
);
137138
}

src/components/ReceiptEmptyState.tsx

Lines changed: 57 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import type {FileObject} from '@src/types/utils/Attachment';
1111

1212
import type {StyleProp, ViewStyle} from 'react-native';
1313

14-
import React, {useEffect, useRef} from 'react';
14+
import React, {useEffect, useRef, useState} from 'react';
1515
import {View} from 'react-native';
1616
import Svg, {Path} from 'react-native-svg';
1717

@@ -37,6 +37,9 @@ type ReceiptEmptyStateProps = {
3737
/** Whether the receipt empty state should extend to the full height of the container. */
3838
shouldUseFullHeight?: boolean;
3939

40+
/** Whether to render the small banner layout (icon + label in a row) instead of the full-height box */
41+
isCompact?: boolean;
42+
4043
style?: StyleProp<ViewStyle>;
4144

4245
/** Callback to be called when the image loads */
@@ -75,6 +78,7 @@ function ReceiptEmptyState({
7578
isThumbnail = false,
7679
isInMoneyRequestView = false,
7780
shouldUseFullHeight = false,
81+
isCompact = false,
7882
style,
7983
onLoad,
8084
isDisplayedInWideRHP = false,
@@ -84,20 +88,23 @@ function ReceiptEmptyState({
8488
const {translate} = useLocalize();
8589
const theme = useTheme();
8690
const isLoadedRef = useRef(false);
87-
const icons = useMemoizedLazyExpensifyIcons(['Receipt']);
91+
const [isHovered, setIsHovered] = useState(false);
92+
const icons = useMemoizedLazyExpensifyIcons(['Receipt', 'ReceiptPlus']);
8893

8994
const {validateFiles, PDFValidationComponent, ErrorModal} = useFilesValidation(setReceiptFile);
9095

9196
const Wrapper = onPress ? PressableWithoutFeedback : View;
92-
const containerStyle = [
93-
styles.alignItemsCenter,
94-
styles.justifyContentCenter,
95-
styles.moneyRequestViewImage,
96-
isDisplayedInWideRHP && !disabled && styles.pb5,
97-
isThumbnail && !isInMoneyRequestView ? styles.moneyRequestAttachReceiptThumbnail : styles.moneyRequestAttachReceipt,
98-
shouldUseFullHeight && styles.receiptEmptyStateFullHeight,
99-
style,
100-
];
97+
const containerStyle = isCompact
98+
? [styles.alignItemsCenter, styles.justifyContentCenter, styles.receiptEmptyStateCompact, styles.moneyRequestAttachReceipt, style]
99+
: [
100+
styles.alignItemsCenter,
101+
styles.justifyContentCenter,
102+
styles.moneyRequestViewImage,
103+
isDisplayedInWideRHP && !disabled && styles.pb5,
104+
isThumbnail && !isInMoneyRequestView ? styles.moneyRequestAttachReceiptThumbnail : styles.moneyRequestAttachReceipt,
105+
shouldUseFullHeight && styles.receiptEmptyStateFullHeight,
106+
style,
107+
];
101108

102109
useEffect(() => {
103110
if (isLoadedRef.current) {
@@ -124,37 +131,52 @@ function ReceiptEmptyState({
124131
}}
125132
disabled={disabled}
126133
disabledStyle={styles.cursorDefault}
134+
hoverStyle={onPress && isCompact ? styles.hoveredComponentBG : undefined}
135+
onHoverIn={onPress && isCompact ? () => setIsHovered(true) : undefined}
136+
onHoverOut={onPress && isCompact ? () => setIsHovered(false) : undefined}
127137
style={containerStyle}
128138
>
129139
{PDFValidationComponent}
130140
{ErrorModal}
131-
<View style={[styles.flex1, styles.justifyContentCenter, styles.alignItemsCenter]}>
132-
<View style={[styles.alignItemsCenter, styles.justifyContentCenter]}>
133-
<View style={styles.pRelative}>
134-
<Icon
135-
fill={theme.border}
136-
src={icons.Receipt}
137-
width={variables.eReceiptEmptyIconWidth}
138-
height={variables.eReceiptEmptyIconWidth}
139-
/>
140-
{!isThumbnail && (
141-
<View style={[styles.moneyRequestAttachReceiptThumbnailIcon, {width: variables.avatarSizeSmall, height: variables.avatarSizeSmall}]}>
142-
<ReceiptPlaceholderPlusIcon
143-
circleFill={theme.success}
144-
plusFill={theme.receiptPlaceholderPlus}
145-
size={variables.avatarSizeSmall}
146-
/>
147-
</View>
141+
{isCompact ? (
142+
<View style={[styles.flexRow, styles.justifyContentCenter, styles.alignItemsCenter, styles.gap2]}>
143+
<Icon
144+
src={icons.ReceiptPlus}
145+
fill={isHovered ? theme.success : theme.icon}
146+
width={variables.iconSizeNormal}
147+
height={variables.iconSizeNormal}
148+
/>
149+
<Text style={styles.textStrong}>{translate('dropzone.addReceipt')}</Text>
150+
</View>
151+
) : (
152+
<View style={[styles.flex1, styles.justifyContentCenter, styles.alignItemsCenter]}>
153+
<View style={[styles.alignItemsCenter, styles.justifyContentCenter]}>
154+
<View style={styles.pRelative}>
155+
<Icon
156+
fill={theme.border}
157+
src={icons.Receipt}
158+
width={variables.eReceiptEmptyIconWidth}
159+
height={variables.eReceiptEmptyIconWidth}
160+
/>
161+
{!isThumbnail && (
162+
<View style={[styles.moneyRequestAttachReceiptThumbnailIcon, {width: variables.avatarSizeSmall, height: variables.avatarSizeSmall}]}>
163+
<ReceiptPlaceholderPlusIcon
164+
circleFill={theme.success}
165+
plusFill={theme.receiptPlaceholderPlus}
166+
size={variables.avatarSizeSmall}
167+
/>
168+
</View>
169+
)}
170+
</View>
171+
{!isThumbnail && isDisplayedInWideRHP && (
172+
<>
173+
<Text style={[styles.textHeadline, styles.mt4]}>{translate('receipt.addAReceipt.phrase1')}</Text>
174+
<Text style={[styles.textSupporting, styles.textNormal]}>{translate('receipt.addAReceipt.phrase2')}</Text>
175+
</>
148176
)}
149177
</View>
150-
{!isThumbnail && isDisplayedInWideRHP && (
151-
<>
152-
<Text style={[styles.textHeadline, styles.mt4]}>{translate('receipt.addAReceipt.phrase1')}</Text>
153-
<Text style={[styles.textSupporting, styles.textNormal]}>{translate('receipt.addAReceipt.phrase2')}</Text>
154-
</>
155-
)}
156178
</View>
157-
</View>
179+
)}
158180
{isDisplayedInWideRHP && !disabled && <ReceiptAlternativeMethods />}
159181
</Wrapper>
160182
)}

src/styles/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4968,6 +4968,14 @@ const staticStyles = (theme: ThemeColors) =>
49684968

49694969
receiptEmptyStateFullHeight: {height: '100%', borderRadius: 12},
49704970

4971+
receiptEmptyStateCompact: {
4972+
...spacing.mh4,
4973+
overflow: 'hidden',
4974+
borderRadius: variables.componentBorderRadiusNormal,
4975+
height: 52,
4976+
maxWidth: '100%',
4977+
},
4978+
49714979
moneyRequestAttachReceiptThumbnailIcon: {
49724980
position: 'absolute',
49734981
bottom: -4,

0 commit comments

Comments
 (0)