From 9e9bfc7f9fdc23c40ae70e098abf47eeb8ed6e35 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Wed, 6 Aug 2025 15:25:30 +0530 Subject: [PATCH] Removed Onyx.connect from DistanceRate Actions (part 1) --- package.json | 2 +- src/libs/actions/Policy/DistanceRate.ts | 58 ++++++------------- .../PolicyDistanceRateDetailsPage.tsx | 37 +++++++++++- .../distanceRates/PolicyDistanceRatesPage.tsx | 54 ++++++++++++++++- tests/unit/DistanceRateTest.ts | 2 +- 5 files changed, 109 insertions(+), 44 deletions(-) diff --git a/package.json b/package.json index bbbabe6152e2..732ef0b90227 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "test:debug": "TZ=utc NODE_OPTIONS='--inspect-brk --experimental-vm-modules' jest --runInBand", "perf-test": "NODE_OPTIONS=--experimental-vm-modules npx reassure", "typecheck": "NODE_OPTIONS=--max_old_space_size=8192 tsc", - "lint": "NODE_OPTIONS=--max_old_space_size=8192 eslint . --max-warnings=312 --cache --cache-location=node_modules/.cache/eslint", + "lint": "NODE_OPTIONS=--max_old_space_size=8192 eslint . --max-warnings=310 --cache --cache-location=node_modules/.cache/eslint", "lint-changed": "NODE_OPTIONS=--max_old_space_size=8192 ./scripts/lintChanged.sh", "lint-watch": "npx eslint-watch --watch --changed", "shellcheck": "./scripts/shellCheck.sh", diff --git a/src/libs/actions/Policy/DistanceRate.ts b/src/libs/actions/Policy/DistanceRate.ts index 4bc028d444cd..90ab1db91106 100644 --- a/src/libs/actions/Policy/DistanceRate.ts +++ b/src/libs/actions/Policy/DistanceRate.ts @@ -18,7 +18,7 @@ import {getDistanceRateCustomUnit, goBackWhenEnableFeature, removePendingFieldsF import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Policy, Report, Transaction, TransactionViolation} from '@src/types/onyx'; +import type {Policy, Report, TransactionViolation} from '@src/types/onyx'; import type {ErrorFields} from '@src/types/onyx/OnyxCommon'; import type {CustomUnit, Rate} from '@src/types/onyx/Policy'; import type {OnyxData} from '@src/types/onyx/Request'; @@ -56,29 +56,6 @@ Onyx.connect({ }, }); -let allTransactions: NonNullable> = {}; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.TRANSACTION, - waitForCollectionCallback: true, - callback: (value) => { - if (!value) { - allTransactions = {}; - return; - } - - allTransactions = value; - }, -}); - -let transactionViolations: OnyxCollection; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, - waitForCollectionCallback: true, - callback: (value) => { - transactionViolations = value; - }, -}); - /** * Takes array of customUnitRates and removes pendingFields and errorFields from each rate - we don't want to send those via API */ @@ -451,7 +428,13 @@ function setPolicyDistanceRatesEnabled(policyID: string, customUnit: CustomUnit, API.write(WRITE_COMMANDS.SET_POLICY_DISTANCE_RATES_ENABLED, params, {optimisticData, successData, failureData}); } -function deletePolicyDistanceRates(policyID: string, customUnit: CustomUnit, rateIDsToDelete: string[]) { +function deletePolicyDistanceRates( + policyID: string, + customUnit: CustomUnit, + rateIDsToDelete: string[], + transactionIDsAffected: string[], + transactionViolations: OnyxCollection, +) { const currentRates = customUnit.rates; const optimisticRates: Record = {}; const successRates: Record = {}; @@ -520,22 +503,18 @@ function deletePolicyDistanceRates(policyID: string, customUnit: CustomUnit, rat }, ]; - const transactions = Object.values(allTransactions ?? {}).filter( - (transaction) => - transaction?.comment?.customUnit?.customUnitID === customUnit.customUnitID && - transaction?.comment?.customUnit?.customUnitRateID && - rateIDsToDelete.includes(transaction?.comment?.customUnit?.customUnitRateID), - ); const optimisticTransactionsViolations: OnyxUpdate[] = []; + const failureTransactionsViolations: OnyxUpdate[] = []; - transactions.forEach((transaction) => { - const currentTransactionViolations = transactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction?.transactionID}`] ?? []; + for (const transactionID of transactionIDsAffected) { + const currentTransactionViolations = transactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`] ?? []; if (currentTransactionViolations.some((violation) => violation.name === CONST.VIOLATIONS.CUSTOM_UNIT_OUT_OF_POLICY)) { return; } + optimisticTransactionsViolations.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction?.transactionID}`, + key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, value: [ ...currentTransactionViolations, { @@ -545,12 +524,13 @@ function deletePolicyDistanceRates(policyID: string, customUnit: CustomUnit, rat }, ], }); - }); - const failureTransactionsViolations: OnyxUpdate[] = transactions.map((transaction) => { - const currentTransactionViolations = transactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction?.transactionID}`]; - return {onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction?.transactionID}`, value: currentTransactionViolations}; - }); + failureTransactionsViolations.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, + value: currentTransactionViolations, + }); + } optimisticData.push(...optimisticTransactionsViolations); failureData.push(...failureTransactionsViolations); diff --git a/src/pages/workspace/distanceRates/PolicyDistanceRateDetailsPage.tsx b/src/pages/workspace/distanceRates/PolicyDistanceRateDetailsPage.tsx index b46c46655596..a91d3ca3488b 100644 --- a/src/pages/workspace/distanceRates/PolicyDistanceRateDetailsPage.tsx +++ b/src/pages/workspace/distanceRates/PolicyDistanceRateDetailsPage.tsx @@ -38,9 +38,42 @@ function PolicyDistanceRateDetailsPage({route}: PolicyDistanceRateDetailsPagePro const policyID = route.params.policyID; const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${route.params.policyID}`, {canBeMissing: true}); const rateID = route.params.rateID; - const customUnit = getDistanceRateCustomUnit(policy); const rate = customUnit?.rates[rateID]; + const customUnitID = customUnit?.customUnitID; + const [eligibleTransactionIDs] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION, { + selector: (transactions) => { + return Object.values(transactions ?? {}).reduce((transactionIDs, transaction) => { + if ( + transaction && + customUnitID && + transaction?.comment?.customUnit?.customUnitID === customUnitID && + transaction?.comment?.customUnit?.customUnitRateID && + transaction?.comment?.customUnit?.customUnitRateID === rateID + ) { + transactionIDs.add(transaction?.transactionID); + } + return transactionIDs; + }, new Set()); + }, + canBeMissing: true, + }); + + const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, { + selector: (violations) => { + if (!eligibleTransactionIDs || eligibleTransactionIDs.size === 0) { + return undefined; + } + return Object.fromEntries( + Object.entries(violations ?? {}).filter(([key]) => { + const id = key.replace(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, ''); + return eligibleTransactionIDs?.has(id); + }), + ); + }, + canBeMissing: true, + }); + const currency = rate?.currency ?? CONST.CURRENCY.USD; const taxClaimablePercentage = rate?.attributes?.taxClaimablePercentage; const taxRateExternalID = rate?.attributes?.taxRateExternalID; @@ -83,7 +116,7 @@ function PolicyDistanceRateDetailsPage({route}: PolicyDistanceRateDetailsPagePro const deleteRate = () => { Navigation.goBack(); - deletePolicyDistanceRates(policyID, customUnit, [rateID]); + deletePolicyDistanceRates(policyID, customUnit, [rateID], Array.from(eligibleTransactionIDs ?? []), transactionViolations); setIsDeleteModalVisible(false); }; diff --git a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx index 5d70b95ec7b4..1a516714a9e1 100644 --- a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx +++ b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx @@ -18,6 +18,7 @@ import useFilteredSelection from '@hooks/useFilteredSelection'; import useLocalize from '@hooks/useLocalize'; import useMobileSelectionMode from '@hooks/useMobileSelectionMode'; import useNetwork from '@hooks/useNetwork'; +import useOnyx from '@hooks/useOnyx'; import usePolicy from '@hooks/usePolicy'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useSearchBackPress from '@hooks/useSearchBackPress'; @@ -42,6 +43,7 @@ import type {WorkspaceSplitNavigatorParamList} from '@navigation/types'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import ButtonWithDropdownMenu from '@src/components/ButtonWithDropdownMenu'; import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type {Rate} from '@src/types/onyx/Policy'; @@ -78,6 +80,54 @@ function PolicyDistanceRatesPage({ [customUnitRates], ); + const rateIDs = new Set(Object.keys(selectableRates)); + + const [eligibleTransactionsData] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION, { + selector: (transactions) => { + if (!customUnit?.customUnitID || rateIDs.size === 0) { + return undefined; + } + return Object.values(transactions ?? {}).reduce( + (transactionsData, transaction) => { + if ( + transaction && + customUnit?.customUnitID && + transaction?.comment?.customUnit?.customUnitID === customUnit.customUnitID && + transaction?.comment?.customUnit?.customUnitRateID && + rateIDs.has(transaction?.comment?.customUnit?.customUnitRateID) + ) { + transactionsData.transactionIDs.add(transaction.transactionID); + if (!transactionsData.rateIDToTransactionIDsMap[transaction?.comment?.customUnit?.customUnitRateID]) { + // eslint-disable-next-line no-param-reassign + transactionsData.rateIDToTransactionIDsMap[transaction?.comment?.customUnit?.customUnitRateID] = []; + } + transactionsData.rateIDToTransactionIDsMap[transaction?.comment?.customUnit?.customUnitRateID]?.push(transaction?.transactionID); + } + return transactionsData; + }, + {transactionIDs: new Set(), rateIDToTransactionIDsMap: {} as Record}, + ); + }, + canBeMissing: true, + }); + + const eligibleTransactionIDs = eligibleTransactionsData?.transactionIDs; + + const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, { + selector: (violations) => { + if (!eligibleTransactionIDs || eligibleTransactionIDs.size === 0) { + return undefined; + } + return Object.fromEntries( + Object.entries(violations ?? {}).filter(([key]) => { + const id = key.replace(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, ''); + return eligibleTransactionIDs?.has(id); + }), + ); + }, + canBeMissing: true, + }); + const filterRateSelection = useCallback( (rate?: Rate) => !!rate && !!customUnitRates?.[rate.customUnitRateID] && customUnitRates?.[rate.customUnitRateID]?.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, [customUnitRates], @@ -235,7 +285,9 @@ function PolicyDistanceRatesPage({ return; } - deletePolicyDistanceRates(policyID, customUnit, selectedDistanceRates); + const transactionIDsAffected = selectedDistanceRates.flatMap((rateID) => eligibleTransactionsData?.rateIDToTransactionIDsMap?.[rateID] ?? []); + + deletePolicyDistanceRates(policyID, customUnit, selectedDistanceRates, transactionIDsAffected, transactionViolations); setIsDeleteModalVisible(false); InteractionManager.runAfterInteractions(() => { diff --git a/tests/unit/DistanceRateTest.ts b/tests/unit/DistanceRateTest.ts index f7eba3a85fd4..5b817a0dccbf 100644 --- a/tests/unit/DistanceRateTest.ts +++ b/tests/unit/DistanceRateTest.ts @@ -76,7 +76,7 @@ describe('DistanceRate', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy); if (policy.customUnits) { - deletePolicyDistanceRates(policy.id, policy.customUnits[customUnitID], [customUnitRateID1]); + deletePolicyDistanceRates(policy.id, policy.customUnits[customUnitID], [customUnitRateID1], [transaction1.transactionID], undefined); } await waitForBatchedUpdates(); const transactionViolations = await new Promise>((resolve) => {