From 69263a4349afadea85763a340f0d16af1825161c Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Wed, 10 Apr 2024 04:07:01 +0700 Subject: [PATCH 001/726] fix Reddot pinned chat appears for approver for submitter's failed scanned --- .../ReportActionItem/MoneyRequestView.tsx | 2 +- src/libs/OptionsListUtils.ts | 4 ++-- src/libs/ReportUtils.ts | 20 ++++++++++++++++--- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index dd34d0ca254..42c85a8ed9d 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -210,7 +210,7 @@ function MoneyRequestView({ const hasReceipt = TransactionUtils.hasReceipt(transaction); let receiptURIs; - const hasErrors = canEdit && TransactionUtils.hasMissingSmartscanFields(transaction); + const hasErrors = TransactionUtils.hasMissingSmartscanFields(transaction); if (hasReceipt) { receiptURIs = ReceiptUtils.getThumbnailAndImageURIs(transaction); } diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index e1a3e9207ad..7e0de5611c8 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -509,10 +509,10 @@ function getAllReportErrors(report: OnyxEntry, reportActions: OnyxEntry< reportActionErrors.smartscan = ErrorUtils.getMicroSecondOnyxError('report.genericSmartscanFailureMessage'); } } else if ((ReportUtils.isIOUReport(report) || ReportUtils.isExpenseReport(report)) && report?.ownerAccountID === currentUserAccountID) { - if (ReportUtils.hasMissingSmartscanFields(report?.reportID ?? '') && !ReportUtils.isSettled(report?.reportID)) { + if (ReportUtils.hasMissingSmartscanFields(report?.reportID ?? '', true) && !ReportUtils.isSettled(report?.reportID)) { reportActionErrors.smartscan = ErrorUtils.getMicroSecondOnyxError('report.genericSmartscanFailureMessage'); } - } else if (ReportUtils.hasSmartscanError(Object.values(reportActions ?? {}))) { + } else if (ReportUtils.hasSmartscanError(Object.values(reportActions ?? {}), true)) { reportActionErrors.smartscan = ErrorUtils.getMicroSecondOnyxError('report.genericSmartscanFailureMessage'); } // All error objects related to the report. Each object in the sources contains error messages keyed by microtime diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index c9241054e74..b2701569bd5 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2503,7 +2503,21 @@ function areAllRequestsBeingSmartScanned(iouReportID: string, reportPreviewActio * Check if any of the transactions in the report has required missing fields * */ -function hasMissingSmartscanFields(iouReportID: string): boolean { +function hasMissingSmartscanFields(iouReportID: string, isLHNPreview = false): boolean { + if (isLHNPreview) { + const reportActions = Object.values(ReportActionsUtils.getAllReportActions(iouReportID)); + return reportActions.some((action) => { + if (!ReportActionsUtils.isMoneyRequestAction(action)) { + return false; + } + const transaction = getLinkedTransaction(action); + if (isEmptyObject(transaction)) { + return false; + } + console.log("22222222222", {transaction}) + return TransactionUtils.hasMissingSmartscanFields(transaction) && currentUserAccountID === action?.actorAccountID; + }); + } return TransactionUtils.getAllReportTransactions(iouReportID).some((transaction) => TransactionUtils.hasMissingSmartscanFields(transaction)); } @@ -5401,13 +5415,13 @@ function canEditPolicyDescription(policy: OnyxEntry): boolean { /** * Checks if report action has error when smart scanning */ -function hasSmartscanError(reportActions: ReportAction[]) { +function hasSmartscanError(reportActions: ReportAction[], isLHNPreview = false) { return reportActions.some((action) => { if (!ReportActionsUtils.isSplitBillAction(action) && !ReportActionsUtils.isReportPreviewAction(action)) { return false; } const IOUReportID = ReportActionsUtils.getIOUReportIDFromReportActionPreview(action); - const isReportPreviewError = ReportActionsUtils.isReportPreviewAction(action) && hasMissingSmartscanFields(IOUReportID) && !isSettled(IOUReportID); + const isReportPreviewError = ReportActionsUtils.isReportPreviewAction(action) && hasMissingSmartscanFields(IOUReportID, true) && !isSettled(IOUReportID); const transactionID = (action.originalMessage as IOUMessage).IOUTransactionID ?? '0'; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? {}; const isSplitBillError = ReportActionsUtils.isSplitBillAction(action) && TransactionUtils.hasMissingSmartscanFields(transaction as Transaction); From fe5f752c317f83725fdbf07ead86600c426bc8b9 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Wed, 10 Apr 2024 04:15:23 +0700 Subject: [PATCH 002/726] fix lint --- src/libs/ReportUtils.ts | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index b2701569bd5..e42b3add59e 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2499,6 +2499,22 @@ function areAllRequestsBeingSmartScanned(iouReportID: string, reportPreviewActio return transactionsWithReceipts.every((transaction) => TransactionUtils.isReceiptBeingScanned(transaction)); } +/** + * Get the transactions related to a report preview with receipts + * Get the details linked to the IOU reportAction + * + * NOTE: This method is only meant to be used inside this action file. Do not export and use it elsewhere. Use withOnyx or Onyx.connect() instead. + */ +function getLinkedTransaction(reportAction: OnyxEntry): Transaction | EmptyObject { + let transactionID = ''; + + if (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) { + transactionID = (reportAction?.originalMessage as IOUMessage)?.IOUTransactionID ?? ''; + } + + return allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? {}; +} + /** * Check if any of the transactions in the report has required missing fields * @@ -2514,29 +2530,12 @@ function hasMissingSmartscanFields(iouReportID: string, isLHNPreview = false): b if (isEmptyObject(transaction)) { return false; } - console.log("22222222222", {transaction}) return TransactionUtils.hasMissingSmartscanFields(transaction) && currentUserAccountID === action?.actorAccountID; }); } return TransactionUtils.getAllReportTransactions(iouReportID).some((transaction) => TransactionUtils.hasMissingSmartscanFields(transaction)); } -/** - * Get the transactions related to a report preview with receipts - * Get the details linked to the IOU reportAction - * - * NOTE: This method is only meant to be used inside this action file. Do not export and use it elsewhere. Use withOnyx or Onyx.connect() instead. - */ -function getLinkedTransaction(reportAction: OnyxEntry): Transaction | EmptyObject { - let transactionID = ''; - - if (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) { - transactionID = (reportAction?.originalMessage as IOUMessage)?.IOUTransactionID ?? ''; - } - - return allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? {}; -} - /** * Given a parent IOU report action get report name for the LHN. */ @@ -5421,7 +5420,7 @@ function hasSmartscanError(reportActions: ReportAction[], isLHNPreview = false) return false; } const IOUReportID = ReportActionsUtils.getIOUReportIDFromReportActionPreview(action); - const isReportPreviewError = ReportActionsUtils.isReportPreviewAction(action) && hasMissingSmartscanFields(IOUReportID, true) && !isSettled(IOUReportID); + const isReportPreviewError = ReportActionsUtils.isReportPreviewAction(action) && hasMissingSmartscanFields(IOUReportID, isLHNPreview) && !isSettled(IOUReportID); const transactionID = (action.originalMessage as IOUMessage).IOUTransactionID ?? '0'; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? {}; const isSplitBillError = ReportActionsUtils.isSplitBillAction(action) && TransactionUtils.hasMissingSmartscanFields(transaction as Transaction); From 894c310bcd560b6135f4d10246bfbd472d225128 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Thu, 11 Apr 2024 04:14:11 +0200 Subject: [PATCH 003/726] Preserve transactions amount in create IOU --- src/components/transactionPropTypes.js | 3 +++ src/libs/CurrencyUtils.ts | 20 +++++++++++++++--- src/libs/actions/IOU.ts | 6 +++--- src/pages/iou/request/IOURequestStartPage.js | 9 +++++++- .../iou/request/step/IOURequestStepAmount.js | 9 +++++++- .../iou/steps/MoneyRequestAmountForm.tsx | 21 +++++++++---------- src/types/onyx/Transaction.ts | 3 +++ tests/unit/CurrencyUtilsTest.ts | 20 +++++++++++++++--- 8 files changed, 69 insertions(+), 22 deletions(-) diff --git a/src/components/transactionPropTypes.js b/src/components/transactionPropTypes.js index 7eb1b776358..46d24694846 100644 --- a/src/components/transactionPropTypes.js +++ b/src/components/transactionPropTypes.js @@ -93,4 +93,7 @@ export default PropTypes.shape({ /** Server side errors keyed by microtime */ errorFields: PropTypes.objectOf(PropTypes.objectOf(translatableTextPropTypes)), + + /** Whether the original input should be shown */ + shouldShowOriginalAmount: PropTypes.bool, }); diff --git a/src/libs/CurrencyUtils.ts b/src/libs/CurrencyUtils.ts index 95970d2a958..4530dc105e0 100644 --- a/src/libs/CurrencyUtils.ts +++ b/src/libs/CurrencyUtils.ts @@ -87,9 +87,22 @@ function convertToBackendAmount(amountAsFloat: number): number { * * @note we do not support any currencies with more than two decimal places. */ -function convertToFrontendAmount(amountAsInt: number): number { +function convertToFrontendAmountAsInteger(amountAsInt: number): number { return Math.trunc(amountAsInt) / 100.0; } + +/** + * Takes an amount in "cents" as an integer and converts it to a string amount used in the frontend. + * + * @note we do not support any currencies with more than two decimal places. + */ +function convertToFrontendAmountAsString(amountAsInt: number | null | undefined): string { + if (amountAsInt === null || amountAsInt === undefined) { + return ''; + } + return convertToFrontendAmountAsInteger(amountAsInt).toFixed(2); +} + /** * Given an amount in the "cents", convert it to a string for display in the UI. * The backend always handle things in "cents" (subunit equal to 1/100) @@ -98,7 +111,7 @@ function convertToFrontendAmount(amountAsInt: number): number { * @param currency - IOU currency */ function convertToDisplayString(amountInCents = 0, currency: string = CONST.CURRENCY.USD): string { - const convertedAmount = convertToFrontendAmount(amountInCents); + const convertedAmount = convertToFrontendAmountAsInteger(amountInCents); return NumberFormatUtils.format(BaseLocaleListener.getPreferredLocale(), convertedAmount, { style: 'currency', currency, @@ -139,7 +152,8 @@ export { getCurrencySymbol, isCurrencySymbolLTR, convertToBackendAmount, - convertToFrontendAmount, + convertToFrontendAmountAsInteger, + convertToFrontendAmountAsString, convertToDisplayString, convertAmountToDisplayString, isValidCurrencyCode, diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index dab0eed1653..8e3ead229a6 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -357,12 +357,12 @@ function startMoneyRequest(iouType: ValueOf, reportID: st } // eslint-disable-next-line @typescript-eslint/naming-convention -function setMoneyRequestAmount_temporaryForRefactor(transactionID: string, amount: number, currency: string, removeOriginalCurrency = false) { +function setMoneyRequestAmount_temporaryForRefactor(transactionID: string, amount: number, currency: string, removeOriginalCurrency = false, shouldShowOriginalAmount = false) { if (removeOriginalCurrency) { - Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {amount, currency, originalCurrency: null}); + Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {amount, currency, originalCurrency: null, shouldShowOriginalAmount}); return; } - Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {amount, currency}); + Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {amount, currency, shouldShowOriginalAmount}); } // eslint-disable-next-line @typescript-eslint/naming-convention diff --git a/src/pages/iou/request/IOURequestStartPage.js b/src/pages/iou/request/IOURequestStartPage.js index e9057fef922..2a96e5b1e1e 100644 --- a/src/pages/iou/request/IOURequestStartPage.js +++ b/src/pages/iou/request/IOURequestStartPage.js @@ -166,7 +166,14 @@ function IOURequestStartPage({ onTabSelected={resetIOUTypeIfChanged} tabBar={TabSelector} > - {() => } + + {() => ( + + )} + {() => } {shouldDisplayDistanceRequest && {() => }} diff --git a/src/pages/iou/request/step/IOURequestStepAmount.js b/src/pages/iou/request/step/IOURequestStepAmount.js index b392ee31020..0dd4d024762 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.js +++ b/src/pages/iou/request/step/IOURequestStepAmount.js @@ -1,6 +1,7 @@ import {useFocusEffect} from '@react-navigation/native'; import lodashGet from 'lodash/get'; import lodashIsEmpty from 'lodash/isEmpty'; +import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useRef} from 'react'; import {withOnyx} from 'react-native-onyx'; import transactionPropTypes from '@components/transactionPropTypes'; @@ -39,6 +40,9 @@ const propTypes = { /** The draft transaction object being modified in Onyx */ draftTransaction: transactionPropTypes, + + /** Whether the user input should be kept or not */ + shouldKeepUserInput: PropTypes.bool, }; const defaultProps = { @@ -46,6 +50,7 @@ const defaultProps = { transaction: {}, splitDraftTransaction: {}, draftTransaction: {}, + shouldKeepUserInput: false, }; function IOURequestStepAmount({ @@ -56,6 +61,7 @@ function IOURequestStepAmount({ transaction, splitDraftTransaction, draftTransaction, + shouldKeepUserInput, }) { const {translate} = useLocalize(); const textInput = useRef(null); @@ -125,7 +131,7 @@ function IOURequestStepAmount({ isSaveButtonPressed.current = true; const amountInSmallestCurrencyUnits = CurrencyUtils.convertToBackendAmount(Number.parseFloat(amount)); - IOU.setMoneyRequestAmount_temporaryForRefactor(transactionID, amountInSmallestCurrencyUnits, currency || CONST.CURRENCY.USD, true); + IOU.setMoneyRequestAmount_temporaryForRefactor(transactionID, amountInSmallestCurrencyUnits, currency || CONST.CURRENCY.USD, true, shouldKeepUserInput); if (backTo) { Navigation.goBack(backTo); @@ -183,6 +189,7 @@ function IOURequestStepAmount({ currency={currency} amount={Math.abs(transactionAmount)} ref={(e) => (textInput.current = e)} + shouldKeepUserInput={transaction.shouldShowOriginalAmount} onCurrencyButtonPress={navigateToCurrencySelectionPage} onSubmitButtonPress={saveAmountAndCurrency} selectedTab={iouRequestType} diff --git a/src/pages/iou/steps/MoneyRequestAmountForm.tsx b/src/pages/iou/steps/MoneyRequestAmountForm.tsx index c8b418f301c..77a953dada9 100644 --- a/src/pages/iou/steps/MoneyRequestAmountForm.tsx +++ b/src/pages/iou/steps/MoneyRequestAmountForm.tsx @@ -49,6 +49,9 @@ type MoneyRequestAmountFormProps = { /** The current tab we have navigated to in the request modal. String that corresponds to the request type. */ selectedTab?: SelectedTabRequest; + + /** Whether the user input should be kept or not */ + shouldKeepUserInput?: boolean; }; type Selection = { @@ -66,7 +69,7 @@ const getNewSelection = (oldSelection: Selection, prevLength: number, newLength: const isAmountInvalid = (amount: string) => !amount.length || parseFloat(amount) < 0.01; const isTaxAmountInvalid = (currentAmount: string, taxAmount: number, isTaxAmountForm: boolean) => - isTaxAmountForm && Number.parseFloat(currentAmount) > CurrencyUtils.convertToFrontendAmount(Math.abs(taxAmount)); + isTaxAmountForm && Number.parseFloat(currentAmount) > CurrencyUtils.convertToFrontendAmountAsInteger(Math.abs(taxAmount)); const AMOUNT_VIEW_ID = 'amountView'; const NUM_PAD_CONTAINER_VIEW_ID = 'numPadContainerView'; @@ -82,6 +85,7 @@ function MoneyRequestAmountForm( onCurrencyButtonPress, onSubmitButtonPress, selectedTab = CONST.TAB_REQUEST.MANUAL, + shouldKeepUserInput = false, }: MoneyRequestAmountFormProps, forwardedRef: ForwardedRef, ) { @@ -93,7 +97,7 @@ function MoneyRequestAmountForm( const isTaxAmountForm = Navigation.getActiveRoute().includes('taxAmount'); const decimals = CurrencyUtils.getCurrencyDecimals(currency); - const selectedAmountAsString = amount ? CurrencyUtils.convertToFrontendAmount(amount).toString() : ''; + const selectedAmountAsString = amount ? CurrencyUtils.convertToFrontendAmountAsString(amount) : ''; const [currentAmount, setCurrentAmount] = useState(selectedAmountAsString); const [formError, setFormError] = useState(''); @@ -135,7 +139,7 @@ function MoneyRequestAmountForm( }; const initializeAmount = useCallback((newAmount: number) => { - const frontendAmount = newAmount ? CurrencyUtils.convertToFrontendAmount(newAmount).toString() : ''; + const frontendAmount = newAmount ? CurrencyUtils.convertToFrontendAmountAsString(newAmount) : ''; setCurrentAmount(frontendAmount); setSelection({ start: frontendAmount.length, @@ -144,13 +148,13 @@ function MoneyRequestAmountForm( }, []); useEffect(() => { - if (!currency || typeof amount !== 'number') { + if (!currency || typeof amount !== 'number' || shouldKeepUserInput) { return; } initializeAmount(amount); // we want to re-initialize the state only when the selected tab or amount changes // eslint-disable-next-line react-hooks/exhaustive-deps - }, [selectedTab, amount]); + }, [selectedTab, amount, shouldKeepUserInput]); /** * Sets the selection and the amount accordingly to the value passed to the input @@ -264,13 +268,8 @@ function MoneyRequestAmountForm( return; } - // Update display amount string post-edit to ensure consistency with backend amount - // Reference: https://github.com/Expensify/App/issues/30505 - const backendAmount = CurrencyUtils.convertToBackendAmount(Number.parseFloat(currentAmount)); - initializeAmount(backendAmount); - onSubmitButtonPress({amount: currentAmount, currency}); - }, [currentAmount, taxAmount, isTaxAmountForm, onSubmitButtonPress, currency, formattedTaxAmount, initializeAmount]); + }, [currentAmount, taxAmount, isTaxAmountForm, onSubmitButtonPress, currency, formattedTaxAmount]); /** * Input handler to check for a forward-delete key (or keyboard shortcut) press. diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 281b6b4228c..6b4bd1fc0d1 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -215,6 +215,9 @@ type Transaction = OnyxCommon.OnyxValueWithOfflineFeedback< /** Indicates transaction loading */ isLoading?: boolean; + + /** Whether the user input should be kept */ + shouldShowOriginalAmount?: boolean; }, keyof Comment >; diff --git a/tests/unit/CurrencyUtilsTest.ts b/tests/unit/CurrencyUtilsTest.ts index a1e4b03fa71..089cdf8426a 100644 --- a/tests/unit/CurrencyUtilsTest.ts +++ b/tests/unit/CurrencyUtilsTest.ts @@ -105,15 +105,29 @@ describe('CurrencyUtils', () => { }); }); - describe('convertToFrontendAmount', () => { + describe('convertToFrontendAmountAsInteger', () => { test.each([ [2500, 25], [2550, 25.5], [25, 0.25], [2500, 25], [2500.5, 25], // The backend should never send a decimal .5 value - ])('Correctly converts %s to amount in units handled in frontend', (amount, expectedResult) => { - expect(CurrencyUtils.convertToFrontendAmount(amount)).toBe(expectedResult); + ])('Correctly converts %s to amount in units handled in frontend as an integer', (amount, expectedResult) => { + expect(CurrencyUtils.convertToFrontendAmountAsInteger(amount)).toBe(expectedResult); + }); + }); + + describe('convertToFrontendAmountAsString', () => { + test.each([ + [2500, '25.00'], + [2550, '25.50'], + [25, '0.25'], + [2500.5, '25.00'], + [null, ''], + [undefined, ''], + [0, '0.00'], + ])('Correctly converts %s to amount in units handled in frontend as a string', (input, expectedResult) => { + expect(CurrencyUtils.convertToFrontendAmountAsString(input)).toBe(expectedResult); }); }); From 5f0df225b999649f6a7c7cccefe138e66ccc3071 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Mon, 15 Apr 2024 20:42:38 +0200 Subject: [PATCH 004/726] fixing types --- src/pages/iou/request/step/IOURequestStepAmount.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepAmount.tsx b/src/pages/iou/request/step/IOURequestStepAmount.tsx index a747084ac2b..ca662d1a2a6 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.tsx +++ b/src/pages/iou/request/step/IOURequestStepAmount.tsx @@ -33,15 +33,15 @@ type IOURequestStepAmountOnyxProps = { /** The draft transaction object being modified in Onyx */ draftTransaction: OnyxEntry; - - /** Whether the user input should be kept or not */ - shouldKeepUserInput: PropTypes.bool; }; type IOURequestStepAmountProps = IOURequestStepAmountOnyxProps & WithWritableReportOrNotFoundProps & { /** The transaction object being modified in Onyx */ transaction: OnyxEntry; + + /** Whether the user input should be kept or not */ + shouldKeepUserInput?: boolean; }; function IOURequestStepAmount({ @@ -169,7 +169,7 @@ function IOURequestStepAmount({ currency={currency} amount={Math.abs(transactionAmount)} ref={(e) => (textInput.current = e)} - shouldKeepUserInput={transaction.shouldShowOriginalAmount} + shouldKeepUserInput={transaction?.shouldShowOriginalAmount} onCurrencyButtonPress={navigateToCurrencySelectionPage} onSubmitButtonPress={saveAmountAndCurrency} selectedTab={iouRequestType} From 1303c69d80688a7ed2ffd6898a8d74999afe6b3a Mon Sep 17 00:00:00 2001 From: dukenv0307 <129500732+dukenv0307@users.noreply.github.com> Date: Wed, 17 Apr 2024 02:13:04 +0700 Subject: [PATCH 005/726] fix update hasMissingSmartscanFields Co-authored-by: Eugene Voloshchak --- src/libs/ReportUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index e42b3add59e..10162cb7e33 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2519,7 +2519,7 @@ function getLinkedTransaction(reportAction: OnyxEntry { From f082a5ab8eb767678b17a64fc308bbb1f5d51df9 Mon Sep 17 00:00:00 2001 From: dukenv0307 <129500732+dukenv0307@users.noreply.github.com> Date: Wed, 17 Apr 2024 02:13:54 +0700 Subject: [PATCH 006/726] fix update hasSmartscanError Co-authored-by: Eugene Voloshchak --- src/libs/ReportUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 10162cb7e33..b962df110ce 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -5414,7 +5414,7 @@ function canEditPolicyDescription(policy: OnyxEntry): boolean { /** * Checks if report action has error when smart scanning */ -function hasSmartscanError(reportActions: ReportAction[], isLHNPreview = false) { +function hasSmartscanError(reportActions: ReportAction[], isLHNPreview: boolean) { return reportActions.some((action) => { if (!ReportActionsUtils.isSplitBillAction(action) && !ReportActionsUtils.isReportPreviewAction(action)) { return false; From df364c5fe9c13b3e8c39c51b2f85d6f798ad54b3 Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Thu, 18 Apr 2024 17:50:35 +0530 Subject: [PATCH 007/726] fix: IOU Scan - In dark mode, the damaged PDF - file is barely visible. Signed-off-by: Krishna Gupta --- src/components/PDFThumbnail/index.tsx | 8 ++++++-- src/components/PDFThumbnail/types.ts | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/components/PDFThumbnail/index.tsx b/src/components/PDFThumbnail/index.tsx index a5b911deb6f..8663357fb50 100644 --- a/src/components/PDFThumbnail/index.tsx +++ b/src/components/PDFThumbnail/index.tsx @@ -4,6 +4,8 @@ import React, {useMemo} from 'react'; import {View} from 'react-native'; import {Document, pdfjs, Thumbnail} from 'react-pdf'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import addEncryptedAuthTokenToURL from '@libs/addEncryptedAuthTokenToURL'; import type PDFThumbnailProps from './types'; @@ -12,8 +14,9 @@ if (!pdfjs.GlobalWorkerOptions.workerSrc) { pdfjs.GlobalWorkerOptions.workerSrc = URL.createObjectURL(new Blob([pdfWorkerSource], {type: 'text/javascript'})); } -function PDFThumbnail({previewSourceURL, style, isAuthTokenRequired = false, enabled = true, onPassword}: PDFThumbnailProps) { +function PDFThumbnail({previewSourceURL, style, isAuthTokenRequired = false, enabled = true, onPassword, errorLabelStyles}: PDFThumbnailProps) { const styles = useThemeStyles(); + const {translate} = useLocalize(); const thumbnail = useMemo( () => ( @@ -26,13 +29,14 @@ function PDFThumbnail({previewSourceURL, style, isAuthTokenRequired = false, ena }} externalLinkTarget="_blank" onPassword={onPassword} + error={{translate('attachmentView.failedToLoadPDF')}} > ), - [isAuthTokenRequired, previewSourceURL, onPassword], + [isAuthTokenRequired, previewSourceURL, onPassword, errorLabelStyles, translate, styles.textLabel], ); return ( diff --git a/src/components/PDFThumbnail/types.ts b/src/components/PDFThumbnail/types.ts index 11253e462ac..5891ac133da 100644 --- a/src/components/PDFThumbnail/types.ts +++ b/src/components/PDFThumbnail/types.ts @@ -1,4 +1,4 @@ -import type {StyleProp, ViewStyle} from 'react-native'; +import type {StyleProp, TextStyle, ViewStyle} from 'react-native'; type PDFThumbnailProps = { /** Source URL for the preview PDF */ @@ -15,6 +15,9 @@ type PDFThumbnailProps = { /** Callback to call if PDF is password protected */ onPassword?: () => void; + + /** Styles for the error label */ + errorLabelStyles?: StyleProp; }; export default PDFThumbnailProps; From 1e046d8530b62a4c0defc37e1b20e411d6ebb91c Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Mon, 22 Apr 2024 18:35:09 +0530 Subject: [PATCH 008/726] fix: show corrupted pdf alert for native devices. Signed-off-by: Krishna Gupta --- src/components/PDFThumbnail/index.native.tsx | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/components/PDFThumbnail/index.native.tsx b/src/components/PDFThumbnail/index.native.tsx index 0232dba99f0..3da6d5b4fa6 100644 --- a/src/components/PDFThumbnail/index.native.tsx +++ b/src/components/PDFThumbnail/index.native.tsx @@ -1,19 +1,24 @@ -import React from 'react'; +import React, {useState} from 'react'; import {View} from 'react-native'; import Pdf from 'react-native-pdf'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import addEncryptedAuthTokenToURL from '@libs/addEncryptedAuthTokenToURL'; import type PDFThumbnailProps from './types'; -function PDFThumbnail({previewSourceURL, style, isAuthTokenRequired = false, enabled = true, onPassword}: PDFThumbnailProps) { +function PDFThumbnail({previewSourceURL, style, isAuthTokenRequired = false, enabled = true, onPassword, errorLabelStyles}: PDFThumbnailProps) { const styles = useThemeStyles(); const sizeStyles = [styles.w100, styles.h100]; + const {translate} = useLocalize(); + + const [isCorrupted, setIsCorrupted] = useState(false); return ( - {enabled && ( + {enabled && !isCorrupted && ( { + if ('message' in error && typeof error.message === 'string' && error.message.match(/corrupted/i)) { + setIsCorrupted(true); + } + if (!('message' in error && typeof error.message === 'string' && error.message.match(/password/i))) { return; } + if (!onPassword) { return; } @@ -32,6 +42,7 @@ function PDFThumbnail({previewSourceURL, style, isAuthTokenRequired = false, ena }} /> )} + {isCorrupted && {translate('attachmentView.failedToLoadPDF')}} ); From 2288b186406b8eac3351a9aca5f4972584efe6d6 Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Mon, 22 Apr 2024 18:36:34 +0530 Subject: [PATCH 009/726] spacing improvement. Signed-off-by: Krishna Gupta --- src/components/PDFThumbnail/index.native.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/components/PDFThumbnail/index.native.tsx b/src/components/PDFThumbnail/index.native.tsx index 3da6d5b4fa6..c008d6823a0 100644 --- a/src/components/PDFThumbnail/index.native.tsx +++ b/src/components/PDFThumbnail/index.native.tsx @@ -12,7 +12,6 @@ function PDFThumbnail({previewSourceURL, style, isAuthTokenRequired = false, ena const styles = useThemeStyles(); const sizeStyles = [styles.w100, styles.h100]; const {translate} = useLocalize(); - const [isCorrupted, setIsCorrupted] = useState(false); return ( @@ -30,11 +29,9 @@ function PDFThumbnail({previewSourceURL, style, isAuthTokenRequired = false, ena if ('message' in error && typeof error.message === 'string' && error.message.match(/corrupted/i)) { setIsCorrupted(true); } - if (!('message' in error && typeof error.message === 'string' && error.message.match(/password/i))) { return; } - if (!onPassword) { return; } From 48ad489edae9af4a69eacaec18411c6dcd3d1be3 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Tue, 23 Apr 2024 09:29:21 +0700 Subject: [PATCH 010/726] fix type --- src/libs/ReportActionsUtils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 97b2b62391c..65d9d8f404c 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -1167,6 +1167,7 @@ export { isActionableJoinRequest, isActionableJoinRequestPending, isActionableTrackExpense, + getAllReportActions, }; export type {LastVisibleMessage}; From 590547fdd5ccebed7ebf44a12d6425b84d7a765c Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Tue, 23 Apr 2024 09:42:45 +0700 Subject: [PATCH 011/726] fix type --- src/libs/ReportUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index a218c0db825..0bf4afff390 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2594,7 +2594,7 @@ function getLinkedTransaction(reportAction: OnyxEntry { From be55619a8a50ffc924b90304cfd58630732c9a5e Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Tue, 23 Apr 2024 16:03:01 +0700 Subject: [PATCH 012/726] fix add center button and blue dot --- src/components/MapView/MapView.tsx | 43 +++++++++++++++++++++- src/components/MapView/MapView.website.tsx | 41 ++++++++++++++++++++- 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/src/components/MapView/MapView.tsx b/src/components/MapView/MapView.tsx index bce241270d7..19b41029b46 100644 --- a/src/components/MapView/MapView.tsx +++ b/src/components/MapView/MapView.tsx @@ -4,6 +4,7 @@ import Mapbox, {MarkerView, setAccessToken} from '@rnmapbox/maps'; import {forwardRef, memo, useCallback, useEffect, useImperativeHandle, useRef, useState} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; +import Button from '@components/Button'; import useThemeStyles from '@hooks/useThemeStyles'; import setUserLocation from '@libs/actions/UserLocation'; import compose from '@libs/compose'; @@ -143,7 +144,17 @@ const MapView = forwardRef( onMapReady(); } }; - + const centerMap = useCallback(() => { + if (directionCoordinates && directionCoordinates.length > 1) { + const bounds = [ + [Math.min(...directionCoordinates.map((coord) => coord[0])), Math.min(...directionCoordinates.map((coord) => coord[1]))], // Southwest + [Math.max(...directionCoordinates.map((coord) => coord[0])), Math.max(...directionCoordinates.map((coord) => coord[1]))], // Northeast + ]; + cameraRef?.current?.fitBounds(bounds[0], bounds[1], undefined, 1000); + return; + } + cameraRef?.current?.setCamera({heading: 0, centerCoordinate: [currentPosition?.longitude ?? 0, currentPosition?.latitude ?? 0]}); + }, [directionCoordinates, currentPosition]); return !isOffline && Boolean(accessToken) && Boolean(currentPosition) ? ( ( zoomLevel: initialState?.zoom, }} /> + + + {waypoints?.map(({coordinate, markerComponent, id}) => { const MarkerComponent = markerComponent; @@ -181,6 +217,11 @@ const MapView = forwardRef( {directionCoordinates && } +