Skip to content

Commit 15266c6

Browse files
authored
Merge pull request Expensify#85438 from software-mansion-labs/jakubkalinski0/Odometer_photo_is_not_cropped_after_saving_cropped_photo
[Odometer] Photo is not cropped after saving cropped photo
2 parents 8b9009d + ff02b72 commit 15266c6

3 files changed

Lines changed: 72 additions & 21 deletions

File tree

src/libs/TransactionUtils/index.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,21 @@ function hasReceiptSource(transaction: OnyxInputOrEntry<Transaction>): boolean {
580580
return !!transaction?.receipt?.source;
581581
}
582582

583+
/** Check if odometer image has the source file */
584+
function hasOdometerImageSource(transaction: OnyxInputOrEntry<Transaction>, imageType: string): boolean {
585+
const odometerImage = imageType === CONST.IOU.ODOMETER_IMAGE_TYPE.START ? transaction?.comment?.odometerStartImage : transaction?.comment?.odometerEndImage;
586+
if (!odometerImage) {
587+
return false;
588+
}
589+
if (typeof odometerImage === 'string') {
590+
return odometerImage.length > 0;
591+
}
592+
if ('uri' in odometerImage) {
593+
return typeof odometerImage.uri === 'string' && odometerImage.uri.length > 0;
594+
}
595+
return true;
596+
}
597+
583598
function isDemoTransaction(transaction: OnyxInputOrEntry<Transaction>): boolean {
584599
return transaction?.comment?.isDemoTransaction ?? false;
585600
}
@@ -2939,6 +2954,7 @@ export {
29392954
removeTransactionFromDuplicateTransactionViolation,
29402955
getCardName,
29412956
hasReceiptSource,
2957+
hasOdometerImageSource,
29422958
shouldShowAttendees,
29432959
getAllSortedTransactions,
29442960
getFormattedPostedDate,

src/pages/iou/request/step/IOURequestStepConfirmation.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1535,7 +1535,7 @@ function IOURequestStepConfirmation({
15351535
shouldEnableMaxHeight={canUseTouchScreen()}
15361536
testID="IOURequestStepConfirmation"
15371537
>
1538-
<DragAndDropProvider isDisabled={!showReceiptEmptyState}>
1538+
<DragAndDropProvider isDisabled={!showReceiptEmptyState || isOdometerDistanceRequest}>
15391539
<View style={styles.flex1}>
15401540
<HeaderWithBackButton
15411541
title={headerTitle}

src/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,14 @@ import useNetwork from '@hooks/useNetwork';
1212
import useOnyx from '@hooks/useOnyx';
1313
import usePolicy from '@hooks/usePolicy';
1414
import useThemeStyles from '@hooks/useThemeStyles';
15-
import {detachReceipt, navigateToStartStepIfScanFileCannotBeRead, removeMoneyRequestOdometerImage, replaceReceipt, setMoneyRequestReceipt} from '@libs/actions/IOU';
15+
import {
16+
detachReceipt,
17+
navigateToStartStepIfScanFileCannotBeRead,
18+
removeMoneyRequestOdometerImage,
19+
replaceReceipt,
20+
setMoneyRequestOdometerImage,
21+
setMoneyRequestReceipt,
22+
} from '@libs/actions/IOU';
1623
import {openReport} from '@libs/actions/Report';
1724
import cropOrRotateImage from '@libs/cropOrRotateImage';
1825
import fetchImage from '@libs/fetchImage';
@@ -22,7 +29,16 @@ import Navigation from '@libs/Navigation/Navigation';
2229
import {getThumbnailAndImageURIs} from '@libs/ReceiptUtils';
2330
import {getReportAction, isTrackExpenseAction} from '@libs/ReportActionsUtils';
2431
import {canEditFieldOfMoneyRequest, isMoneyRequestReport, isTrackExpenseReport} from '@libs/ReportUtils';
25-
import {getRequestType, hasEReceipt, hasMissingSmartscanFields, hasReceipt, hasReceiptSource, isOdometerDistanceRequest, isReceiptBeingScanned} from '@libs/TransactionUtils';
32+
import {
33+
getRequestType,
34+
hasEReceipt,
35+
hasMissingSmartscanFields,
36+
hasOdometerImageSource,
37+
hasReceipt,
38+
hasReceiptSource,
39+
isOdometerDistanceRequest,
40+
isReceiptBeingScanned,
41+
} from '@libs/TransactionUtils';
2642
import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
2743
import type {AttachmentModalBaseContentProps, ThreeDotsMenuItemFactory} from '@pages/media/AttachmentModalScreen/AttachmentModalBaseContent/types';
2844
import AttachmentModalContainer from '@pages/media/AttachmentModalScreen/AttachmentModalContainer';
@@ -90,6 +106,9 @@ function TransactionReceiptModalContent({navigation, route}: AttachmentModalScre
90106
odometerImage = imageType === CONST.IOU.ODOMETER_IMAGE_TYPE.START ? transaction?.comment?.odometerStartImage : transaction?.comment?.odometerEndImage;
91107
}
92108
const odometerFile = typeof odometerImage !== 'string' ? odometerImage : undefined;
109+
const odometerFilename = odometerFile?.name ?? (typeof odometerImage === 'string' ? odometerImage.split('/').pop() : undefined);
110+
const odometerUriExtension = odometerFilename?.split('.').pop()?.toLowerCase();
111+
const odometerFileType = (odometerFile as Partial<File>)?.type ?? (odometerUriExtension ? `image/${odometerUriExtension}` : CONST.IMAGE_FILE_FORMAT.JPEG);
93112
const [odometerImageSource, setOdometerImageSource] = useState<string | undefined>(undefined);
94113

95114
useEffect(() => {
@@ -131,13 +150,15 @@ function TransactionReceiptModalContent({navigation, route}: AttachmentModalScre
131150
const canDeleteReceipt = canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.RECEIPT, true);
132151

133152
const receiptFilename = transaction?.receipt?.filename;
134-
const isImage = !!receiptFilename && Str.isImage(receiptFilename);
135153
const isStitchedOdometerReceipt = isOdometerDistanceRequest(transaction) && !imageType;
136154

137155
const shouldShowReplaceReceiptButton = ((canEditReceipt && !readonly) || isDraftTransaction) && !transaction?.receipt?.isTestDriveReceipt && !isStitchedOdometerReceipt;
138156
const shouldShowDeleteReceiptButton = canDeleteReceipt && !readonly && !isDraftTransaction && !transaction?.receipt?.isTestDriveReceipt;
139157

140158
const isEReceipt = transaction && !hasReceiptSource(transaction) && hasEReceipt(transaction);
159+
const fileName = (isOdometerImage ? odometerFilename : receiptFilename) ?? '';
160+
const isImage = !!fileName && Str.isImage(fileName);
161+
const fileType = isOdometerImage ? odometerFileType : (transaction?.receipt?.type ?? CONST.IMAGE_FILE_FORMAT.JPEG);
141162
const isTrackExpenseActionValue = isTrackExpenseAction(parentReportAction);
142163
const iouType = useMemo(() => iouTypeParam ?? (isTrackExpenseActionValue ? CONST.IOU.TYPE.TRACK : CONST.IOU.TYPE.SUBMIT), [isTrackExpenseActionValue, iouTypeParam]);
143164

@@ -261,13 +282,11 @@ function TransactionReceiptModalContent({navigation, route}: AttachmentModalScre
261282
return;
262283
}
263284

264-
const receiptType = transaction?.receipt?.type ?? CONST.IMAGE_FILE_FORMAT.JPEG;
265-
266285
setIsRotating(true);
267286
cropOrRotateImage(sourceUri as string, [{rotate: -90}], {
268287
compress: 1,
269-
name: receiptFilename,
270-
type: receiptType,
288+
name: fileName,
289+
type: fileType,
271290
})
272291
.then((rotatedImage) => {
273292
if (!rotatedImage) {
@@ -284,8 +303,10 @@ function TransactionReceiptModalContent({navigation, route}: AttachmentModalScre
284303
const file = rotatedImage as File;
285304
const rotatedFilename = file.name ?? receiptFilename;
286305

287-
if (isDraftTransaction) {
288-
setMoneyRequestReceipt(transaction.transactionID, imageUriResult, rotatedFilename, isDraftTransaction, receiptType);
306+
if (isOdometerImage) {
307+
setMoneyRequestOdometerImage(transaction.transactionID, imageType, file, isDraftTransaction);
308+
} else if (isDraftTransaction) {
309+
setMoneyRequestReceipt(transaction.transactionID, imageUriResult, rotatedFilename, isDraftTransaction, fileType);
289310
} else {
290311
replaceReceipt({
291312
transactionID: transaction.transactionID,
@@ -302,17 +323,17 @@ function TransactionReceiptModalContent({navigation, route}: AttachmentModalScre
302323
.catch(() => {
303324
setIsRotating(false);
304325
});
305-
}, [transaction?.transactionID, isDraftTransaction, sourceUri, isImage, receiptFilename, policyCategories, transaction?.receipt, policy]);
326+
}, [transaction?.transactionID, isDraftTransaction, isOdometerImage, imageType, sourceUri, isImage, receiptFilename, fileName, fileType, policyCategories, transaction?.receipt, policy]);
306327

307328
const shouldShowRotateAndCropReceiptButton = useMemo(
308329
() =>
309330
shouldShowReplaceReceiptButton &&
310331
transaction &&
311-
hasReceiptSource(transaction) &&
332+
(hasReceiptSource(transaction) || (isOdometerImage && hasOdometerImageSource(transaction, imageType))) &&
312333
!isEReceipt &&
313334
!transaction?.receipt?.isTestDriveReceipt &&
314-
(receiptFilename ? Str.isImage(receiptFilename) : false),
315-
[shouldShowReplaceReceiptButton, transaction, isEReceipt, receiptFilename],
335+
isImage,
336+
[shouldShowReplaceReceiptButton, transaction, isEReceipt, isOdometerImage, imageType, isImage],
316337
);
317338

318339
const enterCropMode = useCallback(() => {
@@ -335,8 +356,6 @@ function TransactionReceiptModalContent({navigation, route}: AttachmentModalScre
335356
return;
336357
}
337358

338-
const receiptType = transaction?.receipt?.type ?? CONST.IMAGE_FILE_FORMAT.JPEG;
339-
340359
setIsCropSaving(true);
341360
cropOrRotateImage(
342361
sourceUri as string,
@@ -352,8 +371,8 @@ function TransactionReceiptModalContent({navigation, route}: AttachmentModalScre
352371
],
353372
{
354373
compress: 1,
355-
name: receiptFilename,
356-
type: receiptType,
374+
name: fileName,
375+
type: fileType,
357376
},
358377
)
359378
.then((croppedImage) => {
@@ -371,8 +390,10 @@ function TransactionReceiptModalContent({navigation, route}: AttachmentModalScre
371390
const file = croppedImage as File;
372391
const croppedFilename = file.name ?? receiptFilename;
373392

374-
if (isDraftTransaction) {
375-
setMoneyRequestReceipt(transaction.transactionID, imageUriResult, croppedFilename, isDraftTransaction, receiptType);
393+
if (isOdometerImage) {
394+
setMoneyRequestOdometerImage(transaction.transactionID, imageType, file, isDraftTransaction);
395+
} else if (isDraftTransaction) {
396+
setMoneyRequestReceipt(transaction.transactionID, imageUriResult, croppedFilename, isDraftTransaction, fileType);
376397
} else {
377398
replaceReceipt({
378399
transactionID: transaction.transactionID,
@@ -388,7 +409,21 @@ function TransactionReceiptModalContent({navigation, route}: AttachmentModalScre
388409
.catch(() => {
389410
setIsCropSaving(false);
390411
});
391-
}, [transaction?.transactionID, isDraftTransaction, sourceUri, isImage, cropRect, receiptFilename, policyCategories, transaction?.receipt?.type, policy, exitCropMode]);
412+
}, [
413+
transaction?.transactionID,
414+
isDraftTransaction,
415+
isOdometerImage,
416+
imageType,
417+
sourceUri,
418+
isImage,
419+
cropRect,
420+
receiptFilename,
421+
fileName,
422+
fileType,
423+
policyCategories,
424+
policy,
425+
exitCropMode,
426+
]);
392427

393428
const threeDotsMenuItems: ThreeDotsMenuItemFactory = useCallback(
394429
({file, source: innerSource, isLocalSource}) => {

0 commit comments

Comments
 (0)