Skip to content

Commit 9ee91f7

Browse files
authored
Merge pull request #92525 from software-mansion-labs/feat/zoom-map-e-receipts
feat: show full distance e-receipt on hover for map distance requests
2 parents 9d33c33 + 18e68b0 commit 9ee91f7

3 files changed

Lines changed: 87 additions & 25 deletions

File tree

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import React, {useState} from 'react';
2+
import {View} from 'react-native';
3+
import type {LayoutChangeEvent} from 'react-native';
4+
import DistanceEReceipt from '@components/DistanceEReceipt';
5+
import useThemeStyles from '@hooks/useThemeStyles';
6+
import variables from '@styles/variables';
7+
import type {Transaction} from '@src/types/onyx';
8+
9+
// The DistanceEReceipt panel is `variables.eReceiptBGHWidth` wide plus the 20px margin on each side (styles.m5).
10+
const E_RECEIPT_CARD_WIDTH = variables.eReceiptBGHWidth + 40;
11+
12+
type HoveredDistanceEReceiptProps = {
13+
/** The transaction for the distance expense */
14+
transaction: Transaction;
15+
};
16+
17+
function HoveredDistanceEReceipt({transaction}: HoveredDistanceEReceiptProps) {
18+
const styles = useThemeStyles();
19+
const [boxWidth, setBoxWidth] = useState(0);
20+
const [boxHeight, setBoxHeight] = useState(0);
21+
const [cardHeight, setCardHeight] = useState(0);
22+
23+
const scale = boxWidth && boxHeight && cardHeight ? Math.min(boxWidth / E_RECEIPT_CARD_WIDTH, boxHeight / cardHeight) : 0;
24+
25+
const onOverlayLayout = (event: LayoutChangeEvent) => {
26+
setBoxWidth(event.nativeEvent.layout.width);
27+
setBoxHeight(event.nativeEvent.layout.height);
28+
};
29+
30+
const onCardLayout = (event: LayoutChangeEvent) => {
31+
setCardHeight(event.nativeEvent.layout.height);
32+
};
33+
34+
return (
35+
<View
36+
style={[styles.pAbsolute, styles.t0, styles.l0, styles.r0, styles.b0, styles.justifyContentCenter, styles.alignItemsCenter, styles.overflowHidden, styles.eReceiptHoverFill]}
37+
onLayout={onOverlayLayout}
38+
pointerEvents="none"
39+
>
40+
<View
41+
style={[{width: E_RECEIPT_CARD_WIDTH}, scale ? {transform: [{scale}]} : styles.opacity0]}
42+
onLayout={onCardLayout}
43+
>
44+
<DistanceEReceipt transaction={transaction} />
45+
</View>
46+
</View>
47+
);
48+
}
49+
50+
export default HoveredDistanceEReceipt;

src/components/ReportActionItem/MoneyRequestReceiptView.tsx

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import {
5757
import trackExpenseCreationError from '@libs/telemetry/trackExpenseCreationError';
5858
import {
5959
didReceiptScanSucceed as didReceiptScanSucceedTransactionUtils,
60+
getWaypoints,
6061
hasEReceipt,
6162
hasReceiptSource,
6263
hasReceipt as hasReceiptTransactionUtils,
@@ -79,6 +80,7 @@ import type * as OnyxTypes from '@src/types/onyx';
7980
import type {TransactionPendingFieldsKey} from '@src/types/onyx/Transaction';
8081
import type {FileObject} from '@src/types/utils/Attachment';
8182
import {isEmptyObject} from '@src/types/utils/EmptyObject';
83+
import HoveredDistanceEReceipt from './HoveredDistanceEReceipt';
8284
import {isElementHovered, resetButtonHoverState} from './receiptHoverUtils';
8385
import ReportActionItemImage from './ReportActionItemImage';
8486

@@ -171,9 +173,15 @@ function MoneyRequestReceiptView({
171173
const transactionViolations = useTransactionViolations(transaction?.transactionID);
172174
const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${moneyRequestReport?.policyID}`);
173175

174-
const isDistanceRequest = isDistanceRequestTransactionUtils(transaction);
175-
const hasReceipt = hasReceiptTransactionUtils(updatedTransaction ?? transaction);
176-
const isTransactionScanning = isScanning(updatedTransaction ?? transaction);
176+
const displayedTransaction = updatedTransaction ?? transaction;
177+
const isDistanceRequest = isDistanceRequestTransactionUtils(displayedTransaction);
178+
179+
// A merged distance expense can be typed `distance-manual` while still carrying the map waypoints/route from the
180+
// expense it was merged with, so fall back to the presence of waypoints to still surface the distance e-receipt.
181+
const hasDistanceWaypoints = Object.keys(getWaypoints(displayedTransaction) ?? {}).length > 0;
182+
const isMapDistanceRequest = !!displayedTransaction && isDistanceRequest && (!isManualDistanceRequest(displayedTransaction) || hasDistanceWaypoints);
183+
const hasReceipt = hasReceiptTransactionUtils(displayedTransaction);
184+
const isTransactionScanning = isScanning(displayedTransaction);
177185
const didReceiptScanSucceed = hasReceipt && didReceiptScanSucceedTransactionUtils(transaction);
178186
const isInvoice = isInvoiceReport(moneyRequestReport);
179187
const isChatReportArchived = useReportIsArchived(moneyRequestReport?.chatReportID);
@@ -255,10 +263,9 @@ function MoneyRequestReceiptView({
255263

256264
let receiptURIs;
257265
if (hasReceipt) {
258-
receiptURIs = getThumbnailAndImageURIs(updatedTransaction ?? transaction);
266+
receiptURIs = getThumbnailAndImageURIs(displayedTransaction);
259267
}
260-
const transactionForReceipt = updatedTransaction ?? transaction;
261-
const isEReceiptTransaction = !!transactionForReceipt && !hasReceiptSource(transactionForReceipt) && hasEReceipt(transactionForReceipt);
268+
const isEReceiptTransaction = !!displayedTransaction && !hasReceiptSource(displayedTransaction) && hasEReceipt(displayedTransaction);
262269
const canZoomReceipt = hasReceipt && !isLoading && !isTransactionScanning && !isEReceiptTransaction && !!receiptURIs?.image;
263270
const pendingAction = transaction?.pendingAction;
264271
// Need to return undefined when we have pendingAction to avoid the duplicate pending action
@@ -504,8 +511,6 @@ function MoneyRequestReceiptView({
504511

505512
const showBorderlessLoading = isLoading && fillSpace;
506513

507-
const isMapDistanceRequest = !!transaction && isDistanceRequest && !isManualDistanceRequest(transaction);
508-
509514
const canShowReceiptActions = hasReceipt && !isLoading && isEditable && !isMapDistanceRequest && !mergeTransactionID;
510515
const receiptPendingAction = isDistanceRequest ? getPendingFieldAction('waypoints') : getPendingFieldAction('receipt');
511516
const isReceiptOfflinePending = isOffline && !!receiptPendingAction;
@@ -623,23 +628,26 @@ function MoneyRequestReceiptView({
623628
isEnabled={canZoomReceipt}
624629
hoverContainerRef={receiptContainerRef}
625630
>
626-
<ReportActionItemImage
627-
shouldUseThumbnailImage={!fillSpace}
628-
shouldUseFullHeight={fillSpace}
629-
thumbnail={receiptURIs?.thumbnail}
630-
fileExtension={receiptURIs?.fileExtension}
631-
isThumbnail={receiptURIs?.isThumbnail}
632-
image={receiptURIs?.image}
633-
isLocalFile={receiptURIs?.isLocalFile}
634-
filename={receiptURIs?.filename}
635-
transaction={updatedTransaction ?? transaction}
636-
enablePreviewModal
637-
readonly={readonly || !canEditReceipt}
638-
mergeTransactionID={mergeTransactionID}
639-
report={report}
640-
onLoad={() => setIsLoading(false)}
641-
onLoadFailure={() => setIsLoading(false)}
642-
/>
631+
<>
632+
<ReportActionItemImage
633+
shouldUseThumbnailImage={!fillSpace}
634+
shouldUseFullHeight={fillSpace}
635+
thumbnail={receiptURIs?.thumbnail}
636+
fileExtension={receiptURIs?.fileExtension}
637+
isThumbnail={receiptURIs?.isThumbnail}
638+
image={receiptURIs?.image}
639+
isLocalFile={receiptURIs?.isLocalFile}
640+
filename={receiptURIs?.filename}
641+
transaction={updatedTransaction ?? transaction}
642+
enablePreviewModal
643+
readonly={readonly || !canEditReceipt}
644+
mergeTransactionID={mergeTransactionID}
645+
report={report}
646+
onLoad={() => setIsLoading(false)}
647+
onLoadFailure={() => setIsLoading(false)}
648+
/>
649+
{isMapDistanceRequest && hovered && !!displayedTransaction && <HoveredDistanceEReceipt transaction={displayedTransaction} />}
650+
</>
643651
</ReceiptHoverZoom>
644652
</View>
645653
{canShowReceiptActions && (

src/styles/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4228,6 +4228,10 @@ const staticStyles = (theme: ThemeColors) =>
42284228
overflow: 'hidden',
42294229
},
42304230

4231+
eReceiptHoverFill: {
4232+
backgroundColor: colors.green800,
4233+
},
4234+
42314235
eReceiptBackgroundThumbnail: {
42324236
...sizing.w100,
42334237
position: 'absolute',

0 commit comments

Comments
 (0)