From 6999b0caf46cfe514424d425934baa7572e53d91 Mon Sep 17 00:00:00 2001 From: huutech <20178761+huult@users.noreply.github.com> Date: Fri, 26 Dec 2025 13:07:43 +0700 Subject: [PATCH 01/13] Improve deleted tax behavior --- .../ReportActionItem/MoneyRequestView.tsx | 5 +- src/components/TaxPicker.tsx | 48 +++++++++++++------ .../step/IOURequestStepTaxRatePage.tsx | 18 ++++++- 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 3e475e5bfe965..d8366135eb479 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -285,7 +285,8 @@ function MoneyRequestView({ : convertToDisplayString(Math.abs(transactionTaxAmount ?? 0), transactionCurrency); const taxRatesDescription = taxRates?.name; - const taxRateTitle = updatedTransaction ? getTaxName(policy, updatedTransaction) : getTaxName(policy, transaction); + const transactionWithTax = updatedTransaction ?? transaction; + const taxRateTitle = transactionWithTax?.taxCode ? getTaxName(policy, transactionWithTax) : ''; const actualTransactionDate = isFromMergeTransaction && updatedTransaction ? getFormattedCreated(updatedTransaction) : transactionDate; const fallbackTaxRateTitle = transaction?.taxValue; @@ -557,7 +558,7 @@ function MoneyRequestView({ const decodedCategoryName = getDecodedCategoryName(categoryValue); const categoryCopyValue = !canEdit ? decodedCategoryName : undefined; const cardCopyValue = cardProgramName; - const taxRateValue = taxRateTitle ?? fallbackTaxRateTitle; + const taxRateValue = taxRateTitle ?? fallbackTaxRateTitle ?? ''; const taxRateCopyValue = !canEditTaxFields ? taxRateValue : undefined; const taxAmountTitle = formattedTaxAmount ? formattedTaxAmount.toString() : ''; const taxAmountCopyValue = !canEditTaxFields ? taxAmountTitle : undefined; diff --git a/src/components/TaxPicker.tsx b/src/components/TaxPicker.tsx index d254d43fed1ec..82f1782f393f1 100644 --- a/src/components/TaxPicker.tsx +++ b/src/components/TaxPicker.tsx @@ -27,7 +27,7 @@ type TaxPickerProps = { transactionID?: string; /** Callback to fire when a tax is pressed */ - onSubmit: (tax: TaxRatesOption) => void; + onSubmit: (tax: TaxRatesOption, isTaxDeleted?: boolean) => void; /** The action to take */ action?: IOUAction; @@ -69,6 +69,9 @@ function TaxPicker({selectedTaxRate = '', policyID, transactionID, onSubmit, act const shouldShowTextInput = !isTaxRatesCountBelowThreshold; + const isTaxDeleted = + !!transaction?.taxCode && transaction?.taxValue !== undefined && Object.keys(taxRates?.taxes ?? {}).find((taxCode) => taxCode === transaction?.taxCode) === undefined; + const selectedOptions = useMemo(() => { if (!selectedTaxRate) { return []; @@ -83,17 +86,34 @@ function TaxPicker({selectedTaxRate = '', policyID, transactionID, onSubmit, act ]; }, [selectedTaxRate]); - const sections = useMemo( - () => - getTaxRatesSection({ - policy, - searchValue, - localeCompare, - selectedOptions, - transaction: currentTransaction, - }), - [searchValue, selectedOptions, policy, currentTransaction, localeCompare], - ); + const sections = useMemo(() => { + const baseSections = getTaxRatesSection({ + policy, + searchValue, + localeCompare, + selectedOptions, + transaction: currentTransaction, + }); + + if (!isTaxDeleted) { + return baseSections; + } + + const deletedTaxOption = { + code: transaction?.taxCode, + text: transaction?.taxValue ?? '', + keyForList: transaction?.taxCode ?? '', + searchText: transaction?.taxValue ?? '', + tooltipText: transaction?.taxValue ?? '', + isDisabled: true, + isSelected: true, + }; + + return baseSections.map((section) => ({ + ...section, + data: [...section.data, deletedTaxOption], + })); + }, [isTaxDeleted, policy, searchValue, localeCompare, selectedOptions, currentTransaction, transaction?.taxCode, transaction?.taxValue]); const headerMessage = getHeaderMessageForNonUserList((sections.at(0)?.data?.length ?? 0) > 0, searchValue); @@ -105,9 +125,9 @@ function TaxPicker({selectedTaxRate = '', policyID, transactionID, onSubmit, act onDismiss(); return; } - onSubmit(newSelectedOption); + onSubmit(newSelectedOption, isTaxDeleted); }, - [onSubmit, onDismiss, selectedOptionKey], + [selectedOptionKey, onSubmit, isTaxDeleted, onDismiss], ); return ( diff --git a/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx b/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx index 9ff0831ad9c85..fd31f790c8df5 100644 --- a/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx +++ b/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx @@ -63,7 +63,23 @@ function IOURequestStepTaxRatePage({ const taxRateTitle = getTaxName(policy, currentTransaction); - const updateTaxRates = (taxes: TaxRatesOption) => { + const updateTaxRates = (taxes: TaxRatesOption, isTaxDeleted?: boolean) => { + if (isTaxDeleted && isEditing) { + updateMoneyRequestTaxRate({ + transactionID: currentTransaction?.transactionID, + optimisticReportActionID: report?.reportID, + taxCode: '', + taxAmount: convertToBackendAmount(0), + policy, + policyTagList: policyTags, + policyCategories, + currentUserAccountIDParam, + currentUserEmailParam, + isASAPSubmitBetaEnabled, + }); + navigateBack(); + return; + } if (!currentTransaction || !taxes.code || !taxRates) { Navigation.goBack(); return; From 2e421b111759b991c07cbfa401d06ead656d2ea2 Mon Sep 17 00:00:00 2001 From: huutech <20178761+huult@users.noreply.github.com> Date: Mon, 29 Dec 2025 14:39:44 +0700 Subject: [PATCH 02/13] Handle case where tax value changes --- .../ReportActionItem/MoneyRequestView.tsx | 4 +++- src/components/TaxPicker.tsx | 17 +++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 1c81a0378e3c9..9a95cb392d17b 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -79,6 +79,7 @@ import { getTagArrayFromName, getTagForDisplay, getTaxName, + getTaxValue, hasMissingSmartscanFields, hasReservationList, hasRoute as hasRouteTransactionUtils, @@ -295,6 +296,7 @@ function MoneyRequestView({ const taxRatesDescription = taxRates?.name; const transactionWithTax = updatedTransaction ?? transaction; const taxRateTitle = transactionWithTax?.taxCode ? getTaxName(policy, transactionWithTax) : ''; + const isTaxValueChanged = transactionWithTax?.taxCode ? getTaxValue(policy, transactionWithTax, transactionWithTax.taxCode) !== transactionWithTax.taxValue : false; const actualTransactionDate = isFromMergeTransaction && updatedTransaction ? getFormattedCreated(updatedTransaction) : transactionDate; const fallbackTaxRateTitle = transaction?.taxValue; @@ -530,7 +532,7 @@ function MoneyRequestView({ const decodedCategoryName = getDecodedCategoryName(categoryValue); const categoryCopyValue = !canEdit ? decodedCategoryName : undefined; const cardCopyValue = cardProgramName; - const taxRateValue = taxRateTitle ?? fallbackTaxRateTitle ?? ''; + const taxRateValue = isTaxValueChanged ? transactionWithTax?.taxValue : (taxRateTitle ?? fallbackTaxRateTitle ?? ''); const taxRateCopyValue = !canEditTaxFields ? taxRateValue : undefined; const taxAmountTitle = formattedTaxAmount ? formattedTaxAmount.toString() : ''; const taxAmountCopyValue = !canEditTaxFields ? taxAmountTitle : undefined; diff --git a/src/components/TaxPicker.tsx b/src/components/TaxPicker.tsx index 82f1782f393f1..84fa3b1cd7d08 100644 --- a/src/components/TaxPicker.tsx +++ b/src/components/TaxPicker.tsx @@ -69,11 +69,12 @@ function TaxPicker({selectedTaxRate = '', policyID, transactionID, onSubmit, act const shouldShowTextInput = !isTaxRatesCountBelowThreshold; - const isTaxDeleted = - !!transaction?.taxCode && transaction?.taxValue !== undefined && Object.keys(taxRates?.taxes ?? {}).find((taxCode) => taxCode === transaction?.taxCode) === undefined; + const isTaxDeleted = !!transaction?.taxCode && !!transaction?.taxValue && Object.keys(taxRates?.taxes ?? {}).find((taxCode) => taxCode === transaction?.taxCode) === undefined; + + const isTaxValueChanged = !!transaction?.taxCode && !!transaction?.taxValue && !Object.values(taxRates?.taxes ?? {}).some((rate) => rate.value === transaction?.taxValue); const selectedOptions = useMemo(() => { - if (!selectedTaxRate) { + if (!selectedTaxRate || isTaxValueChanged) { return []; } @@ -84,7 +85,7 @@ function TaxPicker({selectedTaxRate = '', policyID, transactionID, onSubmit, act accountID: null, }, ]; - }, [selectedTaxRate]); + }, [selectedTaxRate, isTaxValueChanged]); const sections = useMemo(() => { const baseSections = getTaxRatesSection({ @@ -95,7 +96,7 @@ function TaxPicker({selectedTaxRate = '', policyID, transactionID, onSubmit, act transaction: currentTransaction, }); - if (!isTaxDeleted) { + if (!isTaxDeleted && !isTaxValueChanged) { return baseSections; } @@ -113,7 +114,7 @@ function TaxPicker({selectedTaxRate = '', policyID, transactionID, onSubmit, act ...section, data: [...section.data, deletedTaxOption], })); - }, [isTaxDeleted, policy, searchValue, localeCompare, selectedOptions, currentTransaction, transaction?.taxCode, transaction?.taxValue]); + }, [policy, searchValue, localeCompare, selectedOptions, currentTransaction, isTaxDeleted, isTaxValueChanged, transaction?.taxCode, transaction?.taxValue]); const headerMessage = getHeaderMessageForNonUserList((sections.at(0)?.data?.length ?? 0) > 0, searchValue); @@ -125,9 +126,9 @@ function TaxPicker({selectedTaxRate = '', policyID, transactionID, onSubmit, act onDismiss(); return; } - onSubmit(newSelectedOption, isTaxDeleted); + onSubmit(newSelectedOption, isTaxDeleted || isTaxValueChanged); }, - [selectedOptionKey, onSubmit, isTaxDeleted, onDismiss], + [selectedOptionKey, onSubmit, isTaxDeleted, isTaxValueChanged, onDismiss], ); return ( From c8f59f2d42cf685b0ca92f07c93c019d982e22ed Mon Sep 17 00:00:00 2001 From: huutech <20178761+huult@users.noreply.github.com> Date: Mon, 29 Dec 2025 15:10:14 +0700 Subject: [PATCH 03/13] update case where tax value changes --- src/components/TaxPicker.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/components/TaxPicker.tsx b/src/components/TaxPicker.tsx index 84fa3b1cd7d08..4ed10f0ff8f28 100644 --- a/src/components/TaxPicker.tsx +++ b/src/components/TaxPicker.tsx @@ -101,7 +101,7 @@ function TaxPicker({selectedTaxRate = '', policyID, transactionID, onSubmit, act } const deletedTaxOption = { - code: transaction?.taxCode, + code: undefined, text: transaction?.taxValue ?? '', keyForList: transaction?.taxCode ?? '', searchText: transaction?.taxValue ?? '', @@ -122,13 +122,18 @@ function TaxPicker({selectedTaxRate = '', policyID, transactionID, onSubmit, act const handleSelectRow = useCallback( (newSelectedOption: TaxRatesOption) => { + if (isTaxValueChanged) { + onSubmit(newSelectedOption, !newSelectedOption.code); + return; + } if (selectedOptionKey === newSelectedOption.keyForList) { onDismiss(); return; } - onSubmit(newSelectedOption, isTaxDeleted || isTaxValueChanged); + + onSubmit(newSelectedOption, !newSelectedOption.code); }, - [selectedOptionKey, onSubmit, isTaxDeleted, isTaxValueChanged, onDismiss], + [isTaxValueChanged, selectedOptionKey, onSubmit, onDismiss], ); return ( From d9ff23ba6343efc072d2c2550c1687571236f9e6 Mon Sep 17 00:00:00 2001 From: huutech <20178761+huult@users.noreply.github.com> Date: Mon, 29 Dec 2025 15:13:51 +0700 Subject: [PATCH 04/13] fix perf-4 --- src/components/TaxPicker.tsx | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/components/TaxPicker.tsx b/src/components/TaxPicker.tsx index 4ed10f0ff8f28..64e3d101d4ce7 100644 --- a/src/components/TaxPicker.tsx +++ b/src/components/TaxPicker.tsx @@ -69,7 +69,7 @@ function TaxPicker({selectedTaxRate = '', policyID, transactionID, onSubmit, act const shouldShowTextInput = !isTaxRatesCountBelowThreshold; - const isTaxDeleted = !!transaction?.taxCode && !!transaction?.taxValue && Object.keys(taxRates?.taxes ?? {}).find((taxCode) => taxCode === transaction?.taxCode) === undefined; + const isTaxDeleted = !!transaction?.taxCode && transaction?.taxValue !== undefined && !taxRates?.taxes?.[transaction.taxCode]; const isTaxValueChanged = !!transaction?.taxCode && !!transaction?.taxValue && !Object.values(taxRates?.taxes ?? {}).some((rate) => rate.value === transaction?.taxValue); @@ -87,6 +87,21 @@ function TaxPicker({selectedTaxRate = '', policyID, transactionID, onSubmit, act ]; }, [selectedTaxRate, isTaxValueChanged]); + const deletedTaxOption = useMemo(() => { + if (!isTaxDeleted && !isTaxValueChanged) { + return null; + } + return { + code: undefined, + text: transaction?.taxValue ?? '', + keyForList: transaction?.taxCode ?? '', + searchText: transaction?.taxValue ?? '', + tooltipText: transaction?.taxValue ?? '', + isDisabled: true, + isSelected: true, + }; + }, [isTaxDeleted, isTaxValueChanged, transaction?.taxCode, transaction?.taxValue]); + const sections = useMemo(() => { const baseSections = getTaxRatesSection({ policy, @@ -96,25 +111,15 @@ function TaxPicker({selectedTaxRate = '', policyID, transactionID, onSubmit, act transaction: currentTransaction, }); - if (!isTaxDeleted && !isTaxValueChanged) { + if (!deletedTaxOption) { return baseSections; } - const deletedTaxOption = { - code: undefined, - text: transaction?.taxValue ?? '', - keyForList: transaction?.taxCode ?? '', - searchText: transaction?.taxValue ?? '', - tooltipText: transaction?.taxValue ?? '', - isDisabled: true, - isSelected: true, - }; - return baseSections.map((section) => ({ ...section, data: [...section.data, deletedTaxOption], })); - }, [policy, searchValue, localeCompare, selectedOptions, currentTransaction, isTaxDeleted, isTaxValueChanged, transaction?.taxCode, transaction?.taxValue]); + }, [policy, searchValue, localeCompare, selectedOptions, currentTransaction, deletedTaxOption]); const headerMessage = getHeaderMessageForNonUserList((sections.at(0)?.data?.length ?? 0) > 0, searchValue); From 37e04f10248078d9f8355a9efeb241410da0a99d Mon Sep 17 00:00:00 2001 From: huutech <20178761+huult@users.noreply.github.com> Date: Mon, 29 Dec 2025 15:21:30 +0700 Subject: [PATCH 05/13] Rename variables for clarity --- src/components/TaxPicker.tsx | 8 ++++---- src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/TaxPicker.tsx b/src/components/TaxPicker.tsx index 64e3d101d4ce7..ef2f101a417a5 100644 --- a/src/components/TaxPicker.tsx +++ b/src/components/TaxPicker.tsx @@ -27,7 +27,7 @@ type TaxPickerProps = { transactionID?: string; /** Callback to fire when a tax is pressed */ - onSubmit: (tax: TaxRatesOption, isTaxDeleted?: boolean) => void; + onSubmit: (tax: TaxRatesOption, shouldClearTax?: boolean) => void; /** The action to take */ action?: IOUAction; @@ -71,7 +71,7 @@ function TaxPicker({selectedTaxRate = '', policyID, transactionID, onSubmit, act const isTaxDeleted = !!transaction?.taxCode && transaction?.taxValue !== undefined && !taxRates?.taxes?.[transaction.taxCode]; - const isTaxValueChanged = !!transaction?.taxCode && !!transaction?.taxValue && !Object.values(taxRates?.taxes ?? {}).some((rate) => rate.value === transaction?.taxValue); + const isTaxValueChanged = !!transaction?.taxCode && transaction?.taxValue !== undefined && taxRates?.taxes?.[transaction.taxCode]?.value !== transaction?.taxValue; const selectedOptions = useMemo(() => { if (!selectedTaxRate || isTaxValueChanged) { @@ -136,9 +136,9 @@ function TaxPicker({selectedTaxRate = '', policyID, transactionID, onSubmit, act return; } - onSubmit(newSelectedOption, !newSelectedOption.code); + onSubmit(newSelectedOption, isTaxDeleted); }, - [isTaxValueChanged, selectedOptionKey, onSubmit, onDismiss], + [isTaxValueChanged, selectedOptionKey, onSubmit, isTaxDeleted, onDismiss], ); return ( diff --git a/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx b/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx index fd31f790c8df5..879fb1e7c371e 100644 --- a/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx +++ b/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx @@ -63,8 +63,8 @@ function IOURequestStepTaxRatePage({ const taxRateTitle = getTaxName(policy, currentTransaction); - const updateTaxRates = (taxes: TaxRatesOption, isTaxDeleted?: boolean) => { - if (isTaxDeleted && isEditing) { + const updateTaxRates = (taxes: TaxRatesOption, shouldClearTax?: boolean) => { + if (shouldClearTax && isEditing) { updateMoneyRequestTaxRate({ transactionID: currentTransaction?.transactionID, optimisticReportActionID: report?.reportID, From c34bb58f9468aed047663d2a56196d8c34f6b6af Mon Sep 17 00:00:00 2001 From: huutech <20178761+huult@users.noreply.github.com> Date: Mon, 19 Jan 2026 10:38:55 +0700 Subject: [PATCH 06/13] Update params for updateMoneyRequestTaxRate --- src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx b/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx index e82bcf69fab6a..42e4e8708f05a 100644 --- a/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx +++ b/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx @@ -71,15 +71,17 @@ function IOURequestStepTaxRatePage({ if (shouldClearTax && isEditing) { updateMoneyRequestTaxRate({ transactionID: currentTransaction?.transactionID, - optimisticReportActionID: report?.reportID, + transactionThreadReport: report, + parentReport, taxCode: '', - taxAmount: convertToBackendAmount(0), + taxAmount: 0, policy, policyTagList: policyTags, policyCategories, currentUserAccountIDParam, currentUserEmailParam, isASAPSubmitBetaEnabled, + parentReportNextStep, }); navigateBack(); return; From 25b1f0601bcd96212d4e178feeb40d63911cf955 Mon Sep 17 00:00:00 2001 From: huutech <20178761+huult@users.noreply.github.com> Date: Thu, 22 Jan 2026 09:18:41 +0700 Subject: [PATCH 07/13] Rename variable for clarity --- .../ReportActionItem/MoneyRequestView.tsx | 8 ++--- src/components/TaxPicker.tsx | 29 +++++++++---------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index a049f42eea202..8eef2d8b91971 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -310,9 +310,9 @@ function MoneyRequestView({ : convertToDisplayString(Math.abs(transactionTaxAmount ?? 0), transactionCurrency); const taxRatesDescription = taxRates?.name; - const transactionWithTax = updatedTransaction ?? transaction; - const taxRateTitle = transactionWithTax?.taxCode ? getTaxName(policy, updatedTransaction ?? transaction, isExpenseUnreported) : ''; - const isTaxValueChanged = transactionWithTax?.taxCode ? getTaxValue(policy, transactionWithTax, transactionWithTax.taxCode) !== transactionWithTax.taxValue : false; + + const taxRateTitle = transaction?.taxCode ? getTaxName(policy, updatedTransaction ?? transaction, isExpenseUnreported) : ''; + const hasTaxValueChanged = transaction?.taxCode ? getTaxValue(policy, updatedTransaction ?? transaction, transaction.taxCode) !== (updatedTransaction ?? transaction).taxValue : false; const actualTransactionDate = isFromMergeTransaction && updatedTransaction ? getFormattedCreated(updatedTransaction) : transactionDate; const fallbackTaxRateTitle = transaction?.taxValue; @@ -588,7 +588,7 @@ function MoneyRequestView({ const decodedCategoryName = getDecodedCategoryName(categoryValue); const categoryCopyValue = !canEdit ? decodedCategoryName : undefined; const cardCopyValue = cardProgramName; - const taxRateValue = isTaxValueChanged ? transactionWithTax?.taxValue : (taxRateTitle ?? fallbackTaxRateTitle ?? ''); + const taxRateValue = hasTaxValueChanged ? transaction?.taxValue : (taxRateTitle ?? fallbackTaxRateTitle ?? ''); const taxRateCopyValue = !canEditTaxFields ? taxRateValue : undefined; const taxAmountTitle = formattedTaxAmount ? formattedTaxAmount.toString() : ''; const taxAmountCopyValue = !canEditTaxFields ? taxAmountTitle : undefined; diff --git a/src/components/TaxPicker.tsx b/src/components/TaxPicker.tsx index ef2f101a417a5..df2a9a0638b3e 100644 --- a/src/components/TaxPicker.tsx +++ b/src/components/TaxPicker.tsx @@ -69,12 +69,12 @@ function TaxPicker({selectedTaxRate = '', policyID, transactionID, onSubmit, act const shouldShowTextInput = !isTaxRatesCountBelowThreshold; - const isTaxDeleted = !!transaction?.taxCode && transaction?.taxValue !== undefined && !taxRates?.taxes?.[transaction.taxCode]; - - const isTaxValueChanged = !!transaction?.taxCode && transaction?.taxValue !== undefined && taxRates?.taxes?.[transaction.taxCode]?.value !== transaction?.taxValue; + const {taxCode, taxValue} = transaction ?? {}; + const hasTaxBeenDeleted = !!taxCode && taxValue !== undefined && !taxRates?.taxes?.[taxCode]; + const hasTaxValueChanged = !!taxCode && taxValue !== undefined && taxRates?.taxes?.[taxCode]?.value !== taxValue; const selectedOptions = useMemo(() => { - if (!selectedTaxRate || isTaxValueChanged) { + if (!selectedTaxRate || hasTaxValueChanged) { return []; } @@ -85,23 +85,22 @@ function TaxPicker({selectedTaxRate = '', policyID, transactionID, onSubmit, act accountID: null, }, ]; - }, [selectedTaxRate, isTaxValueChanged]); + }, [selectedTaxRate, hasTaxValueChanged]); const deletedTaxOption = useMemo(() => { - if (!isTaxDeleted && !isTaxValueChanged) { + if (!hasTaxBeenDeleted && !hasTaxValueChanged) { return null; } return { code: undefined, - text: transaction?.taxValue ?? '', - keyForList: transaction?.taxCode ?? '', - searchText: transaction?.taxValue ?? '', - tooltipText: transaction?.taxValue ?? '', + text: taxValue ?? '', + keyForList: taxCode ?? '', + searchText: taxValue ?? '', + tooltipText: taxValue ?? '', isDisabled: true, isSelected: true, }; - }, [isTaxDeleted, isTaxValueChanged, transaction?.taxCode, transaction?.taxValue]); - + }, [hasTaxBeenDeleted, hasTaxValueChanged, taxCode, taxValue]); const sections = useMemo(() => { const baseSections = getTaxRatesSection({ policy, @@ -127,7 +126,7 @@ function TaxPicker({selectedTaxRate = '', policyID, transactionID, onSubmit, act const handleSelectRow = useCallback( (newSelectedOption: TaxRatesOption) => { - if (isTaxValueChanged) { + if (hasTaxValueChanged) { onSubmit(newSelectedOption, !newSelectedOption.code); return; } @@ -136,9 +135,9 @@ function TaxPicker({selectedTaxRate = '', policyID, transactionID, onSubmit, act return; } - onSubmit(newSelectedOption, isTaxDeleted); + onSubmit(newSelectedOption, hasTaxBeenDeleted); }, - [isTaxValueChanged, selectedOptionKey, onSubmit, isTaxDeleted, onDismiss], + [hasTaxValueChanged, selectedOptionKey, onSubmit, hasTaxBeenDeleted, onDismiss], ); return ( From 572e04caaeda915386d471f322bc7c0a536f989c Mon Sep 17 00:00:00 2001 From: huutech <20178761+huult@users.noreply.github.com> Date: Thu, 22 Jan 2026 09:23:15 +0700 Subject: [PATCH 08/13] Refactor if-else conditions for clarity --- src/components/ReportActionItem/MoneyRequestView.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 8eef2d8b91971..62976491b7f8e 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -311,8 +311,11 @@ function MoneyRequestView({ const taxRatesDescription = taxRates?.name; - const taxRateTitle = transaction?.taxCode ? getTaxName(policy, updatedTransaction ?? transaction, isExpenseUnreported) : ''; - const hasTaxValueChanged = transaction?.taxCode ? getTaxValue(policy, updatedTransaction ?? transaction, transaction.taxCode) !== (updatedTransaction ?? transaction).taxValue : false; + const baseTransaction = updatedTransaction ?? transaction; + const {taxCode, taxValue} = transaction ?? {}; + + const taxRateTitle = taxCode ? getTaxName(policy, baseTransaction, isExpenseUnreported) : ''; + const hasTaxValueChanged = taxCode ? getTaxValue(policy, baseTransaction, taxCode) !== baseTransaction?.taxValue : false; const actualTransactionDate = isFromMergeTransaction && updatedTransaction ? getFormattedCreated(updatedTransaction) : transactionDate; const fallbackTaxRateTitle = transaction?.taxValue; @@ -588,7 +591,7 @@ function MoneyRequestView({ const decodedCategoryName = getDecodedCategoryName(categoryValue); const categoryCopyValue = !canEdit ? decodedCategoryName : undefined; const cardCopyValue = cardProgramName; - const taxRateValue = hasTaxValueChanged ? transaction?.taxValue : (taxRateTitle ?? fallbackTaxRateTitle ?? ''); + const taxRateValue = hasTaxValueChanged ? taxValue : (taxRateTitle ?? fallbackTaxRateTitle ?? ''); const taxRateCopyValue = !canEditTaxFields ? taxRateValue : undefined; const taxAmountTitle = formattedTaxAmount ? formattedTaxAmount.toString() : ''; const taxAmountCopyValue = !canEditTaxFields ? taxAmountTitle : undefined; From dfde2dd5bc2bd42209af862b085b06968b347c88 Mon Sep 17 00:00:00 2001 From: huutech <20178761+huult@users.noreply.github.com> Date: Thu, 22 Jan 2026 09:34:14 +0700 Subject: [PATCH 09/13] fix lint --- .../step/IOURequestStepTaxRatePage.tsx | 47 +++++++------------ 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx b/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx index a844cc85c352c..d54b46c3a8ee5 100644 --- a/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx +++ b/src/pages/iou/request/step/IOURequestStepTaxRatePage.tsx @@ -69,21 +69,24 @@ function IOURequestStepTaxRatePage({ const taxRateTitle = getTaxName(policy, currentTransaction); const updateTaxRates = (taxes: TaxRatesOption, shouldClearTax?: boolean) => { + const updateTaxRateParams = { + transactionID: currentTransaction?.transactionID, + transactionThreadReport: report, + parentReport, + taxCode: '', + taxValue: '', + taxAmount: 0, + policy, + policyTagList: policyTags, + policyCategories, + currentUserAccountIDParam, + currentUserEmailParam, + isASAPSubmitBetaEnabled, + parentReportNextStep, + }; + if (shouldClearTax && isEditing) { - updateMoneyRequestTaxRate({ - transactionID: currentTransaction?.transactionID, - transactionThreadReport: report, - parentReport, - taxCode: '', - taxAmount: 0, - policy, - policyTagList: policyTags, - policyCategories, - currentUserAccountIDParam, - currentUserEmailParam, - isASAPSubmitBetaEnabled, - parentReportNextStep, - }); + updateMoneyRequestTaxRate(updateTaxRateParams); navigateBack(); return; } @@ -106,21 +109,7 @@ function IOURequestStepTaxRatePage({ if (isEditing) { const newTaxCode = taxes.code; - updateMoneyRequestTaxRate({ - transactionID: currentTransaction?.transactionID, - transactionThreadReport: report, - parentReport, - taxCode: newTaxCode, - taxValue, - taxAmount: convertToBackendAmount(taxAmount ?? 0), - policy, - policyTagList: policyTags, - policyCategories, - currentUserAccountIDParam, - currentUserEmailParam, - isASAPSubmitBetaEnabled, - parentReportNextStep, - }); + updateMoneyRequestTaxRate({...updateTaxRateParams, taxCode: newTaxCode, taxValue, taxAmount: convertToBackendAmount(taxAmount ?? 0)}); navigateBack(); return; } From 3b6150a911c90a71793832d3e2c1905b5a5a1673 Mon Sep 17 00:00:00 2001 From: huutech <20178761+huult@users.noreply.github.com> Date: Tue, 10 Feb 2026 15:46:55 +0700 Subject: [PATCH 10/13] update selection when tax value changes but tax code stays the same --- src/components/TaxPicker.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/TaxPicker.tsx b/src/components/TaxPicker.tsx index eac6bbcdb524c..53bf824426c4b 100644 --- a/src/components/TaxPicker.tsx +++ b/src/components/TaxPicker.tsx @@ -125,16 +125,16 @@ function TaxPicker({selectedTaxRate = '', policyID, transactionID, onSubmit, act headerMessage: getHeaderMessageForNonUserList((sections.at(0)?.data?.length ?? 0) > 0, searchValue), }; + const updatedSections = deletedTaxOption + ? sections.map((section) => ({ + ...section, + data: [...section.data.map((item) => (item.code === deletedTaxOption.code ? {...item, isSelected: false} : item)), deletedTaxOption], + })) + : sections; + return ( ({ - ...section, - data: [...section.data, deletedTaxOption], - })) - : sections - } + sections={updatedSections} shouldShowTextInput={shouldShowTextInput} textInputOptions={textInputOptions} onSelectRow={handleSelectRow} From 396cb9ba82f01e24e5423e213d101131daa7cd7d Mon Sep 17 00:00:00 2001 From: huutech <20178761+huult@users.noreply.github.com> Date: Tue, 24 Feb 2026 08:27:24 +0700 Subject: [PATCH 11/13] run prettier --- src/components/AvatarCropModal/AvatarCropModal.tsx | 2 +- src/components/HeaderWithBackButton/index.tsx | 2 +- src/components/Lightbox/index.tsx | 2 +- src/components/PDFThumbnail/index.native.tsx | 2 +- src/components/TransactionItemRow/ReceiptPreview/index.tsx | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/AvatarCropModal/AvatarCropModal.tsx b/src/components/AvatarCropModal/AvatarCropModal.tsx index 033279932f39b..ac77934485a92 100644 --- a/src/components/AvatarCropModal/AvatarCropModal.tsx +++ b/src/components/AvatarCropModal/AvatarCropModal.tsx @@ -7,7 +7,6 @@ import ImageSize from 'react-native-image-size'; import {interpolate, useSharedValue} from 'react-native-reanimated'; import {scheduleOnUI} from 'react-native-worklets'; import ActivityIndicator from '@components/ActivityIndicator'; -import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import Button from '@components/Button'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Icon from '@components/Icon'; @@ -24,6 +23,7 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import cropOrRotateImage from '@libs/cropOrRotateImage'; import type {CustomRNImageManipulatorResult} from '@libs/cropOrRotateImage/types'; +import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import CONST from '@src/CONST'; import type IconAsset from '@src/types/utils/IconAsset'; import ImageCropView from './ImageCropView'; diff --git a/src/components/HeaderWithBackButton/index.tsx b/src/components/HeaderWithBackButton/index.tsx index 2d81005e4feb5..96c2c9c6b7f92 100755 --- a/src/components/HeaderWithBackButton/index.tsx +++ b/src/components/HeaderWithBackButton/index.tsx @@ -2,7 +2,6 @@ import React, {useMemo} from 'react'; import {Keyboard, StyleSheet, View} from 'react-native'; import type {SvgProps} from 'react-native-svg'; import ActivityIndicator from '@components/ActivityIndicator'; -import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import Avatar from '@components/Avatar'; import AvatarWithDisplayName from '@components/AvatarWithDisplayName'; import Header from '@components/Header'; @@ -21,6 +20,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useThrottledButtonState from '@hooks/useThrottledButtonState'; import getButtonState from '@libs/getButtonState'; import Navigation from '@libs/Navigation/Navigation'; +import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; diff --git a/src/components/Lightbox/index.tsx b/src/components/Lightbox/index.tsx index 6ad732981b180..63cfeb4fbc799 100644 --- a/src/components/Lightbox/index.tsx +++ b/src/components/Lightbox/index.tsx @@ -3,7 +3,6 @@ import type {LayoutChangeEvent, StyleProp, ViewStyle} from 'react-native'; import {PixelRatio, StyleSheet, View} from 'react-native'; import {useSharedValue} from 'react-native-reanimated'; import ActivityIndicator from '@components/ActivityIndicator'; -import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import AttachmentOfflineIndicator from '@components/AttachmentOfflineIndicator'; import {useAttachmentCarouselPagerActions, useAttachmentCarouselPagerState} from '@components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPagerContext'; import type {Attachment} from '@components/Attachments/types'; @@ -17,6 +16,7 @@ import usePrevious from '@hooks/usePrevious'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import {isLocalFile} from '@libs/fileDownload/FileUtils'; +import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import CONST from '@src/CONST'; import type {Dimensions} from '@src/types/utils/Layout'; import NUMBER_OF_CONCURRENT_LIGHTBOXES from './numberOfConcurrentLightboxes'; diff --git a/src/components/PDFThumbnail/index.native.tsx b/src/components/PDFThumbnail/index.native.tsx index 09778fde31940..024bbad2a627c 100644 --- a/src/components/PDFThumbnail/index.native.tsx +++ b/src/components/PDFThumbnail/index.native.tsx @@ -2,9 +2,9 @@ import React, {useState} from 'react'; import {View} from 'react-native'; import Pdf from 'react-native-pdf'; import LoadingIndicator from '@components/LoadingIndicator'; -import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import useThemeStyles from '@hooks/useThemeStyles'; import addEncryptedAuthTokenToURL from '@libs/addEncryptedAuthTokenToURL'; +import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import PDFThumbnailError from './PDFThumbnailError'; import type PDFThumbnailProps from './types'; diff --git a/src/components/TransactionItemRow/ReceiptPreview/index.tsx b/src/components/TransactionItemRow/ReceiptPreview/index.tsx index f2ffbb0c8da2e..c102d9fdfc6ff 100644 --- a/src/components/TransactionItemRow/ReceiptPreview/index.tsx +++ b/src/components/TransactionItemRow/ReceiptPreview/index.tsx @@ -4,7 +4,6 @@ import type {LayoutChangeEvent} from 'react-native'; import {StyleSheet, View} from 'react-native'; import Animated, {FadeIn, FadeOut} from 'react-native-reanimated'; import ActivityIndicator from '@components/ActivityIndicator'; -import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import DistanceEReceipt from '@components/DistanceEReceipt'; import EReceiptWithSizeCalculation from '@components/EReceiptWithSizeCalculation'; import type {ImageOnLoadEvent} from '@components/Image/types'; @@ -12,6 +11,7 @@ import useDebouncedState from '@hooks/useDebouncedState'; import useResponsiveLayoutOnWideRHP from '@hooks/useResponsiveLayoutOnWideRHP'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; +import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import {hasReceiptSource, isDistanceRequest, isManualDistanceRequest, isPerDiemRequest} from '@libs/TransactionUtils'; import variables from '@styles/variables'; import Image from '@src/components/Image'; From a68b7928346ddc117ef6d6c2a06eca4fbc82d6b6 Mon Sep 17 00:00:00 2001 From: huutech <20178761+huult@users.noreply.github.com> Date: Wed, 4 Mar 2026 09:29:34 +0700 Subject: [PATCH 12/13] Fix logic for adding tax option --- src/components/TaxPicker.tsx | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/components/TaxPicker.tsx b/src/components/TaxPicker.tsx index 487a529a9f3a7..87a5a7f51fb8a 100644 --- a/src/components/TaxPicker.tsx +++ b/src/components/TaxPicker.tsx @@ -72,18 +72,17 @@ function TaxPicker({selectedTaxRate = '', policyID, transactionID, onSubmit, act const hasTaxBeenDeleted = !!taxCode && taxValue !== undefined && !taxRates?.taxes?.[taxCode]; const hasTaxValueChanged = !!taxCode && taxValue !== undefined && taxRates?.taxes?.[taxCode]?.value !== taxValue; - const deletedTaxOption = - !hasTaxBeenDeleted && !hasTaxValueChanged - ? null - : { - code: undefined, - text: taxValue ?? '', - keyForList: taxCode ?? '', - searchText: taxValue ?? '', - tooltipText: taxValue ?? '', - isDisabled: true, - isSelected: true, - }; + const deletedTaxOption = !hasTaxBeenDeleted + ? null + : { + code: undefined, + text: taxValue ?? '', + keyForList: taxCode ?? '', + searchText: taxValue ?? '', + tooltipText: taxValue ?? '', + isDisabled: true, + isSelected: true, + }; const selectedOptions = selectedTaxRate ? [ From 499681aac07c684a0fea6d2ebe6391274799eefe Mon Sep 17 00:00:00 2001 From: huutech <20178761+huult@users.noreply.github.com> Date: Tue, 17 Mar 2026 13:38:55 +0700 Subject: [PATCH 13/13] update to use baseTransaction --- src/components/ReportActionItem/MoneyRequestView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index a86527d815540..41b799d0cfea4 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -307,7 +307,7 @@ function MoneyRequestView({ const taxRatesDescription = taxRates?.name; const baseTransaction = updatedTransaction ?? transaction; - const {taxCode, taxValue} = transaction ?? {}; + const {taxCode, taxValue} = baseTransaction ?? {}; const taxRateTitle = taxCode ? getTaxName(policy, baseTransaction, isExpenseUnreported) : ''; const hasTaxValueChanged = taxCode ? getTaxValue(policy, baseTransaction, taxCode) !== baseTransaction?.taxValue : false;