Skip to content

Commit bd8186e

Browse files
authored
Merge pull request #59944 from FitseTLT/fix-receipt-preview-to-use-aspect-ratio
Fix - [Better Expense Report View] Use aspect-ratio for receipt thumbnail area of expense previews
2 parents e4a523e + f9da8b2 commit bd8186e

File tree

10 files changed

+60
-14
lines changed

10 files changed

+60
-14
lines changed

src/components/EReceiptWithSizeCalculation.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ function EReceiptWithSizeCalculation(props: EReceiptWithSizeCalculationProps) {
2525
<View style={[styles.overflowHidden, styles.w100, styles.h100, styles.userSelectNone]}>
2626
<View
2727
onLayout={onLayout}
28-
style={[styles.w100, styles.h100, {transform: `scale(${scaleFactor})`, transformOrigin: 'top left'}]}
28+
// We are applying transform of 0 translateZ to avoid a sub-pixel rendering error of a thin 1px line
29+
// appearing on EReceipts on web, specifically in chrome. More details in https://github.com/Expensify/App/pull/59944#issuecomment-2797249923.
30+
style={[styles.w100, styles.h100, {transform: `scale(${scaleFactor}) ${styles.translateZ0.transform as string}`, transformOrigin: 'top left'}]}
2931
>
3032
<EReceipt
3133
// eslint-disable-next-line react/jsx-props-no-spreading

src/components/ReceiptEmptyState.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@ type ReceiptEmptyStateProps = {
2323

2424
/** Whether the receipt is in the money request view */
2525
isInMoneyRequestView?: boolean;
26+
27+
/** Whether the receipt empty state should extend to the full height of the container. */
28+
shouldUseFullHeight?: boolean;
2629
};
2730

2831
// Returns an SVG icon indicating that the user should attach a receipt
29-
function ReceiptEmptyState({hasError = false, onPress, disabled = false, isThumbnail = false, isInMoneyRequestView = false}: ReceiptEmptyStateProps) {
32+
function ReceiptEmptyState({hasError = false, onPress, disabled = false, isThumbnail = false, isInMoneyRequestView = false, shouldUseFullHeight = false}: ReceiptEmptyStateProps) {
3033
const styles = useThemeStyles();
3134
const {translate} = useLocalize();
3235
const theme = useTheme();
@@ -47,6 +50,7 @@ function ReceiptEmptyState({hasError = false, onPress, disabled = false, isThumb
4750
isThumbnail ? styles.moneyRequestAttachReceiptThumbnail : styles.moneyRequestAttachReceipt,
4851
isInMoneyRequestView && styles.expenseViewImage,
4952
hasError && styles.borderColorDanger,
53+
shouldUseFullHeight && styles.receiptEmptyStateFullHeight,
5054
]}
5155
>
5256
<View>

src/components/ReceiptImage.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ type ReceiptImageProps = (
9393

9494
/** The transaction data in search */
9595
transactionItem?: TransactionListItemType;
96+
97+
/** Whether the receipt empty state should extend to the full height of the container. */
98+
shouldUseFullHeight?: boolean;
9699
};
97100

98101
function ReceiptImage({
@@ -115,6 +118,7 @@ function ReceiptImage({
115118
onPress,
116119
transactionItem,
117120
isPerDiemRequest,
121+
shouldUseFullHeight,
118122
}: ReceiptImageProps) {
119123
const styles = useThemeStyles();
120124

@@ -124,6 +128,7 @@ function ReceiptImage({
124128
isThumbnail
125129
onPress={onPress}
126130
disabled={!onPress}
131+
shouldUseFullHeight={shouldUseFullHeight}
127132
/>
128133
);
129134
}

src/components/ReportActionItem/ReportActionItemImage.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ type ReportActionItemImageProps = {
6363

6464
/** Callback to be called on pressing the image */
6565
onPress?: () => void;
66+
67+
/** Whether the receipt empty state should extend to the full height of the container. */
68+
shouldUseFullHeight?: boolean;
6669
};
6770

6871
/**
@@ -86,6 +89,7 @@ function ReportActionItemImage({
8689
shouldMapHaveBorderRadius,
8790
isFromReviewDuplicates = false,
8891
onPress,
92+
shouldUseFullHeight,
8993
}: ReportActionItemImageProps) {
9094
const styles = useThemeStyles();
9195
const {translate} = useLocalize();
@@ -163,7 +167,12 @@ function ReportActionItemImage({
163167
);
164168
}
165169

166-
return <ReceiptImage {...propsObj} />;
170+
return (
171+
<ReceiptImage
172+
{...propsObj}
173+
shouldUseFullHeight={shouldUseFullHeight}
174+
/>
175+
);
167176
}
168177

169178
ReportActionItemImage.displayName = 'ReportActionItemImage';

src/components/ReportActionItem/ReportActionItemImages.tsx

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ type ReportActionItemImagesProps = {
3131

3232
/** Callback to be called on onPress */
3333
onPress?: () => void;
34+
35+
/** Whether we should use aspect ratio to decide the height of receipt previews. */
36+
shouldUseAspectRatio?: boolean;
3437
};
3538

3639
/**
@@ -42,7 +45,7 @@ type ReportActionItemImagesProps = {
4245
* additional number when subtracted from size.
4346
*/
4447

45-
function ReportActionItemImages({images, size, total, isHovered = false, onPress}: ReportActionItemImagesProps) {
48+
function ReportActionItemImages({images, size, total, isHovered = false, onPress, shouldUseAspectRatio = false}: ReportActionItemImagesProps) {
4649
const theme = useTheme();
4750
const styles = useThemeStyles();
4851
const StyleUtils = useStyleUtils();
@@ -54,17 +57,15 @@ function ReportActionItemImages({images, size, total, isHovered = false, onPress
5457
const MAX_REMAINING = 9;
5558

5659
// The height varies depending on the number of images we are displaying.
57-
let maxHeightStyle = {};
58-
let minHeightStyle = {};
59-
if (numberOfShownImages === 1) {
60-
maxHeightStyle = StyleUtils.getMaximumHeight(variables.reportActionImagesSingleImageHeight);
61-
minHeightStyle = StyleUtils.getMinimumHeight(variables.reportActionImagesSingleImageHeight);
60+
const layoutStyle = [];
61+
if (shouldUseAspectRatio) {
62+
layoutStyle.push(styles.receiptPreviewAspectRatio);
63+
} else if (numberOfShownImages === 1) {
64+
layoutStyle.push(StyleUtils.getMaximumHeight(variables.reportActionImagesSingleImageHeight), StyleUtils.getMinimumHeight(variables.reportActionImagesSingleImageHeight));
6265
} else if (numberOfShownImages === 2) {
63-
maxHeightStyle = StyleUtils.getMaximumHeight(variables.reportActionImagesDoubleImageHeight);
64-
minHeightStyle = StyleUtils.getMinimumHeight(variables.reportActionImagesDoubleImageHeight);
66+
layoutStyle.push(StyleUtils.getMaximumHeight(variables.reportActionImagesDoubleImageHeight), StyleUtils.getMinimumHeight(variables.reportActionImagesDoubleImageHeight));
6567
} else if (numberOfShownImages > 2) {
66-
maxHeightStyle = StyleUtils.getMaximumHeight(variables.reportActionImagesMultipleImageHeight);
67-
minHeightStyle = StyleUtils.getMinimumHeight(variables.reportActionImagesMultipleImageHeight);
68+
layoutStyle.push(StyleUtils.getMaximumHeight(variables.reportActionImagesMultipleImageHeight), StyleUtils.getMinimumHeight(variables.reportActionImagesMultipleImageHeight));
6869
}
6970

7071
const hoverStyle = isHovered ? styles.reportPreviewBoxHoverBorder : undefined;
@@ -73,7 +74,7 @@ function ReportActionItemImages({images, size, total, isHovered = false, onPress
7374

7475
return (
7576
<View style={styles.reportActionItemImagesContainer}>
76-
<View style={[styles.reportActionItemImages, hoverStyle, minHeightStyle, maxHeightStyle]}>
77+
<View style={[styles.reportActionItemImages, hoverStyle, ...layoutStyle]}>
7778
{shownImages.map(({thumbnail, isThumbnail, image, isEmptyReceipt, transaction, isLocalFile, fileExtension, filename}, index) => {
7879
// Show a border to separate multiple images. Shown to the right for each except the last.
7980
const shouldShowBorder = shownImages.length > 1 && index < shownImages.length - 1;
@@ -96,6 +97,7 @@ function ReportActionItemImages({images, size, total, isHovered = false, onPress
9697
isSingleImage={numberOfShownImages === 1}
9798
shouldMapHaveBorderRadius={false}
9899
onPress={onPress}
100+
shouldUseFullHeight={shouldUseAspectRatio}
99101
/>
100102
</View>
101103
</ImageBehaviorContextProvider>

src/components/ReportActionItem/TransactionPreview/TransactionPreviewContent.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ function TransactionPreviewContent({
202202
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
203203
isHovered={isHovered || isScanning}
204204
size={1}
205+
shouldUseAspectRatio
205206
/>
206207
)}
207208
{shouldShowSkeleton ? (

src/styles/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import sizing from './utils/sizing';
3939
import spacing from './utils/spacing';
4040
import textDecorationLine from './utils/textDecorationLine';
4141
import textUnderline from './utils/textUnderline';
42+
import translateZ0 from './utils/translateZ0';
4243
import userSelect from './utils/userSelect';
4344
import visibility from './utils/visibility';
4445
import whiteSpace from './utils/whiteSpace';
@@ -231,6 +232,7 @@ const styles = (theme: ThemeColors) =>
231232
...overflow,
232233
...positioning,
233234
...wordBreak,
235+
...translateZ0,
234236
...whiteSpace,
235237
...writingDirection,
236238
...cursor,
@@ -4614,6 +4616,10 @@ const styles = (theme: ThemeColors) =>
46144616
margin: 4,
46154617
},
46164618

4619+
receiptPreviewAspectRatio: {
4620+
aspectRatio: 16 / 9,
4621+
},
4622+
46174623
reportActionItemImages: {
46184624
flexDirection: 'row',
46194625
borderRadius: 12,
@@ -4781,6 +4787,8 @@ const styles = (theme: ThemeColors) =>
47814787
borderWidth: 0,
47824788
},
47834789

4790+
receiptEmptyStateFullHeight: {height: '100%', borderRadius: 12},
4791+
47844792
moneyRequestAttachReceiptThumbnailIcon: {
47854793
position: 'absolute',
47864794
bottom: -4,
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import type TranslateZ0Style from './type';
2+
3+
const translateZ0: TranslateZ0Style = {translateZ0: {transform: ''}};
4+
5+
export default translateZ0;

src/styles/utils/translateZ0/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import type TranslateZ0Style from './type';
2+
3+
const translateZ0: TranslateZ0Style = {translateZ0: {transform: 'translateZ(0)'}};
4+
5+
export default translateZ0;

src/styles/utils/translateZ0/type.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import type {ViewStyle} from 'react-native';
2+
3+
type TranslateZ0Style = Record<'translateZ0', Pick<ViewStyle, 'transform'>>;
4+
5+
export default TranslateZ0Style;

0 commit comments

Comments
 (0)