From ab2ef104228f5f12308b1054e0c89978f668ec3e Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Mon, 25 Nov 2024 10:34:24 +0100 Subject: [PATCH 01/29] fix: attempt to use named export to fix cycular dependecies --- ios/Podfile.lock | 8 ++-- src/CONST.ts | 4 +- src/libs/HttpUtils.ts | 12 +++--- src/libs/Log.ts | 4 +- src/libs/Network/MainQueue.ts | 12 +++--- src/libs/Network/SequentialQueue.ts | 66 ++++++++++++++--------------- src/libs/Network/index.ts | 12 +++--- src/libs/ReportConnection.ts | 8 ++-- src/libs/Request.ts | 6 +-- src/libs/actions/BankAccounts.ts | 16 +++---- src/libs/actions/PriorityMode.ts | 10 ++--- 11 files changed, 79 insertions(+), 79 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 5ea5b19896e4..01aefab63378 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -2661,7 +2661,7 @@ PODS: - RNSound/Core (= 0.11.2) - RNSound/Core (0.11.2): - React-Core - - RNSVG (15.9.0): + - RNSVG (15.6.0): - DoubleConversion - glog - hermes-engine @@ -2681,9 +2681,9 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNSVG/common (= 15.9.0) + - RNSVG/common (= 15.6.0) - Yoga - - RNSVG/common (15.9.0): + - RNSVG/common (15.6.0): - DoubleConversion - glog - hermes-engine @@ -3295,7 +3295,7 @@ SPEC CHECKSUMS: RNScreens: de6e57426ba0e6cbc3fb5b4f496e7f08cb2773c2 RNShare: bd4fe9b95d1ee89a200778cc0753ebe650154bb0 RNSound: 6c156f925295bdc83e8e422e7d8b38d33bc71852 - RNSVG: b2fbe96b2bb3887752f8abc1f495953847e90384 + RNSVG: 1079f96b39a35753d481a20e30603fd6fc4f6fa9 SDWebImage: 066c47b573f408f18caa467d71deace7c0f8280d SDWebImageAVIFCoder: 00310d246aab3232ce77f1d8f0076f8c4b021d90 SDWebImageSVGCoder: 15a300a97ec1c8ac958f009c02220ac0402e936c diff --git a/src/CONST.ts b/src/CONST.ts index ed5f1837fe3b..4fb78ab5fb0f 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -7,7 +7,7 @@ import type {ValueOf} from 'type-fest'; import type {Video} from './libs/actions/Report'; import type {MileageRate} from './libs/DistanceRequestUtils'; import BankAccount from './libs/models/BankAccount'; -import * as Url from './libs/Url'; +import {addTrailingForwardSlash} from './libs/Url'; import SCREENS from './SCREENS'; import type PlaidBankAccount from './types/onyx/PlaidBankAccount'; @@ -18,7 +18,7 @@ const EMPTY_OBJECT = Object.freeze({}); const CLOUDFRONT_DOMAIN = 'cloudfront.net'; const CLOUDFRONT_URL = `https://d2k5nsl2zxldvw.${CLOUDFRONT_DOMAIN}`; -const ACTIVE_EXPENSIFY_URL = Url.addTrailingForwardSlash(Config?.NEW_EXPENSIFY_URL ?? 'https://new.expensify.com'); +const ACTIVE_EXPENSIFY_URL = addTrailingForwardSlash(Config?.NEW_EXPENSIFY_URL ?? 'https://new.expensify.com'); const USE_EXPENSIFY_URL = 'https://use.expensify.com'; const EXPENSIFY_URL = 'https://www.expensify.com'; const PLATFORM_OS_MACOS = 'Mac OS'; diff --git a/src/libs/HttpUtils.ts b/src/libs/HttpUtils.ts index 66ce71451c17..773625c93fed 100644 --- a/src/libs/HttpUtils.ts +++ b/src/libs/HttpUtils.ts @@ -5,10 +5,10 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {RequestType} from '@src/types/onyx/Request'; import type Response from '@src/types/onyx/Response'; -import * as NetworkActions from './actions/Network'; -import * as UpdateRequired from './actions/UpdateRequired'; +import {setTimeSkew} from './actions/Network'; +import {alertUser} from './actions/UpdateRequired'; import {READ_COMMANDS, SIDE_EFFECT_REQUEST_COMMANDS, WRITE_COMMANDS} from './API/types'; -import * as ApiUtils from './ApiUtils'; +import {getCommandURL} from './ApiUtils'; import HttpsError from './Errors/HttpsError'; let shouldFailAllRequests = false; @@ -73,7 +73,7 @@ function processHTTPRequest(url: string, method: RequestType = 'get', body: Form const endTime = new Date().valueOf(); const latency = (endTime - startTime) / 2; const skew = serverTime - startTime + latency; - NetworkActions.setTimeSkew(dateHeaderValue ? skew : 0); + setTimeSkew(dateHeaderValue ? skew : 0); } return response; }) @@ -144,7 +144,7 @@ function processHTTPRequest(url: string, method: RequestType = 'get', body: Form } if (response.jsonCode === CONST.JSON_CODE.UPDATE_REQUIRED) { // Trigger a modal and disable the app as the user needs to upgrade to the latest minimum version to continue - UpdateRequired.alertUser(); + alertUser(); } return response as Promise; }); @@ -166,7 +166,7 @@ function xhr(command: string, data: Record, type: RequestType = formData.append(key, data[key] as string | Blob); }); - const url = ApiUtils.getCommandURL({shouldUseSecure, command}); + const url = getCommandURL({shouldUseSecure, command}); const abortSignalController = data.canCancel ? abortControllerMap.get(command as AbortCommand) ?? abortControllerMap.get(ABORT_COMMANDS.All) : undefined; return processHTTPRequest(url, type, formData, abortSignalController?.signal); diff --git a/src/libs/Log.ts b/src/libs/Log.ts index 2ccbd1d37882..64ce973a3fec 100644 --- a/src/libs/Log.ts +++ b/src/libs/Log.ts @@ -12,7 +12,7 @@ import pkg from '../../package.json'; import {addLog, flushAllLogsOnAppLaunch} from './actions/Console'; import {shouldAttachLog} from './Console'; import getPlatform from './getPlatform'; -import * as Network from './Network'; +import {post} from './Network'; import requireParameters from './requireParameters'; let timeout: NodeJS.Timeout; @@ -40,7 +40,7 @@ function LogCommand(parameters: LogCommandParameters): Promise<{requestID: strin // Note: We are forcing Log to run since it requires no authToken and should only be queued when we are offline. // Non-cancellable request: during logout, when requests are cancelled, we don't want to cancel any remaining logs - return Network.post(commandName, {...parameters, forceNetworkRequest: true, canCancel: false}) as Promise<{requestID: string}>; + return post(commandName, {...parameters, forceNetworkRequest: true, canCancel: false}) as Promise<{requestID: string}>; } // eslint-disable-next-line diff --git a/src/libs/Network/MainQueue.ts b/src/libs/Network/MainQueue.ts index b3d6fbea94ab..95e4e260e153 100644 --- a/src/libs/Network/MainQueue.ts +++ b/src/libs/Network/MainQueue.ts @@ -1,7 +1,7 @@ -import * as Request from '@libs/Request'; +import {processWithMiddleware} from '@libs/Request'; import type OnyxRequest from '@src/types/onyx/Request'; -import * as NetworkStore from './NetworkStore'; -import * as SequentialQueue from './SequentialQueue'; +import {isAuthenticating, isOffline} from './NetworkStore'; +import {isRunning} from './SequentialQueue'; // Queue for network requests so we don't lose actions done by the user while offline let networkRequestQueue: OnyxRequest[] = []; @@ -12,7 +12,7 @@ let networkRequestQueue: OnyxRequest[] = []; function canMakeRequest(request: OnyxRequest): boolean { // Some requests are always made even when we are in the process of authenticating (typically because they require no authToken e.g. Log, BeginSignIn) // However, if we are in the process of authenticating we always want to queue requests until we are no longer authenticating. - return request.data?.forceNetworkRequest === true || (!NetworkStore.isAuthenticating() && !SequentialQueue.isRunning()); + return request.data?.forceNetworkRequest === true || (!isAuthenticating() && !isRunning()); } function push(request: OnyxRequest) { @@ -30,7 +30,7 @@ function replay(request: OnyxRequest) { * Process the networkRequestQueue by looping through the queue and attempting to make the requests */ function process() { - if (NetworkStore.isOffline()) { + if (isOffline()) { return; } @@ -57,7 +57,7 @@ function process() { return; } - Request.processWithMiddleware(queuedRequest); + processWithMiddleware(queuedRequest); }); // We clear the request queue at the end by setting the queue to requestsToProcessOnNextRun which will either have some diff --git a/src/libs/Network/SequentialQueue.ts b/src/libs/Network/SequentialQueue.ts index 3f4da20c16e1..08e550967710 100644 --- a/src/libs/Network/SequentialQueue.ts +++ b/src/libs/Network/SequentialQueue.ts @@ -1,15 +1,15 @@ import Onyx from 'react-native-onyx'; -import * as ActiveClientManager from '@libs/ActiveClientManager'; +import {clear, deleteRequestsByIndices, endRequestAndRemoveFromQueue, getAll, processNextRequest, rollbackOngoingRequest, save, update} from '@libs/actions/PersistedRequests'; +import {flushQueue, isEmpty} from '@libs/actions/QueuedOnyxUpdates'; +import {isClientTheLeader} from '@libs/ActiveClientManager'; import Log from '@libs/Log'; -import * as Request from '@libs/Request'; -import * as RequestThrottle from '@libs/RequestThrottle'; -import * as PersistedRequests from '@userActions/PersistedRequests'; -import * as QueuedOnyxUpdates from '@userActions/QueuedOnyxUpdates'; +import {processWithMiddleware} from '@libs/Request'; +import {sleep} from '@libs/RequestThrottle'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type OnyxRequest from '@src/types/onyx/Request'; import type {ConflictData} from '@src/types/onyx/Request'; -import * as NetworkStore from './NetworkStore'; +import {isOffline, onReconnection} from './NetworkStore'; type RequestError = Error & { name?: string; @@ -52,7 +52,7 @@ function flushOnyxUpdatesQueue() { Log.info('[SequentialQueue] Queue already paused'); return; } - QueuedOnyxUpdates.flushQueue(); + flushQueue(); } /** @@ -70,25 +70,25 @@ function process(): Promise { return Promise.resolve(); } - if (NetworkStore.isOffline()) { + if (isOffline()) { Log.info('[SequentialQueue] Unable to process. We are offline.'); return Promise.resolve(); } - const persistedRequests = PersistedRequests.getAll(); + const persistedRequests = getAll(); if (persistedRequests.length === 0) { Log.info('[SequentialQueue] Unable to process. No requests to process.'); return Promise.resolve(); } - const requestToProcess = PersistedRequests.processNextRequest(); + const requestToProcess = processNextRequest(); if (!requestToProcess) { Log.info('[SequentialQueue] Unable to process. No next request to handle.'); return Promise.resolve(); } // Set the current request to a promise awaiting its processing so that getCurrentRequest can be used to take some action after the current request has processed. - currentRequestPromise = Request.processWithMiddleware(requestToProcess, true) + currentRequestPromise = processWithMiddleware(requestToProcess, true) .then((response) => { // A response might indicate that the queue should be paused. This happens when a gap in onyx updates is detected between the client and the server and // that gap needs resolved before the queue can continue. @@ -98,8 +98,8 @@ function process(): Promise { } Log.info('[SequentialQueue] Removing persisted request because it was processed successfully.', false, {request: requestToProcess}); - PersistedRequests.endRequestAndRemoveFromQueue(requestToProcess); - RequestThrottle.clear(); + endRequestAndRemoveFromQueue(requestToProcess); + clear(); return process(); }) .catch((error: RequestError) => { @@ -107,18 +107,18 @@ function process(): Promise { // Duplicate records don't need to be retried as they just mean the record already exists on the server if (error.name === CONST.ERROR.REQUEST_CANCELLED || error.message === CONST.ERROR.DUPLICATE_RECORD) { Log.info("[SequentialQueue] Removing persisted request because it failed and doesn't need to be retried.", false, {error, request: requestToProcess}); - PersistedRequests.endRequestAndRemoveFromQueue(requestToProcess); - RequestThrottle.clear(); + endRequestAndRemoveFromQueue(requestToProcess); + clear(); return process(); } - PersistedRequests.rollbackOngoingRequest(); - return RequestThrottle.sleep(error, requestToProcess.command) + rollbackOngoingRequest(); + return sleep(error, requestToProcess.command) .then(process) .catch(() => { Onyx.update(requestToProcess.failureData ?? []); Log.info('[SequentialQueue] Removing persisted request because it failed too many times.', false, {error, request: requestToProcess}); - PersistedRequests.endRequestAndRemoveFromQueue(requestToProcess); - RequestThrottle.clear(); + endRequestAndRemoveFromQueue(requestToProcess); + clear(); return process(); }); }); @@ -138,14 +138,14 @@ function flush() { return; } - if (PersistedRequests.getAll().length === 0 && QueuedOnyxUpdates.isEmpty()) { + if (getAll().length === 0 && isEmpty()) { Log.info('[SequentialQueue] Unable to flush. No requests or queued Onyx updates to process.'); return; } // ONYXKEYS.PERSISTED_REQUESTS is shared across clients, thus every client/tab will have a copy // It is very important to only process the queue from leader client otherwise requests will be duplicated. - if (!ActiveClientManager.isClientTheLeader()) { + if (!isClientTheLeader()) { Log.info('[SequentialQueue] Unable to flush. Client is not the leader.'); return; } @@ -161,20 +161,20 @@ function flush() { const connection = Onyx.connect({ key: ONYXKEYS.PERSISTED_REQUESTS, // We exceptionally opt out of reusing the connection here to avoid extra callback calls due to - // an existing connection already made in PersistedRequests.ts. + // an existing connection already made in ts. reuseConnection: false, callback: () => { Onyx.disconnect(connection); process().finally(() => { Log.info('[SequentialQueue] Finished processing queue.'); isSequentialQueueRunning = false; - if (NetworkStore.isOffline() || PersistedRequests.getAll().length === 0) { + if (isOffline() || getAll().length === 0) { resolveIsReadyPromise?.(); } currentRequestPromise = null; // The queue can be paused when we sync the data with backend so we should only update the Onyx data when the queue is empty - if (PersistedRequests.getAll().length === 0) { + if (getAll().length === 0) { flushOnyxUpdatesQueue(); } }); @@ -191,7 +191,7 @@ function unpause() { return; } - const numberOfPersistedRequests = PersistedRequests.getAll().length || 0; + const numberOfPersistedRequests = getAll().length || 0; Log.info(`[SequentialQueue] Unpausing the queue and flushing ${numberOfPersistedRequests} requests`); isQueuePaused = false; flush(); @@ -206,17 +206,17 @@ function isPaused(): boolean { } // Flush the queue when the connection resumes -NetworkStore.onReconnection(flush); +onReconnection(flush); function handleConflictActions(conflictAction: ConflictData, newRequest: OnyxRequest) { if (conflictAction.type === 'push') { - PersistedRequests.save(newRequest); + save(newRequest); } else if (conflictAction.type === 'replace') { - PersistedRequests.update(conflictAction.index, conflictAction.request ?? newRequest); + update(conflictAction.index, conflictAction.request ?? newRequest); } else if (conflictAction.type === 'delete') { - PersistedRequests.deleteRequestsByIndices(conflictAction.indices); + deleteRequestsByIndices(conflictAction.indices); if (conflictAction.pushNewRequest) { - PersistedRequests.save(newRequest); + save(newRequest); } if (conflictAction.nextAction) { handleConflictActions(conflictAction.nextAction, newRequest); @@ -230,7 +230,7 @@ function push(newRequest: OnyxRequest) { const {checkAndFixConflictingRequest} = newRequest; if (checkAndFixConflictingRequest) { - const requests = PersistedRequests.getAll(); + const requests = getAll(); const {conflictAction} = checkAndFixConflictingRequest(requests); Log.info(`[SequentialQueue] Conflict action for command ${newRequest.command} - ${conflictAction.type}:`); @@ -240,11 +240,11 @@ function push(newRequest: OnyxRequest) { handleConflictActions(conflictAction, newRequest); } else { // Add request to Persisted Requests so that it can be retried if it fails - PersistedRequests.save(newRequest); + save(newRequest); } // If we are offline we don't need to trigger the queue to empty as it will happen when we come back online - if (NetworkStore.isOffline()) { + if (isOffline()) { return; } diff --git a/src/libs/Network/index.ts b/src/libs/Network/index.ts index 2adb4a2da4c2..e320fe564da6 100644 --- a/src/libs/Network/index.ts +++ b/src/libs/Network/index.ts @@ -3,15 +3,15 @@ import CONST from '@src/CONST'; import type {Request} from '@src/types/onyx'; import type Response from '@src/types/onyx/Response'; import pkg from '../../../package.json'; -import * as MainQueue from './MainQueue'; -import * as SequentialQueue from './SequentialQueue'; +import {process, push} from './MainQueue'; +import {flush} from './SequentialQueue'; // We must wait until the ActiveClientManager is ready so that we ensure only the "leader" tab processes any persisted requests ActiveClientManager.isReady().then(() => { - SequentialQueue.flush(); + flush(); // Start main queue and process once every n ms delay - setInterval(MainQueue.process, CONST.NETWORK.PROCESS_REQUEST_DELAY_MS); + setInterval(process, CONST.NETWORK.PROCESS_REQUEST_DELAY_MS); }); /** @@ -40,7 +40,7 @@ function post(command: string, data: Record = {}, type = CONST. request.reject = reject; // Add the request to a queue of actions to perform - MainQueue.push(request); + push(request); // This check is mainly used to prevent API commands from triggering calls to MainQueue.process() from inside the context of a previous // call to MainQueue.process() e.g. calling a Log command without this would cause the requests in mainQueue to double process @@ -51,7 +51,7 @@ function post(command: string, data: Record = {}, type = CONST. } // Try to fire off the request as soon as it's queued so we don't add a delay to every queued command - MainQueue.process(); + process(); }); } diff --git a/src/libs/ReportConnection.ts b/src/libs/ReportConnection.ts index 7b61b22681e5..415ff054b891 100644 --- a/src/libs/ReportConnection.ts +++ b/src/libs/ReportConnection.ts @@ -2,8 +2,8 @@ import type {OnyxCollection} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Report} from '@src/types/onyx'; -import * as PriorityModeActions from './actions/PriorityMode'; -import * as ReportHelperActions from './actions/Report'; +import {autoSwitchToFocusMode} from './actions/PriorityMode'; +import {handleReportChanged} from './actions/Report'; // Dynamic Import to avoid circular dependency const UnreadIndicatorUpdaterHelper = () => import('./UnreadIndicatorUpdater'); @@ -19,7 +19,7 @@ Onyx.connect({ module.triggerUnreadUpdate(); }); // Each time a new report is added we will check to see if the user should be switched - PriorityModeActions.autoSwitchToFocusMode(); + autoSwitchToFocusMode(); if (!value) { return; @@ -29,7 +29,7 @@ Onyx.connect({ return; } reportIDToNameMap[report.reportID] = report.reportName ?? report.reportID; - ReportHelperActions.handleReportChanged(report); + handleReportChanged(report); }); }, }); diff --git a/src/libs/Request.ts b/src/libs/Request.ts index 8d51486efad1..10e6806f9662 100644 --- a/src/libs/Request.ts +++ b/src/libs/Request.ts @@ -3,16 +3,16 @@ import type Response from '@src/types/onyx/Response'; import HttpUtils from './HttpUtils'; import type Middleware from './Middleware/types'; import enhanceParameters from './Network/enhanceParameters'; -import * as NetworkStore from './Network/NetworkStore'; +import {hasReadRequiredDataFromStorage, isSupportAuthToken, isSupportRequest} from './Network/NetworkStore'; let middlewares: Middleware[] = []; function makeXHR(request: Request): Promise { const finalParameters = enhanceParameters(request.command, request?.data ?? {}); - return NetworkStore.hasReadRequiredDataFromStorage().then((): Promise => { + return hasReadRequiredDataFromStorage().then((): Promise => { // If we're using the Supportal token and this is not a Supportal request // let's just return a promise that will resolve itself. - if (NetworkStore.isSupportAuthToken() && !NetworkStore.isSupportRequest(request.command)) { + if (isSupportAuthToken() && !isSupportRequest(request.command)) { return new Promise((resolve) => { resolve(); }); diff --git a/src/libs/actions/BankAccounts.ts b/src/libs/actions/BankAccounts.ts index bac1dba9ec71..482cc402dfde 100644 --- a/src/libs/actions/BankAccounts.ts +++ b/src/libs/actions/BankAccounts.ts @@ -12,8 +12,8 @@ import type { VerifyIdentityForBankAccountParams, } from '@libs/API/parameters'; import {READ_COMMANDS, WRITE_COMMANDS} from '@libs/API/types'; -import * as ErrorUtils from '@libs/ErrorUtils'; -import * as Localize from '@libs/Localize'; +import {getMicroSecondOnyxErrorWithTranslationKey} from '@libs/ErrorUtils'; +import {translateLocal} from '@libs/Localize'; import Navigation from '@libs/Navigation/Navigation'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -24,7 +24,7 @@ import type {ACHContractStepProps, BeneficialOwnersStepProps, CompanyStepProps, import type PlaidBankAccount from '@src/types/onyx/PlaidBankAccount'; import type {BankAccountStep, ReimbursementAccountStep, ReimbursementAccountSubStep} from '@src/types/onyx/ReimbursementAccount'; import type {OnyxData} from '@src/types/onyx/Request'; -import * as ReimbursementAccount from './ReimbursementAccount'; +import {setBankAccountSubStep} from './ReimbursementAccount'; export { goToWithdrawalAccountSetupStep, @@ -63,7 +63,7 @@ function clearPlaid(): Promise { } function openPlaidView() { - clearPlaid().then(() => ReimbursementAccount.setBankAccountSubStep(CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID)); + clearPlaid().then(() => setBankAccountSubStep(CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID)); } function setPlaidEvent(eventName: string | null) { @@ -161,7 +161,7 @@ function getVBBADataForOnyx(currentStep?: BankAccountStep, shouldShowLoading = t key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, value: { isLoading: false, - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('walletPage.addBankAccountFailure'), + errors: getMicroSecondOnyxErrorWithTranslationKey('walletPage.addBankAccountFailure'), }, }, ], @@ -244,7 +244,7 @@ function addPersonalBankAccount(account: PlaidBankAccount) { key: ONYXKEYS.PERSONAL_BANK_ACCOUNT, value: { isLoading: false, - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('walletPage.addBankAccountFailure'), + errors: getMicroSecondOnyxErrorWithTranslationKey('walletPage.addBankAccountFailure'), }, }, ], @@ -334,7 +334,7 @@ function validateBankAccount(bankAccountID: number, validateCode: string, policy key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, value: { isLoading: false, - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('bankAccount.error.validationAmounts'), + errors: getMicroSecondOnyxErrorWithTranslationKey('bankAccount.error.validationAmounts'), }, }, ], @@ -695,7 +695,7 @@ function validatePlaidSelection(values: FormOnyxValues): Form const errorFields: FormInputErrors = {}; if (!values.selectedPlaidAccountID) { - errorFields.selectedPlaidAccountID = Localize.translateLocal('bankAccount.error.youNeedToSelectAnOption'); + errorFields.selectedPlaidAccountID = translateLocal('bankAccount.error.youNeedToSelectAnOption'); } return errorFields; diff --git a/src/libs/actions/PriorityMode.ts b/src/libs/actions/PriorityMode.ts index 2aca5d9f9de8..6d53cf809d0d 100644 --- a/src/libs/actions/PriorityMode.ts +++ b/src/libs/actions/PriorityMode.ts @@ -1,8 +1,8 @@ import debounce from 'lodash/debounce'; import Onyx from 'react-native-onyx'; import Log from '@libs/Log'; -import * as ReportConnection from '@libs/ReportConnection'; -import * as ReportUtils from '@libs/ReportUtils'; +import {getAllReports} from '@libs/ReportConnection'; +import {isReportParticipant, isValidReport} from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -77,7 +77,7 @@ function resetHasReadRequiredDataFromStorage() { } function checkRequiredData() { - if (ReportConnection.getAllReports() === undefined || hasTriedFocusMode === undefined || isInFocusMode === undefined || isLoadingReportData) { + if (getAllReports() === undefined || hasTriedFocusMode === undefined || isInFocusMode === undefined || isLoadingReportData) { return; } @@ -98,14 +98,14 @@ function tryFocusModeUpdate() { } const validReports = []; - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); Object.keys(allReports ?? {}).forEach((key) => { const report = allReports?.[key]; if (!report) { return; } - if (!ReportUtils.isValidReport(report) || !ReportUtils.isReportParticipant(currentUserAccountID ?? -1, report)) { + if (!isValidReport(report) || !isReportParticipant(currentUserAccountID ?? -1, report)) { return; } From 3b05f56ea10feb6018ffc282436e9694d9978aac Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Tue, 26 Nov 2024 16:58:32 +0100 Subject: [PATCH 02/29] fix more files --- ios/NewExpensify.xcodeproj/project.pbxproj | 4 + ios/Podfile.lock | 4 +- src/libs/DistanceRequestUtils.ts | 38 +-- src/libs/Navigation/Navigation.ts | 4 +- src/libs/ReportUtils.ts | 324 ++++++++++++--------- src/libs/TransactionUtils/index.ts | 46 +-- src/libs/actions/IOU.ts | 129 ++++---- src/libs/actions/Policy/Category.ts | 17 +- src/libs/actions/Policy/Policy.ts | 8 +- src/libs/actions/Policy/Tag.ts | 4 +- src/libs/actions/Report.ts | 251 +++++++++------- src/libs/fileDownload/index.ios.ts | 16 +- src/types/onyx/Report.ts | 2 +- src/types/onyx/SearchResults.ts | 44 ++- 14 files changed, 507 insertions(+), 384 deletions(-) diff --git a/ios/NewExpensify.xcodeproj/project.pbxproj b/ios/NewExpensify.xcodeproj/project.pbxproj index cd38fcaaaf6c..cd2598608a0f 100644 --- a/ios/NewExpensify.xcodeproj/project.pbxproj +++ b/ios/NewExpensify.xcodeproj/project.pbxproj @@ -638,6 +638,7 @@ "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC/FBLPromises_Privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly/RCT-Folly_privacy.bundle", "${PODS_ROOT}/../../node_modules/@expensify/react-native-live-markdown/parser/react-native-live-markdown-parser.js", + "${PODS_CONFIGURATION_BUILD_DIR}/RNSVG/RNSVGFilters.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage/SDWebImage.bundle", @@ -658,6 +659,7 @@ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FBLPromises_Privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCT-Folly_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/react-native-live-markdown-parser.js", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNSVGFilters.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SDWebImage.bundle", @@ -842,6 +844,7 @@ "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC/FBLPromises_Privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly/RCT-Folly_privacy.bundle", "${PODS_ROOT}/../../node_modules/@expensify/react-native-live-markdown/parser/react-native-live-markdown-parser.js", + "${PODS_CONFIGURATION_BUILD_DIR}/RNSVG/RNSVGFilters.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage/SDWebImage.bundle", @@ -862,6 +865,7 @@ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FBLPromises_Privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCT-Folly_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/react-native-live-markdown-parser.js", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNSVGFilters.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SDWebImage.bundle", diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 01aefab63378..b1983e8f7475 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1722,7 +1722,7 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - react-native-keyboard-controller (1.14.1): + - react-native-keyboard-controller (1.14.4): - DoubleConversion - glog - hermes-engine @@ -3236,7 +3236,7 @@ SPEC CHECKSUMS: react-native-geolocation: b9bd12beaf0ebca61a01514517ca8455bd26fa06 react-native-image-picker: f8a13ff106bcc7eb00c71ce11fdc36aac2a44440 react-native-key-command: aae312752fcdfaa2240be9a015fc41ce54087546 - react-native-keyboard-controller: 902c07f41a415b632583b384427a71770a8b02a3 + react-native-keyboard-controller: 97bb7b48fa427c7455afdc8870c2978efd9bfa3a react-native-launch-arguments: 5f41e0abf88a15e3c5309b8875d6fd5ac43df49d react-native-netinfo: fb5112b1fa754975485884ae85a3fb6a684f49d5 react-native-pager-view: c64a744211a46202619a77509f802765d1659dba diff --git a/src/libs/DistanceRequestUtils.ts b/src/libs/DistanceRequestUtils.ts index 3b8e26c9cd33..70dbb4566d61 100644 --- a/src/libs/DistanceRequestUtils.ts +++ b/src/libs/DistanceRequestUtils.ts @@ -7,11 +7,11 @@ import type {LastSelectedDistanceRates, OnyxInputOrEntry, Transaction} from '@sr import type {Unit} from '@src/types/onyx/Policy'; import type Policy from '@src/types/onyx/Policy'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; -import * as CurrencyUtils from './CurrencyUtils'; -import * as PolicyUtils from './PolicyUtils'; -import * as ReportConnection from './ReportConnection'; -import * as ReportUtils from './ReportUtils'; -import * as TransactionUtils from './TransactionUtils'; +import {getCurrencySymbol} from './CurrencyUtils'; +import {getDistanceRateCustomUnit, getDistanceRateCustomUnitRate, getPersonalPolicy, getPolicy, getUnitRateValue} from './PolicyUtils'; +import {getAllReports} from './ReportConnection'; +import {isPolicyExpenseChat} from './ReportUtils'; +import {getCurrency, getRateID, isCustomUnitRateIDForP2P} from './TransactionUtils'; type MileageRate = { customUnitRateID?: string; @@ -40,7 +40,7 @@ function getMileageRates(policy: OnyxInputOrEntry, includeDisabledRates return mileageRates; } - const distanceUnit = PolicyUtils.getDistanceRateCustomUnit(policy); + const distanceUnit = getDistanceRateCustomUnit(policy); if (!distanceUnit?.rates) { return mileageRates; } @@ -82,7 +82,7 @@ function getDefaultMileageRate(policy: OnyxInputOrEntry): MileageRate | return undefined; } - const distanceUnit = PolicyUtils.getDistanceRateCustomUnit(policy); + const distanceUnit = getDistanceRateCustomUnit(policy); if (!distanceUnit?.rates || !distanceUnit.attributes) { return; } @@ -154,9 +154,9 @@ function getRateForDisplay( } const singularDistanceUnit = unit === CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES ? translate('common.mile') : translate('common.kilometer'); - const formattedRate = PolicyUtils.getUnitRateValue(toLocaleDigit, {rate}, useShortFormUnit); + const formattedRate = getUnitRateValue(toLocaleDigit, {rate}, useShortFormUnit); // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const currencySymbol = CurrencyUtils.getCurrencySymbol(currency) || `${currency} `; + const currencySymbol = getCurrencySymbol(currency) || `${currency} `; return `${currencySymbol}${formattedRate} / ${useShortFormUnit ? unit : singularDistanceUnit}`; } @@ -242,7 +242,7 @@ function getRateForP2P(currency: string, transaction: OnyxEntry): M ensureRateDefined(mileageRate.rate); // Ensure the rate is updated when the currency changes, otherwise use the stored rate - const rate = TransactionUtils.getCurrency(transaction) === currency ? transaction?.comment?.customUnit?.defaultP2PRate ?? mileageRate.rate : mileageRate.rate; + const rate = getCurrency(transaction) === currency ? transaction?.comment?.customUnit?.defaultP2PRate ?? mileageRate.rate : mileageRate.rate; return { ...mileageRate, currency: currencyWithExistingRate, @@ -282,13 +282,13 @@ function convertToDistanceInMeters(distance: number, unit: Unit): number { * Returns custom unit rate ID for the distance transaction */ function getCustomUnitRateID(reportID: string) { - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; - const policy = PolicyUtils.getPolicy(report?.policyID ?? parentReport?.policyID ?? '-1'); + const policy = getPolicy(report?.policyID ?? parentReport?.policyID ?? '-1'); let customUnitRateID: string = CONST.CUSTOM_UNITS.FAKE_P2P_ID; - if (ReportUtils.isPolicyExpenseChat(report) || ReportUtils.isPolicyExpenseChat(parentReport)) { + if (isPolicyExpenseChat(report) || isPolicyExpenseChat(parentReport)) { const distanceUnit = Object.values(policy?.customUnits ?? {}).find((unit) => unit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE); const lastSelectedDistanceRateID = lastSelectedDistanceRates?.[policy?.id ?? '-1'] ?? '-1'; const lastSelectedDistanceRate = distanceUnit?.rates[lastSelectedDistanceRateID] ?? {}; @@ -306,9 +306,9 @@ function getCustomUnitRateID(reportID: string) { * Get taxable amount from a specific distance rate, taking into consideration the tax claimable amount configured for the distance rate */ function getTaxableAmount(policy: OnyxEntry, customUnitRateID: string, distance: number) { - const distanceUnit = PolicyUtils.getDistanceRateCustomUnit(policy); - const customUnitRate = PolicyUtils.getDistanceRateCustomUnitRate(policy, customUnitRateID); - if (!distanceUnit || !distanceUnit?.customUnitID || !customUnitRate) { + const distanceUnit = getDistanceRateCustomUnit(policy); + const customUnitRate = getDistanceRateCustomUnitRate(policy, customUnitRateID); + if (!distanceUnit?.customUnitID || !customUnitRate) { return 0; } const unit = distanceUnit?.attributes?.unit ?? CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES; @@ -341,10 +341,10 @@ function getRate({ if (isEmptyObject(mileageRates) && policyDraft) { mileageRates = getMileageRates(policyDraft, true, transaction?.comment?.customUnit?.customUnitRateID); } - const policyCurrency = policy?.outputCurrency ?? PolicyUtils.getPersonalPolicy()?.outputCurrency ?? CONST.CURRENCY.USD; + const policyCurrency = policy?.outputCurrency ?? getPersonalPolicy()?.outputCurrency ?? CONST.CURRENCY.USD; const defaultMileageRate = getDefaultMileageRate(policy); - const customUnitRateID = TransactionUtils.getRateID(transaction) ?? ''; - const mileageRate = TransactionUtils.isCustomUnitRateIDForP2P(transaction) ? getRateForP2P(policyCurrency, transaction) : mileageRates?.[customUnitRateID] ?? defaultMileageRate; + const customUnitRateID = getRateID(transaction) ?? ''; + const mileageRate = isCustomUnitRateIDForP2P(transaction) ? getRateForP2P(policyCurrency, transaction) : mileageRates?.[customUnitRateID] ?? defaultMileageRate; const unit = getDistanceUnit(useTransactionDistanceUnit ? transaction : undefined, mileageRate); return { ...mileageRate, diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index d54668bf3f69..e3672da2f445 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -4,7 +4,7 @@ import {CommonActions, getPathFromState, StackActions} from '@react-navigation/n import type {OnyxEntry} from 'react-native-onyx'; import Log from '@libs/Log'; import {isCentralPaneName, removePolicyIDParamFromState} from '@libs/NavigationUtils'; -import * as ReportConnection from '@libs/ReportConnection'; +import {getAllReports} from '@libs/ReportConnection'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; @@ -66,7 +66,7 @@ const dismissModal = (reportID?: string, ref = navigationRef) => { originalDismissModal(ref); return; } - const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const report = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; originalDismissModalWithReport({reportID, ...report}, ref); }; // Re-exporting the closeRHPFlow here to fill in default value for navigationRef. The closeRHPFlow isn't defined in this file to avoid cyclic dependencies. diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 118eeeb785ee..60b93634d9a2 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -54,6 +54,7 @@ import type {Status} from '@src/types/onyx/PersonalDetails'; import type {ConnectionName} from '@src/types/onyx/Policy'; import type {NotificationPreference, Participants, PendingChatMember, Participant as ReportParticipant} from '@src/types/onyx/Report'; import type {Message, OldDotReportAction, ReportActions} from '@src/types/onyx/ReportAction'; +import type {SearchReport, SearchTransaction} from '@src/types/onyx/SearchResults'; import type {Comment, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type IconAsset from '@src/types/utils/IconAsset'; @@ -83,8 +84,43 @@ import * as PhoneNumber from './PhoneNumber'; import * as PolicyUtils from './PolicyUtils'; import type {LastVisibleMessage} from './ReportActionsUtils'; import * as ReportActionsUtils from './ReportActionsUtils'; -import * as ReportConnection from './ReportConnection'; -import * as TransactionUtils from './TransactionUtils'; +import {getAllReports} from './ReportConnection'; +import { + getAllReportTransactions, + getAmount, + getAttendees, + getBillable, + getCardID, + getCategory, + getCurrency, + getDescription, + getFormattedAttendees, + getFormattedCreated, + getMCCGroup, + getMerchant, + getMerchantOrDescription, + getOriginalAmount, + getOriginalCurrency, + getRateID, + getRecentTransactions, + getReimbursable, + getTag, + getTaxAmount, + getTaxCode, + getWaypoints, + hasMissingSmartscanFields as hasMissingSmartscanFieldsTransactionUtils, + hasNoticeTypeViolation, + hasReceipt as hasReceiptTransactionUtils, + hasViolation, + hasWarningTypeViolation, + isCardTransaction, + isDistanceRequest, + isDuplicate, + isFetchingWaypointsFromServer, + isOnHold as isOnHoldTransactionUtils, + isPayAtEndExpense, + isReceiptBeingScanned, +} from './TransactionUtils'; import * as Url from './Url'; import type {AvatarSource} from './UserUtils'; import * as UserUtils from './UserUtils'; @@ -734,7 +770,7 @@ function getChatType(report: OnyxInputOrEntry | Participant): ValueOf { - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); return allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`] ?? allReportsDraft?.[`${ONYXKEYS.COLLECTION.REPORT_DRAFT}${reportID}`]; } @@ -751,7 +787,7 @@ function isDraftReport(reportID: string | undefined): boolean { * Returns the report */ function getReport(reportID: string): OnyxEntry { - return ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + return getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; } /** @@ -768,7 +804,7 @@ function getParentReport(report: OnyxEntry): OnyxEntry { if (!report?.parentReportID) { return undefined; } - return ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`]; + return getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`]; } /** @@ -861,15 +897,15 @@ function isInvoiceReport(report: OnyxInputOrEntry): boolean { /** * Checks if a report is an Expense report. */ -function isExpenseReport(report: OnyxInputOrEntry): boolean { +function isExpenseReport(report: OnyxInputOrEntry | SearchReport): boolean { return report?.type === CONST.REPORT.TYPE.EXPENSE; } /** * Checks if a report is an IOU report using report or reportID */ -function isIOUReport(reportOrID: OnyxInputOrEntry | string): boolean { - const report = typeof reportOrID === 'string' ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID; +function isIOUReport(reportOrID: OnyxInputOrEntry | SearchReport | string): boolean { + const report = typeof reportOrID === 'string' ? getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID; return report?.type === CONST.REPORT.TYPE.IOU; } @@ -934,7 +970,7 @@ function isReportManager(report: OnyxEntry): boolean { * Checks if the supplied report has been approved */ function isReportApproved(reportOrID: OnyxInputOrEntry | string, parentReportAction: OnyxEntry = undefined): boolean { - const report = typeof reportOrID === 'string' ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID; + const report = typeof reportOrID === 'string' ? getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID; if (!report) { return parentReportAction?.childStateNum === CONST.REPORT.STATE_NUM.APPROVED && parentReportAction?.childStatusNum === CONST.REPORT.STATUS_NUM.APPROVED; } @@ -977,12 +1013,15 @@ function hasParticipantInArray(report: OnyxEntry, memberAccountIDs: numb /** * Whether the Money Request report is settled */ -function isSettled(reportID: string | undefined): boolean { - const allReports = ReportConnection.getAllReports(); - if (!allReports || !reportID) { +function isSettled(reportOrID: OnyxInputOrEntry | SearchReport | string | undefined): boolean { + if (!reportOrID) { return false; } - const report = allReports[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`] ?? null; + const report = typeof reportOrID === 'string' ? getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID; + if (!report) { + return false; + } + if (isEmptyObject(report) || report.isWaitingOnBankAccount) { return false; } @@ -1000,7 +1039,7 @@ function isSettled(reportID: string | undefined): boolean { * Whether the current user is the submitter of the report */ function isCurrentUserSubmitter(reportID: string): boolean { - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); if (!allReports) { return false; } @@ -1063,7 +1102,7 @@ function isInvoiceRoom(report: OnyxEntry): boolean { function isInvoiceRoomWithID(reportID?: string): boolean { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID || -1}`]; + const report = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID || -1}`]; return isInvoiceRoom(report); } @@ -1192,7 +1231,7 @@ function isWorkspaceTaskReport(report: OnyxEntry): boolean { if (!isTaskReport(report)) { return false; } - const parentReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; + const parentReport = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; return isPolicyExpenseChat(parentReport); } @@ -1276,7 +1315,7 @@ function isConciergeChatReport(report: OnyxInputOrEntry): boolean { } function findSelfDMReportID(): string | undefined { - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); if (!allReports) { return; } @@ -1397,7 +1436,7 @@ function findLastAccessedReport(ignoreDomainRooms: boolean, openOnAdminRoom = fa const policyMemberAccountIDs = PolicyUtils.getPolicyEmployeeListByIdWithoutCurrentUser(allPolicies, policyID, currentUserAccountID); - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); let reportsValues = Object.values(allReports ?? {}); if (!!policyID || policyMemberAccountIDs.length > 0) { @@ -1468,7 +1507,7 @@ function isArchivedRoom(report: OnyxInputOrEntry, reportNameValuePairs?: */ function isArchivedRoomWithID(reportID?: string) { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID || -1}`]; + const report = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID || -1}`]; return isArchivedRoom(report, getReportNameValuePairs(reportID)); } @@ -1588,7 +1627,7 @@ function hasOnlyTransactionsWithPendingRoutes(iouReportID: string | undefined): return false; } - return transactions.every((transaction) => TransactionUtils.isFetchingWaypointsFromServer(transaction)); + return transactions.every((transaction) => isFetchingWaypointsFromServer(transaction)); } /** @@ -1613,7 +1652,7 @@ function isChildReport(report: OnyxEntry): boolean { function isExpenseRequest(report: OnyxInputOrEntry): report is Thread { if (isThread(report)) { const parentReportAction = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`]?.[report.parentReportActionID]; - const parentReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; + const parentReport = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; return isExpenseReport(parentReport) && !isEmptyObject(parentReportAction) && ReportActionsUtils.isTransactionThread(parentReportAction); } return false; @@ -1626,7 +1665,7 @@ function isExpenseRequest(report: OnyxInputOrEntry): report is Thread { function isIOURequest(report: OnyxInputOrEntry): boolean { if (isThread(report)) { const parentReportAction = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`]?.[report.parentReportActionID]; - const parentReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; + const parentReport = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; return isIOUReport(parentReport) && !isEmptyObject(parentReportAction) && ReportActionsUtils.isTransactionThread(parentReportAction); } return false; @@ -1649,15 +1688,15 @@ function isTrackExpenseReport(report: OnyxInputOrEntry): boolean { * Checks if a report is an IOU or expense request. */ function isMoneyRequest(reportOrID: OnyxEntry | string): boolean { - const report = typeof reportOrID === 'string' ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID; + const report = typeof reportOrID === 'string' ? getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID; return isIOURequest(report) || isExpenseRequest(report); } /** * Checks if a report is an IOU or expense report. */ -function isMoneyRequestReport(reportOrID: OnyxInputOrEntry | string): boolean { - const report = typeof reportOrID === 'string' ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID; +function isMoneyRequestReport(reportOrID: OnyxInputOrEntry | SearchReport | string): boolean { + const report = typeof reportOrID === 'string' ? getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID; return isIOUReport(report) || isExpenseReport(report); } @@ -1674,7 +1713,7 @@ function hasOnlyNonReimbursableTransactions(iouReportID: string | undefined): bo return false; } - return transactions.every((transaction) => !TransactionUtils.getReimbursable(transaction)); + return transactions.every((transaction) => !getReimbursable(transaction)); } /** @@ -1693,7 +1732,7 @@ function isPayAtEndExpenseReport(reportID: string, transactions: Transaction[] | return false; } - return TransactionUtils.isPayAtEndExpense(transactions?.[0] ?? TransactionUtils.getAllReportTransactions(reportID).at(0)); + return isPayAtEndExpense(transactions?.[0] ?? getAllReportTransactions(reportID).at(0)); } /** @@ -1886,7 +1925,7 @@ function getReportRecipientAccountIDs(report: OnyxEntry, currentLoginAcc // In 1:1 chat threads, the participants will be the same as parent report. If a report is specifically a 1:1 chat thread then we will // get parent report and use its participants array. if (isThread(report) && !(isTaskReport(report) || isMoneyRequestReport(report))) { - const parentReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; + const parentReport = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; if (isOneOnOneChat(parentReport)) { finalReport = parentReport; } @@ -2558,7 +2597,7 @@ function getReimbursementQueuedActionMessage( reportOrID: OnyxEntry | string, shouldUseShortDisplayName = true, ): string { - const report = typeof reportOrID === 'string' ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] : reportOrID; + const report = typeof reportOrID === 'string' ? getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] : reportOrID; const submitterDisplayName = getDisplayNameForParticipant(report?.ownerAccountID, shouldUseShortDisplayName) ?? ''; const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction); let messageKey: TranslationPaths; @@ -2579,7 +2618,7 @@ function getReimbursementDeQueuedActionMessage( reportOrID: OnyxEntry | string, isLHNPreview = false, ): string { - const report = typeof reportOrID === 'string' ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] : reportOrID; + const report = typeof reportOrID === 'string' ? getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] : reportOrID; const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction); const amount = originalMessage?.amount; const currency = originalMessage?.currency; @@ -2833,7 +2872,7 @@ function hasNonReimbursableTransactions(iouReportID: string | undefined): boolea } function getMoneyRequestSpendBreakdown(report: OnyxInputOrEntry, allReportsDict?: OnyxCollection): SpendBreakdown { - const allAvailableReports = allReportsDict ?? ReportConnection.getAllReports(); + const allAvailableReports = allReportsDict ?? getAllReports(); let moneyRequestReport; if (isMoneyRequestReport(report) || isInvoiceReport(report)) { moneyRequestReport = report; @@ -3086,30 +3125,30 @@ function getTransactionDetails(transaction: OnyxInputOrEntry, creat } const report = getReportOrDraftReport(transaction?.reportID); return { - created: TransactionUtils.getFormattedCreated(transaction, createdDateFormat), - amount: TransactionUtils.getAmount(transaction, !isEmptyObject(report) && isExpenseReport(report)), - attendees: TransactionUtils.getAttendees(transaction), - taxAmount: TransactionUtils.getTaxAmount(transaction, !isEmptyObject(report) && isExpenseReport(report)), - taxCode: TransactionUtils.getTaxCode(transaction), - currency: TransactionUtils.getCurrency(transaction), - comment: TransactionUtils.getDescription(transaction), - merchant: TransactionUtils.getMerchant(transaction), - waypoints: TransactionUtils.getWaypoints(transaction), - customUnitRateID: TransactionUtils.getRateID(transaction), - category: TransactionUtils.getCategory(transaction), - billable: TransactionUtils.getBillable(transaction), - tag: TransactionUtils.getTag(transaction), - mccGroup: TransactionUtils.getMCCGroup(transaction), - cardID: TransactionUtils.getCardID(transaction), - originalAmount: TransactionUtils.getOriginalAmount(transaction), - originalCurrency: TransactionUtils.getOriginalCurrency(transaction), + created: getFormattedCreated(transaction, createdDateFormat), + amount: getAmount(transaction, !isEmptyObject(report) && isExpenseReport(report)), + attendees: getAttendees(transaction), + taxAmount: getTaxAmount(transaction, !isEmptyObject(report) && isExpenseReport(report)), + taxCode: getTaxCode(transaction), + currency: getCurrency(transaction), + comment: getDescription(transaction), + merchant: getMerchant(transaction), + waypoints: getWaypoints(transaction), + customUnitRateID: getRateID(transaction), + category: getCategory(transaction), + billable: getBillable(transaction), + tag: getTag(transaction), + mccGroup: getMCCGroup(transaction), + cardID: getCardID(transaction), + originalAmount: getOriginalAmount(transaction), + originalCurrency: getOriginalCurrency(transaction), }; } function getTransactionCommentObject(transaction: OnyxEntry): Comment { return { ...transaction?.comment, - waypoints: TransactionUtils.getWaypoints(transaction), + waypoints: getWaypoints(transaction), }; } @@ -3209,7 +3248,7 @@ function canEditFieldOfMoneyRequest(reportAction: OnyxInputOrEntry } const iouMessage = ReportActionsUtils.getOriginalMessage(reportAction); - const moneyRequestReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${iouMessage?.IOUReportID}`] ?? ({} as Report); + const moneyRequestReport = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${iouMessage?.IOUReportID}`] ?? ({} as Report); const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${iouMessage?.IOUTransactionID}`] ?? ({} as Transaction); if (isSettled(String(moneyRequestReport.reportID)) || isReportApproved(String(moneyRequestReport.reportID))) { @@ -3218,7 +3257,7 @@ function canEditFieldOfMoneyRequest(reportAction: OnyxInputOrEntry if ( (fieldToEdit === CONST.EDIT_REQUEST_FIELD.AMOUNT || fieldToEdit === CONST.EDIT_REQUEST_FIELD.CURRENCY || fieldToEdit === CONST.EDIT_REQUEST_FIELD.DATE) && - TransactionUtils.isCardTransaction(transaction) + isCardTransaction(transaction) ) { return false; } @@ -3227,23 +3266,18 @@ function canEditFieldOfMoneyRequest(reportAction: OnyxInputOrEntry const isAdmin = isExpenseReport(moneyRequestReport) && policy?.role === CONST.POLICY.ROLE.ADMIN; const isManager = isExpenseReport(moneyRequestReport) && currentUserAccountID === moneyRequestReport?.managerID; - if ((fieldToEdit === CONST.EDIT_REQUEST_FIELD.AMOUNT || fieldToEdit === CONST.EDIT_REQUEST_FIELD.CURRENCY) && TransactionUtils.isDistanceRequest(transaction)) { + if ((fieldToEdit === CONST.EDIT_REQUEST_FIELD.AMOUNT || fieldToEdit === CONST.EDIT_REQUEST_FIELD.CURRENCY) && isDistanceRequest(transaction)) { return isAdmin || isManager; } if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.RECEIPT) { const isRequestor = currentUserAccountID === reportAction?.actorAccountID; - return ( - !isInvoiceReport(moneyRequestReport) && - !TransactionUtils.isReceiptBeingScanned(transaction) && - !TransactionUtils.isDistanceRequest(transaction) && - (isAdmin || isManager || isRequestor) - ); + return !isInvoiceReport(moneyRequestReport) && !isReceiptBeingScanned(transaction) && !isDistanceRequest(transaction) && (isAdmin || isManager || isRequestor); } if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.DISTANCE_RATE) { // The distance rate can be modified only on the distance expense reports - return isExpenseReport(moneyRequestReport) && TransactionUtils.isDistanceRequest(transaction); + return isExpenseReport(moneyRequestReport) && isDistanceRequest(transaction); } return true; @@ -3311,8 +3345,8 @@ function canHoldUnholdReportAction(reportAction: OnyxInputOrEntry) parentReportAction.actorAccountID === currentUserPersonalDetails?.accountID; const isApprover = isMoneyRequestReport(moneyRequestReport) && moneyRequestReport?.managerID !== null && currentUserPersonalDetails?.accountID === moneyRequestReport?.managerID; const isAdmin = isPolicyAdmin(moneyRequestReport.policyID ?? '-1', allPolicies); - const isOnHold = TransactionUtils.isOnHold(transaction); - const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction); + const isOnHold = isOnHoldTransactionUtils(transaction); + const isScanning = hasReceiptTransactionUtils(transaction) && isReceiptBeingScanned(transaction); const isClosed = isClosedReport(moneyRequestReport); const canModifyStatus = !isTrackExpenseMoneyReport && (isAdmin || isActionOwner || isApprover); @@ -3322,7 +3356,7 @@ function canHoldUnholdReportAction(reportAction: OnyxInputOrEntry) const canHoldOrUnholdRequest = !isRequestSettled && !isApproved && !isDeletedParentAction && !isClosed; const canHoldRequest = canHoldOrUnholdRequest && !isOnHold && (isRequestIOU || canModifyStatus) && !isScanning && !!transaction?.reimbursable; const canUnholdRequest = - !!(canHoldOrUnholdRequest && isOnHold && !TransactionUtils.isDuplicate(transaction.transactionID, true) && (isRequestIOU ? isHoldActionCreator : canModifyUnholdStatus)) && + !!(canHoldOrUnholdRequest && isOnHold && !isDuplicate(transaction.transactionID, true) && (isRequestIOU ? isHoldActionCreator : canModifyUnholdStatus)) && !!transaction?.reimbursable; return {canHoldRequest, canUnholdRequest}; @@ -3341,7 +3375,7 @@ const changeMoneyRequestHoldStatus = (reportAction: OnyxEntry, bac const transactionID = ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID ?? ''; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? ({} as Transaction); - const isOnHold = TransactionUtils.isOnHold(transaction); + const isOnHold = isOnHoldTransactionUtils(transaction); const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${moneyRequestReport.policyID}`] ?? null; if (isOnHold) { @@ -3360,7 +3394,7 @@ const changeMoneyRequestHoldStatus = (reportAction: OnyxEntry, bac */ function getTransactionsWithReceipts(iouReportID: string | undefined): Transaction[] { const transactions = reportsTransactions[iouReportID ?? ''] ?? []; - return transactions.filter((transaction) => TransactionUtils.hasReceipt(transaction)); + return transactions.filter((transaction) => hasReceiptTransactionUtils(transaction)); } /** @@ -3376,7 +3410,7 @@ function areAllRequestsBeingSmartScanned(iouReportID: string, reportPreviewActio if (ReportActionsUtils.getNumberOfMoneyRequests(reportPreviewAction) > transactionsWithReceipts.length) { return false; } - return transactionsWithReceipts.every((transaction) => TransactionUtils.isReceiptBeingScanned(transaction)); + return transactionsWithReceipts.every((transaction) => isReceiptBeingScanned(transaction)); } /** @@ -3401,7 +3435,7 @@ function getLinkedTransaction(reportAction: OnyxEntry = iouReportAction, ): string { - const report = typeof reportOrID === 'string' ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] : reportOrID; + const report = typeof reportOrID === 'string' ? getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] : reportOrID; const reportActionMessage = ReportActionsUtils.getReportActionHtml(iouReportAction); if (isEmptyObject(report) || !report?.reportID) { @@ -3510,17 +3544,17 @@ function getReportPreviewMessage( } if (!isEmptyObject(linkedTransaction)) { - if (TransactionUtils.isReceiptBeingScanned(linkedTransaction)) { + if (isReceiptBeingScanned(linkedTransaction)) { return Localize.translateLocal('iou.receiptScanning'); } - if (TransactionUtils.hasMissingSmartscanFields(linkedTransaction)) { + if (hasMissingSmartscanFieldsTransactionUtils(linkedTransaction)) { return Localize.translateLocal('iou.receiptMissingDetails'); } - const amount = TransactionUtils.getAmount(linkedTransaction, !isEmptyObject(report) && isExpenseReport(report)) ?? 0; - const formattedAmount = CurrencyUtils.convertToDisplayString(amount, TransactionUtils.getCurrency(linkedTransaction)) ?? ''; - return Localize.translateLocal('iou.didSplitAmount', {formattedAmount, comment: TransactionUtils.getMerchantOrDescription(linkedTransaction)}); + const amount = getAmount(linkedTransaction, !isEmptyObject(report) && isExpenseReport(report)) ?? 0; + const formattedAmount = CurrencyUtils.convertToDisplayString(amount, getCurrency(linkedTransaction)) ?? ''; + return Localize.translateLocal('iou.didSplitAmount', {formattedAmount, comment: getMerchantOrDescription(linkedTransaction)}); } } @@ -3532,17 +3566,17 @@ function getReportPreviewMessage( } if (!isEmptyObject(linkedTransaction)) { - if (TransactionUtils.isReceiptBeingScanned(linkedTransaction)) { + if (isReceiptBeingScanned(linkedTransaction)) { return Localize.translateLocal('iou.receiptScanning'); } - if (TransactionUtils.hasMissingSmartscanFields(linkedTransaction)) { + if (hasMissingSmartscanFieldsTransactionUtils(linkedTransaction)) { return Localize.translateLocal('iou.receiptMissingDetails'); } - const amount = TransactionUtils.getAmount(linkedTransaction, !isEmptyObject(report) && isExpenseReport(report)) ?? 0; - const formattedAmount = CurrencyUtils.convertToDisplayString(amount, TransactionUtils.getCurrency(linkedTransaction)) ?? ''; - return Localize.translateLocal('iou.trackedAmount', {formattedAmount, comment: TransactionUtils.getMerchantOrDescription(linkedTransaction)}); + const amount = getAmount(linkedTransaction, !isEmptyObject(report) && isExpenseReport(report)) ?? 0; + const formattedAmount = CurrencyUtils.convertToDisplayString(amount, getCurrency(linkedTransaction)) ?? ''; + return Localize.translateLocal('iou.trackedAmount', {formattedAmount, comment: getMerchantOrDescription(linkedTransaction)}); } } @@ -3566,11 +3600,11 @@ function getReportPreviewMessage( linkedTransaction = getLinkedTransaction(iouReportAction); } - if (!isEmptyObject(linkedTransaction) && TransactionUtils.hasReceipt(linkedTransaction) && TransactionUtils.isReceiptBeingScanned(linkedTransaction)) { + if (!isEmptyObject(linkedTransaction) && hasReceiptTransactionUtils(linkedTransaction) && isReceiptBeingScanned(linkedTransaction)) { return Localize.translateLocal('iou.receiptScanning'); } - if (!isEmptyObject(linkedTransaction) && TransactionUtils.isFetchingWaypointsFromServer(linkedTransaction) && !TransactionUtils.getAmount(linkedTransaction)) { + if (!isEmptyObject(linkedTransaction) && isFetchingWaypointsFromServer(linkedTransaction) && !getAmount(linkedTransaction)) { return Localize.translateLocal('iou.fieldPending'); } @@ -3610,15 +3644,15 @@ function getReportPreviewMessage( let currency = originalMessage?.currency ? originalMessage?.currency : report.currency; if (!isEmptyObject(linkedTransaction)) { - amount = TransactionUtils.getAmount(linkedTransaction, isExpenseReport(report)); - currency = TransactionUtils.getCurrency(linkedTransaction); + amount = getAmount(linkedTransaction, isExpenseReport(report)); + currency = getCurrency(linkedTransaction); } if (isEmptyObject(linkedTransaction) && !isEmptyObject(iouReportAction)) { linkedTransaction = getLinkedTransaction(iouReportAction); } - let comment = !isEmptyObject(linkedTransaction) ? TransactionUtils.getMerchantOrDescription(linkedTransaction) : undefined; + let comment = !isEmptyObject(linkedTransaction) ? getMerchantOrDescription(linkedTransaction) : undefined; if (!isEmptyObject(originalReportAction) && ReportActionsUtils.isReportPreviewAction(originalReportAction) && ReportActionsUtils.getNumberOfMoneyRequests(originalReportAction) !== 1) { comment = undefined; } @@ -3656,38 +3690,38 @@ function getModifiedExpenseOriginalMessage( // Remark: Comment field is the only one which has new/old prefixes for the keys (newComment/ oldComment), // all others have old/- pattern such as oldCreated/created if ('comment' in transactionChanges) { - originalMessage.oldComment = TransactionUtils.getDescription(oldTransaction); + originalMessage.oldComment = getDescription(oldTransaction); originalMessage.newComment = transactionChanges?.comment; } if ('created' in transactionChanges) { - originalMessage.oldCreated = TransactionUtils.getFormattedCreated(oldTransaction); + originalMessage.oldCreated = getFormattedCreated(oldTransaction); originalMessage.created = transactionChanges?.created; } if ('merchant' in transactionChanges) { - originalMessage.oldMerchant = TransactionUtils.getMerchant(oldTransaction); + originalMessage.oldMerchant = getMerchant(oldTransaction); originalMessage.merchant = transactionChanges?.merchant; } if ('attendees' in transactionChanges) { - [originalMessage.oldAttendees, originalMessage.attendees] = TransactionUtils.getFormattedAttendees(transactionChanges?.attendees, TransactionUtils.getAttendees(oldTransaction)); + [originalMessage.oldAttendees, originalMessage.attendees] = getFormattedAttendees(transactionChanges?.attendees, getAttendees(oldTransaction)); } // The amount is always a combination of the currency and the number value so when one changes we need to store both // to match how we handle the modified expense action in oldDot const didAmountOrCurrencyChange = 'amount' in transactionChanges || 'currency' in transactionChanges; if (didAmountOrCurrencyChange) { - originalMessage.oldAmount = TransactionUtils.getAmount(oldTransaction, isFromExpenseReport); + originalMessage.oldAmount = getAmount(oldTransaction, isFromExpenseReport); originalMessage.amount = transactionChanges?.amount ?? transactionChanges.oldAmount; - originalMessage.oldCurrency = TransactionUtils.getCurrency(oldTransaction); + originalMessage.oldCurrency = getCurrency(oldTransaction); originalMessage.currency = transactionChanges?.currency ?? transactionChanges.oldCurrency; } if ('category' in transactionChanges) { - originalMessage.oldCategory = TransactionUtils.getCategory(oldTransaction); + originalMessage.oldCategory = getCategory(oldTransaction); originalMessage.category = transactionChanges?.category; } if ('tag' in transactionChanges) { - originalMessage.oldTag = TransactionUtils.getTag(oldTransaction); + originalMessage.oldTag = getTag(oldTransaction); originalMessage.tag = transactionChanges?.tag; } @@ -3695,30 +3729,30 @@ function getModifiedExpenseOriginalMessage( // Tax rate can change as a result of currency update. In such cases, we want to skip displaying a system message, as discussed. const didTaxCodeChange = 'taxCode' in transactionChanges; if (didTaxCodeChange && !didAmountOrCurrencyChange) { - originalMessage.oldTaxRate = policy?.taxRates?.taxes[TransactionUtils.getTaxCode(oldTransaction)]?.value; + originalMessage.oldTaxRate = policy?.taxRates?.taxes[getTaxCode(oldTransaction)]?.value; originalMessage.taxRate = transactionChanges?.taxCode && policy?.taxRates?.taxes[transactionChanges?.taxCode]?.value; } // We only want to display a tax amount update system message when tax amount is updated by user. // Tax amount can change as a result of amount, currency or tax rate update. In such cases, we want to skip displaying a system message, as discussed. if ('taxAmount' in transactionChanges && !(didAmountOrCurrencyChange || didTaxCodeChange)) { - originalMessage.oldTaxAmount = TransactionUtils.getTaxAmount(oldTransaction, isFromExpenseReport); + originalMessage.oldTaxAmount = getTaxAmount(oldTransaction, isFromExpenseReport); originalMessage.taxAmount = transactionChanges?.taxAmount; - originalMessage.currency = TransactionUtils.getCurrency(oldTransaction); + originalMessage.currency = getCurrency(oldTransaction); } if ('billable' in transactionChanges) { - const oldBillable = TransactionUtils.getBillable(oldTransaction); + const oldBillable = getBillable(oldTransaction); originalMessage.oldBillable = oldBillable ? Localize.translateLocal('common.billable').toLowerCase() : Localize.translateLocal('common.nonBillable').toLowerCase(); originalMessage.billable = transactionChanges?.billable ? Localize.translateLocal('common.billable').toLowerCase() : Localize.translateLocal('common.nonBillable').toLowerCase(); } if ('customUnitRateID' in transactionChanges && updatedTransaction?.comment?.customUnit?.customUnitRateID) { - originalMessage.oldAmount = TransactionUtils.getAmount(oldTransaction, isFromExpenseReport); - originalMessage.oldCurrency = TransactionUtils.getCurrency(oldTransaction); - originalMessage.oldMerchant = TransactionUtils.getMerchant(oldTransaction); + originalMessage.oldAmount = getAmount(oldTransaction, isFromExpenseReport); + originalMessage.oldCurrency = getCurrency(oldTransaction); + originalMessage.oldMerchant = getMerchant(oldTransaction); - // For the originalMessage, we should use the non-negative amount, similar to what TransactionUtils.getAmount does for oldAmount + // For the originalMessage, we should use the non-negative amount, similar to what getAmount does for oldAmount originalMessage.amount = Math.abs(updatedTransaction.modifiedAmount ?? 0); originalMessage.currency = updatedTransaction.modifiedCurrency ?? CONST.CURRENCY.USD; originalMessage.merchant = updatedTransaction.modifiedMerchant; @@ -4674,7 +4708,7 @@ function buildOptimisticExpenseReport( ): OptimisticExpenseReport { // The amount for Expense reports are stored as negative value in the database const storedTotal = total * -1; - const policyName = getPolicyName(ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`]); + const policyName = getPolicyName(getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`]); const formattedTotal = CurrencyUtils.convertToDisplayString(storedTotal, currency); const policy = getPolicy(policyID); @@ -5135,7 +5169,7 @@ function buildOptimisticReportPreview( childReportID?: string, reportActionID?: string, ): ReportAction { - const hasReceipt = TransactionUtils.hasReceipt(transaction); + const hasReceipt = hasReceiptTransactionUtils(transaction); const message = getReportPreviewMessage(iouReport); const created = DateUtils.getDBTime(); const reportActorAccountID = (isInvoiceReport(iouReport) ? iouReport?.ownerAccountID : iouReport?.managerID) ?? -1; @@ -5304,9 +5338,9 @@ function updateReportPreview( comment = '', transaction?: OnyxEntry, ): ReportAction { - const hasReceipt = TransactionUtils.hasReceipt(transaction); + const hasReceipt = hasReceiptTransactionUtils(transaction); const recentReceiptTransactions = reportPreviewAction?.childRecentReceiptTransactionIDs ?? {}; - const transactionsToKeep = TransactionUtils.getRecentTransactions(recentReceiptTransactions); + const transactionsToKeep = getRecentTransactions(recentReceiptTransactions); const previousTransactionsArray = Object.entries(recentReceiptTransactions ?? {}).map(([key, value]) => (transactionsToKeep.includes(key) ? {[key]: value} : null)); const previousTransactions: Record = {}; @@ -6247,7 +6281,7 @@ function isUnread(report: OnyxEntry): boolean { } function isIOUOwnedByCurrentUser(report: OnyxEntry, allReportsDict?: OnyxCollection): boolean { - const allAvailableReports = allReportsDict ?? ReportConnection.getAllReports(); + const allAvailableReports = allReportsDict ?? getAllReports(); if (!report || !allAvailableReports) { return false; } @@ -6335,7 +6369,7 @@ function shouldDisplayViolationsRBRInLHN(report: OnyxEntry, transactionV // - Are either open or submitted // - Belong to the same workspace // And if any have a violation, then it should have a RBR - const allReports = Object.values(ReportConnection.getAllReports() ?? {}) as Report[]; + const allReports = Object.values(getAllReports() ?? {}) as Report[]; const potentialReports = allReports.filter((r) => r?.ownerAccountID === currentUserAccountID && (r?.stateNum ?? 0) <= 1 && r?.policyID === report.policyID); return potentialReports.some( (potentialReport) => hasViolations(potentialReport.reportID, transactionViolations) || hasWarningTypeViolations(potentialReport.reportID, transactionViolations), @@ -6347,7 +6381,7 @@ function shouldDisplayViolationsRBRInLHN(report: OnyxEntry, transactionV */ function hasViolations(reportID: string, transactionViolations: OnyxCollection, shouldShowInReview?: boolean): boolean { const transactions = reportsTransactions[reportID] ?? []; - return transactions.some((transaction) => TransactionUtils.hasViolation(transaction.transactionID, transactionViolations, shouldShowInReview)); + return transactions.some((transaction) => hasViolation(transaction.transactionID, transactionViolations, shouldShowInReview)); } /** @@ -6355,7 +6389,7 @@ function hasViolations(reportID: string, transactionViolations: OnyxCollection, shouldShowInReview?: boolean): boolean { const transactions = reportsTransactions[reportID] ?? []; - return transactions.some((transaction) => TransactionUtils.hasWarningTypeViolation(transaction.transactionID, transactionViolations, shouldShowInReview)); + return transactions.some((transaction) => hasWarningTypeViolation(transaction.transactionID, transactionViolations, shouldShowInReview)); } /** @@ -6363,7 +6397,7 @@ function hasWarningTypeViolations(reportID: string, transactionViolations: OnyxC */ function hasNoticeTypeViolations(reportID: string, transactionViolations: OnyxCollection, shouldShowInReview?: boolean): boolean { const transactions = reportsTransactions[reportID] ?? []; - return transactions.some((transaction) => TransactionUtils.hasNoticeTypeViolation(transaction.transactionID, transactionViolations, shouldShowInReview)); + return transactions.some((transaction) => hasNoticeTypeViolation(transaction.transactionID, transactionViolations, shouldShowInReview)); } function hasReportViolations(reportID: string) { @@ -6413,7 +6447,7 @@ function getAllReportActionsErrorsAndReportActionThatRequiresAttention(report: O if (ReportActionsUtils.wasActionTakenByCurrentUser(parentReportAction) && ReportActionsUtils.isTransactionThread(parentReportAction)) { const transactionID = ReportActionsUtils.isMoneyRequestAction(parentReportAction) ? ReportActionsUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID : null; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; - if (TransactionUtils.hasMissingSmartscanFields(transaction ?? null) && !isSettled(transaction?.reportID)) { + if (hasMissingSmartscanFieldsTransactionUtils(transaction ?? null) && !isSettled(transaction?.reportID)) { reportActionErrors.smartscan = ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericSmartscanFailureMessage'); reportAction = undefined; } @@ -6651,7 +6685,7 @@ function shouldReportBeInOptionList(params: ShouldReportBeInOptionListParams) { * Returns the system report from the list of reports. */ function getSystemChat(): OnyxEntry { - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); if (!allReports) { return undefined; } @@ -6662,7 +6696,7 @@ function getSystemChat(): OnyxEntry { /** * Attempts to find a report in onyx with the provided list of participants. Does not include threads, task, expense, room, and policy expense chat. */ -function getChatByParticipants(newParticipantList: number[], reports: OnyxCollection = ReportConnection.getAllReports(), shouldIncludeGroupChats = false): OnyxEntry { +function getChatByParticipants(newParticipantList: number[], reports: OnyxCollection = getAllReports(), shouldIncludeGroupChats = false): OnyxEntry { const sortedNewParticipantList = newParticipantList.sort(); return Object.values(reports ?? {}).find((report) => { const participantAccountIDs = Object.keys(report?.participants ?? {}); @@ -6687,7 +6721,7 @@ function getChatByParticipants(newParticipantList: number[], reports: OnyxCollec /** * Attempts to find an invoice chat report in onyx with the provided policyID and receiverID. */ -function getInvoiceChatByParticipants(policyID: string, receiverID: string | number, reports: OnyxCollection = ReportConnection.getAllReports()): OnyxEntry { +function getInvoiceChatByParticipants(policyID: string, receiverID: string | number, reports: OnyxCollection = getAllReports()): OnyxEntry { return Object.values(reports ?? {}).find((report) => { if (!report || !isInvoiceRoom(report) || isArchivedRoom(report)) { return false; @@ -6706,7 +6740,7 @@ function getInvoiceChatByParticipants(policyID: string, receiverID: string | num * Attempts to find a policy expense report in onyx that is owned by ownerAccountID in a given policy */ function getPolicyExpenseChat(ownerAccountID: number, policyID: string): OnyxEntry { - return Object.values(ReportConnection.getAllReports() ?? {}).find((report: OnyxEntry) => { + return Object.values(getAllReports() ?? {}).find((report: OnyxEntry) => { // If the report has been deleted, then skip it if (!report) { return false; @@ -6717,7 +6751,7 @@ function getPolicyExpenseChat(ownerAccountID: number, policyID: string): OnyxEnt } function getAllPolicyReports(policyID: string): Array> { - return Object.values(ReportConnection.getAllReports() ?? {}).filter((report) => report?.policyID === policyID); + return Object.values(getAllReports() ?? {}).filter((report) => report?.policyID === policyID); } /** @@ -6730,7 +6764,7 @@ function chatIncludesChronos(report: OnyxInputOrEntry): boolean { function chatIncludesChronosWithID(reportID?: string): boolean { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID || -1}`]; + const report = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID || -1}`]; return chatIncludesChronos(report); } @@ -6882,7 +6916,7 @@ function getReportIDFromLink(url: string | null): string { */ function hasIOUWaitingOnCurrentUserBankAccount(chatReport: OnyxInputOrEntry): boolean { if (chatReport?.iouReportID) { - const iouReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReport?.iouReportID}`]; + const iouReport = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReport?.iouReportID}`]; if (iouReport?.isWaitingOnBankAccount && iouReport?.ownerAccountID === currentUserAccountID) { return true; } @@ -7210,7 +7244,7 @@ function shouldReportShowSubscript(report: OnyxEntry): boolean { * Return true if reports data exists */ function isReportDataReady(): boolean { - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); return !isEmptyObject(allReports) && Object.keys(allReports ?? {}).some((key) => allReports?.[key]?.reportID); } @@ -7234,7 +7268,7 @@ function getAddWorkspaceRoomOrChatReportErrors(report: OnyxEntry): Error * Return true if the expense report is marked for deletion. */ function isMoneyRequestReportPendingDeletion(reportOrID: OnyxEntry | string): boolean { - const report = typeof reportOrID === 'string' ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] : reportOrID; + const report = typeof reportOrID === 'string' ? getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] : reportOrID; if (!isMoneyRequestReport(report)) { return false; } @@ -7264,7 +7298,7 @@ function getOriginalReportID(reportID: string, reportAction: OnyxInputOrEntry, policy: OnyxEntry, return requestOptions.includes(iouType); } -function getWorkspaceChats(policyID: string, accountIDs: number[], allReports: OnyxCollection = ReportConnection.getAllReports()): Array> { +function getWorkspaceChats(policyID: string, accountIDs: number[], allReports: OnyxCollection = getAllReports()): Array> { return Object.values(allReports ?? {}).filter((report) => isPolicyExpenseChat(report) && (report?.policyID ?? '-1') === policyID && accountIDs.includes(report?.ownerAccountID ?? -1)); } @@ -7314,7 +7348,7 @@ function getWorkspaceChats(policyID: string, accountIDs: number[], allReports: O * @param policyID - the workspace ID to get all associated reports */ function getAllWorkspaceReports(policyID: string): Array> { - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); return Object.values(allReports ?? {}).filter((report) => (report?.policyID ?? '-1') === policyID); } @@ -7522,8 +7556,8 @@ function getIOUReportActionDisplayMessage(reportAction: OnyxEntry, return Localize.translateLocal(translationKey, {amount: formattedAmount, payer: ''}); } - const amount = TransactionUtils.getAmount(transaction, !isEmptyObject(iouReport) && isExpenseReport(iouReport)) ?? 0; - const formattedAmount = CurrencyUtils.convertToDisplayString(amount, TransactionUtils.getCurrency(transaction)) ?? ''; + const amount = getAmount(transaction, !isEmptyObject(iouReport) && isExpenseReport(iouReport)) ?? 0; + const formattedAmount = CurrencyUtils.convertToDisplayString(amount, getCurrency(transaction)) ?? ''; const isRequestSettled = isSettled(IOUReportID); const isApproved = isReportApproved(iouReport); if (isRequestSettled) { @@ -7545,7 +7579,7 @@ function getIOUReportActionDisplayMessage(reportAction: OnyxEntry, } return Localize.translateLocal(translationKey, { formattedAmount, - comment: TransactionUtils.getMerchantOrDescription(transaction), + comment: getMerchantOrDescription(transaction), }); } @@ -7622,7 +7656,7 @@ function shouldUseFullTitleToDisplay(report: OnyxEntry): boolean { } function getRoom(type: ValueOf, policyID: string): OnyxEntry { - const room = Object.values(ReportConnection.getAllReports() ?? {}).find((report) => report?.policyID === policyID && report?.chatType === type && !isThread(report)); + const room = Object.values(getAllReports() ?? {}).find((report) => report?.policyID === policyID && report?.chatType === type && !isThread(report)); return room; } @@ -7660,7 +7694,7 @@ function getReportActionWithSmartscanError(reportActions: ReportAction[]): Repor const transactionID = ReportActionsUtils.isMoneyRequestAction(action) ? ReportActionsUtils.getOriginalMessage(action)?.IOUTransactionID ?? '-1' : '-1'; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? {}; - const isSplitBillError = isSplitReportAction && TransactionUtils.hasMissingSmartscanFields(transaction as Transaction); + const isSplitBillError = isSplitReportAction && hasMissingSmartscanFieldsTransactionUtils(transaction as Transaction); return isSplitBillError; }); @@ -7710,23 +7744,23 @@ function navigateToPrivateNotes(report: OnyxEntry, session: OnyxEntry TransactionUtils.isOnHold(transaction)); + return transactions.filter((transaction) => isOnHoldTransactionUtils(transaction)); } /** * Check if Report has any held expenses */ -function hasHeldExpenses(iouReportID?: string): boolean { - const transactions = reportsTransactions[iouReportID ?? ''] ?? []; - return transactions.some((transaction) => TransactionUtils.isOnHold(transaction)); +function hasHeldExpenses(iouReportID?: string, allReportTransactions?: SearchTransaction[]): boolean { + const transactions = allReportTransactions ?? reportsTransactions[iouReportID ?? ''] ?? []; + return transactions.some((transaction) => isOnHoldTransactionUtils(transaction)); } /** * Check if all expenses in the Report are on hold */ -function hasOnlyHeldExpenses(iouReportID: string): boolean { - const reportTransactions = reportsTransactions[iouReportID ?? ''] ?? []; - return reportTransactions.length > 0 && !reportTransactions.some((transaction) => !TransactionUtils.isOnHold(transaction)); +function hasOnlyHeldExpenses(iouReportID: string, allReportTransactions?: SearchTransaction[]): boolean { + const reportTransactions = allReportTransactions ?? reportsTransactions[iouReportID ?? ''] ?? []; + return reportTransactions.length > 0 && !reportTransactions.some((transaction) => !isOnHoldTransactionUtils(transaction)); } /** @@ -7766,7 +7800,7 @@ function getNonHeldAndFullAmount(iouReport: OnyxEntry, policy: OnyxEntry const coefficient = isExpenseReport(iouReport) ? -1 : 1; if (hasUpdatedTotal(iouReport, policy) && hasPendingTransaction) { - const unheldTotal = reportTransactions.reduce((currentVal, transaction) => currentVal + (!TransactionUtils.isOnHold(transaction) ? transaction.amount : 0), 0); + const unheldTotal = reportTransactions.reduce((currentVal, transaction) => currentVal + (!isOnHoldTransactionUtils(transaction) ? transaction.amount : 0), 0); return { nonHeldAmount: CurrencyUtils.convertToDisplayString(unheldTotal * coefficient, iouReport?.currency), @@ -8023,7 +8057,7 @@ function shouldCreateNewMoneyRequestReport(existingIOUReport: OnyxInputOrEntry report && report?.[reportFieldToCompare] === tripRoomReportID) .map((report) => report?.reportID); return tripTransactionReportIDs.flatMap((reportID) => reportsTransactions[reportID ?? ''] ?? []); @@ -8238,7 +8272,7 @@ function canReportBeMentionedWithinPolicy(report: OnyxEntry, policyID: s } function shouldShowMerchantColumn(transactions: Transaction[]) { - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); return transactions.some((transaction) => isExpenseReport(allReports?.[transaction.reportID] ?? null)); } @@ -8261,7 +8295,7 @@ function isChatUsedForOnboarding(optionOrReport: OnyxEntry | OptionData) * we also used the system DM for A/B tests. */ function getChatUsedForOnboarding(): OnyxEntry { - return Object.values(ReportConnection.getAllReports() ?? {}).find(isChatUsedForOnboarding); + return Object.values(getAllReports() ?? {}).find(isChatUsedForOnboarding); } /** @@ -8303,7 +8337,7 @@ function getReportViolations(reportID: string): ReportViolations | undefined { } function findPolicyExpenseChatByPolicyID(policyID: string): OnyxEntry { - return Object.values(ReportConnection.getAllReports() ?? {}).find((report) => isPolicyExpenseChat(report) && report?.policyID === policyID); + return Object.values(getAllReports() ?? {}).find((report) => isPolicyExpenseChat(report) && report?.policyID === policyID); } /** @@ -8410,7 +8444,7 @@ function hasMissingInvoiceBankAccount(iouReportID: string): boolean { } function hasInvoiceReports() { - const allReports = Object.values(ReportConnection.getAllReports() ?? {}); + const allReports = Object.values(getAllReports() ?? {}); return allReports.some((report) => isInvoiceReport(report)); } diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index cb2c1a52e2d2..d41def6f09b2 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -15,18 +15,25 @@ import {toLocaleDigit} from '@libs/LocaleDigitUtils'; import * as Localize from '@libs/Localize'; import * as NumberUtils from '@libs/NumberUtils'; import Permissions from '@libs/Permissions'; -import {getCleanedTagName, getDistanceRateCustomUnitRate} from '@libs/PolicyUtils'; -import * as PolicyUtils from '@libs/PolicyUtils'; -// eslint-disable-next-line import/no-cycle -import * as ReportActionsUtils from '@libs/ReportActionsUtils'; -import * as ReportConnection from '@libs/ReportConnection'; -import * as ReportUtils from '@libs/ReportUtils'; +import { + getCleanedTagName, + getDistanceRateCustomUnitRate, + getPolicy, + getTaxByID, + isInstantSubmitEnabled, + isMultiLevelTags as isMultiLevelTagsPolicyUtils, + isPolicyAdmin, +} from '@libs/PolicyUtils'; +import {getOriginalMessage, getReportAction, isMoneyRequestAction} from '@libs/ReportActionsUtils'; +import {getAllReports} from '@libs/ReportConnection'; +import {isOpenExpenseReport, isProcessingReport, isReportApproved, isSettled} from '@libs/ReportUtils'; import type {IOURequestType} from '@userActions/IOU'; import CONST from '@src/CONST'; import type {IOUType} from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Beta, OnyxInputOrEntry, Policy, RecentWaypoint, Report, ReviewDuplicates, TaxRate, TaxRates, Transaction, TransactionViolation, TransactionViolations} from '@src/types/onyx'; import type {Attendee} from '@src/types/onyx/IOU'; +import type {SearchReport} from '@src/types/onyx/SearchResults'; import type {Comment, Receipt, TransactionChanges, TransactionPendingFieldsKey, Waypoint, WaypointCollection} from '@src/types/onyx/Transaction'; import type DeepValueOf from '@src/types/utils/DeepValueOf'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -237,7 +244,7 @@ function isCreatedMissing(transaction: OnyxEntry) { } function areRequiredFieldsEmpty(transaction: OnyxEntry): boolean { - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transaction?.reportID}`] ?? null; const isFromExpenseReport = parentReport?.type === CONST.REPORT.TYPE.EXPENSE; const isSplitPolicyExpenseChat = !!transaction?.comment?.splits?.some((participant) => allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.chatReportID}`]?.isOwnPolicyExpenseChat); @@ -715,11 +722,8 @@ function hasBrokenConnectionViolation(transactionID: string): boolean { /** * Check if user should see broken connection violation warning. */ -function shouldShowBrokenConnectionViolation(transactionID: string, report: OnyxEntry, policy: OnyxEntry): boolean { - return ( - hasBrokenConnectionViolation(transactionID) && - (!PolicyUtils.isPolicyAdmin(policy) || ReportUtils.isOpenExpenseReport(report) || (ReportUtils.isProcessingReport(report) && PolicyUtils.isInstantSubmitEnabled(policy))) - ); +function shouldShowBrokenConnectionViolation(transactionID: string, report: OnyxEntry | SearchReport, policy: OnyxEntry): boolean { + return hasBrokenConnectionViolation(transactionID) && (!isPolicyAdmin(policy) || isOpenExpenseReport(report) || (isProcessingReport(report) && isInstantSubmitEnabled(policy))); } /** @@ -1020,8 +1024,8 @@ type FieldsToChange = { function removeSettledAndApprovedTransactions(transactionIDs: string[]) { return transactionIDs.filter( (transactionID) => - !ReportUtils.isSettled(allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]?.reportID) && - !ReportUtils.isReportApproved(allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]?.reportID), + !isSettled(allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]?.reportID) && + !isReportApproved(allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]?.reportID), ); } @@ -1104,8 +1108,8 @@ function compareDuplicateTransactionFields(transactionID: string, reportID: stri const keys = fieldsToCompare[fieldName]; const firstTransaction = transactions.at(0); const isFirstTransactionCommentEmptyObject = typeof firstTransaction?.comment === 'object' && firstTransaction?.comment?.comment === ''; - const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`] ?? null; - const policy = PolicyUtils.getPolicy(report?.policyID); + const report = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`] ?? null; + const policy = getPolicy(report?.policyID); const areAllFieldsEqualForKey = areAllFieldsEqual(transactions, (item) => keys.map((key) => item?.[key]).join('|')); if (fieldName === 'description') { @@ -1125,7 +1129,7 @@ function compareDuplicateTransactionFields(transactionID: string, reportID: stri } else if (fieldName === 'taxCode') { const differentValues = getDifferentValues(transactions, keys); const validTaxes = differentValues?.filter((taxID) => { - const tax = PolicyUtils.getTaxByID(policy, (taxID as string) ?? ''); + const tax = getTaxByID(policy, (taxID as string) ?? ''); return tax?.name && !tax.isDisabled && tax.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE; }); @@ -1148,7 +1152,7 @@ function compareDuplicateTransactionFields(transactionID: string, reportID: stri } } else if (fieldName === 'tag') { const policyTags = getPolicyTagsData(report?.policyID ?? '-1'); - const isMultiLevelTags = PolicyUtils.isMultiLevelTags(policyTags); + const isMultiLevelTags = isMultiLevelTagsPolicyUtils(policyTags); if (isMultiLevelTags) { if (areAllFieldsEqualForKey || !policy?.areTagsEnabled) { keep[fieldName] = firstTransaction?.[keys[0]] ?? firstTransaction?.[keys[1]]; @@ -1179,9 +1183,9 @@ function compareDuplicateTransactionFields(transactionID: string, reportID: stri } function getTransactionID(threadReportID: string): string { - const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${threadReportID}`] ?? null; - const parentReportAction = ReportActionsUtils.getReportAction(report?.parentReportID ?? '', report?.parentReportActionID ?? ''); - const IOUTransactionID = ReportActionsUtils.isMoneyRequestAction(parentReportAction) ? ReportActionsUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID ?? '-1' : '-1'; + const report = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${threadReportID}`] ?? null; + const parentReportAction = getReportAction(report?.parentReportID ?? '', report?.parentReportActionID ?? ''); + const IOUTransactionID = isMoneyRequestAction(parentReportAction) ? getOriginalMessage(parentReportAction)?.IOUTransactionID ?? '-1' : '-1'; return IOUTransactionID; } diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index dd6686b9ff7d..a35477a37a2a 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -48,13 +48,26 @@ import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as PhoneNumber from '@libs/PhoneNumber'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; -import * as ReportConnection from '@libs/ReportConnection'; +import {getAllReports} from '@libs/ReportConnection'; import type {OptimisticChatReport, OptimisticCreatedReportAction, OptimisticIOUReportAction, TransactionDetails} from '@libs/ReportUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as SessionUtils from '@libs/SessionUtils'; import * as SubscriptionUtils from '@libs/SubscriptionUtils'; -import * as TransactionUtils from '@libs/TransactionUtils'; -import {getCurrency, getTransaction} from '@libs/TransactionUtils'; +import { + buildOptimisticTransaction, + getAllReportTransactions, + getAmount, + getCurrency, + getMerchant, + getTransaction, + getTransactionID, + getUpdatedTransaction, + hasReceipt as hasReceiptTransactionUtils, + isDistanceRequest as isDistanceRequestTransactionUtils, + isFetchingWaypointsFromServer, + isReceiptBeingScanned as isReceiptBeingScannedTransactionUtils, + isScanRequest as isScanRequestTransactionUtils, +} from '@libs/TransactionUtils'; import ViolationsUtils from '@libs/Violations/ViolationsUtils'; import type {IOUAction, IOUType} from '@src/CONST'; import CONST from '@src/CONST'; @@ -540,16 +553,16 @@ function buildOnyxDataForMoneyRequest( existingTransactionThreadReportID?: string, optimisticRecentlyUsedCurrencies?: string[], ): [OnyxUpdate[], OnyxUpdate[], OnyxUpdate[]] { - const isScanRequest = TransactionUtils.isScanRequest(transaction); + const isScanRequest = isScanRequestTransactionUtils(transaction); const outstandingChildRequest = ReportUtils.getOutstandingChildRequest(iouReport); const clearedPendingFields = Object.fromEntries(Object.keys(transaction.pendingFields ?? {}).map((key) => [key, null])); const optimisticData: OnyxUpdate[] = []; const successData: OnyxUpdate[] = []; let newQuickAction: ValueOf = isScanRequest ? CONST.QUICK_ACTIONS.REQUEST_SCAN : CONST.QUICK_ACTIONS.REQUEST_MANUAL; - if (TransactionUtils.isDistanceRequest(transaction)) { + if (isDistanceRequestTransactionUtils(transaction)) { newQuickAction = CONST.QUICK_ACTIONS.REQUEST_DISTANCE; } - const existingTransactionThreadReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${existingTransactionThreadReportID}`] ?? null; + const existingTransactionThreadReport = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${existingTransactionThreadReportID}`] ?? null; if (chatReport) { optimisticData.push({ @@ -1309,8 +1322,8 @@ function buildOnyxDataForTrackExpense( existingTransactionThreadReportID?: string, actionableTrackExpenseWhisper?: OnyxInputValue, ): [OnyxUpdate[], OnyxUpdate[], OnyxUpdate[]] { - const isScanRequest = TransactionUtils.isScanRequest(transaction); - const isDistanceRequest = TransactionUtils.isDistanceRequest(transaction); + const isScanRequest = isScanRequestTransactionUtils(transaction); + const isDistanceRequest = isDistanceRequestTransactionUtils(transaction); const clearedPendingFields = Object.fromEntries(Object.keys(transaction.pendingFields ?? {}).map((key) => [key, null])); const optimisticData: OnyxUpdate[] = []; const successData: OnyxUpdate[] = []; @@ -1322,7 +1335,7 @@ function buildOnyxDataForTrackExpense( } else if (isDistanceRequest) { newQuickAction = CONST.QUICK_ACTIONS.TRACK_DISTANCE; } - const existingTransactionThreadReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${existingTransactionThreadReportID}`] ?? null; + const existingTransactionThreadReport = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${existingTransactionThreadReportID}`] ?? null; if (chatReport) { optimisticData.push( @@ -1678,7 +1691,7 @@ function getDeleteTrackExpenseInformation( actionableWhisperReportActionID = '', resolution = '', ) { - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); // STEP 1: Get all collections we're updating const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`] ?? null; const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; @@ -1897,7 +1910,7 @@ function getSendInvoiceInformation( receiptObject.state = receipt.state ?? CONST.IOU.RECEIPT_STATE.SCANREADY; filename = receipt.name; } - const optimisticTransaction = TransactionUtils.buildOptimisticTransaction( + const optimisticTransaction = buildOptimisticTransaction( amount, currency, optimisticInvoiceReport.reportID, @@ -2035,7 +2048,7 @@ function getMoneyRequestInformation( let isNewChatReport = false; let chatReport = !isEmptyObject(parentChatReport) && parentChatReport?.reportID ? parentChatReport : null; - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); // If this is a policyExpenseChat, the chatReport must exist and we can get it from Onyx. // report is null if the flow is initiated from the global create menu. However, participant always stores the reportID if it exists, which is the case for policyExpenseChats if (!chatReport && isPolicyExpenseChat) { @@ -2079,7 +2092,7 @@ function getMoneyRequestInformation( // STEP 3: Build an optimistic transaction with the receipt const isDistanceRequest = existingTransaction && existingTransaction.iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE; - let optimisticTransaction = TransactionUtils.buildOptimisticTransaction( + let optimisticTransaction = buildOptimisticTransaction( ReportUtils.isExpenseReport(iouReport) ? -amount : amount, currency, iouReport.reportID, @@ -2253,7 +2266,7 @@ function getTrackExpenseInformation( // STEP 1: Get existing chat report let chatReport = !isEmptyObject(parentChatReport) && parentChatReport?.reportID ? parentChatReport : null; - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); // The chatReport always exists, and we can get it from Onyx if chatReport is null. if (!chatReport) { chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.reportID}`] ?? null; @@ -2321,7 +2334,7 @@ function getTrackExpenseInformation( filename = existingTransaction?.filename; } const isDistanceRequest = existingTransaction && existingTransaction.iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE; - let optimisticTransaction = TransactionUtils.buildOptimisticTransaction( + let optimisticTransaction = buildOptimisticTransaction( ReportUtils.isExpenseReport(iouReport) ? -amount : amount, currency, shouldUseMoneyReport && iouReport ? iouReport.reportID : '-1', @@ -2446,11 +2459,11 @@ function calculateDiffAmount( return 0; } const isExpenseReport = ReportUtils.isExpenseReport(iouReport); - const updatedCurrency = TransactionUtils.getCurrency(updatedTransaction); - const currentCurrency = TransactionUtils.getCurrency(transaction); + const updatedCurrency = getCurrency(updatedTransaction); + const currentCurrency = getCurrency(transaction); - const currentAmount = TransactionUtils.getAmount(transaction, isExpenseReport); - const updatedAmount = TransactionUtils.getAmount(updatedTransaction, isExpenseReport); + const currentAmount = getAmount(transaction, isExpenseReport); + const updatedAmount = getAmount(updatedTransaction, isExpenseReport); if (updatedCurrency === iouReport?.currency && currentCurrency !== iouReport?.currency) { // Add the diff to the total if we change the currency from a different currency to the currency of the IOU report @@ -2492,15 +2505,15 @@ function getUpdateMoneyRequestParams( const clearedPendingFields = Object.fromEntries(Object.keys(transactionChanges).map((key) => [key, null])); const errorFields = Object.fromEntries(Object.keys(pendingFields).map((key) => [key, {[DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.genericEditFailureMessage')}])); - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); // Step 2: Get all the collections being updated const transactionThread = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThread?.parentReportID}`] ?? null; const isFromExpenseReport = ReportUtils.isExpenseReport(iouReport); - const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction); + const isScanning = hasReceiptTransactionUtils(transaction) && isReceiptBeingScannedTransactionUtils(transaction); const updatedTransaction: OnyxEntry = transaction - ? TransactionUtils.getUpdatedTransaction({ + ? getUpdatedTransaction({ transaction, transactionChanges, isFromExpenseReport, @@ -2553,7 +2566,7 @@ function getUpdateMoneyRequestParams( // In these cases, there isn't a valid optimistic mileage data we can use, // and the report action is created on the server with the distance-related response from the MapBox API const updatedReportAction = ReportUtils.buildOptimisticModifiedExpenseReportAction(transactionThread, transaction, transactionChanges, isFromExpenseReport, policy, updatedTransaction); - if (!hasPendingWaypoints && !(hasModifiedDistanceRate && TransactionUtils.isFetchingWaypointsFromServer(transaction))) { + if (!hasPendingWaypoints && !(hasModifiedDistanceRate && isFetchingWaypointsFromServer(transaction))) { params.reportActionID = updatedReportAction.reportActionID; optimisticData.push({ @@ -2614,7 +2627,7 @@ function getUpdateMoneyRequestParams( updatedMoneyRequestReport.nonReimbursableTotal -= diff; } } else { - updatedMoneyRequestReport = IOUUtils.updateIOUOwnerAndTotal(iouReport, updatedReportAction.actorAccountID ?? -1, diff, TransactionUtils.getCurrency(transaction), false, true); + updatedMoneyRequestReport = IOUUtils.updateIOUOwnerAndTotal(iouReport, updatedReportAction.actorAccountID ?? -1, diff, getCurrency(transaction), false, true); } optimisticData.push( @@ -2723,7 +2736,7 @@ function getUpdateMoneyRequestParams( // Update violation limit, if we modify attendees. The given limit value is for a single attendee, if we have multiple attendees we should multpiply limit by attende count if ('attendees' in transactionChanges && !!overLimitViolation) { const limitForSingleAttendee = ViolationsUtils.getViolationAmountLimit(overLimitViolation); - if (limitForSingleAttendee * (transactionChanges?.attendees?.length ?? 1) > Math.abs(TransactionUtils.getAmount(transaction))) { + if (limitForSingleAttendee * (transactionChanges?.attendees?.length ?? 1) > Math.abs(getAmount(transaction))) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, @@ -2818,14 +2831,14 @@ function getUpdateTrackExpenseParams( const clearedPendingFields = Object.fromEntries(Object.keys(transactionChanges).map((key) => [key, null])); const errorFields = Object.fromEntries(Object.keys(pendingFields).map((key) => [key, {[DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.genericEditFailureMessage')}])); - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); // Step 2: Get all the collections being updated const transactionThread = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThread?.parentReportID}`] ?? null; - const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction); + const isScanning = hasReceiptTransactionUtils(transaction) && isReceiptBeingScannedTransactionUtils(transaction); const updatedTransaction = transaction - ? TransactionUtils.getUpdatedTransaction({ + ? getUpdatedTransaction({ transaction, transactionChanges, isFromExpenseReport: false, @@ -2877,7 +2890,7 @@ function getUpdateTrackExpenseParams( // In these cases, there isn't a valid optimistic mileage data we can use, // and the report action is created on the server with the distance-related response from the MapBox API const updatedReportAction = ReportUtils.buildOptimisticModifiedExpenseReportAction(transactionThread, transaction, transactionChanges, false, policy, updatedTransaction); - if (!hasPendingWaypoints && !(hasModifiedDistanceRate && TransactionUtils.isFetchingWaypointsFromServer(transaction))) { + if (!hasPendingWaypoints && !(hasModifiedDistanceRate && isFetchingWaypointsFromServer(transaction))) { params.reportActionID = updatedReportAction.reportActionID; optimisticData.push({ @@ -2988,7 +3001,7 @@ function updateMoneyRequestDate( const transactionChanges: TransactionChanges = { created: value, }; - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); const transactionThreadReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.parentReportID}`] ?? null; let data: UpdateMoneyRequestData; @@ -3029,7 +3042,7 @@ function updateMoneyRequestMerchant( const transactionChanges: TransactionChanges = { merchant: value, }; - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); const transactionThreadReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.parentReportID}`] ?? null; let data: UpdateMoneyRequestData; @@ -3136,7 +3149,7 @@ function updateMoneyRequestDistance({ waypoints: sanitizeRecentWaypoints(waypoints), routes, }; - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); const transactionThreadReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.parentReportID}`] ?? null; let data: UpdateMoneyRequestData; @@ -3185,7 +3198,7 @@ function updateMoneyRequestDescription( const transactionChanges: TransactionChanges = { comment, }; - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); const transactionThreadReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.parentReportID}`] ?? null; let data: UpdateMoneyRequestData; @@ -3214,7 +3227,7 @@ function updateMoneyRequestDistanceRate( ...(typeof updatedTaxAmount === 'number' ? {taxAmount: updatedTaxAmount} : {}), ...(updatedTaxCode ? {taxCode: updatedTaxCode} : {}), }; - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); const transactionThreadReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.parentReportID}`] ?? null; @@ -3225,7 +3238,7 @@ function updateMoneyRequestDistanceRate( // If the distanceUnit is set and the rate is changed to one that has a different unit, mark the merchant as modified to make the distance field pending if (existingDistanceUnit && newDistanceUnit && newDistanceUnit !== existingDistanceUnit) { - transactionChanges.merchant = TransactionUtils.getMerchant(transaction); + transactionChanges.merchant = getMerchant(transaction); } } @@ -3936,7 +3949,7 @@ function getOrCreateOptimisticSplitChatReport(existingSplitChatReportID: string, const existingChatReportID = existingSplitChatReportID || (participants.at(0)?.reportID ?? '-1'); // Check if the report is available locally if we do have one - let existingSplitChatReport = existingChatReportID ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${existingChatReportID}`] : null; + let existingSplitChatReport = existingChatReportID ? getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${existingChatReportID}`] : null; const allParticipantsAccountIDs = [...participantAccountIDs, currentUserAccountID]; if (!existingSplitChatReport) { @@ -4014,7 +4027,7 @@ function createSplitsAndOnyxData( const existingTransaction = allTransactionDrafts[`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`]; const isDistanceRequest = existingTransaction && existingTransaction.iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE; - let splitTransaction = TransactionUtils.buildOptimisticTransaction( + let splitTransaction = buildOptimisticTransaction( amount, currency, CONST.REPORT.SPLIT_REPORTID, @@ -4235,9 +4248,7 @@ function createSplitsAndOnyxData( } // STEP 2: Get existing IOU/Expense report and update its total OR build a new optimistic one - let oneOnOneIOUReport: OneOnOneIOUReport = oneOnOneChatReport.iouReportID - ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`] - : null; + let oneOnOneIOUReport: OneOnOneIOUReport = oneOnOneChatReport.iouReportID ? getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`] : null; const shouldCreateNewOneOnOneIOUReport = ReportUtils.shouldCreateNewMoneyRequestReport(oneOnOneIOUReport, oneOnOneChatReport); if (!oneOnOneIOUReport || shouldCreateNewOneOnOneIOUReport) { @@ -4254,7 +4265,7 @@ function createSplitsAndOnyxData( } // STEP 3: Build optimistic transaction - const oneOnOneTransaction = TransactionUtils.buildOptimisticTransaction( + const oneOnOneTransaction = buildOptimisticTransaction( ReportUtils.isExpenseReport(oneOnOneIOUReport) ? -splitAmount : splitAmount, currency, oneOnOneIOUReport.reportID, @@ -4604,7 +4615,7 @@ function startSplitBill({ const receiptObject: Receipt = {state, source}; // ReportID is -2 (aka "deleted") on the group transaction - const splitTransaction = TransactionUtils.buildOptimisticTransaction( + const splitTransaction = buildOptimisticTransaction( 0, currency, CONST.REPORT.SPLIT_REPORTID, @@ -4989,7 +5000,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA let oneOnOneChatReport: OnyxEntry; let isNewOneOnOneChatReport = false; - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); if (isPolicyExpenseChat) { // The workspace chat reportID is saved in the splits array when starting a split expense with a workspace oneOnOneChatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.chatReportID}`]; @@ -5015,7 +5026,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(oneOnOneIOUReport, sessionAccountID, splitAmount, currency ?? ''); } - const oneOnOneTransaction = TransactionUtils.buildOptimisticTransaction( + const oneOnOneTransaction = buildOptimisticTransaction( isPolicyExpenseChat ? -splitAmount : splitAmount, currency ?? '', oneOnOneIOUReport?.reportID ?? '-1', @@ -5139,7 +5150,7 @@ function setDraftSplitTransaction(transactionID: string, transactionChanges: Tra } const updatedTransaction = draftSplitTransaction - ? TransactionUtils.getUpdatedTransaction({ + ? getUpdatedTransaction({ transaction: draftSplitTransaction, transactionChanges, isFromExpenseReport: false, @@ -5340,7 +5351,7 @@ function updateMoneyRequestAmountAndCurrency({ taxCode, taxAmount, }; - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); const transactionThreadReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.parentReportID}`] ?? null; let data: UpdateMoneyRequestData; @@ -5362,7 +5373,7 @@ function updateMoneyRequestAmountAndCurrency({ */ function prepareToCleanUpMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) { // STEP 1: Get all collections we're updating - const allReports = ReportConnection.getAllReports(); + const allReports = getAllReports(); const iouReportID = ReportActionsUtils.isMoneyRequestAction(reportAction) ? ReportActionsUtils.getOriginalMessage(reportAction)?.IOUReportID : '-1'; const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReportID}`] ?? null; const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`]; @@ -5414,7 +5425,7 @@ function prepareToCleanUpMoneyRequest(transactionID: string, reportAction: OnyxT // STEP 4: Update the iouReport and reportPreview with new totals and messages if it wasn't deleted let updatedIOUReport: OnyxInputValue; - const currency = TransactionUtils.getCurrency(transaction); + const currency = getCurrency(transaction); const updatedReportPreviewAction: OnyxTypes.ReportAction = {...reportPreviewAction}; updatedReportPreviewAction.pendingAction = shouldDeleteIOUReport ? CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE : CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE; if (iouReport && ReportUtils.isExpenseReport(iouReport)) { @@ -5422,7 +5433,7 @@ function prepareToCleanUpMoneyRequest(transactionID: string, reportAction: OnyxT if (typeof updatedIOUReport.total === 'number' && currency === iouReport?.currency) { // Because of the Expense reports are stored as negative values, we add the total from the amount - const amountDiff = TransactionUtils.getAmount(transaction, true); + const amountDiff = getAmount(transaction, true); updatedIOUReport.total += amountDiff; if (!transaction?.reimbursable && typeof updatedIOUReport.nonReimbursableTotal === 'number') { @@ -5430,7 +5441,7 @@ function prepareToCleanUpMoneyRequest(transactionID: string, reportAction: OnyxT } } } else { - updatedIOUReport = IOUUtils.updateIOUOwnerAndTotal(iouReport, reportAction.actorAccountID ?? -1, TransactionUtils.getAmount(transaction, false), currency, true); + updatedIOUReport = IOUUtils.updateIOUOwnerAndTotal(iouReport, reportAction.actorAccountID ?? -1, getAmount(transaction, false), currency, true); } if (updatedIOUReport) { @@ -5881,7 +5892,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor function deleteTrackExpense(chatReportID: string, transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) { // STEP 1: Get all collections we're updating - const chatReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`] ?? null; + const chatReport = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`] ?? null; if (!ReportUtils.isSelfDM(chatReport)) { return deleteMoneyRequest(transactionID, reportAction, isSingleTransactionView); } @@ -5941,7 +5952,7 @@ function getSendMoneyParams( } const optimisticIOUReport = ReportUtils.buildOptimisticIOUReport(recipientAccountID, managerID, amount, chatReport.reportID, currency, true); - const optimisticTransaction = TransactionUtils.buildOptimisticTransaction(amount, currency, optimisticIOUReport.reportID, comment); + const optimisticTransaction = buildOptimisticTransaction(amount, currency, optimisticIOUReport.reportID, comment); const optimisticTransactionData: OnyxUpdate = { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${optimisticTransaction.transactionID}`, @@ -6276,7 +6287,7 @@ function getReportFromHoldRequestsOnyxData( const newParentReportActionID = rand64(); const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(chatReport); - const holdTransactionAmount = holdTransactions.reduce((acc, transaction) => acc + TransactionUtils.getAmount(transaction), 0); + const holdTransactionAmount = holdTransactions.reduce((acc, transaction) => acc + getAmount(transaction), 0); const optimisticExpenseReport = isPolicyExpenseChat ? ReportUtils.buildOptimisticExpenseReport( chatReport.reportID, @@ -6665,7 +6676,7 @@ function getPayMoneyRequestParams( // Optimistically unhold all transactions if we pay all requests if (full) { - const reportTransactions = TransactionUtils.getAllReportTransactions(iouReport?.reportID); + const reportTransactions = getAllReportTransactions(iouReport?.reportID); for (const transaction of reportTransactions) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, @@ -6766,10 +6777,10 @@ function canApproveIOU(iouReport: OnyxTypes.OnyxInputOrEntry, const reportNameValuePairs = ReportUtils.getReportNameValuePairs(iouReport?.reportID); const isArchivedReport = ReportUtils.isArchivedRoom(iouReport, reportNameValuePairs); let isTransactionBeingScanned = false; - const reportTransactions = TransactionUtils.getAllReportTransactions(iouReport?.reportID); + const reportTransactions = getAllReportTransactions(iouReport?.reportID); for (const transaction of reportTransactions) { - const hasReceipt = TransactionUtils.hasReceipt(transaction); - const isReceiptBeingScanned = TransactionUtils.isReceiptBeingScanned(transaction); + const hasReceipt = hasReceiptTransactionUtils(transaction); + const isReceiptBeingScanned = isReceiptBeingScannedTransactionUtils(transaction); // If transaction has receipt (scan) and its receipt is being scanned, we shouldn't be able to Approve if (hasReceipt && isReceiptBeingScanned) { @@ -8072,7 +8083,7 @@ function mergeDuplicates(params: TransactionMergeParams) { return total + duplicateTransaction.amount; }, 0); - const expenseReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${params.reportID}`]; + const expenseReport = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${params.reportID}`]; const expenseReportOptimisticData: OnyxUpdate = { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${params.reportID}`, @@ -8217,7 +8228,7 @@ function resolveDuplicates(params: TransactionMergeParams) { transactionThreadReportIDList.forEach((transactionThreadReportID) => { const createdReportAction = ReportUtils.buildOptimisticHoldReportAction(); reportActionIDList.push(createdReportAction.reportActionID); - const transactionID = TransactionUtils.getTransactionID(transactionThreadReportID ?? '-1'); + const transactionID = getTransactionID(transactionThreadReportID ?? '-1'); optimisticHoldTransactionActions.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, diff --git a/src/libs/actions/Policy/Category.ts b/src/libs/actions/Policy/Category.ts index dced49976c5a..c31594d5f2b0 100644 --- a/src/libs/actions/Policy/Category.ts +++ b/src/libs/actions/Policy/Category.ts @@ -27,10 +27,9 @@ import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import {translateLocal} from '@libs/Localize'; import Log from '@libs/Log'; import enhanceParameters from '@libs/Network/enhanceParameters'; -import * as OptionsListUtils from '@libs/OptionsListUtils'; -import {navigateWhenEnableFeature, removePendingFieldsFromCustomUnit} from '@libs/PolicyUtils'; -import * as PolicyUtils from '@libs/PolicyUtils'; -import * as ReportUtils from '@libs/ReportUtils'; +import {hasEnabledOptions} from '@libs/OptionsListUtils'; +import {getPolicy, navigateWhenEnableFeature, removePendingFieldsFromCustomUnit} from '@libs/PolicyUtils'; +import {getAllPolicyReports} from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Policy, PolicyCategories, PolicyCategory, RecentlyUsedCategories, Report} from '@src/types/onyx'; @@ -50,7 +49,7 @@ Onyx.connect({ // and unset the draft indicator (pencil icon) alongside removing any draft comments. Clearing these values will keep the newly archived chats from being displayed in the LHN. // More info: https://github.com/Expensify/App/issues/14260 const policyID = key.replace(ONYXKEYS.COLLECTION.POLICY, ''); - const policyReports = ReportUtils.getAllPolicyReports(policyID); + const policyReports = getAllPolicyReports(policyID); const cleanUpMergeQueries: Record<`${typeof ONYXKEYS.COLLECTION.REPORT}${string}`, NullishDeep> = {}; const cleanUpSetQueries: Record<`${typeof ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${string}` | `${typeof ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}${string}`, null> = {}; policyReports.forEach((policyReport) => { @@ -229,7 +228,7 @@ function setWorkspaceCategoryEnabled(policyID: string, categoriesToUpdate: Recor return acc; }, {}), }; - const shouldDisableRequiresCategory = !OptionsListUtils.hasEnabledOptions({...policyCategories, ...optimisticPolicyCategoriesData}); + const shouldDisableRequiresCategory = !hasEnabledOptions({...policyCategories, ...optimisticPolicyCategoriesData}); const onyxData: OnyxData = { optimisticData: [ { @@ -535,7 +534,7 @@ function importPolicyCategories(policyID: string, categories: PolicyCategory[]) } function renamePolicyCategory(policyID: string, policyCategory: {oldName: string; newName: string}) { - const policy = PolicyUtils.getPolicy(policyID); + const policy = getPolicy(policyID); const policyCategoryToUpdate = allPolicyCategories?.[`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`]?.[policyCategory.oldName]; const policyCategoryApproverRule = CategoryUtils.getCategoryApproverRule(policy?.rules?.approvalRules ?? [], policyCategory.oldName); @@ -863,7 +862,7 @@ function deleteWorkspaceCategories(policyID: string, categoryNamesToDelete: stri acc[categoryName] = {pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, enabled: false}; return acc; }, {}); - const shouldDisableRequiresCategory = !OptionsListUtils.hasEnabledOptions( + const shouldDisableRequiresCategory = !hasEnabledOptions( Object.values(policyCategories).filter((category) => !categoryNamesToDelete.includes(category.name) && category.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE), ); const onyxData: OnyxData = { @@ -1282,7 +1281,7 @@ function setPolicyCategoryApprover(policyID: string, categoryName: string, appro } function setPolicyCategoryTax(policyID: string, categoryName: string, taxID: string) { - const policy = PolicyUtils.getPolicy(policyID); + const policy = getPolicy(policyID); const expenseRules = policy?.rules?.expenseRules ?? []; const updatedExpenseRules: ExpenseRule[] = lodashCloneDeep(expenseRules); const existingCategoryExpenseRule = updatedExpenseRules.find((rule) => rule.applyWhen.some((when) => when.value === categoryName)); diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 628e0918aa54..61ef13c95e50 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -71,9 +71,9 @@ import * as PhoneNumber from '@libs/PhoneNumber'; import * as PolicyUtils from '@libs/PolicyUtils'; import {navigateWhenEnableFeature} from '@libs/PolicyUtils'; import * as ReportActionsConnection from '@libs/ReportActionsConnection'; -import * as ReportConnection from '@libs/ReportConnection'; +import {getAllReports} from '@libs/ReportConnection'; import * as ReportUtils from '@libs/ReportUtils'; -import * as TransactionUtils from '@libs/TransactionUtils'; +import {getAllReportTransactions} from '@libs/TransactionUtils'; import type {PolicySelector} from '@pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover'; import * as PaymentMethods from '@userActions/PaymentMethods'; import * as PersistedRequests from '@userActions/PersistedRequests'; @@ -308,7 +308,7 @@ function deleteWorkspace(policyID: string, policyName: string) { : []), ]; - const reportsToArchive = Object.values(ReportConnection.getAllReports() ?? {}).filter( + const reportsToArchive = Object.values(getAllReports() ?? {}).filter( (report) => ReportUtils.isPolicyRelatedReport(report, policyID) && (ReportUtils.isChatRoom(report) || ReportUtils.isPolicyExpenseChat(report) || ReportUtils.isTaskReport(report)), ); const finallyData: OnyxUpdate[] = []; @@ -2418,7 +2418,7 @@ function createWorkspaceFromIOUPayment(iouReport: OnyxEntry): WorkspaceF }); // The expense report transactions need to have the amount reversed to negative values - const reportTransactions = TransactionUtils.getAllReportTransactions(iouReportID); + const reportTransactions = getAllReportTransactions(iouReportID); // For performance reasons, we are going to compose a merge collection data for transactions const transactionsOptimisticData: Record = {}; diff --git a/src/libs/actions/Policy/Tag.ts b/src/libs/actions/Policy/Tag.ts index 772e748ad4f2..9e5b38a1c8eb 100644 --- a/src/libs/actions/Policy/Tag.ts +++ b/src/libs/actions/Policy/Tag.ts @@ -24,7 +24,7 @@ import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; import {navigateWhenEnableFeature} from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; -import * as TransactionUtils from '@libs/TransactionUtils'; +import {getTagArrayFromName} from '@libs/TransactionUtils'; import type {PolicyTagList} from '@pages/workspace/tags/types'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -117,7 +117,7 @@ function buildOptimisticPolicyRecentlyUsedTags(policyID?: string, transactionTag const policyRecentlyUsedTags = allRecentlyUsedTags?.[`${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${policyID}`] ?? {}; const newOptimisticPolicyRecentlyUsedTags: RecentlyUsedTags = {}; - TransactionUtils.getTagArrayFromName(transactionTags).forEach((tag, index) => { + getTagArrayFromName(transactionTags).forEach((tag, index) => { if (!tag) { return; } diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 2cace722dbdc..3df841e4fe52 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -81,10 +81,47 @@ import {extractPolicyIDFromPath, getPolicy} from '@libs/PolicyUtils'; import processReportIDDeeplink from '@libs/processReportIDDeeplink'; import * as Pusher from '@libs/Pusher/pusher'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; -import * as ReportConnection from '@libs/ReportConnection'; -import type {OptimisticAddCommentReportAction} from '@libs/ReportUtils'; -import * as ReportUtils from '@libs/ReportUtils'; -import {doesReportBelongToWorkspace} from '@libs/ReportUtils'; +import {getAllReports, getReport} from '@libs/ReportConnection'; +import type {OptimisticAddCommentReportAction, OptimisticChatReport} from '@libs/ReportUtils'; +import { + buildOptimisticAddCommentReportAction, + buildOptimisticChangeFieldAction, + buildOptimisticChatReport, + buildOptimisticCreatedReportAction, + buildOptimisticExportIntegrationAction, + buildOptimisticGroupChatReport, + buildOptimisticRenamedRoomReportAction, + buildOptimisticRoomDescriptionUpdatedReportAction, + buildOptimisticTaskCommentReportAction, + buildOptimisticTaskReport, + buildOptimisticTaskReportAction, + canUserPerformWriteAction as canUserPerformWriteActionReportUtils, + completeShortMention, + doesReportBelongToWorkspace, + findLastAccessedReport, + formatReportLastMessageText, + getChatByParticipants, + getChildReportNotificationPreference, + getDefaultNotificationPreferenceForReport, + getFieldViolation, + getLastVisibleMessage, + getOptimisticDataForParentReportAction, + getOriginalReportID, + getParsedComment, + getPendingChatMembers, + getReportFieldKey, + getReportIDFromLink, + getReportLastMessage, + getReportNotificationPreference, + getReportViolations, + getRouteFromLink, + isChatThread as isChatThreadReportUtils, + isConciergeChatReport, + isGroupChat as isGroupChatReportUtils, + isMoneyRequestReport, + isSelfDM, + isValidReportIDFromPath, +} from '@libs/ReportUtils'; import shouldSkipDeepLinkNavigation from '@libs/shouldSkipDeepLinkNavigation'; import {getNavatticURL} from '@libs/TourUtils'; import Visibility from '@libs/Visibility'; @@ -319,8 +356,8 @@ registerPaginationConfig({ resourceCollectionKey: ONYXKEYS.COLLECTION.REPORT_ACTIONS, pageCollectionKey: ONYXKEYS.COLLECTION.REPORT_ACTIONS_PAGES, sortItems: (reportActions, reportID) => { - const report = ReportUtils.getReport(reportID); - const canUserPerformWriteAction = ReportUtils.canUserPerformWriteAction(report); + const report = getReport(reportID); + const canUserPerformWriteAction = canUserPerformWriteActionReportUtils(report); return ReportActionsUtils.getSortedReportActionsForDisplay(reportActions, canUserPerformWriteAction, true); }, getItemID: (reportAction) => reportAction.reportActionID, @@ -499,7 +536,7 @@ function addActions(reportID: string, text = '', file?: FileObject) { let commandName: typeof WRITE_COMMANDS.ADD_COMMENT | typeof WRITE_COMMANDS.ADD_ATTACHMENT | typeof WRITE_COMMANDS.ADD_TEXT_AND_ATTACHMENT = WRITE_COMMANDS.ADD_COMMENT; if (text && !file) { - const reportComment = ReportUtils.buildOptimisticAddCommentReportAction(text, undefined, undefined, undefined, undefined, reportID); + const reportComment = buildOptimisticAddCommentReportAction(text, undefined, undefined, undefined, undefined, reportID); reportCommentAction = reportComment.reportAction; reportCommentText = reportComment.commentText; } @@ -508,13 +545,13 @@ function addActions(reportID: string, text = '', file?: FileObject) { // When we are adding an attachment we will call AddAttachment. // It supports sending an attachment with an optional comment and AddComment supports adding a single text comment only. commandName = WRITE_COMMANDS.ADD_ATTACHMENT; - const attachment = ReportUtils.buildOptimisticAddCommentReportAction(text, file, undefined, undefined, undefined, reportID); + const attachment = buildOptimisticAddCommentReportAction(text, file, undefined, undefined, undefined, reportID); attachmentAction = attachment.reportAction; } if (text && file) { // When there is both text and a file, the text for the report comment needs to be parsed) - reportCommentText = ReportUtils.getParsedComment(text ?? '', {reportID}); + reportCommentText = getParsedComment(text ?? '', {reportID}); // And the API command needs to go to the new API which supports combining both text and attachments in a single report action commandName = WRITE_COMMANDS.ADD_TEXT_AND_ATTACHMENT; @@ -524,7 +561,7 @@ function addActions(reportID: string, text = '', file?: FileObject) { const lastAction = attachmentAction ?? reportCommentAction; const currentTime = DateUtils.getDBTimeWithSkew(); const lastComment = ReportActionsUtils.getReportActionMessage(lastAction); - const lastCommentText = ReportUtils.formatReportLastMessageText(lastComment?.text ?? ''); + const lastCommentText = formatReportLastMessageText(lastComment?.text ?? ''); const optimisticReport: Partial = { lastVisibleActionCreated: lastAction?.created, @@ -535,12 +572,12 @@ function addActions(reportID: string, text = '', file?: FileObject) { lastReadTime: currentTime, }; - const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; - const shouldUpdateNotificationPrefernece = !isEmptyObject(report) && ReportUtils.getReportNotificationPreference(report) === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; + const report = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const shouldUpdateNotificationPrefernece = !isEmptyObject(report) && getReportNotificationPreference(report) === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; if (shouldUpdateNotificationPrefernece) { optimisticReport.participants = { - [currentUserAccountID]: {notificationPreference: ReportUtils.getDefaultNotificationPreferenceForReport(report)}, + [currentUserAccountID]: {notificationPreference: getDefaultNotificationPreferenceForReport(report)}, }; } @@ -565,7 +602,7 @@ function addActions(reportID: string, text = '', file?: FileObject) { idempotencyKey: Str.guid(), }; - if (reportIDDeeplinkedFromOldDot === reportID && ReportUtils.isConciergeChatReport(report)) { + if (reportIDDeeplinkedFromOldDot === reportID && isConciergeChatReport(report)) { parameters.isOldDotConciergeChat = true; } @@ -638,7 +675,7 @@ function addActions(reportID: string, text = '', file?: FileObject) { ]; // Update optimistic data for parent report action if the report is a child report - const optimisticParentReportData = ReportUtils.getOptimisticDataForParentReportAction(reportID, currentTime, CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); + const optimisticParentReportData = getOptimisticDataForParentReportAction(reportID, currentTime, CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); optimisticParentReportData.forEach((parentReportData) => { if (isEmptyObject(parentReportData)) { return; @@ -713,7 +750,7 @@ function updateGroupChatName(reportID: string, reportName: string) { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, value: { - reportName: ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.reportName ?? null, + reportName: getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.reportName ?? null, pendingFields: { reportName: null, }, @@ -742,7 +779,7 @@ function updateGroupChatAvatar(reportID: string, file?: File | CustomRNImageMani }, ]; - const fetchedReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const fetchedReport = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, @@ -798,7 +835,7 @@ function openReport( reportID: string, reportActionID?: string, participantLoginList: string[] = [], - newReportObject?: ReportUtils.OptimisticChatReport, + newReportObject?: OptimisticChatReport, parentReportActionID = '-1', isFromDeepLink = false, participantAccountIDList: number[] = [], @@ -811,7 +848,7 @@ function openReport( const optimisticReport = reportActionsExist(reportID) ? {} : { - reportName: ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.reportName ?? CONST.REPORT.DEFAULT_REPORT_NAME, + reportName: getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.reportName ?? CONST.REPORT.DEFAULT_REPORT_NAME, }; const optimisticData: OnyxUpdate[] = [ @@ -906,7 +943,7 @@ function openReport( } } - const isGroupChat = ReportUtils.isGroupChat(newReportObject); + const isGroupChat = isGroupChatReportUtils(newReportObject); if (isGroupChat) { parameters.chatType = CONST.REPORT.CHAT_TYPE.GROUP; parameters.groupChatAdminLogins = currentUserEmail; @@ -949,7 +986,7 @@ function openReport( if (newReportObject.ownerAccountID && newReportObject.ownerAccountID !== CONST.REPORT.OWNER_ACCOUNT_ID_FAKE) { emailCreatingAction = allPersonalDetails?.[newReportObject.ownerAccountID]?.login ?? ''; } - const optimisticCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(emailCreatingAction); + const optimisticCreatedAction = buildOptimisticCreatedReportAction(emailCreatingAction); optimisticData.push({ onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, @@ -1036,7 +1073,7 @@ function openReport( } } - parameters.clientLastReadTime = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.lastReadTime ?? ''; + parameters.clientLastReadTime = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.lastReadTime ?? ''; const paginationConfig = { resourceID: reportID, @@ -1077,21 +1114,21 @@ function navigateToAndOpenReport( optimisticReportID?: string, isGroupChat = false, ) { - let newChat: ReportUtils.OptimisticChatReport | undefined; + let newChat: OptimisticChatReport | undefined; let chat: OnyxEntry; const participantAccountIDs = PersonalDetailsUtils.getAccountIDsByLogins(userLogins); // If we are not creating a new Group Chat then we are creating a 1:1 DM and will look for an existing chat if (!isGroupChat) { - chat = ReportUtils.getChatByParticipants([...participantAccountIDs, currentUserAccountID]); + chat = getChatByParticipants([...participantAccountIDs, currentUserAccountID]); } if (isEmptyObject(chat)) { if (isGroupChat) { // If we are creating a group chat then participantAccountIDs is expected to contain currentUserAccountID - newChat = ReportUtils.buildOptimisticGroupChatReport(participantAccountIDs, reportName ?? '', avatarUri ?? '', optimisticReportID, CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS); + newChat = buildOptimisticGroupChatReport(participantAccountIDs, reportName ?? '', avatarUri ?? '', optimisticReportID, CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS); } else { - newChat = ReportUtils.buildOptimisticChatReport( + newChat = buildOptimisticChatReport( [...participantAccountIDs, currentUserAccountID], undefined, undefined, @@ -1123,10 +1160,10 @@ function navigateToAndOpenReport( * @param participantAccountIDs of user logins to start a chat report with. */ function navigateToAndOpenReportWithAccountIDs(participantAccountIDs: number[]) { - let newChat: ReportUtils.OptimisticChatReport | undefined; - const chat = ReportUtils.getChatByParticipants([...participantAccountIDs, currentUserAccountID]); + let newChat: OptimisticChatReport | undefined; + const chat = getChatByParticipants([...participantAccountIDs, currentUserAccountID]); if (!chat) { - newChat = ReportUtils.buildOptimisticChatReport([...participantAccountIDs, currentUserAccountID]); + newChat = buildOptimisticChatReport([...participantAccountIDs, currentUserAccountID]); } const report = chat ?? newChat; @@ -1147,10 +1184,10 @@ function navigateToAndOpenChildReport(childReportID = '-1', parentReportAction: Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(childReportID)); } else { const participantAccountIDs = [...new Set([currentUserAccountID, Number(parentReportAction.actorAccountID)])]; - const parentReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${parentReportID}`]; + const parentReport = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${parentReportID}`]; // Threads from DMs and selfDMs don't have a chatType. All other threads inherit the chatType from their parent - const childReportChatType = parentReport && ReportUtils.isSelfDM(parentReport) ? undefined : parentReport?.chatType; - const newChat = ReportUtils.buildOptimisticChatReport( + const childReportChatType = parentReport && isSelfDM(parentReport) ? undefined : parentReport?.chatType; + const newChat = buildOptimisticChatReport( participantAccountIDs, ReportActionsUtils.getReportActionText(parentReportAction), childReportChatType, @@ -1160,7 +1197,7 @@ function navigateToAndOpenChildReport(childReportID = '-1', parentReportAction: parentReport?.policyName ?? '', undefined, undefined, - ReportUtils.getChildReportNotificationPreference(parentReportAction), + getChildReportNotificationPreference(parentReportAction), parentReportAction.reportActionID, parentReportID, ); @@ -1346,7 +1383,7 @@ function markCommentAsUnread(reportID: string, reportActionCreated: string) { // If no action created date is provided, use the last action's from other user const actionCreationTime = reportActionCreated || - (latestReportActionFromOtherUsers?.created ?? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.lastVisibleActionCreated ?? DateUtils.getDBTime(0)); + (latestReportActionFromOtherUsers?.created ?? getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.lastVisibleActionCreated ?? DateUtils.getDBTime(0)); // We subtract 1 millisecond so that the lastReadTime is updated to just before a given reportAction's created date // For example, if we want to mark a report action with ID 100 and created date '2014-04-01 16:07:02.999' unread, we set the lastReadTime to '2014-04-01 16:07:02.998' @@ -1427,7 +1464,7 @@ function handleReportChanged(report: OnyxEntry) { } // Handle cleanup of stale optimistic IOU report and its report preview separately - if (report?.reportID && report.preexistingReportID && ReportUtils.isMoneyRequestReport(report) && report?.parentReportActionID) { + if (report?.reportID && report.preexistingReportID && isMoneyRequestReport(report) && report?.parentReportActionID) { Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`, { [report.parentReportActionID]: null, }); @@ -1476,7 +1513,7 @@ function handleReportChanged(report: OnyxEntry) { } if (report?.reportID) { - if (ReportUtils.isConciergeChatReport(report)) { + if (isConciergeChatReport(report)) { conciergeChatReportID = report.reportID; } } @@ -1484,7 +1521,7 @@ function handleReportChanged(report: OnyxEntry) { /** Deletes a comment from the report, basically sets it as empty string */ function deleteReportComment(reportID: string, reportAction: ReportAction) { - const originalReportID = ReportUtils.getOriginalReportID(reportID, reportAction); + const originalReportID = getOriginalReportID(reportID, reportAction); const reportActionID = reportAction.reportActionID; if (!reportActionID || !originalReportID) { @@ -1519,9 +1556,9 @@ function deleteReportComment(reportID: string, reportAction: ReportAction) { lastMessageText: '', lastVisibleActionCreated: '', }; - const {lastMessageText = '', lastMessageTranslationKey = ''} = ReportUtils.getLastVisibleMessage(originalReportID, optimisticReportActions as ReportActions); - const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; - const canUserPerformWriteAction = ReportUtils.canUserPerformWriteAction(report); + const {lastMessageText = '', lastMessageTranslationKey = ''} = getLastVisibleMessage(originalReportID, optimisticReportActions as ReportActions); + const report = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const canUserPerformWriteAction = canUserPerformWriteActionReportUtils(report); if (lastMessageText || lastMessageTranslationKey) { const lastVisibleAction = ReportActionsUtils.getLastVisibleAction(originalReportID, canUserPerformWriteAction, optimisticReportActions as ReportActions); const lastVisibleActionCreated = lastVisibleAction?.created; @@ -1586,7 +1623,7 @@ function deleteReportComment(reportID: string, reportAction: ReportAction) { // Update optimistic data for parent report action if the report is a child report and the reportAction has no visible child const childVisibleActionCount = reportAction.childVisibleActionCount ?? 0; if (childVisibleActionCount === 0) { - const optimisticParentReportData = ReportUtils.getOptimisticDataForParentReportAction( + const optimisticParentReportData = getOptimisticDataForParentReportAction( originalReportID, optimisticReport?.lastVisibleActionCreated ?? '', CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, @@ -1651,7 +1688,7 @@ function handleUserDeletedLinksInHtml(newCommentText: string, originalCommentMar return newCommentText; } - const textWithMention = ReportUtils.completeShortMention(newCommentText); + const textWithMention = completeShortMention(newCommentText); const htmlForNewComment = Parser.replace(textWithMention, { extras: {videoAttributeCache}, @@ -1662,9 +1699,9 @@ function handleUserDeletedLinksInHtml(newCommentText: string, originalCommentMar /** Saves a new message for a comment. Marks the comment as edited, which will be reflected in the UI. */ function editReportComment(reportID: string, originalReportAction: OnyxEntry, textForNewComment: string, videoAttributeCache?: Record) { - const originalReportID = ReportUtils.getOriginalReportID(reportID, originalReportAction); - const report = ReportUtils.getReport(originalReportID ?? '-1'); - const canUserPerformWriteAction = ReportUtils.canUserPerformWriteAction(report); + const originalReportID = getOriginalReportID(reportID, originalReportAction); + const report = getReport(originalReportID ?? '-1'); + const canUserPerformWriteAction = canUserPerformWriteActionReportUtils(report); if (!originalReportID || !originalReportAction) { return; @@ -1732,7 +1769,7 @@ function editReportComment(reportID: string, originalReportAction: OnyxEntry = { [`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]: null, [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`]: null, @@ -2442,7 +2479,7 @@ function updatePolicyRoomName(policyRoomReport: Report, policyRoomName: string) return; } - const optimisticRenamedAction = ReportUtils.buildOptimisticRenamedRoomReportAction(policyRoomName, previousName ?? ''); + const optimisticRenamedAction = buildOptimisticRenamedRoomReportAction(policyRoomName, previousName ?? ''); const optimisticData: OnyxUpdate[] = [ { @@ -2544,7 +2581,7 @@ function shouldShowReportActionNotification(reportID: string, action: ReportActi } // We don't want to send a local notification if the user preference is daily, mute or hidden. - const notificationPreference = ReportUtils.getReportNotificationPreference(ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]); + const notificationPreference = getReportNotificationPreference(getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]); if (notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS) { Log.info(`${tag} No notification because user preference is to be notified: ${notificationPreference}`); return false; @@ -2562,7 +2599,7 @@ function shouldShowReportActionNotification(reportID: string, action: ReportActi return false; } - const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const report = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; if (!report || (report && report.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE)) { Log.info(`${tag} No notification because the report does not exist or is pending deleted`, false); return false; @@ -2597,7 +2634,7 @@ function showReportActionNotification(reportID: string, reportAction: ReportActi Log.info('[LocalNotification] Creating notification'); const localReportID = `${ONYXKEYS.COLLECTION.REPORT}${reportID}`; - const report = ReportConnection.getAllReports()?.[localReportID] ?? null; + const report = getAllReports()?.[localReportID] ?? null; if (!report) { Log.hmmm("[LocalNotification] couldn't show report action notification because the report wasn't found", {localReportID, reportActionID: reportAction.reportActionID}); return; @@ -2733,7 +2770,7 @@ function toggleEmojiReaction( paramSkinTone: number = preferredSkinTone, ignoreSkinToneOnCompare = false, ) { - const originalReportID = ReportUtils.getOriginalReportID(reportID, reportAction); + const originalReportID = getOriginalReportID(reportID, reportAction); if (!originalReportID) { return; @@ -2762,7 +2799,7 @@ function toggleEmojiReaction( } function openReportFromDeepLink(url: string) { - const reportID = ReportUtils.getReportIDFromLink(url); + const reportID = getReportIDFromLink(url); const isAuthenticated = Session.hasAuthToken(); if (reportID && !isAuthenticated) { @@ -2778,7 +2815,7 @@ function openReportFromDeepLink(url: string) { Onyx.set(ONYXKEYS.IS_CHECKING_PUBLIC_ROOM, false); } - const route = ReportUtils.getRouteFromLink(url); + const route = getRouteFromLink(url); // If we are not authenticated and are navigating to a public screen, we don't want to navigate again to the screen after sign-in/sign-up if (!isAuthenticated && isPublicScreenRoute(route)) { @@ -2846,13 +2883,13 @@ function getCurrentUserAccountID(): number { } function navigateToMostRecentReport(currentReport: OnyxEntry) { - const lastAccessedReportID = ReportUtils.findLastAccessedReport(false, false, undefined, currentReport?.reportID)?.reportID; + const lastAccessedReportID = findLastAccessedReport(false, false, undefined, currentReport?.reportID)?.reportID; if (lastAccessedReportID) { const lastAccessedReportRoute = ROUTES.REPORT_WITH_ID.getRoute(lastAccessedReportID ?? '-1'); Navigation.goBack(lastAccessedReportRoute); } else { - const isChatThread = ReportUtils.isChatThread(currentReport); + const isChatThread = isChatThreadReportUtils(currentReport); // If it is not a chat thread we should call Navigation.goBack to pop the current route first before navigating to Concierge. if (!isChatThread) { @@ -2864,7 +2901,7 @@ function navigateToMostRecentReport(currentReport: OnyxEntry) { } function getMostRecentReportID(currentReport: OnyxEntry) { - const lastAccessedReportID = ReportUtils.findLastAccessedReport(false, false, undefined, currentReport?.reportID)?.reportID; + const lastAccessedReportID = findLastAccessedReport(false, false, undefined, currentReport?.reportID)?.reportID; return lastAccessedReportID ?? conciergeChatReportID; } @@ -2874,15 +2911,15 @@ function joinRoom(report: OnyxEntry) { } updateNotificationPreference( report.reportID, - ReportUtils.getReportNotificationPreference(report), - ReportUtils.getDefaultNotificationPreferenceForReport(report), + getReportNotificationPreference(report), + getDefaultNotificationPreferenceForReport(report), report.parentReportID, report.parentReportActionID, ); } function leaveGroupChat(reportID: string) { - const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const report = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; if (!report) { Log.warn('Attempting to leave Group Chat that does not existing locally'); return; @@ -2940,12 +2977,12 @@ function leaveGroupChat(reportID: string) { /** Leave a report by setting the state to submitted and closed */ function leaveRoom(reportID: string, isWorkspaceMemberLeavingWorkspaceRoom = false) { - const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const report = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; if (!report) { return; } - const isChatThread = ReportUtils.isChatThread(report); + const isChatThread = isChatThreadReportUtils(report); // Pusher's leavingStatus should be sent earlier. // Place the broadcast before calling the LeaveRoom API to prevent a race condition @@ -3023,7 +3060,7 @@ function leaveRoom(reportID: string, isWorkspaceMemberLeavingWorkspaceRoom = fal failureData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`, - value: {[report.parentReportActionID]: {childReportNotificationPreference: ReportUtils.getReportNotificationPreference(report, false)}}, + value: {[report.parentReportActionID]: {childReportNotificationPreference: getReportNotificationPreference(report, false)}}, }); } @@ -3044,12 +3081,12 @@ function leaveRoom(reportID: string, isWorkspaceMemberLeavingWorkspaceRoom = fal /** Invites people to a room */ function inviteToRoom(reportID: string, inviteeEmailsToAccountIDs: InvitedEmailsToAccountIDs) { - const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const report = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; if (!report) { return; } - const defaultNotificationPreference = ReportUtils.getDefaultNotificationPreferenceForReport(report); + const defaultNotificationPreference = getDefaultNotificationPreferenceForReport(report); const inviteeEmails = Object.keys(inviteeEmailsToAccountIDs); const inviteeAccountIDs = Object.values(inviteeEmailsToAccountIDs); @@ -3071,7 +3108,7 @@ function inviteToRoom(reportID: string, inviteeEmailsToAccountIDs: InvitedEmails ); const newPersonalDetailsOnyxData = PersonalDetailsUtils.getPersonalDetailsOnyxDataForOptimisticUsers(newLogins, newAccountIDs); - const pendingChatMembers = ReportUtils.getPendingChatMembers(inviteeAccountIDs, report?.pendingChatMembers ?? [], CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); + const pendingChatMembers = getPendingChatMembers(inviteeAccountIDs, report?.pendingChatMembers ?? [], CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); const newParticipantAccountCleanUp = newAccountIDs.reduce>((participantCleanUp, newAccountID) => { // eslint-disable-next-line no-param-reassign @@ -3127,7 +3164,7 @@ function inviteToRoom(reportID: string, inviteeEmailsToAccountIDs: InvitedEmails }, ]; - if (ReportUtils.isGroupChat(report)) { + if (isGroupChatReportUtils(report)) { const parameters: InviteToGroupChatParams = { reportID, inviteeEmails, @@ -3149,7 +3186,7 @@ function inviteToRoom(reportID: string, inviteeEmailsToAccountIDs: InvitedEmails } function clearAddRoomMemberError(reportID: string, invitedAccountID: string) { - const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const report = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, { pendingChatMembers: report?.pendingChatMembers?.filter((pendingChatMember) => pendingChatMember.accountID !== invitedAccountID), participants: { @@ -3211,7 +3248,7 @@ function inviteToGroupChat(reportID: string, inviteeEmailsToAccountIDs: InvitedE * Please see https://github.com/Expensify/App/blob/main/README.md#Security for more details */ function removeFromRoom(reportID: string, targetAccountIDs: number[]) { - const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const report = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; if (!report) { return; } @@ -3220,7 +3257,7 @@ function removeFromRoom(reportID: string, targetAccountIDs: number[]) { targetAccountIDs.forEach((accountID) => { removeParticipantsData[accountID] = null; }); - const pendingChatMembers = ReportUtils.getPendingChatMembers(targetAccountIDs, report?.pendingChatMembers ?? [], CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE); + const pendingChatMembers = getPendingChatMembers(targetAccountIDs, report?.pendingChatMembers ?? [], CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE); const optimisticData: OnyxUpdate[] = [ { @@ -3255,7 +3292,7 @@ function removeFromRoom(reportID: string, targetAccountIDs: number[]) { }, ]; - if (ReportUtils.isGroupChat(report)) { + if (isGroupChatReportUtils(report)) { const parameters: RemoveFromGroupChatParams = { reportID, accountIDList: targetAccountIDs.join(), @@ -3291,7 +3328,7 @@ function openLastOpenedPublicRoom(lastOpenedPublicRoomID: string) { /** Flag a comment as offensive */ function flagComment(reportID: string, reportAction: OnyxEntry, severity: string) { - const originalReportID = ReportUtils.getOriginalReportID(reportID, reportAction); + const originalReportID = getOriginalReportID(reportID, reportAction); const message = ReportActionsUtils.getReportActionMessage(reportAction); if (!message || !reportAction) { @@ -3493,11 +3530,11 @@ function prepareOnboardingOptimisticData( const integrationName = userReportedIntegration ? CONST.ONBOARDING_ACCOUNTING_MAPPING[userReportedIntegration] : ''; const actorAccountID = CONST.ACCOUNT_ID.CONCIERGE; - const targetChatReport = ReportUtils.getChatByParticipants([actorAccountID, currentUserAccountID]); + const targetChatReport = getChatByParticipants([actorAccountID, currentUserAccountID]); const {reportID: targetChatReportID = '', policyID: targetChatPolicyID = ''} = targetChatReport ?? {}; // Text message - const textComment = ReportUtils.buildOptimisticAddCommentReportAction(data.message, undefined, actorAccountID, 1); + const textComment = buildOptimisticAddCommentReportAction(data.message, undefined, actorAccountID, 1); const textCommentAction: OptimisticAddCommentReportAction = textComment.reportAction; const textMessage: AddCommentOrAttachementParams = { reportID: targetChatReportID, @@ -3508,7 +3545,7 @@ function prepareOnboardingOptimisticData( let videoCommentAction: OptimisticAddCommentReportAction | null = null; let videoMessage: AddCommentOrAttachementParams | null = null; if ('video' in data && data.video) { - const videoComment = ReportUtils.buildOptimisticAddCommentReportAction(CONST.ATTACHMENT_MESSAGE_TEXT, undefined, actorAccountID, 2); + const videoComment = buildOptimisticAddCommentReportAction(CONST.ATTACHMENT_MESSAGE_TEXT, undefined, actorAccountID, 2); videoCommentAction = videoComment.reportAction; videoMessage = { reportID: targetChatReportID, @@ -3547,7 +3584,7 @@ function prepareOnboardingOptimisticData( integrationName, }) : task.title; - const currentTask = ReportUtils.buildOptimisticTaskReport( + const currentTask = buildOptimisticTaskReport( actorAccountID, currentUserAccountID, targetChatReportID, @@ -3556,20 +3593,12 @@ function prepareOnboardingOptimisticData( targetChatPolicyID, CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, ); - const taskCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(CONST.EMAIL.CONCIERGE); - const taskReportAction = ReportUtils.buildOptimisticTaskCommentReportAction( - currentTask.reportID, - taskTitle, - 0, - `task for ${taskTitle}`, - targetChatReportID, - actorAccountID, - index + 3, - ); + const taskCreatedAction = buildOptimisticCreatedReportAction(CONST.EMAIL.CONCIERGE); + const taskReportAction = buildOptimisticTaskCommentReportAction(currentTask.reportID, taskTitle, 0, `task for ${taskTitle}`, targetChatReportID, actorAccountID, index + 3); currentTask.parentReportActionID = taskReportAction.reportAction.reportActionID; const completedTaskReportAction = task.autoCompleted - ? ReportUtils.buildOptimisticTaskReportAction(currentTask.reportID, CONST.REPORT.ACTIONS.TYPE.TASK_COMPLETED, 'marked as complete', actorAccountID, 2) + ? buildOptimisticTaskReportAction(currentTask.reportID, CONST.REPORT.ACTIONS.TYPE.TASK_COMPLETED, 'marked as complete', actorAccountID, 2) : null; return { @@ -3774,8 +3803,8 @@ function prepareOnboardingOptimisticData( lastVisibleActionCreated: '', hasOutstandingChildTask: false, }; - const report = ReportUtils.getReport(targetChatReportID); - const canUserPerformWriteAction = ReportUtils.canUserPerformWriteAction(report); + const report = getReport(targetChatReportID); + const canUserPerformWriteAction = canUserPerformWriteActionReportUtils(report); const {lastMessageText = '', lastMessageTranslationKey = ''} = ReportActionsUtils.getLastVisibleMessage(targetChatReportID, canUserPerformWriteAction); if (lastMessageText || lastMessageTranslationKey) { const lastVisibleAction = ReportActionsUtils.getLastVisibleAction(targetChatReportID, canUserPerformWriteAction); @@ -4010,14 +4039,14 @@ function searchInServer(searchInput: string, policyID?: string) { } function updateLastVisitTime(reportID: string) { - if (!ReportUtils.isValidReportIDFromPath(reportID)) { + if (!isValidReportIDFromPath(reportID)) { return; } Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`, {lastVisitTime: DateUtils.getDBTime()}); } function updateLoadingInitialReportAction(reportID: string) { - if (!ReportUtils.isValidReportIDFromPath(reportID)) { + if (!isValidReportIDFromPath(reportID)) { return; } Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`, {isLoadingInitialReportActions: false}); @@ -4055,8 +4084,8 @@ function resolveActionableMentionWhisper(reportId: string, reportAction: OnyxEnt }, }; - const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportId}`]; - const reportUpdateDataWithPreviousLastMessage = ReportUtils.getReportLastMessage(reportId, optimisticReportActions as ReportActions); + const report = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportId}`]; + const reportUpdateDataWithPreviousLastMessage = getReportLastMessage(reportId, optimisticReportActions as ReportActions); const reportUpdateDataWithCurrentLastMessage = { lastMessageTranslationKey: report?.lastMessageTranslationKey, @@ -4130,8 +4159,8 @@ function resolveActionableReportMentionWhisper( }, }; - const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportId}`]; - const reportUpdateDataWithPreviousLastMessage = ReportUtils.getReportLastMessage(reportId, optimisticReportActions as ReportActions); + const report = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportId}`]; + const reportUpdateDataWithPreviousLastMessage = getReportLastMessage(reportId, optimisticReportActions as ReportActions); const reportUpdateDataWithCurrentLastMessage = { lastMessageTranslationKey: report?.lastMessageTranslationKey, @@ -4240,7 +4269,7 @@ function setGroupDraft(newGroupDraft: Partial) { } function exportToIntegration(reportID: string, connectionName: ConnectionName) { - const action = ReportUtils.buildOptimisticExportIntegrationAction(connectionName); + const action = buildOptimisticExportIntegrationAction(connectionName); const optimisticReportActionID = action.reportActionID; const optimisticData: OnyxUpdate[] = [ @@ -4278,7 +4307,7 @@ function exportToIntegration(reportID: string, connectionName: ConnectionName) { } function markAsManuallyExported(reportID: string, connectionName: ConnectionName) { - const action = ReportUtils.buildOptimisticExportIntegrationAction(connectionName, true); + const action = buildOptimisticExportIntegrationAction(connectionName, true); const label = CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[connectionName]; const optimisticReportActionID = action.reportActionID; diff --git a/src/libs/fileDownload/index.ios.ts b/src/libs/fileDownload/index.ios.ts index 10695dacd658..7558bad70ec0 100644 --- a/src/libs/fileDownload/index.ios.ts +++ b/src/libs/fileDownload/index.ios.ts @@ -4,7 +4,7 @@ import RNFetchBlob from 'react-native-blob-util'; import RNFS from 'react-native-fs'; import Share from 'react-native-share'; import CONST from '@src/CONST'; -import * as FileUtils from './FileUtils'; +import {appendTimeToFileName, getFileName, getFileType, showGeneralErrorAlert, showPermissionErrorAlert, showSuccessAlert} from './FileUtils'; import type {FileDownload} from './types'; /** @@ -46,7 +46,7 @@ const postDownloadFile = (url: string, fileName?: string, formData?: FormData, o return response.text(); }) .then((fileData) => { - const finalFileName = FileUtils.appendTimeToFileName(fileName ?? 'Expensify'); + const finalFileName = appendTimeToFileName(fileName ?? 'Expensify'); const expensifyDir = `${RNFS.DocumentDirectoryPath}/Expensify`; const localPath = `${expensifyDir}/${finalFileName}`; return RNFS.mkdir(expensifyDir).then(() => { @@ -57,7 +57,7 @@ const postDownloadFile = (url: string, fileName?: string, formData?: FormData, o }) .catch(() => { if (!onDownloadFailed) { - FileUtils.showGeneralErrorAlert(); + showGeneralErrorAlert(); } onDownloadFailed?.(); }); @@ -107,9 +107,9 @@ function downloadVideo(fileUrl: string, fileName: string): Promise new Promise((resolve) => { let fileDownloadPromise; - const fileType = FileUtils.getFileType(fileUrl); + const fileType = getFileType(fileUrl); // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- Disabling this line for safeness as nullish coalescing works only if the value is undefined or null, and since fileName can be an empty string we want to default to `FileUtils.getFileName(url)` - const attachmentName = FileUtils.appendTimeToFileName(fileName || FileUtils.getFileName(fileUrl)); + const attachmentName = appendTimeToFileName(fileName || getFileName(fileUrl)); switch (fileType) { case CONST.ATTACHMENT_FILE_TYPE.IMAGE: @@ -134,15 +134,15 @@ const fileDownload: FileDownload = (fileUrl, fileName, successMessage, _, formDa return; } - FileUtils.showSuccessAlert(successMessage); + showSuccessAlert(successMessage); }) .catch((err: Error) => { // iOS shows permission popup only once. Subsequent request will only throw an error. // We catch the error and show a redirection link to the settings screen if (err.message === CONST.IOS_CAMERAROLL_ACCESS_ERROR) { - FileUtils.showPermissionErrorAlert(); + showPermissionErrorAlert(); } else { - FileUtils.showGeneralErrorAlert(); + showGeneralErrorAlert(); } }) .finally(() => resolve()); diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts index 58ebdacfdfef..0fec22cd9e34 100644 --- a/src/types/onyx/Report.ts +++ b/src/types/onyx/Report.ts @@ -250,4 +250,4 @@ type ReportCollectionDataSet = CollectionDataSet; +/** Model of report search result */ /** Model of report search result */ type SearchReport = { /** The ID of the report */ - reportID?: string; + reportID: string; + + /** ID of the chat report */ + chatReportID?: string; /** The name of the report */ reportName?: string; @@ -107,6 +112,43 @@ type SearchReport = { /** The action that can be performed for the report */ action?: SearchTransactionAction; + + /** The type of chat if this is a chat report */ + chatType?: ValueOf; + + /** Invoice room receiver data */ + invoiceReceiver?: InvoiceReceiver; + + /** Whether the report has a single transaction */ + isOneTransactionReport?: boolean; + + /** Whether the report is policyExpenseChat */ + isPolicyExpenseChat?: boolean; + + /** Whether the report is waiting on a bank account */ + isWaitingOnBankAccount?: boolean; + + /** If the report contains nonreimbursable expenses, send the nonreimbursable total */ + nonReimbursableTotal?: number; + + /** Account ID of the report owner */ + ownerAccountID?: number; + + /** The state that the report is currently in */ + stateNum?: ValueOf; + + /** The status of the current report */ + statusNum?: ValueOf; + + /** For expense reports, this is the total amount requested */ + unheldTotal?: number; + + /** Whether the report is archived */ + // eslint-disable-next-line @typescript-eslint/naming-convention + private_isArchived?: string; + + /** Whether the action is loading */ + isActionLoading?: boolean; }; /** Model of report action search result */ From 1eee2764053f9273a6f0057d60f0533da1df49bb Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Tue, 26 Nov 2024 17:06:54 +0100 Subject: [PATCH 03/29] lint --- src/components/Search/SearchPageHeader.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx index 1c3370cd72d5..d7b679f21891 100644 --- a/src/components/Search/SearchPageHeader.tsx +++ b/src/components/Search/SearchPageHeader.tsx @@ -182,7 +182,7 @@ function SearchPageHeader({queryJSON, hash}: SearchPageHeaderProps) { return; } - const reportIDList = (selectedReports?.filter((report) => !!report) as string[]) ?? []; + const reportIDList = selectedReports?.filter((report) => !!report) ?? []; SearchActions.exportSearchItemsToCSV( {query: status, jsonQuery: JSON.stringify(queryJSON), reportIDList, transactionIDList: selectedTransactionsKeys, policyIDs: [activeWorkspaceID ?? '']}, () => { From 765e46d7a4a1b54834e421be3d236e0733c4335d Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Wed, 27 Nov 2024 14:37:46 +0100 Subject: [PATCH 04/29] refactor imports in ReportUtils for PolicyUtils and ReportActionsUtils --- src/libs/ReportUtils.ts | 423 +++++++++++++++++++++++----------------- 1 file changed, 239 insertions(+), 184 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 799d78e3e103..3d6155477ba7 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -81,9 +81,78 @@ import Parser from './Parser'; import Permissions from './Permissions'; import * as PersonalDetailsUtils from './PersonalDetailsUtils'; import * as PhoneNumber from './PhoneNumber'; -import * as PolicyUtils from './PolicyUtils'; +import { + arePaymentsEnabled, + canSendInvoiceFromWorkspace, + getForwardsToAccount, + getPolicyEmployeeListByIdWithoutCurrentUser, + getSubmitToAccountID, + getSubmitToEmail, + isControlOnAdvancedApprovalMode, + isExpensifyTeam, + isInstantSubmitEnabled, + isPaidGroupPolicy as isPaidGroupPolicyPolicyUtils, + isPolicyAdmin as isPolicyAdminPolicyUtils, + isPolicyAuditor, + isPolicyOwner, + isSubmitAndClose, +} from './PolicyUtils'; import type {LastVisibleMessage} from './ReportActionsUtils'; -import * as ReportActionsUtils from './ReportActionsUtils'; +import { + formatLastMessageText, + getActionableJoinRequestPendingReportAction, + getAllReportActions, + getCardIssuedMessage, + getDismissedViolationMessageText, + getExportIntegrationLastMessageText, + getIOUReportIDFromReportActionPreview, + getLastClosedReportAction, + getLastVisibleAction as getLastVisibleActionReportActionsUtils, + getLastVisibleMessage as getLastVisibleMessageReportActionsUtils, + getMessageOfOldDotReportAction, + getNumberOfMoneyRequests, + getOneTransactionThreadReportID, + getOriginalMessage, + getReportAction, + getReportActionHtml, + getReportActionMessage as getReportActionMessageReportUtils, + getReportActionMessageText, + getReportActionText, + isActionableJoinRequestPending, + isActionableTrackExpense, + isActionOfType, + isApprovedAction, + isApprovedOrSubmittedReportAction, + isCardIssuedAction, + isClosedAction, + isCreatedAction, + isCreatedTaskReportAction, + isCurrentActionUnread, + isDeletedAction, + isDeletedParentAction, + isExportIntegrationAction, + isForwardedAction, + isModifiedExpenseAction, + isMoneyRequestAction, + isOldDotReportAction, + isPendingRemove, + isPolicyChangeLogAction, + isReimbursementQueuedAction, + isReportActionAttachment, + isReportPreviewAction, + isReversedTransaction, + isRoomChangeLogAction, + isSentMoneyReportAction, + isSplitBillAction, + isSubmittedAction, + isSubmittedAndClosedAction, + isThreadParentMessage, + isTrackExpenseAction, + isTransactionThread, + isUnapprovedAction, + isWhisperAction, + wasActionTakenByCurrentUser, +} from './ReportActionsUtils'; import {getAllReports} from './ReportConnection'; import { getAllReportTransactions, @@ -929,7 +998,7 @@ function isTaskReport(report: OnyxInputOrEntry): boolean { * In this case, we have added the key to the report itself */ function isCanceledTaskReport(report: OnyxInputOrEntry, parentReportAction: OnyxInputOrEntry = null): boolean { - if (!isEmptyObject(parentReportAction) && (ReportActionsUtils.getReportActionMessage(parentReportAction)?.isDeletedParentAction ?? false)) { + if (!isEmptyObject(parentReportAction) && (getReportActionMessageReportUtils(parentReportAction)?.isDeletedParentAction ?? false)) { return true; } @@ -1122,8 +1191,8 @@ function isCurrentUserInvoiceReceiver(report: OnyxEntry): boolean { } if (report?.invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.BUSINESS) { - const policy = PolicyUtils.getPolicy(report.invoiceReceiver.policyID); - return PolicyUtils.isPolicyAdmin(policy); + const policy = getPolicy(report.invoiceReceiver.policyID); + return isPolicyAdminPolicyUtils(policy); } return false; @@ -1360,7 +1429,7 @@ function isAwaitingFirstLevelApproval(report: OnyxEntry): boolean { return false; } - const submitsToAccountID = PolicyUtils.getSubmitToAccountID(getPolicy(report.policyID), report); + const submitsToAccountID = getSubmitToAccountID(getPolicy(report.policyID), report); return isProcessingReport(report) && submitsToAccountID === report.managerID; } @@ -1433,7 +1502,7 @@ function findLastAccessedReport(ignoreDomainRooms: boolean, openOnAdminRoom = fa // If it's the latter, we'll use the deeplinked report over the Concierge report, // since the Concierge report would be incorrectly selected over the deep-linked report in the logic below. - const policyMemberAccountIDs = PolicyUtils.getPolicyEmployeeListByIdWithoutCurrentUser(allPolicies, policyID, currentUserAccountID); + const policyMemberAccountIDs = getPolicyEmployeeListByIdWithoutCurrentUser(allPolicies, policyID, currentUserAccountID); const allReports = getAllReports(); let reportsValues = Object.values(allReports ?? {}); @@ -1529,11 +1598,11 @@ function isJoinRequestInAdminRoom(report: OnyxEntry): boolean { // since they are not a part of the company, and should not action it on their behalf. if (report.policyID) { const policy = getPolicy(report.policyID); - if (!PolicyUtils.isExpensifyTeam(policy?.owner) && PolicyUtils.isExpensifyTeam(currentUserPersonalDetails?.login)) { + if (!isExpensifyTeam(policy?.owner) && isExpensifyTeam(currentUserPersonalDetails?.login)) { return false; } } - return ReportActionsUtils.isActionableJoinRequestPending(report.reportID); + return isActionableJoinRequestPending(report.reportID); } /** @@ -1542,7 +1611,7 @@ function isJoinRequestInAdminRoom(report: OnyxEntry): boolean { function isAuditor(report: OnyxEntry): boolean { if (report?.policyID) { const policy = getPolicy(report.policyID); - return PolicyUtils.isPolicyAuditor(policy); + return isPolicyAuditor(policy); } if (Array.isArray(report?.permissions) && report?.permissions.length > 0) { @@ -1652,7 +1721,7 @@ function isExpenseRequest(report: OnyxInputOrEntry): report is Thread { if (isThread(report)) { const parentReportAction = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`]?.[report.parentReportActionID]; const parentReport = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; - return isExpenseReport(parentReport) && !isEmptyObject(parentReportAction) && ReportActionsUtils.isTransactionThread(parentReportAction); + return isExpenseReport(parentReport) && !isEmptyObject(parentReportAction) && isTransactionThread(parentReportAction); } return false; } @@ -1665,7 +1734,7 @@ function isIOURequest(report: OnyxInputOrEntry): boolean { if (isThread(report)) { const parentReportAction = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`]?.[report.parentReportActionID]; const parentReport = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; - return isIOUReport(parentReport) && !isEmptyObject(parentReportAction) && ReportActionsUtils.isTransactionThread(parentReportAction); + return isIOUReport(parentReport) && !isEmptyObject(parentReportAction) && isTransactionThread(parentReportAction); } return false; } @@ -1678,7 +1747,7 @@ function isTrackExpenseReport(report: OnyxInputOrEntry): boolean { if (isThread(report)) { const selfDMReportID = findSelfDMReportID(); const parentReportAction = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`]?.[report.parentReportActionID]; - return !isEmptyObject(parentReportAction) && selfDMReportID === report.parentReportID && ReportActionsUtils.isTrackExpenseAction(parentReportAction); + return !isEmptyObject(parentReportAction) && selfDMReportID === report.parentReportID && isTrackExpenseAction(parentReportAction); } return false; } @@ -1720,7 +1789,7 @@ function hasOnlyNonReimbursableTransactions(iouReportID: string | undefined): bo */ function isOneTransactionReport(reportID: string): boolean { const reportActions = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? ([] as ReportAction[]); - return ReportActionsUtils.getOneTransactionThreadReportID(reportID, reportActions) !== null; + return getOneTransactionThreadReportID(reportID, reportActions) !== null; } /* @@ -1739,8 +1808,8 @@ function isPayAtEndExpenseReport(reportID: string, transactions: Transaction[] | */ function isOneTransactionThread(reportID: string, parentReportID: string, threadParentReportAction: OnyxEntry): boolean { const parentReportActions = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`] ?? ([] as ReportAction[]); - const transactionThreadReportID = ReportActionsUtils.getOneTransactionThreadReportID(parentReportID, parentReportActions); - return reportID === transactionThreadReportID && !ReportActionsUtils.isSentMoneyReportAction(threadParentReportAction); + const transactionThreadReportID = getOneTransactionThreadReportID(parentReportID, parentReportActions); + return reportID === transactionThreadReportID && !isSentMoneyReportAction(threadParentReportAction); } /** @@ -1749,7 +1818,7 @@ function isOneTransactionThread(reportID: string, parentReportID: string, thread function getDisplayedReportID(reportID: string): string { const report = getReport(reportID); const parentReportID = report?.parentReportID ?? ''; - const parentReportAction = ReportActionsUtils.getReportAction(parentReportID, report?.parentReportActionID ?? ''); + const parentReportAction = getReportAction(parentReportID, report?.parentReportActionID ?? ''); return isOneTransactionThread(reportID, parentReportID, parentReportAction) ? parentReportID : reportID; } @@ -1816,15 +1885,15 @@ function canAddOrDeleteTransactions(moneyRequestReport: OnyxEntry): bool } const policy = getPolicy(moneyRequestReport?.policyID); - if (PolicyUtils.isInstantSubmitEnabled(policy) && PolicyUtils.isSubmitAndClose(policy) && hasOnlyNonReimbursableTransactions(moneyRequestReport?.reportID)) { + if (isInstantSubmitEnabled(policy) && isSubmitAndClose(policy) && hasOnlyNonReimbursableTransactions(moneyRequestReport?.reportID)) { return false; } - if (PolicyUtils.isInstantSubmitEnabled(policy) && PolicyUtils.isSubmitAndClose(policy) && !PolicyUtils.arePaymentsEnabled(policy)) { + if (isInstantSubmitEnabled(policy) && isSubmitAndClose(policy) && !arePaymentsEnabled(policy)) { return false; } - if (PolicyUtils.isInstantSubmitEnabled(policy) && isProcessingReport(moneyRequestReport)) { + if (isInstantSubmitEnabled(policy) && isProcessingReport(moneyRequestReport)) { return isAwaitingFirstLevelApproval(moneyRequestReport); } @@ -1847,7 +1916,7 @@ function canAddTransaction(moneyRequestReport: OnyxEntry): boolean { return false; } - if (isReportInGroupPolicy(moneyRequestReport) && isProcessingReport(moneyRequestReport) && !PolicyUtils.isInstantSubmitEnabled(getPolicy(moneyRequestReport?.policyID))) { + if (isReportInGroupPolicy(moneyRequestReport) && isProcessingReport(moneyRequestReport) && !isInstantSubmitEnabled(getPolicy(moneyRequestReport?.policyID))) { return false; } @@ -1874,9 +1943,9 @@ function canDeleteReportAction(reportAction: OnyxInputOrEntry, rep const isActionOwner = reportAction?.actorAccountID === currentUserAccountID; const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`] ?? null; - if (ReportActionsUtils.isMoneyRequestAction(reportAction)) { + if (isMoneyRequestAction(reportAction)) { // For now, users cannot delete split actions - const isSplitAction = ReportActionsUtils.getOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT; + const isSplitAction = getOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT; if (isSplitAction) { return false; @@ -1893,7 +1962,7 @@ function canDeleteReportAction(reportAction: OnyxInputOrEntry, rep if ( reportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT || reportAction?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || - ReportActionsUtils.isCreatedTaskReportAction(reportAction) || + isCreatedTaskReportAction(reportAction) || reportAction?.actorAccountID === CONST.ACCOUNT_ID.CONCIERGE ) { return false; @@ -1979,7 +2048,7 @@ function formatReportLastMessageText(lastMessageText: string, isModifiedExpenseM return String(lastMessageText).trim().replace(CONST.REGEX.LINE_BREAK, '').trim(); } - return ReportActionsUtils.formatLastMessageText(lastMessageText); + return formatLastMessageText(lastMessageText); } /** @@ -2581,7 +2650,7 @@ function getUserDetailTooltipText(accountID: number, fallbackUserDisplayName = ' function getDeletedParentActionMessageForChatReport(reportAction: OnyxEntry): string { // By default, let us display [Deleted message] let deletedMessageText = Localize.translateLocal('parentReportAction.deletedMessage'); - if (ReportActionsUtils.isCreatedTaskReportAction(reportAction)) { + if (isCreatedTaskReportAction(reportAction)) { // For canceled task report, let us display [Deleted task] deletedMessageText = Localize.translateLocal('parentReportAction.deletedTask'); } @@ -2598,7 +2667,7 @@ function getReimbursementQueuedActionMessage( ): string { const report = typeof reportOrID === 'string' ? getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] : reportOrID; const submitterDisplayName = getDisplayNameForParticipant(report?.ownerAccountID, shouldUseShortDisplayName) ?? ''; - const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction); + const originalMessage = getOriginalMessage(reportAction); let messageKey: TranslationPaths; if (originalMessage?.paymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) { messageKey = 'iou.waitingOnEnabledWallet'; @@ -2618,7 +2687,7 @@ function getReimbursementDeQueuedActionMessage( isLHNPreview = false, ): string { const report = typeof reportOrID === 'string' ? getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] : reportOrID; - const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction); + const originalMessage = getOriginalMessage(reportAction); const amount = originalMessage?.amount; const currency = originalMessage?.currency; const formattedAmount = CurrencyUtils.convertToDisplayString(amount, currency); @@ -2727,10 +2796,10 @@ function buildOptimisticCancelPaymentReportAction(expenseReportID: string, amoun */ function getLastVisibleMessage(reportID: string | undefined, actionsToMerge: ReportActions = {}): LastVisibleMessage { const report = getReportOrDraftReport(reportID); - const lastVisibleAction = ReportActionsUtils.getLastVisibleAction(reportID ?? '-1', canUserPerformWriteAction(report), actionsToMerge); + const lastVisibleAction = getLastVisibleActionReportActionsUtils(reportID ?? '-1', canUserPerformWriteAction(report), actionsToMerge); // For Chat Report with deleted parent actions, let us fetch the correct message - if (ReportActionsUtils.isDeletedParentAction(lastVisibleAction) && !isEmptyObject(report) && isChatReport(report)) { + if (isDeletedParentAction(lastVisibleAction) && !isEmptyObject(report) && isChatReport(report)) { const lastMessageText = getDeletedParentActionMessageForChatReport(lastVisibleAction); return { lastMessageText, @@ -2738,7 +2807,7 @@ function getLastVisibleMessage(reportID: string | undefined, actionsToMerge: Rep } // Fetch the last visible message for report represented by reportID and based on actions to merge. - return ReportActionsUtils.getLastVisibleMessage(reportID ?? '-1', canUserPerformWriteAction(report), actionsToMerge); + return getLastVisibleMessageReportActionsUtils(reportID ?? '-1', canUserPerformWriteAction(report), actionsToMerge); } /** @@ -2788,12 +2857,12 @@ function getReasonAndReportActionThatRequiresAttention( return null; } - const reportActions = ReportActionsUtils.getAllReportActions(optionOrReport.reportID); + const reportActions = getAllReportActions(optionOrReport.reportID); if (isJoinRequestInAdminRoom(optionOrReport)) { return { reason: CONST.REQUIRES_ATTENTION_REASONS.HAS_JOIN_REQUEST, - reportAction: ReportActionsUtils.getActionableJoinRequestPendingReportAction(optionOrReport.reportID), + reportAction: getActionableJoinRequestPendingReportAction(optionOrReport.reportID), }; } @@ -2931,8 +3000,8 @@ function getPolicyExpenseChatName(report: OnyxEntry, policy?: OnyxEntry< // If this user is not admin and this policy expense chat has been archived because of account merging, this must be an old workspace chat // of the account which was merged into the current user's account. Use the name of the policy as the name of the report. if (isArchivedRoom(report, getReportNameValuePairs(report?.reportID))) { - const lastAction = ReportActionsUtils.getLastVisibleAction(report?.reportID ?? '-1'); - const archiveReason = ReportActionsUtils.isClosedAction(lastAction) ? ReportActionsUtils.getOriginalMessage(lastAction)?.reason : CONST.REPORT.ARCHIVE_REASON.DEFAULT; + const lastAction = getLastVisibleActionReportActionsUtils(report?.reportID ?? '-1'); + const archiveReason = isClosedAction(lastAction) ? getOriginalMessage(lastAction)?.reason : CONST.REPORT.ARCHIVE_REASON.DEFAULT; if (archiveReason === CONST.REPORT.ARCHIVE_REASON.ACCOUNT_MERGED && policyExpenseChatRole !== CONST.POLICY.ROLE.ADMIN) { return getPolicyName(report, false, policy); } @@ -2943,13 +3012,13 @@ function getPolicyExpenseChatName(report: OnyxEntry, policy?: OnyxEntry< } function getArchiveReason(reportActions: OnyxEntry): ValueOf | undefined { - const lastClosedReportAction = ReportActionsUtils.getLastClosedReportAction(reportActions); + const lastClosedReportAction = getLastClosedReportAction(reportActions); if (!lastClosedReportAction) { return undefined; } - return ReportActionsUtils.isClosedAction(lastClosedReportAction) ? ReportActionsUtils.getOriginalMessage(lastClosedReportAction)?.reason : CONST.REPORT.ARCHIVE_REASON.DEFAULT; + return isClosedAction(lastClosedReportAction) ? getOriginalMessage(lastClosedReportAction)?.reason : CONST.REPORT.ARCHIVE_REASON.DEFAULT; } /** @@ -2963,7 +3032,7 @@ function isReportFieldOfTypeTitle(reportField: OnyxEntry): bo * Check if Report has any held expenses */ function isHoldCreator(transaction: OnyxEntry, reportID: string): boolean { - const holdReportAction = ReportActionsUtils.getReportAction(reportID, `${transaction?.comment?.hold ?? ''}`); + const holdReportAction = getReportAction(reportID, `${transaction?.comment?.hold ?? ''}`); return isActionCreator(holdReportAction); } @@ -3165,14 +3234,14 @@ function getTransactionCommentObject(transaction: OnyxEntry): Comme * On its own, it only controls allowing/disallowing navigating to the editing pages or showing/hiding the 'Edit' icon on report actions */ function canEditMoneyRequest(reportAction: OnyxInputOrEntry>, linkedTransaction?: OnyxEntry): boolean { - const isDeleted = ReportActionsUtils.isDeletedAction(reportAction); + const isDeleted = isDeletedAction(reportAction); if (isDeleted) { return false; } const allowedReportActionType: Array> = [CONST.IOU.REPORT_ACTION_TYPE.TRACK, CONST.IOU.REPORT_ACTION_TYPE.CREATE]; - const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction); + const originalMessage = getOriginalMessage(reportAction); const actionType = originalMessage?.type; if (!actionType || !allowedReportActionType.includes(actionType)) { @@ -3214,7 +3283,7 @@ function canEditMoneyRequest(reportAction: OnyxInputOrEntry CONST.EDIT_REQUEST_FIELD.DISTANCE_RATE, ]; - if (!ReportActionsUtils.isMoneyRequestAction(reportAction) || !canEditMoneyRequest(reportAction)) { + if (!isMoneyRequestAction(reportAction) || !canEditMoneyRequest(reportAction)) { return false; } @@ -3246,7 +3315,7 @@ function canEditFieldOfMoneyRequest(reportAction: OnyxInputOrEntry return true; } - const iouMessage = ReportActionsUtils.getOriginalMessage(reportAction); + const iouMessage = getOriginalMessage(reportAction); const moneyRequestReport = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${iouMessage?.IOUReportID}`] ?? ({} as Report); const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${iouMessage?.IOUTransactionID}`] ?? ({} as Transaction); @@ -3292,26 +3361,26 @@ function canEditFieldOfMoneyRequest(reportAction: OnyxInputOrEntry */ function canEditReportAction(reportAction: OnyxInputOrEntry): boolean { const isCommentOrIOU = reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT || reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU; - const message = reportAction ? ReportActionsUtils.getReportActionMessage(reportAction) : undefined; + const message = reportAction ? getReportActionMessageReportUtils(reportAction) : undefined; return !!( reportAction?.actorAccountID === currentUserAccountID && isCommentOrIOU && - (!ReportActionsUtils.isMoneyRequestAction(reportAction) || canEditMoneyRequest(reportAction)) && // Returns true for non-IOU actions + (!isMoneyRequestAction(reportAction) || canEditMoneyRequest(reportAction)) && // Returns true for non-IOU actions !isReportMessageAttachment(message) && ((!reportAction.isAttachmentWithText && !reportAction.isAttachmentOnly) || !reportAction.isOptimisticAction) && - !ReportActionsUtils.isDeletedAction(reportAction) && - !ReportActionsUtils.isCreatedTaskReportAction(reportAction) && + !isDeletedAction(reportAction) && + !isCreatedTaskReportAction(reportAction) && reportAction?.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE ); } function canHoldUnholdReportAction(reportAction: OnyxInputOrEntry): {canHoldRequest: boolean; canUnholdRequest: boolean} { - if (!ReportActionsUtils.isMoneyRequestAction(reportAction)) { + if (!isMoneyRequestAction(reportAction)) { return {canHoldRequest: false, canUnholdRequest: false}; } - const moneyRequestReportID = ReportActionsUtils.getOriginalMessage(reportAction)?.IOUReportID ?? 0; + const moneyRequestReportID = getOriginalMessage(reportAction)?.IOUReportID ?? 0; const moneyRequestReport = getReportOrDraftReport(String(moneyRequestReportID)); if (!moneyRequestReportID || !moneyRequestReport) { @@ -3327,7 +3396,7 @@ function canHoldUnholdReportAction(reportAction: OnyxInputOrEntry) const isRequestSettled = isSettled(moneyRequestReport?.reportID); const isApproved = isReportApproved(moneyRequestReport); - const transactionID = moneyRequestReport ? ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID : 0; + const transactionID = moneyRequestReport ? getOriginalMessage(reportAction)?.IOUTransactionID : 0; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? ({} as Transaction); const parentReportAction = isThread(moneyRequestReport) @@ -3350,9 +3419,9 @@ function canHoldUnholdReportAction(reportAction: OnyxInputOrEntry) const canModifyStatus = !isTrackExpenseMoneyReport && (isAdmin || isActionOwner || isApprover); const canModifyUnholdStatus = !isTrackExpenseMoneyReport && (isAdmin || (isActionOwner && isHoldActionCreator) || isApprover); - const isDeletedParentAction = isEmptyObject(parentReportAction) || ReportActionsUtils.isDeletedAction(parentReportAction); + const isDeletedParentActionLocal = isEmptyObject(parentReportAction) || isDeletedAction(parentReportAction); - const canHoldOrUnholdRequest = !isRequestSettled && !isApproved && !isDeletedParentAction && !isClosed; + const canHoldOrUnholdRequest = !isRequestSettled && !isApproved && !isDeletedParentActionLocal && !isClosed; const canHoldRequest = canHoldOrUnholdRequest && !isOnHold && (isRequestIOU || canModifyStatus) && !isScanning && !!transaction?.reimbursable; const canUnholdRequest = !!(canHoldOrUnholdRequest && isOnHold && !isDuplicate(transaction.transactionID, true) && (isRequestIOU ? isHoldActionCreator : canModifyUnholdStatus)) && @@ -3362,17 +3431,17 @@ function canHoldUnholdReportAction(reportAction: OnyxInputOrEntry) } const changeMoneyRequestHoldStatus = (reportAction: OnyxEntry, backTo?: string, searchHash?: number): void => { - if (!ReportActionsUtils.isMoneyRequestAction(reportAction)) { + if (!isMoneyRequestAction(reportAction)) { return; } - const moneyRequestReportID = ReportActionsUtils.getOriginalMessage(reportAction)?.IOUReportID ?? 0; + const moneyRequestReportID = getOriginalMessage(reportAction)?.IOUReportID ?? 0; const moneyRequestReport = getReportOrDraftReport(String(moneyRequestReportID)); if (!moneyRequestReportID || !moneyRequestReport) { return; } - const transactionID = ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID ?? ''; + const transactionID = getOriginalMessage(reportAction)?.IOUTransactionID ?? ''; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? ({} as Transaction); const isOnHold = isOnHoldTransactionUtils(transaction); const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${moneyRequestReport.policyID}`] ?? null; @@ -3406,7 +3475,7 @@ function getTransactionsWithReceipts(iouReportID: string | undefined): Transacti function areAllRequestsBeingSmartScanned(iouReportID: string, reportPreviewAction: OnyxEntry): boolean { const transactionsWithReceipts = getTransactionsWithReceipts(iouReportID); // If we have more requests than requests with receipts, we have some manual requests - if (ReportActionsUtils.getNumberOfMoneyRequests(reportPreviewAction) > transactionsWithReceipts.length) { + if (getNumberOfMoneyRequests(reportPreviewAction) > transactionsWithReceipts.length) { return false; } return transactionsWithReceipts.every((transaction) => isReceiptBeingScanned(transaction)); @@ -3421,8 +3490,8 @@ function areAllRequestsBeingSmartScanned(iouReportID: string, reportPreviewActio function getLinkedTransaction(reportAction: OnyxEntry): OnyxEntry { let transactionID = ''; - if (ReportActionsUtils.isMoneyRequestAction(reportAction)) { - transactionID = ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID ?? '-1'; + if (isMoneyRequestAction(reportAction)) { + transactionID = getOriginalMessage(reportAction)?.IOUTransactionID ?? '-1'; } return allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; @@ -3441,16 +3510,16 @@ function hasMissingSmartscanFields(iouReportID: string): boolean { * Get report action which is missing smartscan fields */ function getReportActionWithMissingSmartscanFields(iouReportID: string): ReportAction | undefined { - const reportActions = Object.values(ReportActionsUtils.getAllReportActions(iouReportID)); + const reportActions = Object.values(getAllReportActions(iouReportID)); return reportActions.find((action) => { - if (!ReportActionsUtils.isMoneyRequestAction(action)) { + if (!isMoneyRequestAction(action)) { return false; } const transaction = getLinkedTransaction(action); if (isEmptyObject(transaction)) { return false; } - if (!ReportActionsUtils.wasActionTakenByCurrentUser(action)) { + if (!wasActionTakenByCurrentUser(action)) { return false; } return hasMissingSmartscanFieldsTransactionUtils(transaction); @@ -3468,11 +3537,11 @@ function shouldShowRBRForMissingSmartscanFields(iouReportID: string): boolean { * Given a parent IOU report action get report name for the LHN. */ function getTransactionReportName(reportAction: OnyxEntry): string { - if (ReportActionsUtils.isReversedTransaction(reportAction)) { + if (isReversedTransaction(reportAction)) { return Localize.translateLocal('parentReportAction.reversedTransaction'); } - if (ReportActionsUtils.isDeletedAction(reportAction)) { + if (isDeletedAction(reportAction)) { return Localize.translateLocal('parentReportAction.deletedExpense'); } @@ -3480,7 +3549,7 @@ function getTransactionReportName(reportAction: OnyxEntry = iouReportAction, ): string { const report = typeof reportOrID === 'string' ? getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] : reportOrID; - const reportActionMessage = ReportActionsUtils.getReportActionHtml(iouReportAction); + const reportActionMessage = getReportActionHtml(iouReportAction); if (isEmptyObject(report) || !report?.reportID) { // The iouReport is not found locally after SignIn because the OpenApp API won't return iouReports if they're settled @@ -3535,7 +3604,7 @@ function getReportPreviewMessage( return reportActionMessage; } - if (!isEmptyObject(iouReportAction) && !isIOUReport(report) && iouReportAction && ReportActionsUtils.isSplitBillAction(iouReportAction)) { + if (!isEmptyObject(iouReportAction) && !isIOUReport(report) && iouReportAction && isSplitBillAction(iouReportAction)) { // This covers group chats where the last action is a split expense action const linkedTransaction = getLinkedTransaction(iouReportAction); if (isEmptyObject(linkedTransaction)) { @@ -3557,7 +3626,7 @@ function getReportPreviewMessage( } } - if (!isEmptyObject(iouReportAction) && !isIOUReport(report) && iouReportAction && ReportActionsUtils.isTrackExpenseAction(iouReportAction)) { + if (!isEmptyObject(iouReportAction) && !isIOUReport(report) && iouReportAction && isTrackExpenseAction(iouReportAction)) { // This covers group chats where the last action is a track expense action const linkedTransaction = getLinkedTransaction(iouReportAction); if (isEmptyObject(linkedTransaction)) { @@ -3595,7 +3664,7 @@ function getReportPreviewMessage( } let linkedTransaction; - if (!isEmptyObject(iouReportAction) && shouldConsiderScanningReceiptOrPendingRoute && iouReportAction && ReportActionsUtils.isMoneyRequestAction(iouReportAction)) { + if (!isEmptyObject(iouReportAction) && shouldConsiderScanningReceiptOrPendingRoute && iouReportAction && isMoneyRequestAction(iouReportAction)) { linkedTransaction = getLinkedTransaction(iouReportAction); } @@ -3607,7 +3676,7 @@ function getReportPreviewMessage( return Localize.translateLocal('iou.fieldPending'); } - const originalMessage = !isEmptyObject(iouReportAction) && ReportActionsUtils.isMoneyRequestAction(iouReportAction) ? ReportActionsUtils.getOriginalMessage(iouReportAction) : undefined; + const originalMessage = !isEmptyObject(iouReportAction) && isMoneyRequestAction(iouReportAction) ? getOriginalMessage(iouReportAction) : undefined; // Show Paid preview message if it's settled or if the amount is paid & stuck at receivers end for only chat reports. if (isSettled(report.reportID) || (report.isWaitingOnBankAccount && isPreviewMessageForParentChatReport)) { @@ -3652,7 +3721,7 @@ function getReportPreviewMessage( } let comment = !isEmptyObject(linkedTransaction) ? getMerchantOrDescription(linkedTransaction) : undefined; - if (!isEmptyObject(originalReportAction) && ReportActionsUtils.isReportPreviewAction(originalReportAction) && ReportActionsUtils.getNumberOfMoneyRequests(originalReportAction) !== 1) { + if (!isEmptyObject(originalReportAction) && isReportPreviewAction(originalReportAction) && getNumberOfMoneyRequests(originalReportAction) !== 1) { comment = undefined; } @@ -3780,14 +3849,14 @@ function getAdminRoomInvitedParticipants(parentReportAction: OnyxEntry { @@ -3844,7 +3913,7 @@ function parseReportActionHtmlToText(reportAction: OnyxEntry, repo return cachedText; } - const {html, text} = ReportActionsUtils.getReportActionMessage(reportAction) ?? {}; + const {html, text} = getReportActionMessageReportUtils(reportAction) ?? {}; if (!html) { return text ?? ''; @@ -3885,16 +3954,16 @@ function getReportActionMessage(reportAction: OnyxEntry, reportID? } if (reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_INTEGRATION) { - return ReportActionsUtils.getExportIntegrationLastMessageText(reportAction); + return getExportIntegrationLastMessageText(reportAction); } if (reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.UNHOLD) { return Localize.translateLocal('iou.unheldExpense'); } - if (ReportActionsUtils.isApprovedOrSubmittedReportAction(reportAction)) { - return ReportActionsUtils.getReportActionMessageText(reportAction); + if (isApprovedOrSubmittedReportAction(reportAction)) { + return getReportActionMessageText(reportAction); } - if (ReportActionsUtils.isReimbursementQueuedAction(reportAction)) { + if (isReimbursementQueuedAction(reportAction)) { return getReimbursementQueuedActionMessage(reportAction, getReportOrDraftReport(reportID), false); } @@ -3910,7 +3979,7 @@ function getInvoicesChatName(report: OnyxEntry, receiverPolicy: OnyxEntr const invoiceReceiverAccountID = isIndividual ? invoiceReceiver.accountID : -1; const invoiceReceiverPolicyID = isIndividual ? '' : invoiceReceiver?.policyID ?? '-1'; const invoiceReceiverPolicy = receiverPolicy ?? getPolicy(invoiceReceiverPolicyID); - const isCurrentUserReceiver = (isIndividual && invoiceReceiverAccountID === currentUserAccountID) || (!isIndividual && PolicyUtils.isPolicyAdmin(invoiceReceiverPolicy)); + const isCurrentUserReceiver = (isIndividual && invoiceReceiverAccountID === currentUserAccountID) || (!isIndividual && isPolicyAdminPolicyUtils(invoiceReceiverPolicy)); if (isCurrentUserReceiver) { return getPolicyName(report); @@ -3958,20 +4027,17 @@ function getReportName( } else { parentReportAction = isThread(report) ? allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`]?.[report.parentReportActionID] : undefined; } - const parentReportActionMessage = ReportActionsUtils.getReportActionMessage(parentReportAction); + const parentReportActionMessage = getReportActionMessageReportUtils(parentReportAction); - if ( - ReportActionsUtils.isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.SUBMITTED) || - ReportActionsUtils.isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.SUBMITTED_AND_CLOSED) - ) { - const {harvesting} = ReportActionsUtils.getOriginalMessage(parentReportAction) ?? {}; + if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.SUBMITTED) || isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.SUBMITTED_AND_CLOSED)) { + const {harvesting} = getOriginalMessage(parentReportAction) ?? {}; if (harvesting) { return Parser.htmlToText(getReportAutomaticallySubmittedMessage(parentReportAction)); } return getIOUSubmittedMessage(parentReportAction); } - if (ReportActionsUtils.isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.FORWARDED)) { - const {automaticAction} = ReportActionsUtils.getOriginalMessage(parentReportAction) ?? {}; + if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.FORWARDED)) { + const {automaticAction} = getOriginalMessage(parentReportAction) ?? {}; if (automaticAction) { return Parser.htmlToText(getReportAutomaticallyForwardedMessage(parentReportAction, reportID)); } @@ -3980,19 +4046,19 @@ function getReportName( if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REJECTED) { return getRejectedReportMessage(); } - if (ReportActionsUtils.isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.APPROVED)) { - const {automaticAction} = ReportActionsUtils.getOriginalMessage(parentReportAction) ?? {}; + if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.APPROVED)) { + const {automaticAction} = getOriginalMessage(parentReportAction) ?? {}; if (automaticAction) { return Parser.htmlToText(getReportAutomaticallyApprovedMessage(parentReportAction)); } return getIOUApprovedMessage(parentReportAction); } - if (ReportActionsUtils.isUnapprovedAction(parentReportAction)) { + if (isUnapprovedAction(parentReportAction)) { return getIOUUnapprovedMessage(parentReportAction); } if (isChatThread(report)) { - if (!isEmptyObject(parentReportAction) && ReportActionsUtils.isTransactionThread(parentReportAction)) { + if (!isEmptyObject(parentReportAction) && isTransactionThread(parentReportAction)) { formattedName = getTransactionReportName(parentReportAction); if (isArchivedRoom(report, getReportNameValuePairs(report?.reportID))) { formattedName += ` (${Localize.translateLocal('common.archived')})`; @@ -4000,15 +4066,15 @@ function getReportName( return formatReportLastMessageText(formattedName); } - if (!isEmptyObject(parentReportAction) && ReportActionsUtils.isOldDotReportAction(parentReportAction)) { - return ReportActionsUtils.getMessageOfOldDotReportAction(parentReportAction); + if (!isEmptyObject(parentReportAction) && isOldDotReportAction(parentReportAction)) { + return getMessageOfOldDotReportAction(parentReportAction); } if (parentReportActionMessage?.isDeletedParentAction) { return Localize.translateLocal('parentReportAction.deletedMessage'); } - const isAttachment = ReportActionsUtils.isReportActionAttachment(!isEmptyObject(parentReportAction) ? parentReportAction : undefined); + const isAttachment = isReportActionAttachment(!isEmptyObject(parentReportAction) ? parentReportAction : undefined); const reportActionMessage = getReportActionMessage(parentReportAction, report?.parentReportID, report?.reportID ?? '').replace(/(\n+|\r\n|\n|\r)/gm, ' '); if (isAttachment && reportActionMessage) { return `[${Localize.translateLocal('common.attachment')}]`; @@ -4026,7 +4092,7 @@ function getReportName( if (reportActionMessage && isArchivedRoom(report, getReportNameValuePairs(report?.reportID))) { return `${reportActionMessage} (${Localize.translateLocal('common.archived')})`; } - if (!isEmptyObject(parentReportAction) && ReportActionsUtils.isModifiedExpenseAction(parentReportAction)) { + if (!isEmptyObject(parentReportAction) && isModifiedExpenseAction(parentReportAction)) { const modifiedMessage = ModifiedExpenseMessage.getForReportAction(report?.reportID, parentReportAction); return formatReportLastMessageText(modifiedMessage); } @@ -4034,8 +4100,8 @@ function getReportName( return report?.reportName ?? ''; } - if (ReportActionsUtils.isCardIssuedAction(parentReportAction)) { - return ReportActionsUtils.getCardIssuedMessage(parentReportAction); + if (isCardIssuedAction(parentReportAction)) { + return getCardIssuedMessage(parentReportAction); } return reportActionMessage; } @@ -4523,8 +4589,8 @@ function buildOptimisticTaskCommentReportAction( // Added when we fetch the reportActions on a report // eslint-disable-next-line reportAction.reportAction.originalMessage = { - html: ReportActionsUtils.getReportActionHtml(reportAction.reportAction), - taskReportID: ReportActionsUtils.getReportActionMessage(reportAction.reportAction)?.taskReportID, + html: getReportActionHtml(reportAction.reportAction), + taskReportID: getReportActionMessageReportUtils(reportAction.reportAction)?.taskReportID, whisperedTo: [], }; reportAction.reportAction.childReportID = taskReportID; @@ -4661,18 +4727,18 @@ function buildOptimisticInvoiceReport(chatReportID: string, policyID: string, re * @param policy */ function getExpenseReportStateAndStatus(policy: OnyxEntry) { - const isInstantSubmitEnabled = PolicyUtils.isInstantSubmitEnabled(policy); - const isSubmitAndClose = PolicyUtils.isSubmitAndClose(policy); + const isInstantSubmitEnabledLocal = isInstantSubmitEnabled(policy); + const isSubmitAndCloseLocal = isSubmitAndClose(policy); const arePaymentsDisabled = policy?.reimbursementChoice === CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_NO; - if (isInstantSubmitEnabled && arePaymentsDisabled && isSubmitAndClose) { + if (isInstantSubmitEnabledLocal && arePaymentsDisabled && isSubmitAndCloseLocal) { return { stateNum: CONST.REPORT.STATE_NUM.APPROVED, statusNum: CONST.REPORT.STATUS_NUM.CLOSED, }; } - if (isInstantSubmitEnabled) { + if (isInstantSubmitEnabledLocal) { return { stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, @@ -4737,7 +4803,7 @@ function buildOptimisticExpenseReport( }; // Get the approver/manager for this report to properly display the optimistic data - const submitToAccountID = PolicyUtils.getSubmitToAccountID(policy, expenseReport); + const submitToAccountID = getSubmitToAccountID(policy, expenseReport); if (submitToAccountID) { expenseReport.managerID = submitToAccountID; } @@ -4754,15 +4820,15 @@ function buildOptimisticExpenseReport( function getFormattedAmount(reportAction: ReportAction) { if ( - !ReportActionsUtils.isSubmittedAction(reportAction) && - !ReportActionsUtils.isForwardedAction(reportAction) && - !ReportActionsUtils.isApprovedAction(reportAction) && - !ReportActionsUtils.isUnapprovedAction(reportAction) && - !ReportActionsUtils.isSubmittedAndClosedAction(reportAction) + !isSubmittedAction(reportAction) && + !isForwardedAction(reportAction) && + !isApprovedAction(reportAction) && + !isUnapprovedAction(reportAction) && + !isSubmittedAndClosedAction(reportAction) ) { return ''; } - const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction); + const originalMessage = getOriginalMessage(reportAction); const formattedAmount = CurrencyUtils.convertToDisplayString(Math.abs(originalMessage?.amount ?? 0), originalMessage?.currency); return formattedAmount; } @@ -4795,7 +4861,7 @@ function getIOUApprovedMessage(reportAction: ReportAction, reportOrID: OnyxInputOrEntry | string) { const expenseReport = typeof reportOrID === 'string' ? getReport(reportOrID) : reportOrID; - const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction) as OriginalMessageIOU; + const originalMessage = getOriginalMessage(reportAction) as OriginalMessageIOU; let formattedAmount; // Older FORWARDED action might not have the amount stored in the original message, we'll fallback to getting the amount from the report instead. @@ -4814,7 +4880,7 @@ function getReportAutomaticallyForwardedMessage(reportAction: ReportAction, reportOrID: OnyxInputOrEntry | string) { const expenseReport = typeof reportOrID === 'string' ? getReport(reportOrID) : reportOrID; - const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction) as OriginalMessageIOU; + const originalMessage = getOriginalMessage(reportAction) as OriginalMessageIOU; let formattedAmount; // Older FORWARDED action might not have the amount stored in the original message, we'll fallback to getting the amount from the report instead. @@ -4832,8 +4898,8 @@ function getRejectedReportMessage() { } function getWorkspaceNameUpdatedMessage(action: ReportAction) { - const {oldName, newName} = ReportActionsUtils.getOriginalMessage(action as ReportAction) ?? {}; - const message = oldName && newName ? Localize.translateLocal('workspaceActions.renamedWorkspaceNameAction', {oldName, newName}) : ReportActionsUtils.getReportActionText(action); + const {oldName, newName} = getOriginalMessage(action as ReportAction) ?? {}; + const message = oldName && newName ? Localize.translateLocal('workspaceActions.renamedWorkspaceNameAction', {oldName, newName}) : getReportActionText(action); return message; } @@ -5353,7 +5419,7 @@ function updateReportPreview( } const message = getReportPreviewMessage(iouReport, reportPreviewAction); - const originalMessage = ReportActionsUtils.getOriginalMessage(reportPreviewAction); + const originalMessage = getOriginalMessage(reportPreviewAction); return { ...reportPreviewAction, message: [ @@ -5891,7 +5957,7 @@ function buildOptimisticDismissedViolationReportAction( { type: CONST.REPORT.MESSAGE.TYPE.TEXT, style: 'normal', - text: ReportActionsUtils.getDismissedViolationMessageText(originalMessage), + text: getDismissedViolationMessageText(originalMessage), }, ], originalMessage, @@ -6411,9 +6477,9 @@ function hasReportViolations(reportID: string) { */ function shouldAdminsRoomBeVisible(report: OnyxEntry): boolean { const accountIDs = Object.entries(report?.participants ?? {}).map(([accountID]) => Number(accountID)); - const adminAccounts = PersonalDetailsUtils.getLoginsByAccountIDs(accountIDs).filter((login) => !PolicyUtils.isExpensifyTeam(login)); - const lastVisibleAction = ReportActionsUtils.getLastVisibleAction(report?.reportID ?? ''); - if ((lastVisibleAction ? ReportActionsUtils.isCreatedAction(lastVisibleAction) : report?.lastActionType === CONST.REPORT.ACTIONS.TYPE.CREATED) && adminAccounts.length <= 1) { + const adminAccounts = PersonalDetailsUtils.getLoginsByAccountIDs(accountIDs).filter((login) => !isExpensifyTeam(login)); + const lastVisibleAction = getLastVisibleActionReportActionsUtils(report?.reportID ?? ''); + if ((lastVisibleAction ? isCreatedAction(lastVisibleAction) : report?.lastActionType === CONST.REPORT.ACTIONS.TYPE.CREATED) && adminAccounts.length <= 1) { return false; } return true; @@ -6425,7 +6491,7 @@ type ReportErrorsAndReportActionThatRequiresAttention = { }; function getAllReportActionsErrorsAndReportActionThatRequiresAttention(report: OnyxEntry, reportActions: OnyxEntry): ReportErrorsAndReportActionThatRequiresAttention { - const reportActionsArray = Object.values(reportActions ?? {}).filter((action) => !ReportActionsUtils.isDeletedAction(action)); + const reportActionsArray = Object.values(reportActions ?? {}).filter((action) => !isDeletedAction(action)); const reportActionErrors: ErrorFields = {}; let reportAction: OnyxEntry; @@ -6444,8 +6510,8 @@ function getAllReportActionsErrorsAndReportActionThatRequiresAttention(report: O : allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID ?? '-1'}`]?.[report.parentReportActionID ?? '-1']; if (!isArchivedRoom(report)) { - if (ReportActionsUtils.wasActionTakenByCurrentUser(parentReportAction) && ReportActionsUtils.isTransactionThread(parentReportAction)) { - const transactionID = ReportActionsUtils.isMoneyRequestAction(parentReportAction) ? ReportActionsUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID : null; + if (wasActionTakenByCurrentUser(parentReportAction) && isTransactionThread(parentReportAction)) { + const transactionID = isMoneyRequestAction(parentReportAction) ? getOriginalMessage(parentReportAction)?.IOUTransactionID : null; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; if (hasMissingSmartscanFieldsTransactionUtils(transaction ?? null) && !isSettled(transaction?.reportID)) { reportActionErrors.smartscan = ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericSmartscanFailureMessage'); @@ -6496,8 +6562,8 @@ function getAllReportErrors(report: OnyxEntry, reportActions: OnyxEntry< function hasReportErrorsOtherThanFailedReceipt(report: Report, doesReportHaveViolations: boolean, transactionViolations: OnyxCollection) { const reportActions = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`] ?? {}; const allReportErrors = getAllReportErrors(report, reportActions) ?? {}; - const transactionReportActions = ReportActionsUtils.getAllReportActions(report.reportID); - const oneTransactionThreadReportID = ReportActionsUtils.getOneTransactionThreadReportID(report.reportID, transactionReportActions, undefined); + const transactionReportActions = getAllReportActions(report.reportID); + const oneTransactionThreadReportID = getOneTransactionThreadReportID(report.reportID, transactionReportActions, undefined); let doesTransactionThreadReportHasViolations = false; if (oneTransactionThreadReportID) { const transactionReport = getReport(oneTransactionThreadReportID); @@ -6657,11 +6723,7 @@ function reasonForReportToBeInOptionList({ } // Hide chat threads where the parent message is pending removal - if ( - !isEmptyObject(parentReportAction) && - ReportActionsUtils.isPendingRemove(parentReportAction) && - ReportActionsUtils.isThreadParentMessage(parentReportAction, report?.reportID ?? '') - ) { + if (!isEmptyObject(parentReportAction) && isPendingRemove(parentReportAction) && isThreadParentMessage(parentReportAction, report?.reportID ?? '')) { return null; } @@ -6782,7 +6844,7 @@ function canFlagReportAction(reportAction: OnyxInputOrEntry, repor report = getReportOrDraftReport(report?.parentReportID); } const isCurrentUserAction = reportAction?.actorAccountID === currentUserAccountID; - if (ReportActionsUtils.isWhisperAction(reportAction)) { + if (isWhisperAction(reportAction)) { // Allow flagging whispers that are sent by other users if (!isCurrentUserAction && reportAction?.actorAccountID !== CONST.ACCOUNT_ID.CONCIERGE) { return true; @@ -6795,8 +6857,8 @@ function canFlagReportAction(reportAction: OnyxInputOrEntry, repor return !!( !isCurrentUserAction && reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT && - !ReportActionsUtils.isDeletedAction(reportAction) && - !ReportActionsUtils.isCreatedTaskReportAction(reportAction) && + !isDeletedAction(reportAction) && + !isCreatedTaskReportAction(reportAction) && !isEmptyObject(report) && report && isAllowedToComment(report) @@ -7014,7 +7076,7 @@ function getMoneyRequestOptions(report: OnyxEntry, policy: OnyxEntry | str return false; } - const parentReportAction = ReportActionsUtils.getReportAction(report?.parentReportID ?? '-1', report?.parentReportActionID ?? '-1'); + const parentReportAction = getReportAction(report?.parentReportID ?? '-1', report?.parentReportActionID ?? '-1'); return parentReportAction?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE; } @@ -7293,7 +7355,7 @@ function canUserPerformWriteAction(report: OnyxEntry) { function getOriginalReportID(reportID: string, reportAction: OnyxInputOrEntry): string | undefined { const reportActions = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`]; const currentReportAction = reportActions?.[reportAction?.reportActionID ?? '-1'] ?? null; - const transactionThreadReportID = ReportActionsUtils.getOneTransactionThreadReportID(reportID, reportActions ?? ([] as ReportAction[])); + const transactionThreadReportID = getOneTransactionThreadReportID(reportID, reportActions ?? ([] as ReportAction[])); const isThreadReportParentAction = reportAction?.childReportID?.toString() === reportID; if (Object.keys(currentReportAction ?? {}).length === 0) { return isThreadReportParentAction ? getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.parentReportID : transactionThreadReportID ?? reportID; @@ -7384,14 +7446,14 @@ function shouldDisableRename(report: OnyxEntry): boolean { * @param policy - the workspace the report is on, null if the user isn't a member of the workspace */ function canEditWriteCapability(report: OnyxEntry, policy: OnyxEntry): boolean { - return PolicyUtils.isPolicyAdmin(policy) && !isAdminRoom(report) && !isArchivedRoom(report, getReportNameValuePairs(report?.reportID)) && !isThread(report) && !isInvoiceRoom(report); + return isPolicyAdminPolicyUtils(policy) && !isAdminRoom(report) && !isArchivedRoom(report, getReportNameValuePairs(report?.reportID)) && !isThread(report) && !isInvoiceRoom(report); } /** * @param policy - the workspace the report is on, null if the user isn't a member of the workspace */ function canEditRoomVisibility(report: OnyxEntry, policy: OnyxEntry): boolean { - return PolicyUtils.isPolicyAdmin(policy) && !isArchivedRoom(report, getReportNameValuePairs(report?.reportID)); + return isPolicyAdminPolicyUtils(policy) && !isArchivedRoom(report, getReportNameValuePairs(report?.reportID)); } /** @@ -7476,7 +7538,7 @@ function getTaskAssigneeChatOnyxData( // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const displayname = allPersonalDetails?.[assigneeAccountID]?.displayName || allPersonalDetails?.[assigneeAccountID]?.login || ''; optimisticAssigneeAddComment = buildOptimisticTaskCommentReportAction(taskReportID, title, assigneeAccountID, `assigned to ${displayname}`, parentReportID); - const lastAssigneeCommentText = formatReportLastMessageText(ReportActionsUtils.getReportActionText(optimisticAssigneeAddComment.reportAction as ReportAction)); + const lastAssigneeCommentText = formatReportLastMessageText(getReportActionText(optimisticAssigneeAddComment.reportAction as ReportAction)); const optimisticAssigneeReport = { lastVisibleActionCreated: currentTime, lastMessageText: lastAssigneeCommentText, @@ -7521,10 +7583,10 @@ function getTaskAssigneeChatOnyxData( * Return iou report action display message */ function getIOUReportActionDisplayMessage(reportAction: OnyxEntry, transaction?: OnyxEntry): string { - if (!ReportActionsUtils.isMoneyRequestAction(reportAction)) { + if (!isMoneyRequestAction(reportAction)) { return ''; } - const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction); + const originalMessage = getOriginalMessage(reportAction); const {IOUReportID, automaticAction} = originalMessage ?? {}; const iouReport = getReportOrDraftReport(IOUReportID); let translationKey: TranslationPaths; @@ -7567,9 +7629,9 @@ function getIOUReportActionDisplayMessage(reportAction: OnyxEntry, amount: formattedAmount, }); } - if (ReportActionsUtils.isSplitBillAction(reportAction)) { + if (isSplitBillAction(reportAction)) { translationKey = 'iou.didSplitAmount'; - } else if (ReportActionsUtils.isTrackExpenseAction(reportAction)) { + } else if (isTrackExpenseAction(reportAction)) { translationKey = 'iou.trackedAmount'; } else { translationKey = 'iou.submittedAmount'; @@ -7673,23 +7735,23 @@ function canEditReportDescription(report: OnyxEntry, policy: OnyxEntry

): boolean { - return PolicyUtils.isPolicyAdmin(policy); + return isPolicyAdminPolicyUtils(policy); } function getReportActionWithSmartscanError(reportActions: ReportAction[]): ReportAction | undefined { return reportActions.find((action) => { - const isReportPreview = ReportActionsUtils.isReportPreviewAction(action); - const isSplitReportAction = ReportActionsUtils.isSplitBillAction(action); + const isReportPreview = isReportPreviewAction(action); + const isSplitReportAction = isSplitBillAction(action); if (!isSplitReportAction && !isReportPreview) { return false; } - const IOUReportID = ReportActionsUtils.getIOUReportIDFromReportActionPreview(action); + const IOUReportID = getIOUReportIDFromReportActionPreview(action); const isReportPreviewError = isReportPreview && shouldShowRBRForMissingSmartscanFields(IOUReportID) && !isSettled(IOUReportID); if (isReportPreviewError) { return true; } - const transactionID = ReportActionsUtils.isMoneyRequestAction(action) ? ReportActionsUtils.getOriginalMessage(action)?.IOUTransactionID ?? '-1' : '-1'; + const transactionID = isMoneyRequestAction(action) ? getOriginalMessage(action)?.IOUTransactionID ?? '-1' : '-1'; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? {}; const isSplitBillError = isSplitReportAction && hasMissingSmartscanFieldsTransactionUtils(transaction as Transaction); @@ -7824,20 +7886,20 @@ function getNonHeldAndFullAmount(iouReport: OnyxEntry, policy: OnyxEntry * - The action is the thread's first chat */ function shouldDisableThread(reportAction: OnyxInputOrEntry, reportID: string, isThreadReportParentAction: boolean): boolean { - const isSplitBillAction = ReportActionsUtils.isSplitBillAction(reportAction); - const isDeletedAction = ReportActionsUtils.isDeletedAction(reportAction); - const isReportPreviewAction = ReportActionsUtils.isReportPreviewAction(reportAction); - const isIOUAction = ReportActionsUtils.isMoneyRequestAction(reportAction); - const isWhisperAction = ReportActionsUtils.isWhisperAction(reportAction) || ReportActionsUtils.isActionableTrackExpense(reportAction); + const isSplitBillActionLocal = isSplitBillAction(reportAction); + const isDeletedActionLocal = isDeletedAction(reportAction); + const isReportPreviewActionLocal = isReportPreviewAction(reportAction); + const isIOUAction = isMoneyRequestAction(reportAction); + const isWhisperActionLocal = isWhisperAction(reportAction) || isActionableTrackExpense(reportAction); const isArchivedReport = isArchivedRoom(getReportOrDraftReport(reportID), getReportNameValuePairs(reportID)); const isActionDisabled = CONST.REPORT.ACTIONS.THREAD_DISABLED.some((action: string) => action === reportAction?.actionName); return ( isActionDisabled || - isSplitBillAction || - (isDeletedAction && !reportAction?.childVisibleActionCount) || + isSplitBillActionLocal || + (isDeletedActionLocal && !reportAction?.childVisibleActionCount) || (isArchivedReport && !reportAction?.childVisibleActionCount) || - (isWhisperAction && !isReportPreviewAction && !isIOUAction) || + (isWhisperActionLocal && !isReportPreviewActionLocal && !isIOUAction) || isThreadReportParentAction ); } @@ -7852,18 +7914,13 @@ function getAllAncestorReportActions(report: Report | null | undefined, currentU while (parentReportID) { const parentReport = currentUpdatedReport && currentUpdatedReport.reportID === parentReportID ? currentUpdatedReport : getReportOrDraftReport(parentReportID); - const parentReportAction = ReportActionsUtils.getReportAction(parentReportID, parentReportActionID ?? '-1'); + const parentReportAction = getReportAction(parentReportID, parentReportActionID ?? '-1'); - if ( - !parentReport || - !parentReportAction || - (ReportActionsUtils.isTransactionThread(parentReportAction) && !ReportActionsUtils.isSentMoneyReportAction(parentReportAction)) || - ReportActionsUtils.isReportPreviewAction(parentReportAction) - ) { + if (!parentReport || !parentReportAction || (isTransactionThread(parentReportAction) && !isSentMoneyReportAction(parentReportAction)) || isReportPreviewAction(parentReportAction)) { break; } - const isParentReportActionUnread = ReportActionsUtils.isCurrentActionUnread(parentReport, parentReportAction); + const isParentReportActionUnread = isCurrentActionUnread(parentReport, parentReportAction); allAncestors.push({ report: parentReport, reportAction: parentReportAction, @@ -7894,13 +7951,11 @@ function getAllAncestorReportActionIDs(report: Report | null | undefined, includ while (parentReportID) { const parentReport = getReportOrDraftReport(parentReportID); - const parentReportAction = ReportActionsUtils.getReportAction(parentReportID, parentReportActionID ?? '-1'); + const parentReportAction = getReportAction(parentReportID, parentReportActionID ?? '-1'); if ( !parentReportAction || - (!includeTransactionThread && - ((ReportActionsUtils.isTransactionThread(parentReportAction) && !ReportActionsUtils.isSentMoneyReportAction(parentReportAction)) || - ReportActionsUtils.isReportPreviewAction(parentReportAction))) + (!includeTransactionThread && ((isTransactionThread(parentReportAction) && !isSentMoneyReportAction(parentReportAction)) || isReportPreviewAction(parentReportAction))) ) { break; } @@ -7942,7 +7997,7 @@ function getOptimisticDataForParentReportAction(reportID: string, lastVisibleAct return null; } - const ancestorReportAction = ReportActionsUtils.getReportAction(ancestorReport.reportID, ancestors.reportActionsIDs.at(index) ?? ''); + const ancestorReportAction = getReportAction(ancestorReport.reportID, ancestors.reportActionsIDs.at(index) ?? ''); if (!ancestorReportAction || isEmptyObject(ancestorReportAction)) { return null; @@ -8011,7 +8066,7 @@ function isAllowedToApproveExpenseReport(report: OnyxEntry, approverAcco function isAllowedToSubmitDraftExpenseReport(report: OnyxEntry): boolean { const policy = getPolicy(report?.policyID); - const submitToAccountID = PolicyUtils.getSubmitToAccountID(policy, report); + const submitToAccountID = getSubmitToAccountID(policy, report); return isAllowedToApproveExpenseReport(report, submitToAccountID); } @@ -8021,10 +8076,10 @@ function isAllowedToSubmitDraftExpenseReport(report: OnyxEntry): boolean */ function getIndicatedMissingPaymentMethod(userWallet: OnyxEntry, reportId: string, reportAction: ReportAction): MissingPaymentMethod | undefined { const isSubmitterOfUnsettledReport = isCurrentUserSubmitter(reportId) && !isSettled(reportId); - if (!isSubmitterOfUnsettledReport || !ReportActionsUtils.isReimbursementQueuedAction(reportAction)) { + if (!isSubmitterOfUnsettledReport || !isReimbursementQueuedAction(reportAction)) { return undefined; } - const paymentType = ReportActionsUtils.getOriginalMessage(reportAction)?.paymentType; + const paymentType = getOriginalMessage(reportAction)?.paymentType; if (paymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) { return isEmpty(userWallet) || userWallet.tierName === CONST.WALLET.TIER_NAME.SILVER ? 'wallet' : undefined; } @@ -8075,13 +8130,13 @@ function hasActionsWithErrors(reportID: string): boolean { } function isNonAdminOrOwnerOfPolicyExpenseChat(report: OnyxInputOrEntry, policy: OnyxInputOrEntry): boolean { - return isPolicyExpenseChat(report) && !(PolicyUtils.isPolicyAdmin(policy) || PolicyUtils.isPolicyOwner(policy, currentUserAccountID ?? -1) || isReportOwner(report)); + return isPolicyExpenseChat(report) && !(isPolicyAdminPolicyUtils(policy) || isPolicyOwner(policy, currentUserAccountID ?? -1) || isReportOwner(report)); } function isAdminOwnerApproverOrReportOwner(report: OnyxEntry, policy: OnyxEntry): boolean { const isApprover = isMoneyRequestReport(report) && report?.managerID !== null && currentUserPersonalDetails?.accountID === report?.managerID; - return PolicyUtils.isPolicyAdmin(policy) || PolicyUtils.isPolicyOwner(policy, currentUserAccountID ?? -1) || isReportOwner(report) || isApprover; + return isPolicyAdminPolicyUtils(policy) || isPolicyOwner(policy, currentUserAccountID ?? -1) || isReportOwner(report) || isApprover; } /** @@ -8090,7 +8145,7 @@ function isAdminOwnerApproverOrReportOwner(report: OnyxEntry, policy: On function canJoinChat(report: OnyxEntry, parentReportAction: OnyxInputOrEntry, policy: OnyxInputOrEntry): boolean { // We disabled thread functions for whisper action // So we should not show join option for existing thread on whisper message that has already been left, or manually leave it - if (ReportActionsUtils.isWhisperAction(parentReportAction)) { + if (isWhisperAction(parentReportAction)) { return false; } @@ -8121,7 +8176,7 @@ function canLeaveChat(report: OnyxEntry, policy: OnyxEntry): boo return true; } - if (isPolicyExpenseChat(report) && !report?.isOwnPolicyExpenseChat && !PolicyUtils.isPolicyAdmin(policy)) { + if (isPolicyExpenseChat(report) && !report?.isOwnPolicyExpenseChat && !isPolicyAdminPolicyUtils(policy)) { return true; } @@ -8199,7 +8254,7 @@ function createDraftTransactionAndNavigateToParticipantSelector(transactionID: s const linkedTrackedExpenseReportAction = Object.values(reportActions) .filter(Boolean) - .find((action) => ReportActionsUtils.isMoneyRequestAction(action) && ReportActionsUtils.getOriginalMessage(action)?.IOUTransactionID === transactionID); + .find((action) => isMoneyRequestAction(action) && getOriginalMessage(action)?.IOUTransactionID === transactionID); const {created, amount, currency, merchant, mccGroup} = getTransactionDetails(transaction) ?? {}; const comment = getTransactionCommentObject(transaction); @@ -8249,7 +8304,7 @@ function getOutstandingChildRequest(iouReport: OnyxInputOrEntry): Outsta } const policy = getPolicy(iouReport.policyID); - const shouldBeManuallySubmitted = PolicyUtils.isPaidGroupPolicy(policy) && !policy?.harvesting?.enabled; + const shouldBeManuallySubmitted = isPaidGroupPolicyPolicyUtils(policy) && !policy?.harvesting?.enabled; if (shouldBeManuallySubmitted) { return { hasOutstandingChildRequest: true, @@ -8355,7 +8410,7 @@ function getReportLastMessage(reportID: string, actionsToMerge?: ReportActions) if (lastMessageText || lastMessageTranslationKey) { const report = getReport(reportID); - const lastVisibleAction = ReportActionsUtils.getLastVisibleAction(reportID, canUserPerformWriteAction(report), actionsToMerge); + const lastVisibleAction = getLastVisibleActionReportActionsUtils(reportID, canUserPerformWriteAction(report), actionsToMerge); const lastVisibleActionCreated = lastVisibleAction?.created; const lastActorAccountID = lastVisibleAction?.actorAccountID; result = { @@ -8406,7 +8461,7 @@ function isExported(reportActions: OnyxEntry) { if (!reportActions) { return false; } - return Object.values(reportActions).some((action) => ReportActionsUtils.isExportIntegrationAction(action)); + return Object.values(reportActions).some((action) => isExportIntegrationAction(action)); } function getApprovalChain(policy: OnyxEntry, expenseReport: OnyxEntry): string[] { @@ -8414,15 +8469,15 @@ function getApprovalChain(policy: OnyxEntry, expenseReport: OnyxEntry Date: Thu, 28 Nov 2024 11:48:43 +0100 Subject: [PATCH 05/29] refacort imports in ReportUtils and actions/IOU --- src/libs/ReportUtils.ts | 100 ++++++------ src/libs/actions/IOU.ts | 337 +++++++++++++++++++++------------------- 2 files changed, 223 insertions(+), 214 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 3d6155477ba7..00713459160f 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -76,11 +76,11 @@ import {isEmailPublicDomain} from './LoginUtils'; import ModifiedExpenseMessage from './ModifiedExpenseMessage'; import linkingConfig from './Navigation/linkingConfig'; import Navigation from './Navigation/Navigation'; -import * as NumberUtils from './NumberUtils'; +import {rand64} from './NumberUtils'; import Parser from './Parser'; import Permissions from './Permissions'; -import * as PersonalDetailsUtils from './PersonalDetailsUtils'; -import * as PhoneNumber from './PhoneNumber'; +import {getAccountIDsByLogins, getDisplayNameOrDefault, getLoginsByAccountIDs, getPersonalDetailByEmail} from './PersonalDetailsUtils'; +import {addSMSDomainIfPhoneNumber} from './PhoneNumber'; import { arePaymentsEnabled, canSendInvoiceFromWorkspace, @@ -190,9 +190,9 @@ import { isPayAtEndExpense, isReceiptBeingScanned, } from './TransactionUtils'; -import * as Url from './Url'; +import {addTrailingForwardSlash} from './Url'; import type {AvatarSource} from './UserUtils'; -import * as UserUtils from './UserUtils'; +import {getDefaultAvatarURL} from './UserUtils'; type AvatarRange = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18; @@ -2248,7 +2248,7 @@ function getDisplayNameForParticipant( // For selfDM, we display the user's displayName followed by '(you)' as a postfix const shouldAddPostfix = shouldAddCurrentUserPostfix && accountID === currentUserAccountID; - const longName = PersonalDetailsUtils.getDisplayNameOrDefault(personalDetails, formattedLogin, shouldFallbackToHidden, shouldAddPostfix); + const longName = getDisplayNameOrDefault(personalDetails, formattedLogin, shouldFallbackToHidden, shouldAddPostfix); // If the user's personal details (first name) should be hidden, make sure we return "hidden" instead of the short name if (shouldFallbackToHidden && longName === hiddenTranslation) { @@ -2436,7 +2436,7 @@ function getIcons( const parentReportAction = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`]?.[report.parentReportActionID]; const actorAccountID = getReportActionActorAccountID(parentReportAction, report, report); - const actorDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(allPersonalDetails?.[actorAccountID ?? -1], '', false); + const actorDisplayName = getDisplayNameOrDefault(allPersonalDetails?.[actorAccountID ?? -1], '', false); const actorIcon = { id: actorAccountID, source: personalDetails?.[actorAccountID ?? -1]?.avatar ?? FallbackAvatar, @@ -2743,7 +2743,7 @@ function buildOptimisticChangeFieldAction(reportField: PolicyReportField, previo type: 'TEXT', }, ], - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), created: DateUtils.getDBTime(), pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }; @@ -2780,7 +2780,7 @@ function buildOptimisticCancelPaymentReportAction(expenseReportID: string, amoun type: 'TEXT', }, ], - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), shouldShow: true, created: DateUtils.getDBTime(), pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, @@ -3894,7 +3894,7 @@ function getInvoicePayerName(report: OnyxEntry, invoiceReceiverPolicy?: const isIndividual = invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL; if (isIndividual) { - return PersonalDetailsUtils.getDisplayNameOrDefault(allPersonalDetails?.[invoiceReceiver.accountID]); + return getDisplayNameOrDefault(allPersonalDetails?.[invoiceReceiver.accountID]); } return getPolicyName(report, false, invoiceReceiverPolicy ?? allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${invoiceReceiver?.policyID}`]); @@ -3933,7 +3933,7 @@ function parseReportActionHtmlToText(reportAction: OnyxEntry, repo const mentionUserRegex = //gi; const accountIDToName: Record = {}; const accountIDs = Array.from(html.matchAll(mentionUserRegex), (mention) => Number(mention[1])); - const logins = PersonalDetailsUtils.getLoginsByAccountIDs(accountIDs); + const logins = getLoginsByAccountIDs(accountIDs); accountIDs.forEach((id, index) => (accountIDToName[id] = logins.at(index) ?? '')); const textMessage = Str.removeSMSDomain(Parser.htmlToText(html, {reportIDToName, accountIDToName})); @@ -3986,7 +3986,7 @@ function getInvoicesChatName(report: OnyxEntry, receiverPolicy: OnyxEntr } if (isIndividual) { - return PersonalDetailsUtils.getDisplayNameOrDefault(allPersonalDetails?.[invoiceReceiverAccountID]); + return getDisplayNameOrDefault(allPersonalDetails?.[invoiceReceiverAccountID]); } return getPolicyName(report, false, invoiceReceiverPolicy); @@ -4358,7 +4358,7 @@ function addDomainToShortMention(mention: string): string | undefined { } } if (Str.isValidE164Phone(mention)) { - const mentionWithSmsDomain = PhoneNumber.addSMSDomainIfPhoneNumber(mention); + const mentionWithSmsDomain = addSMSDomainIfPhoneNumber(mention); if (allPersonalDetailLogins.includes(mentionWithSmsDomain)) { return mentionWithSmsDomain; } @@ -4473,13 +4473,13 @@ function buildOptimisticAddCommentReportAction( const isAttachmentOnly = file && !text; const isAttachmentWithText = !!text && file !== undefined; const accountID = actorAccountID ?? currentUserAccountID ?? -1; - const delegateAccountDetails = PersonalDetailsUtils.getPersonalDetailByEmail(delegateEmail); + const delegateAccountDetails = getPersonalDetailByEmail(delegateEmail); // Remove HTML from text when applying optimistic offline comment return { commentText, reportAction: { - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), actionName: CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT, actorAccountID: accountID, person: [ @@ -5015,7 +5015,7 @@ function buildOptimisticIOUReportAction( type, }; - const delegateAccountDetails = PersonalDetailsUtils.getPersonalDetailByEmail(delegateEmail); + const delegateAccountDetails = getPersonalDetailByEmail(delegateEmail); if (type === CONST.IOU.REPORT_ACTION_TYPE.PAY) { // In pay someone flow, we store amount, comment, currency in IOUDetails when type = pay @@ -5064,7 +5064,7 @@ function buildOptimisticIOUReportAction( type: 'TEXT', }, ], - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), shouldShow: true, created, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, @@ -5081,7 +5081,7 @@ function buildOptimisticApprovedReportAction(amount: number, currency: string, e currency, expenseReportID, }; - const delegateAccountDetails = PersonalDetailsUtils.getPersonalDetailByEmail(delegateEmail); + const delegateAccountDetails = getPersonalDetailByEmail(delegateEmail); return { actionName: CONST.REPORT.ACTIONS.TYPE.APPROVED, @@ -5098,7 +5098,7 @@ function buildOptimisticApprovedReportAction(amount: number, currency: string, e type: 'TEXT', }, ], - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), shouldShow: true, created: DateUtils.getDBTime(), pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, @@ -5110,7 +5110,7 @@ function buildOptimisticApprovedReportAction(amount: number, currency: string, e * Builds an optimistic APPROVED report action with a randomly generated reportActionID. */ function buildOptimisticUnapprovedReportAction(amount: number, currency: string, expenseReportID: string): OptimisticUnapprovedReportAction { - const delegateAccountDetails = PersonalDetailsUtils.getPersonalDetailByEmail(delegateEmail); + const delegateAccountDetails = getPersonalDetailByEmail(delegateEmail); return { actionName: CONST.REPORT.ACTIONS.TYPE.UNAPPROVED, actorAccountID: currentUserAccountID, @@ -5130,7 +5130,7 @@ function buildOptimisticUnapprovedReportAction(amount: number, currency: string, type: 'TEXT', }, ], - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), shouldShow: true, created: DateUtils.getDBTime(), pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, @@ -5173,7 +5173,7 @@ function buildOptimisticMovedReportAction(fromPolicyID: string, toPolicyID: stri type: 'TEXT', }, ], - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), shouldShow: true, created: DateUtils.getDBTime(), pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, @@ -5191,7 +5191,7 @@ function buildOptimisticSubmittedReportAction(amount: number, currency: string, expenseReportID, }; - const delegateAccountDetails = PersonalDetailsUtils.getPersonalDetailByEmail(delegateEmail); + const delegateAccountDetails = getPersonalDetailByEmail(delegateEmail); return { actionName: CONST.REPORT.ACTIONS.TYPE.SUBMITTED, @@ -5209,7 +5209,7 @@ function buildOptimisticSubmittedReportAction(amount: number, currency: string, type: 'TEXT', }, ], - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), shouldShow: true, created: DateUtils.getDBTime(), pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, @@ -5239,7 +5239,7 @@ function buildOptimisticReportPreview( const created = DateUtils.getDBTime(); const reportActorAccountID = (isInvoiceReport(iouReport) ? iouReport?.ownerAccountID : iouReport?.managerID) ?? -1; return { - reportActionID: reportActionID ?? NumberUtils.rand64(), + reportActionID: reportActionID ?? rand64(), reportID: chatReport?.reportID, actionName: CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, @@ -5272,12 +5272,12 @@ function buildOptimisticReportPreview( function buildOptimisticActionableTrackExpenseWhisper(iouAction: OptimisticIOUReportAction, transactionID: string): ReportAction { const currentTime = DateUtils.getDBTime(); const targetEmail = CONST.EMAIL.CONCIERGE; - const actorAccountID = PersonalDetailsUtils.getAccountIDsByLogins([targetEmail]).at(0); - const reportActionID = NumberUtils.rand64(); + const actorAccountID = getAccountIDsByLogins([targetEmail]).at(0); + const reportActionID = rand64(); return { actionName: CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_TRACK_EXPENSE_WHISPER, actorAccountID, - avatar: UserUtils.getDefaultAvatarURL(actorAccountID), + avatar: getDefaultAvatarURL(actorAccountID), created: DateUtils.addMillisecondsFromDateTime(currentTime, 1), lastModified: DateUtils.addMillisecondsFromDateTime(currentTime, 1), message: [ @@ -5316,7 +5316,7 @@ function buildOptimisticModifiedExpenseReportAction( updatedTransaction?: OnyxInputOrEntry, ): OptimisticModifiedExpenseReportAction { const originalMessage = getModifiedExpenseOriginalMessage(oldTransaction, transactionChanges, isFromExpenseReport, policy, updatedTransaction); - const delegateAccountDetails = PersonalDetailsUtils.getPersonalDetailByEmail(delegateEmail); + const delegateAccountDetails = getPersonalDetailByEmail(delegateEmail); return { actionName: CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE, @@ -5342,7 +5342,7 @@ function buildOptimisticModifiedExpenseReportAction( }, ], pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), reportID: transactionThread?.reportID, shouldShow: true, delegateAccountID: delegateAccountDetails?.accountID, @@ -5355,7 +5355,7 @@ function buildOptimisticModifiedExpenseReportAction( * @param movedToReportID - The reportID of the report the transaction is moved to */ function buildOptimisticMovedTrackedExpenseModifiedReportAction(transactionThreadID: string, movedToReportID: string): OptimisticModifiedExpenseReportAction { - const delegateAccountDetails = PersonalDetailsUtils.getPersonalDetailByEmail(delegateEmail); + const delegateAccountDetails = getPersonalDetailByEmail(delegateEmail); return { actionName: CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE, @@ -5383,7 +5383,7 @@ function buildOptimisticMovedTrackedExpenseModifiedReportAction(transactionThrea }, ], pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), reportID: transactionThreadID, shouldShow: true, delegateAccountID: delegateAccountDetails?.accountID, @@ -5462,7 +5462,7 @@ function buildOptimisticTaskReportAction( html: message, whisperedTo: [], }; - const delegateAccountDetails = PersonalDetailsUtils.getPersonalDetailByEmail(delegateEmail); + const delegateAccountDetails = getPersonalDetailByEmail(delegateEmail); return { actionName, @@ -5485,7 +5485,7 @@ function buildOptimisticTaskReportAction( type: 'TEXT', }, ], - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), shouldShow: true, created: DateUtils.getDBTimeWithSkew(Date.now() + createdOffset), isFirstItem: false, @@ -5601,7 +5601,7 @@ function buildOptimisticGroupChatReport( */ function buildOptimisticCreatedReportAction(emailCreatingAction: string, created = DateUtils.getDBTime()): OptimisticCreatedReportAction { return { - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), actionName: CONST.REPORT.ACTIONS.TYPE.CREATED, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, actorAccountID: currentUserAccountID, @@ -5637,7 +5637,7 @@ function buildOptimisticCreatedReportAction(emailCreatingAction: string, created function buildOptimisticRenamedRoomReportAction(newName: string, oldName: string): OptimisticRenamedReportAction { const now = DateUtils.getDBTime(); return { - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), actionName: CONST.REPORT.ACTIONS.TYPE.RENAMED, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, actorAccountID: currentUserAccountID, @@ -5679,7 +5679,7 @@ function buildOptimisticRenamedRoomReportAction(newName: string, oldName: string function buildOptimisticRoomDescriptionUpdatedReportAction(description: string): OptimisticRoomDescriptionUpdatedReportAction { const now = DateUtils.getDBTime(); return { - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), actionName: CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.UPDATE_ROOM_DESCRIPTION, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, actorAccountID: currentUserAccountID, @@ -5711,7 +5711,7 @@ function buildOptimisticRoomDescriptionUpdatedReportAction(description: string): */ function buildOptimisticHoldReportAction(created = DateUtils.getDBTime()): OptimisticHoldReportAction { return { - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), actionName: CONST.REPORT.ACTIONS.TYPE.HOLD, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, actorAccountID: currentUserAccountID, @@ -5742,7 +5742,7 @@ function buildOptimisticHoldReportAction(created = DateUtils.getDBTime()): Optim */ function buildOptimisticHoldReportActionComment(comment: string, created = DateUtils.getDBTime()): OptimisticHoldReportAction { return { - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), actionName: CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, actorAccountID: currentUserAccountID, @@ -5773,7 +5773,7 @@ function buildOptimisticHoldReportActionComment(comment: string, created = DateU */ function buildOptimisticUnHoldReportAction(created = DateUtils.getDBTime()): OptimisticHoldReportAction { return { - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), actionName: CONST.REPORT.ACTIONS.TYPE.UNHOLD, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, actorAccountID: currentUserAccountID, @@ -5816,10 +5816,10 @@ function buildOptimisticEditedTaskFieldReportAction({title, description}: Task): } else if (field) { changelog = `removed the ${field}`; } - const delegateAccountDetails = PersonalDetailsUtils.getPersonalDetailByEmail(delegateEmail); + const delegateAccountDetails = getPersonalDetailByEmail(delegateEmail); return { - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), actionName: CONST.REPORT.ACTIONS.TYPE.TASK_EDITED, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, actorAccountID: currentUserAccountID, @@ -5861,16 +5861,16 @@ function buildOptimisticCardAssignedReportAction(assigneeAccountID: number): Opt text: getCurrentUserDisplayNameOrEmail(), }, ], - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), shouldShow: true, }; } function buildOptimisticChangedTaskAssigneeReportAction(assigneeAccountID: number): OptimisticEditedTaskReportAction { - const delegateAccountDetails = PersonalDetailsUtils.getPersonalDetailByEmail(delegateEmail); + const delegateAccountDetails = getPersonalDetailByEmail(delegateEmail); return { - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), actionName: CONST.REPORT.ACTIONS.TYPE.TASK_EDITED, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, actorAccountID: currentUserAccountID, @@ -5936,7 +5936,7 @@ function buildOptimisticClosedReportAction( text: getCurrentUserDisplayNameOrEmail(), }, ], - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), shouldShow: true, }; } @@ -5969,7 +5969,7 @@ function buildOptimisticDismissedViolationReportAction( text: getCurrentUserDisplayNameOrEmail(), }, ], - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), shouldShow: true, }; } @@ -6191,7 +6191,7 @@ function buildOptimisticTaskReport( function buildOptimisticExportIntegrationAction(integration: ConnectionName, markedManually = false): OptimisticExportIntegrationAction { const label = CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[integration]; return { - reportActionID: NumberUtils.rand64(), + reportActionID: rand64(), actionName: CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_INTEGRATION, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, actorAccountID: currentUserAccountID, @@ -6477,7 +6477,7 @@ function hasReportViolations(reportID: string) { */ function shouldAdminsRoomBeVisible(report: OnyxEntry): boolean { const accountIDs = Object.entries(report?.participants ?? {}).map(([accountID]) => Number(accountID)); - const adminAccounts = PersonalDetailsUtils.getLoginsByAccountIDs(accountIDs).filter((login) => !isExpensifyTeam(login)); + const adminAccounts = getLoginsByAccountIDs(accountIDs).filter((login) => !isExpensifyTeam(login)); const lastVisibleAction = getLastVisibleActionReportActionsUtils(report?.reportID ?? ''); if ((lastVisibleAction ? isCreatedAction(lastVisibleAction) : report?.lastActionType === CONST.REPORT.ACTIONS.TYPE.CREATED) && adminAccounts.length <= 1) { return false; @@ -6941,7 +6941,7 @@ function parseReportRouteParams(route: string): ReportRouteParams { parsingRoute = parsingRoute.slice(1); } - if (!parsingRoute.startsWith(Url.addTrailingForwardSlash(ROUTES.REPORT))) { + if (!parsingRoute.startsWith(addTrailingForwardSlash(ROUTES.REPORT))) { return {reportID: '', isSubReportPageRoute: false}; } diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index cf833fa47429..4deec4022f70 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -30,29 +30,62 @@ import type { UpdateMoneyRequestParams, } from '@libs/API/parameters'; import {WRITE_COMMANDS} from '@libs/API/types'; -import * as CurrencyUtils from '@libs/CurrencyUtils'; +import '@libs/CurrencyUtils'; import DateUtils from '@libs/DateUtils'; import DistanceRequestUtils from '@libs/DistanceRequestUtils'; -import * as ErrorUtils from '@libs/ErrorUtils'; -import * as FileUtils from '@libs/fileDownload/FileUtils'; +import {getMicroSecondOnyxErrorObject, getMicroSecondOnyxErrorWithTranslationKey} from '@libs/ErrorUtils'; +import '@libs/fileDownload/FileUtils'; import GoogleTagManager from '@libs/GoogleTagManager'; -import * as IOUUtils from '@libs/IOUUtils'; -import * as LocalePhoneNumber from '@libs/LocalePhoneNumber'; +import {formatCurrentUserToAttendee, updateIOUOwnerAndTotal} from '@libs/IOUUtils'; +import {formatPhoneNumber} from '@libs/LocalePhoneNumber'; import * as Localize from '@libs/Localize'; import isSearchTopmostCentralPane from '@libs/Navigation/isSearchTopmostCentralPane'; import Navigation from '@libs/Navigation/Navigation'; -import * as NextStepUtils from '@libs/NextStepUtils'; +import {buildNextStep} from '@libs/NextStepUtils'; import {rand64} from '@libs/NumberUtils'; -import * as OptionsListUtils from '@libs/OptionsListUtils'; -import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; -import * as PhoneNumber from '@libs/PhoneNumber'; -import * as PolicyUtils from '@libs/PolicyUtils'; -import * as ReportActionsUtils from '@libs/ReportActionsUtils'; +import '@libs/OptionsListUtils'; +import '@libs/PersonalDetailsUtils'; +import {addSMSDomainIfPhoneNumber} from '@libs/PhoneNumber'; +import {hasDependentTags, isControlPolicy, isPaidGroupPolicy} from '@libs/PolicyUtils'; +import { + getLastVisibleAction, + getLastVisibleMessage, + getOriginalMessage, + getReportAction, + getReportActionHtml, + getReportActionText, + isActionableTrackExpense, + isDeletedParentAction, + isReportPreviewAction, +} from '@libs/ReportActionsUtils'; import {getAllReports} from '@libs/ReportConnection'; import type {OptimisticChatReport, OptimisticCreatedReportAction, OptimisticIOUReportAction, TransactionDetails} from '@libs/ReportUtils'; -import * as ReportUtils from '@libs/ReportUtils'; -import * as SessionUtils from '@libs/SessionUtils'; -import * as SubscriptionUtils from '@libs/SubscriptionUtils'; +import { + buildOptimisticActionableTrackExpenseWhisper, + buildOptimisticChatReport, + buildOptimisticExpenseReport, + buildOptimisticInvoiceReport, + buildOptimisticIOUReport, + buildOptimisticModifiedExpenseReportAction, + buildOptimisticMoneyRequestEntities, + buildOptimisticMovedTrackedExpenseModifiedReportAction, + buildOptimisticReportPreview, + canUserPerformWriteAction as canUserPerformWriteActionReportUtils, + getChatByParticipants, + getInvoiceChatByParticipants, + getOutstandingChildRequest, + getPersonalDetailsForAccountID, + getTransactionDetails, + isDraftReport, + isExpenseReport, + isInvoiceReport, + isSelfDM, + isTrackExpenseReport, + shouldCreateNewMoneyRequestReport as shouldCreateNewMoneyRequestReportReportUtils, + updateReportPreview, +} from '@libs/ReportUtils'; +import '@libs/SessionUtils'; +import '@libs/SubscriptionUtils'; import { buildOptimisticTransaction, getAllReportTransactions, @@ -355,7 +388,7 @@ function getReportPreviewAction(chatReportID: string, iouReportID: string): Onyx return ( Object.values(reportActions).find( (reportAction): reportAction is ReportAction => - reportAction && ReportActionsUtils.isReportPreviewAction(reportAction) && ReportActionsUtils.getOriginalMessage(reportAction)?.linkedReportID === iouReportID, + reportAction && isReportPreviewAction(reportAction) && getOriginalMessage(reportAction)?.linkedReportID === iouReportID, ) ?? null ); } @@ -413,7 +446,7 @@ function initMoneyRequest( // Use set() here so that there is no way that data will be leaked between objects when it gets reset Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${newTransactionID}`, { amount: 0, - attendees: IOUUtils.formatCurrentUserToAttendee(currentUserPersonalDetails, reportID), + attendees: formatCurrentUserToAttendee(currentUserPersonalDetails, reportID), comment, created, currency, @@ -532,8 +565,8 @@ function setMoneyRequestDistanceRate(transactionID: string, rateID: string, poli /** Helper function to get the receipt error for expenses, or the generic error if there's no receipt */ function getReceiptError(receipt: OnyxEntry, filename?: string, isScanRequest = true, errorKey?: number): Errors | ErrorFields { return isEmptyObject(receipt) || !isScanRequest - ? ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage', errorKey) - : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: receipt.source?.toString() ?? '', filename: filename ?? ''}, errorKey); + ? getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage', errorKey) + : getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: receipt.source?.toString() ?? '', filename: filename ?? ''}, errorKey); } /** Helper function to get optimistic fields violations onyx data */ @@ -594,7 +627,7 @@ function buildOnyxDataForMoneyRequest( optimisticRecentlyUsedCurrencies?: string[], ): [OnyxUpdate[], OnyxUpdate[], OnyxUpdate[]] { const isScanRequest = isScanRequestTransactionUtils(transaction); - const outstandingChildRequest = ReportUtils.getOutstandingChildRequest(iouReport); + const outstandingChildRequest = getOutstandingChildRequest(iouReport); const clearedPendingFields = Object.fromEntries(Object.keys(transaction.pendingFields ?? {}).map((key) => [key, null])); const optimisticData: OnyxUpdate[] = []; const successData: OnyxUpdate[] = []; @@ -626,8 +659,8 @@ function buildOnyxDataForMoneyRequest( key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, value: { ...iouReport, - lastMessageText: ReportActionsUtils.getReportActionText(iouAction), - lastMessageHtml: ReportActionsUtils.getReportActionHtml(iouAction), + lastMessageHtml: getReportActionHtml(iouAction), + lastMessageText: getReportActionText(iouAction), lastVisibleActionCreated: iouAction.created, pendingFields: { ...(shouldCreateNewMoneyRequestReport ? {createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD} : {preview: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}), @@ -857,7 +890,7 @@ function buildOnyxDataForMoneyRequest( ...(isNewChatReport ? { errorFields: { - createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), + createChat: getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, } : {}), @@ -869,7 +902,7 @@ function buildOnyxDataForMoneyRequest( value: { pendingFields: null, errorFields: { - ...(shouldCreateNewMoneyRequestReport ? {createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage')} : {}), + ...(shouldCreateNewMoneyRequestReport ? {createChat: getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage')} : {}), }, }, }, @@ -881,7 +914,7 @@ function buildOnyxDataForMoneyRequest( errorFields: existingTransactionThreadReport ? null : { - createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), + createChat: getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, }, }, @@ -907,7 +940,7 @@ function buildOnyxDataForMoneyRequest( errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest, errorKey), }, [iouAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, } : { @@ -944,25 +977,18 @@ function buildOnyxDataForMoneyRequest( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReport?.reportID}`, value: { [transactionThreadCreatedReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, }, }); } // We don't need to compute violations unless we're on a paid policy - if (!policy || !PolicyUtils.isPaidGroupPolicy(policy)) { + if (!policy || !isPaidGroupPolicy(policy)) { return [optimisticData, successData, failureData]; } - const violationsOnyxData = ViolationsUtils.getViolationsOnyxData( - transaction, - [], - policy, - policyTagList ?? {}, - policyCategories ?? {}, - PolicyUtils.hasDependentTags(policy, policyTagList ?? {}), - ); + const violationsOnyxData = ViolationsUtils.getViolationsOnyxData(transaction, [], policy, policyTagList ?? {}, policyCategories ?? {}, hasDependentTags(policy, policyTagList ?? {})); if (violationsOnyxData) { optimisticData.push(violationsOnyxData); @@ -1005,8 +1031,8 @@ function buildOnyxDataForInvoice( key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, value: { ...iouReport, - lastMessageText: ReportActionsUtils.getReportActionText(iouAction), - lastMessageHtml: ReportActionsUtils.getReportActionHtml(iouAction), + lastMessageText: getReportActionText(iouAction), + lastMessageHtml: getReportActionHtml(iouAction), pendingFields: { createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }, @@ -1217,7 +1243,7 @@ function buildOnyxDataForInvoice( ...(isNewChatReport ? { errorFields: { - createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), + createChat: getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, } : {}), @@ -1229,7 +1255,7 @@ function buildOnyxDataForInvoice( value: { pendingFields: null, errorFields: { - createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), + createChat: getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, }, }, @@ -1238,7 +1264,7 @@ function buildOnyxDataForInvoice( key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport.reportID}`, value: { errorFields: { - createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), + createChat: getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, }, }, @@ -1246,7 +1272,7 @@ function buildOnyxDataForInvoice( onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`, value: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateInvoiceFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateInvoiceFailureMessage'), pendingAction: null, pendingFields: clearedPendingFields, }, @@ -1261,7 +1287,7 @@ function buildOnyxDataForInvoice( errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt?.filename, false, errorKey), }, [iouAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateInvoiceFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateInvoiceFailureMessage'), }, }, }, @@ -1270,7 +1296,7 @@ function buildOnyxDataForInvoice( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReport.reportID}`, value: { [transactionThreadCreatedReportAction?.reportActionID ?? '-1']: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateInvoiceFailureMessage', errorKey), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateInvoiceFailureMessage', errorKey), }, }, }, @@ -1320,18 +1346,11 @@ function buildOnyxDataForInvoice( } // We don't need to compute violations unless we're on a paid policy - if (!policy || !PolicyUtils.isPaidGroupPolicy(policy)) { + if (!policy || !isPaidGroupPolicy(policy)) { return [optimisticData, successData, failureData]; } - const violationsOnyxData = ViolationsUtils.getViolationsOnyxData( - transaction, - [], - policy, - policyTagList ?? {}, - policyCategories ?? {}, - PolicyUtils.hasDependentTags(policy, policyTagList ?? {}), - ); + const violationsOnyxData = ViolationsUtils.getViolationsOnyxData(transaction, [], policy, policyTagList ?? {}, policyCategories ?? {}, hasDependentTags(policy, policyTagList ?? {})); if (violationsOnyxData) { optimisticData.push(violationsOnyxData); @@ -1384,8 +1403,8 @@ function buildOnyxDataForTrackExpense( key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, value: { ...chatReport, - lastMessageText: ReportActionsUtils.getReportActionText(iouAction), - lastMessageHtml: ReportActionsUtils.getReportActionHtml(iouAction), + lastMessageText: getReportActionText(iouAction), + lastMessageHtml: getReportActionHtml(iouAction), lastReadTime: DateUtils.getDBTime(), iouReportID: iouReport?.reportID, }, @@ -1439,8 +1458,8 @@ function buildOnyxDataForTrackExpense( key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, value: { ...iouReport, - lastMessageText: ReportActionsUtils.getReportActionText(iouAction), - lastMessageHtml: ReportActionsUtils.getReportActionHtml(iouAction), + lastMessageText: getReportActionText(iouAction), + lastMessageHtml: getReportActionHtml(iouAction), pendingFields: { ...(shouldCreateNewMoneyRequestReport ? {createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD} : {preview: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}), }, @@ -1604,7 +1623,7 @@ function buildOnyxDataForTrackExpense( value: { pendingFields: null, errorFields: { - ...(shouldCreateNewMoneyRequestReport ? {createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage')} : {}), + ...(shouldCreateNewMoneyRequestReport ? {createChat: getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage')} : {}), }, }, }, @@ -1620,7 +1639,7 @@ function buildOnyxDataForTrackExpense( errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest), }, [iouAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, } : { @@ -1665,7 +1684,7 @@ function buildOnyxDataForTrackExpense( errorFields: existingTransactionThreadReport ? null : { - createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), + createChat: getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, }, }, @@ -1684,25 +1703,18 @@ function buildOnyxDataForTrackExpense( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReport?.reportID}`, value: { [transactionThreadCreatedReportAction?.reportActionID ?? '-1']: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, }, }, ); // We don't need to compute violations unless we're on a paid policy - if (!policy || !PolicyUtils.isPaidGroupPolicy(policy)) { + if (!policy || !isPaidGroupPolicy(policy)) { return [optimisticData, successData, failureData]; } - const violationsOnyxData = ViolationsUtils.getViolationsOnyxData( - transaction, - [], - policy, - policyTagList ?? {}, - policyCategories ?? {}, - PolicyUtils.hasDependentTags(policy, policyTagList ?? {}), - ); + const violationsOnyxData = ViolationsUtils.getViolationsOnyxData(transaction, [], policy, policyTagList ?? {}, policyCategories ?? {}, hasDependentTags(policy, policyTagList ?? {})); if (violationsOnyxData) { optimisticData.push(violationsOnyxData); @@ -1714,7 +1726,7 @@ function buildOnyxDataForTrackExpense( } // Show field violations only for control policies - if (PolicyUtils.isControlPolicy(policy) && iouReport) { + if (isControlPolicy(policy) && iouReport) { const {optimisticData: fieldViolationsOptimisticData, failureData: fieldViolationsFailureData} = getFieldViolationsOnyxData(iouReport); optimisticData.push(...fieldViolationsOptimisticData); failureData.push(...fieldViolationsFailureData); @@ -1773,10 +1785,10 @@ function getDeleteTrackExpenseInformation( } as OnyxTypes.ReportActions; let canUserPerformWriteAction = true; if (chatReport) { - canUserPerformWriteAction = !!ReportUtils.canUserPerformWriteAction(chatReport); + canUserPerformWriteAction = !!canUserPerformWriteActionReportUtils(chatReport); } - const lastVisibleAction = ReportActionsUtils.getLastVisibleAction(chatReport?.reportID ?? '-1', canUserPerformWriteAction, updatedReportAction); - const {lastMessageText = '', lastMessageHtml = ''} = ReportActionsUtils.getLastVisibleMessage(chatReport?.reportID ?? '-1', canUserPerformWriteAction, updatedReportAction); + const lastVisibleAction = getLastVisibleAction(chatReport?.reportID ?? '-1', canUserPerformWriteAction, updatedReportAction); + const {lastMessageText = '', lastMessageHtml = ''} = getLastVisibleMessage(chatReport?.reportID ?? '-1', canUserPerformWriteAction, updatedReportAction); // STEP 4: Build Onyx data const optimisticData: OnyxUpdate[] = []; @@ -1865,16 +1877,14 @@ function getDeleteTrackExpenseInformation( } if (actionableWhisperReportActionID) { - const actionableWhisperReportAction = ReportActionsUtils.getReportAction(chatReportID, actionableWhisperReportActionID); + const actionableWhisperReportAction = getReportAction(chatReportID, actionableWhisperReportActionID); failureData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`, value: { [actionableWhisperReportActionID]: { originalMessage: { - resolution: ReportActionsUtils.isActionableTrackExpense(actionableWhisperReportAction) - ? ReportActionsUtils.getOriginalMessage(actionableWhisperReportAction)?.resolution ?? null - : null, + resolution: isActionableTrackExpense(actionableWhisperReportAction) ? getOriginalMessage(actionableWhisperReportAction)?.resolution ?? null : null, }, }, }, @@ -1888,7 +1898,7 @@ function getDeleteTrackExpenseInformation( [reportAction.reportActionID]: { ...reportAction, pendingAction: null, - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericDeleteFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericDeleteFailureMessage'), }, }, }, @@ -1924,7 +1934,7 @@ function getSendInvoiceInformation( const senderWorkspaceID = participants?.find((participant) => participant?.isSender)?.policyID ?? '-1'; const receiverParticipant = participants?.find((participant) => participant?.accountID) ?? invoiceChatReport?.invoiceReceiver; const receiverAccountID = receiverParticipant && 'accountID' in receiverParticipant && receiverParticipant.accountID ? receiverParticipant.accountID : -1; - let receiver = ReportUtils.getPersonalDetailsForAccountID(receiverAccountID); + let receiver = getPersonalDetailsForAccountID(receiverAccountID); let optimisticPersonalDetailListAction = {}; // STEP 1: Get existing chat report OR build a new optimistic one @@ -1932,16 +1942,16 @@ function getSendInvoiceInformation( let chatReport = !isEmptyObject(invoiceChatReport) && invoiceChatReport?.reportID ? invoiceChatReport : null; if (!chatReport) { - chatReport = ReportUtils.getInvoiceChatByParticipants(senderWorkspaceID, receiverAccountID) ?? null; + chatReport = getInvoiceChatByParticipants(senderWorkspaceID, receiverAccountID) ?? null; } if (!chatReport) { isNewChatReport = true; - chatReport = ReportUtils.buildOptimisticChatReport([receiverAccountID, currentUserAccountID], CONST.REPORT.DEFAULT_REPORT_NAME, CONST.REPORT.CHAT_TYPE.INVOICE, senderWorkspaceID); + chatReport = buildOptimisticChatReport([receiverAccountID, currentUserAccountID], CONST.REPORT.DEFAULT_REPORT_NAME, CONST.REPORT.CHAT_TYPE.INVOICE, senderWorkspaceID); } // STEP 2: Create a new optimistic invoice report. - const optimisticInvoiceReport = ReportUtils.buildOptimisticInvoiceReport(chatReport.reportID, senderWorkspaceID, receiverAccountID, receiver.displayName ?? '', amount, currency); + const optimisticInvoiceReport = buildOptimisticInvoiceReport(chatReport.reportID, senderWorkspaceID, receiverAccountID, receiver.displayName ?? '', amount, currency); // STEP 3: Build optimistic receipt and transaction const receiptObject: Receipt = {}; @@ -1981,7 +1991,7 @@ function getSendInvoiceInformation( const receiverLogin = receiverParticipant && 'login' in receiverParticipant && receiverParticipant.login ? receiverParticipant.login : ''; receiver = { accountID: receiverAccountID, - displayName: LocalePhoneNumber.formatPhoneNumber(receiverLogin), + displayName: formatPhoneNumber(receiverLogin), login: receiverLogin, isOptimisticPersonalDetail: true, }; @@ -1990,11 +2000,11 @@ function getSendInvoiceInformation( } // STEP 5: Build optimistic reportActions. - const reportPreviewAction = ReportUtils.buildOptimisticReportPreview(chatReport, optimisticInvoiceReport, trimmedComment, optimisticTransaction); + const reportPreviewAction = buildOptimisticReportPreview(chatReport, optimisticInvoiceReport, trimmedComment, optimisticTransaction); optimisticInvoiceReport.parentReportActionID = reportPreviewAction.reportActionID; chatReport.lastVisibleActionCreated = reportPreviewAction.created; const [optimisticCreatedActionForChat, optimisticCreatedActionForIOUReport, iouAction, optimisticTransactionThread, optimisticCreatedActionForTransactionThread] = - ReportUtils.buildOptimisticMoneyRequestEntities( + buildOptimisticMoneyRequestEntities( optimisticInvoiceReport, CONST.IOU.REPORT_ACTION_TYPE.CREATE, amount, @@ -2081,7 +2091,7 @@ function getMoneyRequestInformation( attendees?: Attendee[], existingTransaction: OnyxEntry | undefined = undefined, ): MoneyRequestInformation { - const payerEmail = PhoneNumber.addSMSDomainIfPhoneNumber(participant.login ?? ''); + const payerEmail = addSMSDomainIfPhoneNumber(participant.login ?? ''); const payerAccountID = Number(participant.accountID); const isPolicyExpenseChat = participant.isPolicyExpenseChat; @@ -2097,13 +2107,13 @@ function getMoneyRequestInformation( } if (!chatReport) { - chatReport = ReportUtils.getChatByParticipants([payerAccountID, payeeAccountID]) ?? null; + chatReport = getChatByParticipants([payerAccountID, payeeAccountID]) ?? null; } // If we still don't have a report, it likely doens't exist and we need to build an optimistic one if (!chatReport) { isNewChatReport = true; - chatReport = ReportUtils.buildOptimisticChatReport([payerAccountID, payeeAccountID]); + chatReport = buildOptimisticChatReport([payerAccountID, payeeAccountID]); } // STEP 2: Get the Expense/IOU report. If the moneyRequestReportID has been provided, we want to add the transaction to this specific report. @@ -2115,12 +2125,12 @@ function getMoneyRequestInformation( iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReport.iouReportID}`] ?? null; } - const shouldCreateNewMoneyRequestReport = ReportUtils.shouldCreateNewMoneyRequestReport(iouReport, chatReport); + const shouldCreateNewMoneyRequestReport = shouldCreateNewMoneyRequestReportReportUtils(iouReport, chatReport); if (!iouReport || shouldCreateNewMoneyRequestReport) { iouReport = isPolicyExpenseChat - ? ReportUtils.buildOptimisticExpenseReport(chatReport.reportID, chatReport.policyID ?? '-1', payeeAccountID, amount, currency) - : ReportUtils.buildOptimisticIOUReport(payeeAccountID, payerAccountID, amount, chatReport.reportID, currency); + ? buildOptimisticExpenseReport(chatReport.reportID, chatReport.policyID ?? '-1', payeeAccountID, amount, currency) + : buildOptimisticIOUReport(payeeAccountID, payerAccountID, amount, chatReport.reportID, currency); } else if (isPolicyExpenseChat) { iouReport = {...iouReport}; if (iouReport?.currency === currency && typeof iouReport.total === 'number') { @@ -2128,13 +2138,13 @@ function getMoneyRequestInformation( iouReport.total -= amount; } } else { - iouReport = IOUUtils.updateIOUOwnerAndTotal(iouReport, payeeAccountID, amount, currency); + iouReport = updateIOUOwnerAndTotal(iouReport, payeeAccountID, amount, currency); } // STEP 3: Build an optimistic transaction with the receipt const isDistanceRequest = existingTransaction && existingTransaction.iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE; let optimisticTransaction = buildOptimisticTransaction( - ReportUtils.isExpenseReport(iouReport) ? -amount : amount, + isExpenseReport(iouReport) ? -amount : amount, currency, iouReport.reportID, comment, @@ -2149,7 +2159,7 @@ function getMoneyRequestInformation( category, tag, taxCode, - ReportUtils.isExpenseReport(iouReport) ? -(taxAmount ?? 0) : taxAmount, + isExpenseReport(iouReport) ? -(taxAmount ?? 0) : taxAmount, billable, isDistanceRequest ? {waypoints: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD} : undefined, undefined, @@ -2178,7 +2188,7 @@ function getMoneyRequestInformation( // 5. REPORT_PREVIEW action for the chatReport // Note: The CREATED action for the IOU report must be optimistically generated before the IOU action so there's no chance that it appears after the IOU action in the chat const [optimisticCreatedActionForChat, optimisticCreatedActionForIOUReport, iouAction, optimisticTransactionThread, optimisticCreatedActionForTransactionThread] = - ReportUtils.buildOptimisticMoneyRequestEntities( + buildOptimisticMoneyRequestEntities( iouReport, CONST.IOU.REPORT_ACTION_TYPE.CREATE, amount, @@ -2199,9 +2209,9 @@ function getMoneyRequestInformation( let reportPreviewAction = shouldCreateNewMoneyRequestReport ? null : getReportPreviewAction(chatReport.reportID, iouReport.reportID); if (reportPreviewAction) { - reportPreviewAction = ReportUtils.updateReportPreview(iouReport, reportPreviewAction, false, comment, optimisticTransaction); + reportPreviewAction = updateReportPreview(iouReport, reportPreviewAction, false, comment, optimisticTransaction); } else { - reportPreviewAction = ReportUtils.buildOptimisticReportPreview(chatReport, iouReport, comment, optimisticTransaction); + reportPreviewAction = buildOptimisticReportPreview(chatReport, iouReport, comment, optimisticTransaction); chatReport.lastVisibleActionCreated = reportPreviewAction.created; // Generated ReportPreview action is a parent report action of the iou report. @@ -2217,7 +2227,7 @@ function getMoneyRequestInformation( accountID: payerAccountID, // Disabling this line since participant.displayName can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - displayName: LocalePhoneNumber.formatPhoneNumber(participant.displayName || payerEmail), + displayName: formatPhoneNumber(participant.displayName || payerEmail), login: participant.login, isOptimisticPersonalDetail: true, }, @@ -2225,7 +2235,7 @@ function getMoneyRequestInformation( : {}; const predictedNextStatus = policy?.reimbursementChoice === CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_NO ? CONST.REPORT.STATUS_NUM.CLOSED : CONST.REPORT.STATUS_NUM.OPEN; - const optimisticNextStep = NextStepUtils.buildNextStep(iouReport, predictedNextStatus); + const optimisticNextStep = buildNextStep(iouReport, predictedNextStatus); // STEP 5: Build Onyx Data const [optimisticData, successData, failureData] = buildOnyxDataForMoneyRequest( @@ -2320,11 +2330,11 @@ function getTrackExpenseInformation( } // Check if the report is a draft - const isDraftReport = ReportUtils.isDraftReport(chatReport?.reportID); + const isDraftReportLocal = isDraftReport(chatReport?.reportID); let createdWorkspaceParams: CreateWorkspaceParams | undefined; - if (isDraftReport) { + if (isDraftReportLocal) { const workspaceData = Policy.buildPolicyData(undefined, policy?.makeMeAdmin, policy?.name, policy?.id, chatReport?.reportID); createdWorkspaceParams = workspaceData.params; optimisticData.push(...workspaceData.optimisticData); @@ -2346,9 +2356,9 @@ function getTrackExpenseInformation( iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReport.iouReportID}`] ?? null; } - shouldCreateNewMoneyRequestReport = ReportUtils.shouldCreateNewMoneyRequestReport(iouReport, chatReport); + shouldCreateNewMoneyRequestReport = shouldCreateNewMoneyRequestReportReportUtils(iouReport, chatReport); if (!iouReport || shouldCreateNewMoneyRequestReport) { - iouReport = ReportUtils.buildOptimisticExpenseReport(chatReport.reportID, chatReport.policyID ?? '-1', payeeAccountID, amount, currency, false); + iouReport = buildOptimisticExpenseReport(chatReport.reportID, chatReport.policyID ?? '-1', payeeAccountID, amount, currency, false); } else { iouReport = {...iouReport}; if (iouReport?.currency === currency && typeof iouReport.total === 'number' && typeof iouReport.nonReimbursableTotal === 'number') { @@ -2376,7 +2386,7 @@ function getTrackExpenseInformation( } const isDistanceRequest = existingTransaction && existingTransaction.iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE; let optimisticTransaction = buildOptimisticTransaction( - ReportUtils.isExpenseReport(iouReport) ? -amount : amount, + isExpenseReport(iouReport) ? -amount : amount, currency, shouldUseMoneyReport && iouReport ? iouReport.reportID : '-1', comment, @@ -2413,7 +2423,7 @@ function getTrackExpenseInformation( // 2. IOU action for the iouReport (if tracking in the Expense chat), otherwise – for chatReport // 3. The transaction thread, which requires the iouAction, and CREATED action for the transaction thread // 4. REPORT_PREVIEW action for the chatReport (if tracking in the Expense chat) - const [, optimisticCreatedActionForIOUReport, iouAction, optimisticTransactionThread, optimisticCreatedActionForTransactionThread] = ReportUtils.buildOptimisticMoneyRequestEntities( + const [, optimisticCreatedActionForIOUReport, iouAction, optimisticTransactionThread, optimisticCreatedActionForTransactionThread] = buildOptimisticMoneyRequestEntities( shouldUseMoneyReport && iouReport ? iouReport : chatReport, CONST.IOU.REPORT_ACTION_TYPE.TRACK, amount, @@ -2436,9 +2446,9 @@ function getTrackExpenseInformation( reportPreviewAction = shouldCreateNewMoneyRequestReport ? null : getReportPreviewAction(chatReport.reportID, iouReport.reportID); if (reportPreviewAction) { - reportPreviewAction = ReportUtils.updateReportPreview(iouReport, reportPreviewAction, false, comment, optimisticTransaction); + reportPreviewAction = updateReportPreview(iouReport, reportPreviewAction, false, comment, optimisticTransaction); } else { - reportPreviewAction = ReportUtils.buildOptimisticReportPreview(chatReport, iouReport, comment, optimisticTransaction); + reportPreviewAction = buildOptimisticReportPreview(chatReport, iouReport, comment, optimisticTransaction); // Generated ReportPreview action is a parent report action of the iou report. // We are setting the iou report's parentReportActionID to display subtitle correctly in IOU page when offline. iouReport.parentReportActionID = reportPreviewAction.reportActionID; @@ -2447,7 +2457,7 @@ function getTrackExpenseInformation( let actionableTrackExpenseWhisper: OnyxInputValue = null; if (!isPolicyExpenseChat) { - actionableTrackExpenseWhisper = ReportUtils.buildOptimisticActionableTrackExpenseWhisper(iouAction, optimisticTransaction.transactionID); + actionableTrackExpenseWhisper = buildOptimisticActionableTrackExpenseWhisper(iouAction, optimisticTransaction.transactionID); } // STEP 5: Build Onyx Data @@ -2499,12 +2509,12 @@ function calculateDiffAmount( if (!iouReport) { return 0; } - const isExpenseReport = ReportUtils.isExpenseReport(iouReport); + const isExpenseReportLocal = isExpenseReport(iouReport); const updatedCurrency = getCurrency(updatedTransaction); const currentCurrency = getCurrency(transaction); - const currentAmount = getAmount(transaction, isExpenseReport); - const updatedAmount = getAmount(updatedTransaction, isExpenseReport); + const currentAmount = getAmount(transaction, isExpenseReportLocal); + const updatedAmount = getAmount(updatedTransaction, isExpenseReportLocal); if (updatedCurrency === iouReport?.currency && currentCurrency !== iouReport?.currency) { // Add the diff to the total if we change the currency from a different currency to the currency of the IOU report @@ -2551,7 +2561,7 @@ function getUpdateMoneyRequestParams( const transactionThread = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThread?.parentReportID}`] ?? null; - const isFromExpenseReport = ReportUtils.isExpenseReport(iouReport); + const isFromExpenseReport = isExpenseReport(iouReport); const isScanning = hasReceiptTransactionUtils(transaction) && isReceiptBeingScannedTransactionUtils(transaction); const updatedTransaction: OnyxEntry = transaction ? getUpdatedTransaction({ @@ -2561,7 +2571,7 @@ function getUpdateMoneyRequestParams( policy, }) : undefined; - const transactionDetails = ReportUtils.getTransactionDetails(updatedTransaction); + const transactionDetails = getTransactionDetails(updatedTransaction); if (transactionDetails?.waypoints) { // This needs to be a JSON string since we're sending this to the MapBox API @@ -2606,7 +2616,7 @@ function getUpdateMoneyRequestParams( // - we're updating the distance rate while the waypoints are still pending // In these cases, there isn't a valid optimistic mileage data we can use, // and the report action is created on the server with the distance-related response from the MapBox API - const updatedReportAction = ReportUtils.buildOptimisticModifiedExpenseReportAction(transactionThread, transaction, transactionChanges, isFromExpenseReport, policy, updatedTransaction); + const updatedReportAction = buildOptimisticModifiedExpenseReportAction(transactionThread, transaction, transactionChanges, isFromExpenseReport, policy, updatedTransaction); if (!hasPendingWaypoints && !(hasModifiedDistanceRate && isFetchingWaypointsFromServer(transaction))) { params.reportActionID = updatedReportAction.reportActionID; @@ -2646,7 +2656,7 @@ function getUpdateMoneyRequestParams( value: { [updatedReportAction.reportActionID]: { ...(updatedReportAction as OnyxTypes.ReportAction), - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericEditFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericEditFailureMessage'), }, }, }); @@ -2658,7 +2668,7 @@ function getUpdateMoneyRequestParams( let updatedMoneyRequestReport: OnyxTypes.OnyxInputOrEntry; if (!iouReport) { updatedMoneyRequestReport = null; - } else if ((ReportUtils.isExpenseReport(iouReport) || ReportUtils.isInvoiceReport(iouReport)) && typeof iouReport.total === 'number') { + } else if ((isExpenseReport(iouReport) || isInvoiceReport(iouReport)) && typeof iouReport.total === 'number') { // For expense report, the amount is negative, so we should subtract total from diff updatedMoneyRequestReport = { ...iouReport, @@ -2668,7 +2678,7 @@ function getUpdateMoneyRequestParams( updatedMoneyRequestReport.nonReimbursableTotal -= diff; } } else { - updatedMoneyRequestReport = IOUUtils.updateIOUOwnerAndTotal(iouReport, updatedReportAction.actorAccountID ?? -1, diff, getCurrency(transaction), false, true); + updatedMoneyRequestReport = updateIOUOwnerAndTotal(iouReport, updatedReportAction.actorAccountID ?? -1, diff, getCurrency(transaction), false, true); } optimisticData.push( @@ -2680,7 +2690,7 @@ function getUpdateMoneyRequestParams( { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.parentReportID}`, - value: ReportUtils.getOutstandingChildRequest(updatedMoneyRequestReport), + value: getOutstandingChildRequest(updatedMoneyRequestReport), }, ); successData.push({ @@ -2818,7 +2828,7 @@ function getUpdateMoneyRequestParams( }); } - if (policy && PolicyUtils.isPaidGroupPolicy(policy) && updatedTransaction && (hasModifiedTag || hasModifiedCategory || hasModifiedDistanceRate)) { + if (policy && isPaidGroupPolicy(policy) && updatedTransaction && (hasModifiedTag || hasModifiedCategory || hasModifiedDistanceRate)) { const currentTransactionViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`] ?? []; optimisticData.push( ViolationsUtils.getViolationsOnyxData( @@ -2827,7 +2837,7 @@ function getUpdateMoneyRequestParams( policy, policyTagList ?? {}, policyCategories ?? {}, - PolicyUtils.hasDependentTags(policy, policyTagList ?? {}), + hasDependentTags(policy, policyTagList ?? {}), ), ); failureData.push({ @@ -2886,7 +2896,7 @@ function getUpdateTrackExpenseParams( policy, }) : null; - const transactionDetails = ReportUtils.getTransactionDetails(updatedTransaction); + const transactionDetails = getTransactionDetails(updatedTransaction); if (transactionDetails?.waypoints) { // This needs to be a JSON string since we're sending this to the MapBox API @@ -2930,7 +2940,7 @@ function getUpdateTrackExpenseParams( // - we're updating the distance rate while the waypoints are still pending // In these cases, there isn't a valid optimistic mileage data we can use, // and the report action is created on the server with the distance-related response from the MapBox API - const updatedReportAction = ReportUtils.buildOptimisticModifiedExpenseReportAction(transactionThread, transaction, transactionChanges, false, policy, updatedTransaction); + const updatedReportAction = buildOptimisticModifiedExpenseReportAction(transactionThread, transaction, transactionChanges, false, policy, updatedTransaction); if (!hasPendingWaypoints && !(hasModifiedDistanceRate && isFetchingWaypointsFromServer(transaction))) { params.reportActionID = updatedReportAction.reportActionID; @@ -2954,7 +2964,7 @@ function getUpdateTrackExpenseParams( value: { [updatedReportAction.reportActionID]: { ...(updatedReportAction as OnyxTypes.ReportAction), - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericEditFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericEditFailureMessage'), }, }, }); @@ -3046,7 +3056,7 @@ function updateMoneyRequestDate( const transactionThreadReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.parentReportID}`] ?? null; let data: UpdateMoneyRequestData; - if (ReportUtils.isTrackExpenseReport(transactionThreadReport) && ReportUtils.isSelfDM(parentReport)) { + if (isTrackExpenseReport(transactionThreadReport) && isSelfDM(parentReport)) { data = getUpdateTrackExpenseParams(transactionID, transactionThreadReportID, transactionChanges, policy); } else { data = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, policy, policyTags, policyCategories); @@ -3087,7 +3097,7 @@ function updateMoneyRequestMerchant( const transactionThreadReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.parentReportID}`] ?? null; let data: UpdateMoneyRequestData; - if (ReportUtils.isTrackExpenseReport(transactionThreadReport) && ReportUtils.isSelfDM(parentReport)) { + if (isTrackExpenseReport(transactionThreadReport) && isSelfDM(parentReport)) { data = getUpdateTrackExpenseParams(transactionID, transactionThreadReportID, transactionChanges, policy); } else { data = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, policy, policyTagList, policyCategories); @@ -3194,7 +3204,7 @@ function updateMoneyRequestDistance({ const transactionThreadReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.parentReportID}`] ?? null; let data: UpdateMoneyRequestData; - if (ReportUtils.isTrackExpenseReport(transactionThreadReport) && ReportUtils.isSelfDM(parentReport)) { + if (isTrackExpenseReport(transactionThreadReport) && isSelfDM(parentReport)) { data = getUpdateTrackExpenseParams(transactionID, transactionThreadReportID, transactionChanges, policy); } else { data = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, policy, policyTagList, policyCategories); @@ -3243,7 +3253,7 @@ function updateMoneyRequestDescription( const transactionThreadReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.parentReportID}`] ?? null; let data: UpdateMoneyRequestData; - if (ReportUtils.isTrackExpenseReport(transactionThreadReport) && ReportUtils.isSelfDM(parentReport)) { + if (isTrackExpenseReport(transactionThreadReport) && isSelfDM(parentReport)) { data = getUpdateTrackExpenseParams(transactionID, transactionThreadReportID, transactionChanges, policy); } else { data = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, policy, policyTagList, policyCategories); @@ -3284,7 +3294,7 @@ function updateMoneyRequestDistanceRate( } let data: UpdateMoneyRequestData; - if (ReportUtils.isTrackExpenseReport(transactionThreadReport) && ReportUtils.isSelfDM(parentReport)) { + if (isTrackExpenseReport(transactionThreadReport) && isSelfDM(parentReport)) { data = getUpdateTrackExpenseParams(transactionID, transactionThreadReportID, transactionChanges, policy); } else { data = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, policy, policyTagList, policyCategories); @@ -3320,7 +3330,7 @@ const getConvertTrackedExpenseInformation = ( failureData?.push(...deleteFailureData); // Build modified expense report action with the transaction changes - const modifiedExpenseReportAction = ReportUtils.buildOptimisticMovedTrackedExpenseModifiedReportAction(transactionThreadReportID, moneyRequestReportID); + const modifiedExpenseReportAction = buildOptimisticMovedTrackedExpenseModifiedReportAction(transactionThreadReportID, moneyRequestReportID); optimisticData?.push({ onyxMethod: Onyx.METHOD.MERGE, @@ -3342,7 +3352,7 @@ const getConvertTrackedExpenseInformation = ( value: { [modifiedExpenseReportAction.reportActionID]: { ...(modifiedExpenseReportAction as OnyxTypes.ReportAction), - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericEditFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericEditFailureMessage'), }, }, }); @@ -3601,7 +3611,7 @@ function requestMoney(requestMoneyInformation: RequestMoneyInformation) { } = transactionParams; // If the report is iou or expense report, we should get the linked chat report to be passed to the getMoneyRequestInformation function - const isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report); + const isMoneyRequestReport = isMoneyRequestReport(report); const currentChatReport = isMoneyRequestReport ? ReportUtils.getReportOrDraftReport(report?.chatReportID) : report; const moneyRequestReportID = isMoneyRequestReport ? report?.reportID : ''; const isMovingTransactionFromTrackExpense = IOUUtils.isMovingTransactionFromTrackExpense(action); @@ -4189,7 +4199,7 @@ function createSplitsAndOnyxData( onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${splitTransaction.transactionID}`, value: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), pendingAction: null, pendingFields: null, }, @@ -4207,7 +4217,7 @@ function createSplitsAndOnyxData( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`, value: { [splitIOUReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, }, }); @@ -4218,7 +4228,7 @@ function createSplitsAndOnyxData( key: `${ONYXKEYS.COLLECTION.REPORT}${splitChatReport.reportID}`, value: { errorFields: { - createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), + createChat: getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, }, }, @@ -4227,7 +4237,7 @@ function createSplitsAndOnyxData( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`, value: { [splitIOUReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, }, }, @@ -4768,7 +4778,7 @@ function startSplitBill({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${splitTransaction.transactionID}`, value: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, }, { @@ -4795,7 +4805,7 @@ function startSplitBill({ key: `${ONYXKEYS.COLLECTION.REPORT}${splitChatReport.reportID}`, value: { errorFields: { - createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), + createChat: getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, }, }, @@ -4804,7 +4814,7 @@ function startSplitBill({ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`, value: { [splitChatCreatedReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, [splitIOUReportAction.reportActionID]: { errors: getReceiptError(receipt, filename), @@ -4990,7 +5000,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, value: { ...unmodifiedTransaction, - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, }, { @@ -4999,7 +5009,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA value: { [reportAction.reportActionID]: { ...reportAction, - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, }, }, @@ -5452,19 +5462,18 @@ function prepareToCleanUpMoneyRequest(transactionID: string, reportAction: OnyxT let canUserPerformWriteAction = true; if (chatReport) { - canUserPerformWriteAction = !!ReportUtils.canUserPerformWriteAction(chatReport); + canUserPerformWriteAction = !!canUserPerformWriteActionReportUtils(chatReport); } - const lastVisibleAction = ReportActionsUtils.getLastVisibleAction(iouReport?.reportID ?? '-1', canUserPerformWriteAction, updatedReportAction); - const iouReportLastMessageText = ReportActionsUtils.getLastVisibleMessage(iouReport?.reportID ?? '-1', canUserPerformWriteAction, updatedReportAction).lastMessageText; - const shouldDeleteIOUReport = - iouReportLastMessageText.length === 0 && !ReportActionsUtils.isDeletedParentAction(lastVisibleAction) && (!transactionThreadID || shouldDeleteTransactionThread); + const lastVisibleAction = getLastVisibleAction(iouReport?.reportID ?? '-1', canUserPerformWriteAction, updatedReportAction); + const iouReportLastMessageText = getLastVisibleMessage(iouReport?.reportID ?? '-1', canUserPerformWriteAction, updatedReportAction).lastMessageText; + const shouldDeleteIOUReport = iouReportLastMessageText.length === 0 && !isDeletedParentAction(lastVisibleAction) && (!transactionThreadID || shouldDeleteTransactionThread); // STEP 4: Update the iouReport and reportPreview with new totals and messages if it wasn't deleted let updatedIOUReport: OnyxInputValue; const currency = getCurrency(transaction); const updatedReportPreviewAction: OnyxTypes.ReportAction = {...reportPreviewAction}; updatedReportPreviewAction.pendingAction = shouldDeleteIOUReport ? CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE : CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE; - if (iouReport && ReportUtils.isExpenseReport(iouReport)) { + if (iouReport && isExpenseReport(iouReport)) { updatedIOUReport = {...iouReport}; if (typeof updatedIOUReport.total === 'number' && currency === iouReport?.currency) { @@ -5477,7 +5486,7 @@ function prepareToCleanUpMoneyRequest(transactionID: string, reportAction: OnyxT } } } else { - updatedIOUReport = IOUUtils.updateIOUOwnerAndTotal(iouReport, reportAction.actorAccountID ?? -1, getAmount(transaction, false), currency, true); + updatedIOUReport = updateIOUOwnerAndTotal(iouReport, reportAction.actorAccountID ?? -1, getAmount(transaction, false), currency, true); } if (updatedIOUReport) { @@ -5650,7 +5659,7 @@ function cleanUpMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repo if (shouldDeleteIOUReport) { let canUserPerformWriteAction = true; if (chatReport) { - canUserPerformWriteAction = !!ReportUtils.canUserPerformWriteAction(chatReport); + canUserPerformWriteAction = !!canUserPerformWriteActionReportUtils(chatReport); } onyxUpdates.push( { @@ -5774,7 +5783,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor if (shouldDeleteIOUReport) { let canUserPerformWriteAction = true; if (chatReport) { - canUserPerformWriteAction = !!ReportUtils.canUserPerformWriteAction(chatReport); + canUserPerformWriteAction = !!canUserPerformWriteActionReportUtils(chatReport); } optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, @@ -6185,7 +6194,7 @@ function getSendMoneyParams( onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${optimisticTransaction.transactionID}`, value: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.other'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.other'), }, }, { @@ -6193,7 +6202,7 @@ function getSendMoneyParams( key: `${ONYXKEYS.COLLECTION.REPORT}${optimisticTransactionThread.reportID}`, value: { errorFields: { - createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), + createChat: getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, }, }, @@ -6202,7 +6211,7 @@ function getSendMoneyParams( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${optimisticTransactionThread.reportID}`, value: { [optimisticCreatedActionForTransactionThread?.reportActionID ?? '-1']: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, }, }, @@ -6226,7 +6235,7 @@ function getSendMoneyParams( key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, value: { errorFields: { - createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), + createChat: getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, }, }, @@ -6235,7 +6244,7 @@ function getSendMoneyParams( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${optimisticIOUReport.reportID}`, value: { [optimisticIOUReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, }, }, @@ -6251,7 +6260,7 @@ function getSendMoneyParams( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${optimisticIOUReport.reportID}`, value: { [optimisticIOUReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.other'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.other'), }, }, }); @@ -6675,7 +6684,7 @@ function getPayMoneyRequestParams( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.reportID ?? ''}`, value: { [optimisticIOUReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.other'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.other'), }, }, }, @@ -7062,7 +7071,7 @@ function approveMoneyRequest(expenseReport: OnyxEntry, full?: key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport?.reportID}`, value: { [optimisticApprovedReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.other'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.other'), }, }, }, @@ -7203,7 +7212,7 @@ function unapproveExpenseReport(expenseReport: OnyxEntry) { key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`, value: { [optimisticUnapprovedReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.other'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.other'), }, }, }, @@ -7350,7 +7359,7 @@ function submitReport(expenseReport: OnyxTypes.Report) { key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`, value: { [optimisticSubmittedReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.other'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.other'), }, }, }); @@ -7435,7 +7444,7 @@ function cancelPayment(expenseReport: OnyxEntry, chatReport: O key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`, value: { [optimisticReportAction.reportActionID ?? '-1']: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.other'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.other'), }, }, }, @@ -7648,7 +7657,7 @@ function detachReceipt(transactionID: string) { key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, value: { ...(transaction ?? null), - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.receiptDeleteFailureError'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.receiptDeleteFailureError'), pendingFields: { receipt: null, }, @@ -7938,7 +7947,7 @@ function putOnHold(transactionID: string, comment: string, reportID: string, sea comment: { hold: null, }, - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericHoldExpenseFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericHoldExpenseFailureMessage'), }, }, ]; @@ -8037,7 +8046,7 @@ function unholdRequest(transactionID: string, reportID: string, searchHash?: num key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, value: { pendingAction: null, - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericUnholdExpenseFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericUnholdExpenseFailureMessage'), }, }, { @@ -8384,7 +8393,7 @@ function resolveDuplicates(params: TransactionMergeParams) { key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReportID}`, value: { [createdReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericHoldExpenseFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericHoldExpenseFailureMessage'), }, }, }); From 09b1e4c04b4f81acb0ed515b6c74501dba1f000e Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Mon, 2 Dec 2024 07:55:35 +0100 Subject: [PATCH 06/29] refactor imports in ReportUtils, SearchQueryUtils, App, IOU, PriorityMode, Session, API, Reauthentication, extractPolicyIDFromQuery, Navigation --- ios/Podfile.lock | 8 +- metro.config.js | 8 + package-lock.json | 9 +- package.json | 2 +- src/libs/API/index.ts | 36 +- src/libs/Middleware/Reauthentication.ts | 24 +- src/libs/Navigation/Navigation.ts | 8 +- .../Navigation/extractPolicyIDFromQuery.ts | 6 +- src/libs/ReportUtils.ts | 8 +- src/libs/SearchQueryUtils.ts | 34 +- src/libs/actions/App.ts | 16 +- src/libs/actions/IOU.ts | 525 ++++++++++-------- src/libs/actions/PriorityMode.ts | 6 +- src/libs/actions/Session/index.ts | 15 +- src/libs/actions/SignInRedirect.ts | 8 +- 15 files changed, 380 insertions(+), 333 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index e421d7bb9592..21633b432c12 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -2661,7 +2661,7 @@ PODS: - RNSound/Core (= 0.11.2) - RNSound/Core (0.11.2): - React-Core - - RNSVG (15.6.0): + - RNSVG (15.9.0): - DoubleConversion - glog - hermes-engine @@ -2681,9 +2681,9 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNSVG/common (= 15.6.0) + - RNSVG/common (= 15.9.0) - Yoga - - RNSVG/common (15.6.0): + - RNSVG/common (15.9.0): - DoubleConversion - glog - hermes-engine @@ -3295,7 +3295,7 @@ SPEC CHECKSUMS: RNScreens: de6e57426ba0e6cbc3fb5b4f496e7f08cb2773c2 RNShare: bd4fe9b95d1ee89a200778cc0753ebe650154bb0 RNSound: 6c156f925295bdc83e8e422e7d8b38d33bc71852 - RNSVG: 1079f96b39a35753d481a20e30603fd6fc4f6fa9 + RNSVG: b2fbe96b2bb3887752f8abc1f495953847e90384 SDWebImage: 066c47b573f408f18caa467d71deace7c0f8280d SDWebImageAVIFCoder: 00310d246aab3232ce77f1d8f0076f8c4b021d90 SDWebImageSVGCoder: 15a300a97ec1c8ac958f009c02220ac0402e936c diff --git a/metro.config.js b/metro.config.js index c6e4ba6bb4ec..3aaed6164d50 100644 --- a/metro.config.js +++ b/metro.config.js @@ -24,6 +24,14 @@ const config = { // When we run the e2e tests we want files that have the extension e2e.js to be resolved as source files sourceExts: [...(isE2ETesting ? e2eSourceExts : []), ...defaultSourceExts, 'jsx'], }, + transformer: { + getTransformOptions: async () => ({ + transform: { + experimentalImportSupport: false, + inlineRequires: true, + }, + }), + }, }; module.exports = mergeConfig(defaultConfig, expoConfig, config); diff --git a/package-lock.json b/package-lock.json index f9c188dfc4d9..847909868b64 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "dependencies": { "@dotlottie/react-player": "^1.6.3", "@expensify/react-native-live-markdown": "0.1.187", - "@expo/metro-runtime": "~3.2.3", + "@expo/metro-runtime": "4.0.0", "@firebase/app": "^0.10.10", "@firebase/performance": "^0.6.8", "@formatjs/intl-datetimeformat": "^6.12.5", @@ -4883,9 +4883,10 @@ } }, "node_modules/@expo/metro-runtime": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/@expo/metro-runtime/-/metro-runtime-3.2.3.tgz", - "integrity": "sha512-v5ji+fAGi7B9YavrxvekuF8gXEV/5fz0+PhaED5AaFDnbGB4IJIbpaiqK9nqZV1axjGZNQSw6Q8TsnFetCR3bQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@expo/metro-runtime/-/metro-runtime-4.0.0.tgz", + "integrity": "sha512-+zgCyuXqIzgZVN8h0g36sursGXBy3xqtJW9han7t/iR2HTTrrbEoep5ftW1a27bdSINU96ng+rSsPLbyHYeBvw==", + "license": "MIT", "peerDependencies": { "react-native": "*" } diff --git a/package.json b/package.json index 4145dee91d6c..f8a11302cd4a 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "dependencies": { "@dotlottie/react-player": "^1.6.3", "@expensify/react-native-live-markdown": "0.1.187", - "@expo/metro-runtime": "~3.2.3", + "@expo/metro-runtime": "4.0.0", "@firebase/app": "^0.10.10", "@firebase/performance": "^0.6.8", "@formatjs/intl-datetimeformat": "^6.12.5", diff --git a/src/libs/API/index.ts b/src/libs/API/index.ts index ad0650374011..458a2feffee3 100644 --- a/src/libs/API/index.ts +++ b/src/libs/API/index.ts @@ -2,11 +2,11 @@ import type {OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import type {SetRequired} from 'type-fest'; import Log from '@libs/Log'; -import * as Middleware from '@libs/Middleware'; -import * as SequentialQueue from '@libs/Network/SequentialQueue'; -import * as Pusher from '@libs/Pusher/pusher'; -import * as Request from '@libs/Request'; -import * as PersistedRequests from '@userActions/PersistedRequests'; +import {HandleUnusedOptimisticID, Logging, Pagination, Reauthentication, RecheckConnection, SaveResponseInOnyx} from '@libs/Middleware'; +import {push, waitForIdle} from '@libs/Network/SequentialQueue'; +import {getPusherSocketID} from '@libs/Pusher/pusher'; +import {processWithMiddleware, use} from '@libs/Request'; +import {getLength} from '@userActions/PersistedRequests'; import CONST from '@src/CONST'; import type OnyxRequest from '@src/types/onyx/Request'; import type {PaginatedRequest, PaginationConfig, RequestConflictResolver} from '@src/types/onyx/Request'; @@ -18,22 +18,22 @@ import type {ApiCommand, ApiRequestCommandParameters, ApiRequestType, CommandOfT // e.g. an error thrown in Logging or Reauthenticate logic will be caught by the next middleware or the SequentialQueue which retries failing requests. // Logging - Logs request details and errors. -Request.use(Middleware.Logging); +use(Logging); // RecheckConnection - Sets a timer for a request that will "recheck" if we are connected to the internet if time runs out. Also triggers the connection recheck when we encounter any error. -Request.use(Middleware.RecheckConnection); +use(RecheckConnection); // Reauthentication - Handles jsonCode 407 which indicates an expired authToken. We need to reauthenticate and get a new authToken with our stored credentials. -Request.use(Middleware.Reauthentication); +use(Reauthentication); // If an optimistic ID is not used by the server, this will update the remaining serialized requests using that optimistic ID to use the correct ID instead. -Request.use(Middleware.HandleUnusedOptimisticID); +use(HandleUnusedOptimisticID); -Request.use(Middleware.Pagination); +use(Pagination); // SaveResponseInOnyx - Merges either the successData or failureData (or finallyData, if included in place of the former two values) into Onyx depending on if the call was successful or not. This needs to be the LAST middleware we use, don't add any // middlewares after this, because the SequentialQueue depends on the result of this middleware to pause the queue (if needed) to bring the app to an up-to-date state. -Request.use(Middleware.SaveResponseInOnyx); +use(SaveResponseInOnyx); type OnyxData = { optimisticData?: OnyxUpdate[]; @@ -69,7 +69,7 @@ function prepareRequest( // We send the pusherSocketID with all write requests so that the api can include it in push events to prevent Pusher from sending the events to the requesting client. The push event // is sent back to the requesting client in the response data instead, which prevents a replay effect in the UI. See https://github.com/Expensify/App/issues/12775. - pusherSocketID: isWriteRequest ? Pusher.getPusherSocketID() : undefined, + pusherSocketID: isWriteRequest ? getPusherSocketID() : undefined, }; // Assemble all request metadata (used by middlewares, and for persisted requests stored in Onyx) @@ -95,18 +95,18 @@ function prepareRequest( function processRequest(request: OnyxRequest, type: ApiRequestType): Promise { // Write commands can be saved and retried, so push it to the SequentialQueue if (type === CONST.API_REQUEST_TYPE.WRITE) { - SequentialQueue.push(request); + push(request); return Promise.resolve(); } // Read requests are processed right away, but don't return the response to the caller if (type === CONST.API_REQUEST_TYPE.READ) { - Request.processWithMiddleware(request); + processWithMiddleware(request); return Promise.resolve(); } // Requests with side effects process right away, and return the response to the caller - return Request.processWithMiddleware(request); + return processWithMiddleware(request); } /** @@ -172,10 +172,10 @@ function makeRequestWithSideEffects( * write requests that use the same Onyx keys and haven't responded yet. */ function waitForWrites(command: TCommand) { - if (PersistedRequests.getLength() > 0) { - Log.info(`[API] '${command}' is waiting on ${PersistedRequests.getLength()} write commands`); + if (getLength() > 0) { + Log.info(`[API] '${command}' is waiting on ${getLength()} write commands`); } - return SequentialQueue.waitForIdle(); + return waitForIdle(); } /** diff --git a/src/libs/Middleware/Reauthentication.ts b/src/libs/Middleware/Reauthentication.ts index 9d95fa8af873..deebfe4349b7 100644 --- a/src/libs/Middleware/Reauthentication.ts +++ b/src/libs/Middleware/Reauthentication.ts @@ -1,11 +1,11 @@ import redirectToSignIn from '@libs/actions/SignInRedirect'; -import * as Authentication from '@libs/Authentication'; +import {reauthenticate as reauthenticateLibs} from '@libs/Authentication'; import Log from '@libs/Log'; -import * as MainQueue from '@libs/Network/MainQueue'; -import * as NetworkStore from '@libs/Network/NetworkStore'; +import {replay} from '@libs/Network/MainQueue'; +import {isAuthenticating as isAuthenticatingNetworkStore, isOffline, setIsAuthenticating} from '@libs/Network/NetworkStore'; import type {RequestError} from '@libs/Network/SequentialQueue'; import NetworkConnection from '@libs/NetworkConnection'; -import * as Request from '@libs/Request'; +import {processWithMiddleware} from '@libs/Request'; import RequestThrottle from '@libs/RequestThrottle'; import CONST from '@src/CONST'; import type Middleware from './types'; @@ -35,12 +35,12 @@ function reauthenticate(commandName?: string): Promise { } function retryReauthenticate(commandName?: string): Promise { - return Authentication.reauthenticate(commandName).catch((error: RequestError) => { + return reauthenticateLibs(commandName).catch((error: RequestError) => { return reauthThrottle .sleep(error, 'Authenticate') .then(() => retryReauthenticate(commandName)) .catch(() => { - NetworkStore.setIsAuthenticating(false); + setIsAuthenticating(false); Log.hmmm('Redirecting to Sign In because we failed to reauthenticate after multiple attempts', {error}); redirectToSignIn('passwordForm.error.fallback'); }); @@ -66,7 +66,7 @@ const Reauthentication: Middleware = (response, request, isFromSequentialQueue) } if (data.jsonCode === CONST.JSON_CODE.NOT_AUTHENTICATED) { - if (NetworkStore.isOffline()) { + if (isOffline()) { // If we are offline and somehow handling this response we do not want to reauthenticate throw new Error('Unable to reauthenticate because we are offline'); } @@ -93,15 +93,15 @@ const Reauthentication: Middleware = (response, request, isFromSequentialQueue) } // We are already authenticating and using the DeprecatedAPI so we will replay the request - if (!apiRequestType && NetworkStore.isAuthenticating()) { - MainQueue.replay(request); + if (!apiRequestType && isAuthenticatingNetworkStore()) { + replay(request); return data; } return reauthenticate(request?.commandName) .then((authenticateResponse) => { if (isFromSequentialQueue || apiRequestType === CONST.API_REQUEST_TYPE.MAKE_REQUEST_WITH_SIDE_EFFECTS) { - return Request.processWithMiddleware(request, isFromSequentialQueue); + return processWithMiddleware(request, isFromSequentialQueue); } if (apiRequestType === CONST.API_REQUEST_TYPE.READ) { @@ -109,7 +109,7 @@ const Reauthentication: Middleware = (response, request, isFromSequentialQueue) return Promise.resolve(); } - MainQueue.replay(request); + replay(request); return authenticateResponse; }) .catch(() => { @@ -118,7 +118,7 @@ const Reauthentication: Middleware = (response, request, isFromSequentialQueue) } // If we make it here, then our reauthenticate request could not be made due to a networking issue. The original request can be retried safely. - MainQueue.replay(request); + replay(request); }); } diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index e3672da2f445..b5819bd5ba5a 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -5,7 +5,7 @@ import type {OnyxEntry} from 'react-native-onyx'; import Log from '@libs/Log'; import {isCentralPaneName, removePolicyIDParamFromState} from '@libs/NavigationUtils'; import {getAllReports} from '@libs/ReportConnection'; -import * as ReportUtils from '@libs/ReportUtils'; +import {generateReportID} from '@libs/ReportUtils'; import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -105,12 +105,12 @@ function getActiveRouteIndex(stateOrRoute: StateOrRoute, index?: number): number function parseHybridAppUrl(url: HybridAppRoute | Route): Route { switch (url) { case HYBRID_APP_ROUTES.MONEY_REQUEST_CREATE_TAB_MANUAL: - return ROUTES.MONEY_REQUEST_CREATE_TAB_MANUAL.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.SUBMIT, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, ReportUtils.generateReportID()); + return ROUTES.MONEY_REQUEST_CREATE_TAB_MANUAL.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.SUBMIT, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, generateReportID()); case HYBRID_APP_ROUTES.MONEY_REQUEST_CREATE_TAB_DISTANCE: - return ROUTES.MONEY_REQUEST_CREATE_TAB_DISTANCE.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.SUBMIT, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, ReportUtils.generateReportID()); + return ROUTES.MONEY_REQUEST_CREATE_TAB_DISTANCE.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.SUBMIT, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, generateReportID()); case HYBRID_APP_ROUTES.MONEY_REQUEST_CREATE: case HYBRID_APP_ROUTES.MONEY_REQUEST_CREATE_TAB_SCAN: - return ROUTES.MONEY_REQUEST_CREATE_TAB_SCAN.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.SUBMIT, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, ReportUtils.generateReportID()); + return ROUTES.MONEY_REQUEST_CREATE_TAB_SCAN.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.SUBMIT, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, generateReportID()); default: return url; } diff --git a/src/libs/Navigation/extractPolicyIDFromQuery.ts b/src/libs/Navigation/extractPolicyIDFromQuery.ts index f091690c16f2..b0ef3d393983 100644 --- a/src/libs/Navigation/extractPolicyIDFromQuery.ts +++ b/src/libs/Navigation/extractPolicyIDFromQuery.ts @@ -1,4 +1,4 @@ -import * as SearchQueryUtils from '@libs/SearchQueryUtils'; +import {buildSearchQueryJSON, getPolicyIDFromSearchQuery} from '@libs/SearchQueryUtils'; import type {NavigationPartialRoute} from './types'; function extractPolicyIDFromQuery(route?: NavigationPartialRoute) { @@ -11,12 +11,12 @@ function extractPolicyIDFromQuery(route?: NavigationPartialRoute) { } const queryString = route.params.q as string; - const queryJSON = SearchQueryUtils.buildSearchQueryJSON(queryString); + const queryJSON = buildSearchQueryJSON(queryString); if (!queryJSON) { return undefined; } - return SearchQueryUtils.getPolicyIDFromSearchQuery(queryJSON); + return getPolicyIDFromSearchQuery(queryJSON); } export default extractPolicyIDFromQuery; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 00713459160f..250524ce24ce 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -59,9 +59,9 @@ import type {Comment, TransactionChanges, WaypointCollection} from '@src/types/o import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type IconAsset from '@src/types/utils/IconAsset'; import * as IOU from './actions/IOU'; -import * as PolicyActions from './actions/Policy/Policy'; +import {createDraftWorkspace} from './actions/Policy/Policy'; import * as store from './actions/ReimbursementAccount/store'; -import * as SessionUtils from './actions/Session'; +import {isAnonymousUser as isAnonymousUserSessionUtils} from './actions/Session'; import * as CurrencyUtils from './CurrencyUtils'; import DateUtils from './DateUtils'; import {hasValidDraftComment} from './DraftCommentUtils'; @@ -8180,7 +8180,7 @@ function canLeaveChat(report: OnyxEntry, policy: OnyxEntry): boo return true; } - if (isPublicRoom(report) && SessionUtils.isAnonymousUser()) { + if (isPublicRoom(report) && isAnonymousUserSessionUtils()) { return false; } @@ -8226,7 +8226,7 @@ function getReportActionActorAccountID( } function createDraftWorkspaceAndNavigateToConfirmationScreen(transactionID: string, actionName: IOUAction): void { const isCategorizing = actionName === CONST.IOU.ACTION.CATEGORIZE; - const {expenseChatReportID, policyID, policyName} = PolicyActions.createDraftWorkspace(); + const {expenseChatReportID, policyID, policyName} = createDraftWorkspace(); IOU.setMoneyRequestParticipants(transactionID, [ { selected: true, diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index 9645cc76a037..1a7eee242e2c 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -8,15 +8,15 @@ import type {SearchAdvancedFiltersForm} from '@src/types/form'; import FILTER_KEYS from '@src/types/form/SearchAdvancedFiltersForm'; import type * as OnyxTypes from '@src/types/onyx'; import type {SearchDataTypes} from '@src/types/onyx/SearchResults'; -import * as CurrencyUtils from './CurrencyUtils'; +import {convertToBackendAmount, convertToFrontendAmountAsInteger} from './CurrencyUtils'; import localeCompare from './LocaleCompare'; import {validateAmount} from './MoneyRequestUtils'; -import * as PersonalDetailsUtils from './PersonalDetailsUtils'; +import {getPersonalDetailByEmail} from './PersonalDetailsUtils'; import {getTagNamesFromTagsLists} from './PolicyUtils'; -import * as ReportUtils from './ReportUtils'; -import * as searchParser from './SearchParser/searchParser'; -import * as UserUtils from './UserUtils'; -import * as ValidationUtils from './ValidationUtils'; +import {getReportName} from './ReportUtils'; +import {parse} from './SearchParser/searchParser'; +import {hashText} from './UserUtils'; +import {isValidDate} from './ValidationUtils'; type FilterKeys = keyof typeof CONST.SEARCH.SYNTAX_FILTER_KEYS; @@ -171,10 +171,10 @@ function getFindIDFromDisplayValue(cardList: OnyxTypes.CardList, taxRates: Recor if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM || filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TO) { if (typeof filter === 'string') { const email = filter; - return PersonalDetailsUtils.getPersonalDetailByEmail(email)?.accountID.toString() ?? filter; + return getPersonalDetailByEmail(email)?.accountID.toString() ?? filter; } const emails = filter; - return emails.map((email) => PersonalDetailsUtils.getPersonalDetailByEmail(email)?.accountID.toString() ?? email); + return emails.map((email) => getPersonalDetailByEmail(email)?.accountID.toString() ?? email); } if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE) { const names = Array.isArray(filter) ? filter : ([filter] as string[]); @@ -216,11 +216,11 @@ function getUpdatedAmountValue(filterName: ValueOf { - const backendAmount = CurrencyUtils.convertToBackendAmount(Number(amount)); + const backendAmount = convertToBackendAmount(Number(amount)); return Number.isNaN(backendAmount) ? amount : backendAmount.toString(); }); } @@ -244,14 +244,14 @@ function getQueryHashes(query: SearchQueryJSON): {primaryHash: number; recentSea .sort() .forEach((filterString) => (orderedQuery += ` ${filterString}`)); - const recentSearchHash = UserUtils.hashText(orderedQuery, 2 ** 32); + const recentSearchHash = hashText(orderedQuery, 2 ** 32); orderedQuery += ` ${CONST.SEARCH.SYNTAX_ROOT_KEYS.SORT_BY}:${query.sortBy}`; orderedQuery += ` ${CONST.SEARCH.SYNTAX_ROOT_KEYS.SORT_ORDER}:${query.sortOrder}`; if (query.policyID) { orderedQuery += ` ${CONST.SEARCH.SYNTAX_ROOT_KEYS.POLICY_ID}:${query.policyID} `; } - const primaryHash = UserUtils.hashText(orderedQuery, 2 ** 32); + const primaryHash = hashText(orderedQuery, 2 ** 32); return {primaryHash, recentSearchHash}; } @@ -264,7 +264,7 @@ function getQueryHashes(query: SearchQueryJSON): {primaryHash: number; recentSea */ function buildSearchQueryJSON(query: SearchQueryString) { try { - const result = searchParser.parse(query) as SearchQueryJSON; + const result = parse(query) as SearchQueryJSON; const flatFilters = getFilters(result); // Add the full input and hash to the results @@ -475,9 +475,9 @@ function buildFilterFormValuesFromQuery( } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.DATE) { filtersForm[FILTER_KEYS.DATE_BEFORE] = - filterList.find((filter) => filter.operator === 'lt' && ValidationUtils.isValidDate(filter.value.toString()))?.value.toString() ?? filtersForm[FILTER_KEYS.DATE_BEFORE]; + filterList.find((filter) => filter.operator === 'lt' && isValidDate(filter.value.toString()))?.value.toString() ?? filtersForm[FILTER_KEYS.DATE_BEFORE]; filtersForm[FILTER_KEYS.DATE_AFTER] = - filterList.find((filter) => filter.operator === 'gt' && ValidationUtils.isValidDate(filter.value.toString()))?.value.toString() ?? filtersForm[FILTER_KEYS.DATE_AFTER]; + filterList.find((filter) => filter.operator === 'gt' && isValidDate(filter.value.toString()))?.value.toString() ?? filtersForm[FILTER_KEYS.DATE_AFTER]; } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.AMOUNT) { // backend amount is an integer and is 2 digits longer than frontend amount @@ -544,10 +544,10 @@ function getDisplayValue(filterName: string, filter: string, personalDetails: On return cardList[filter]?.bank || filter; } if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.IN) { - return ReportUtils.getReportName(reports?.[`${ONYXKEYS.COLLECTION.REPORT}${filter}`]) || filter; + return getReportName(reports?.[`${ONYXKEYS.COLLECTION.REPORT}${filter}`]) || filter; } if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.AMOUNT) { - const frontendAmount = CurrencyUtils.convertToFrontendAmountAsInteger(Number(filter)); + const frontendAmount = convertToFrontendAmountAsInteger(Number(filter)); return Number.isNaN(frontendAmount) ? filter : frontendAmount.toString(); } return filter; diff --git a/src/libs/actions/App.ts b/src/libs/actions/App.ts index f1f46aee0a93..0379a5fd555a 100644 --- a/src/libs/actions/App.ts +++ b/src/libs/actions/App.ts @@ -16,7 +16,7 @@ import getCurrentUrl from '@libs/Navigation/currentUrl'; import Navigation from '@libs/Navigation/Navigation'; import Performance from '@libs/Performance'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; -import * as SessionUtils from '@libs/SessionUtils'; +import {isLoggingInAsNewUser as isLoggingInAsNewUserSessionUtils} from '@libs/SessionUtils'; import {clearSoundAssetsCache} from '@libs/Sound'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -27,9 +27,9 @@ import type * as OnyxTypes from '@src/types/onyx'; import type {OnyxData} from '@src/types/onyx/Request'; import {setShouldForceOffline} from './Network'; import * as PersistedRequests from './PersistedRequests'; -import * as Policy from './Policy/Policy'; +import {createDraftInitialWorkspace, createWorkspace, generatePolicyID} from './Policy/Policy'; import {resolveDuplicationConflictAction} from './RequestConflictUtils'; -import * as Session from './Session'; +import {isAnonymousUser} from './Session'; import Timing from './Timing'; type PolicyParamsForOpenOrReconnect = { @@ -369,8 +369,8 @@ function endSignOnTransition() { * @param [backTo] An optional return path. If provided, it will be URL-encoded and appended to the resulting URL. */ function createWorkspaceWithPolicyDraftAndNavigateToIt(policyOwnerEmail = '', policyName = '', transitionFromOldDot = false, makeMeAdmin = false, backTo = '') { - const policyID = Policy.generatePolicyID(); - Policy.createDraftInitialWorkspace(policyOwnerEmail, policyName, policyID, makeMeAdmin); + const policyID = generatePolicyID(); + createDraftInitialWorkspace(policyOwnerEmail, policyName, policyID, makeMeAdmin); Navigation.isNavigationReady() .then(() => { @@ -393,7 +393,7 @@ function createWorkspaceWithPolicyDraftAndNavigateToIt(policyOwnerEmail = '', po * @param [makeMeAdmin] Optional, leave the calling account as an admin on the policy */ function savePolicyDraftByNewWorkspace(policyID?: string, policyName?: string, policyOwnerEmail = '', makeMeAdmin = false) { - Policy.createWorkspace(policyOwnerEmail, makeMeAdmin, policyName, policyID); + createWorkspace(policyOwnerEmail, makeMeAdmin, policyName, policyID); } /** @@ -421,7 +421,7 @@ function setUpPoliciesAndNavigate(session: OnyxEntry) { return; } - const isLoggingInAsNewUser = !!session.email && SessionUtils.isLoggingInAsNewUser(currentUrl, session.email); + const isLoggingInAsNewUser = !!session.email && isLoggingInAsNewUserSessionUtils(currentUrl, session.email); const url = new URL(currentUrl); const exitTo = url.searchParams.get('exitTo') as Route | null; @@ -468,7 +468,7 @@ function redirectThirdPartyDesktopSignIn() { */ function beginDeepLinkRedirect(shouldAuthenticateWithCurrentAccount = true, initialRoute?: string) { // There's no support for anonymous users on desktop - if (Session.isAnonymousUser()) { + if (isAnonymousUser()) { return; } diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 4deec4022f70..975f3fe26376 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -30,62 +30,104 @@ import type { UpdateMoneyRequestParams, } from '@libs/API/parameters'; import {WRITE_COMMANDS} from '@libs/API/types'; -import '@libs/CurrencyUtils'; +import {convertToDisplayString} from '@libs/CurrencyUtils'; import DateUtils from '@libs/DateUtils'; import DistanceRequestUtils from '@libs/DistanceRequestUtils'; import {getMicroSecondOnyxErrorObject, getMicroSecondOnyxErrorWithTranslationKey} from '@libs/ErrorUtils'; -import '@libs/fileDownload/FileUtils'; +import {readFileAsync} from '@libs/fileDownload/FileUtils'; import GoogleTagManager from '@libs/GoogleTagManager'; -import {formatCurrentUserToAttendee, updateIOUOwnerAndTotal} from '@libs/IOUUtils'; +import { + calculateAmount, + formatCurrentUserToAttendee, + isMovingTransactionFromTrackExpense as isMovingTransactionFromTrackExpenseIOUUtils, + navigateToStartMoneyRequestStep, + updateIOUOwnerAndTotal, +} from '@libs/IOUUtils'; import {formatPhoneNumber} from '@libs/LocalePhoneNumber'; import * as Localize from '@libs/Localize'; import isSearchTopmostCentralPane from '@libs/Navigation/isSearchTopmostCentralPane'; import Navigation from '@libs/Navigation/Navigation'; import {buildNextStep} from '@libs/NextStepUtils'; import {rand64} from '@libs/NumberUtils'; -import '@libs/OptionsListUtils'; -import '@libs/PersonalDetailsUtils'; +import {getPersonalDetailsForAccountIDs} from '@libs/OptionsListUtils'; +import {getAccountIDsByLogins} from '@libs/PersonalDetailsUtils'; import {addSMSDomainIfPhoneNumber} from '@libs/PhoneNumber'; -import {hasDependentTags, isControlPolicy, isPaidGroupPolicy} from '@libs/PolicyUtils'; +import {getPolicy, getSubmitToAccountID, hasDependentTags, isControlPolicy, isPaidGroupPolicy, isPolicyAdmin, isSubmitAndClose} from '@libs/PolicyUtils'; import { + getAllReportActions, getLastVisibleAction, getLastVisibleMessage, getOriginalMessage, getReportAction, getReportActionHtml, + getReportActionMessage, getReportActionText, + getTrackExpenseActionableWhisper, isActionableTrackExpense, isDeletedParentAction, + isMoneyRequestAction, isReportPreviewAction, } from '@libs/ReportActionsUtils'; import {getAllReports} from '@libs/ReportConnection'; -import type {OptimisticChatReport, OptimisticCreatedReportAction, OptimisticIOUReportAction, TransactionDetails} from '@libs/ReportUtils'; +import type {OptimisticChatReport, OptimisticCreatedReportAction, OptimisticIOUReportAction, OptionData, TransactionDetails} from '@libs/ReportUtils'; import { buildOptimisticActionableTrackExpenseWhisper, + buildOptimisticApprovedReportAction, + buildOptimisticCancelPaymentReportAction, buildOptimisticChatReport, + buildOptimisticCreatedReportAction, + buildOptimisticDismissedViolationReportAction, buildOptimisticExpenseReport, + buildOptimisticHoldReportAction, + buildOptimisticHoldReportActionComment, buildOptimisticInvoiceReport, buildOptimisticIOUReport, + buildOptimisticIOUReportAction, buildOptimisticModifiedExpenseReportAction, buildOptimisticMoneyRequestEntities, buildOptimisticMovedTrackedExpenseModifiedReportAction, buildOptimisticReportPreview, + buildOptimisticSubmittedReportAction, + buildOptimisticUnapprovedReportAction, + buildOptimisticUnHoldReportAction, + canBeAutoReimbursed, canUserPerformWriteAction as canUserPerformWriteActionReportUtils, + getAllHeldTransactions as getAllHeldTransactionsReportUtils, + getApprovalChain, getChatByParticipants, + getDisplayedReportID, getInvoiceChatByParticipants, + getMoneyRequestSpendBreakdown, + getOptimisticDataForParentReportAction, getOutstandingChildRequest, getPersonalDetailsForAccountID, + getReportNameValuePairs, + getReportOrDraftReport, getTransactionDetails, + hasHeldExpenses as hasHeldExpensesReportUtils, + hasNonReimbursableTransactions as hasNonReimbursableTransactionsReportUtils, + hasViolations as hasViolationsReportUtils, + isArchivedRoom, isDraftReport, isExpenseReport, - isInvoiceReport, + isIndividualInvoiceRoom, + isInvoiceReport as isInvoiceReportReportUtils, + isInvoiceRoom, + isMoneyRequestReport as isMoneyRequestReportReportUtils, + isOpenExpenseReport as isOpenExpenseReportReportUtils, + isOptimisticPersonalDetail, + isPayAtEndExpenseReport as isPayAtEndExpenseReportReportUtils, + isPayer as isPayerReportUtils, + isPolicyExpenseChat as isPolicyExpenseChatReportUtils, + isReportApproved, isSelfDM, + isSettled, isTrackExpenseReport, shouldCreateNewMoneyRequestReport as shouldCreateNewMoneyRequestReportReportUtils, updateReportPreview, } from '@libs/ReportUtils'; -import '@libs/SessionUtils'; -import '@libs/SubscriptionUtils'; +import {getSession} from '@libs/SessionUtils'; +import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils'; import { buildOptimisticTransaction, getAllReportTransactions, @@ -115,13 +157,13 @@ import type {OnyxData} from '@src/types/onyx/Request'; import type {SearchPolicy, SearchReport, SearchTransaction} from '@src/types/onyx/SearchResults'; import type {Comment, Receipt, ReceiptSource, Routes, SplitShares, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; -import * as CachedPDFPaths from './CachedPDFPaths'; -import * as Category from './Policy/Category'; -import * as Policy from './Policy/Policy'; -import * as Tag from './Policy/Tag'; -import * as Report from './Report'; +import {clearByKey} from './CachedPDFPaths'; +import {buildOptimisticPolicyRecentlyUsedCategories} from './Policy/Category'; +import {buildOptimisticRecentlyUsedCurrencies, buildPolicyData, generatePolicyID} from './Policy/Policy'; +import {buildOptimisticPolicyRecentlyUsedTags} from './Policy/Tag'; +import {notifyNewAction} from './Report'; import {getRecentWaypoints, sanitizeRecentWaypoints} from './Transaction'; -import * as TransactionEdit from './TransactionEdit'; +import {removeDraftTransaction} from './TransactionEdit'; type IOURequestType = ValueOf; @@ -1981,9 +2023,9 @@ function getSendInvoiceInformation( billable, ); - const optimisticPolicyRecentlyUsedCategories = Category.buildOptimisticPolicyRecentlyUsedCategories(optimisticInvoiceReport.policyID, category); - const optimisticPolicyRecentlyUsedTags = Tag.buildOptimisticPolicyRecentlyUsedTags(optimisticInvoiceReport.policyID, tag); - const optimisticRecentlyUsedCurrencies = Policy.buildOptimisticRecentlyUsedCurrencies(currency); + const optimisticPolicyRecentlyUsedCategories = buildOptimisticPolicyRecentlyUsedCategories(optimisticInvoiceReport.policyID, category); + const optimisticPolicyRecentlyUsedTags = buildOptimisticPolicyRecentlyUsedTags(optimisticInvoiceReport.policyID, tag); + const optimisticRecentlyUsedCurrencies = buildOptimisticRecentlyUsedCurrencies(currency); // STEP 4: Add optimistic personal details for participant const shouldCreateOptimisticPersonalDetails = isNewChatReport && !allPersonalDetails[receiverAccountID]; @@ -2167,9 +2209,9 @@ function getMoneyRequestInformation( policy, ); - const optimisticPolicyRecentlyUsedCategories = Category.buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, category); - const optimisticPolicyRecentlyUsedTags = Tag.buildOptimisticPolicyRecentlyUsedTags(iouReport.policyID, tag); - const optimisticPolicyRecentluUsedCurrencies = Policy.buildOptimisticRecentlyUsedCurrencies(currency); + const optimisticPolicyRecentlyUsedCategories = buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, category); + const optimisticPolicyRecentlyUsedTags = buildOptimisticPolicyRecentlyUsedTags(iouReport.policyID, tag); + const optimisticPolicyRecentluUsedCurrencies = buildOptimisticRecentlyUsedCurrencies(currency); // If there is an existing transaction (which is the case for distance requests), then the data from the existing transaction // needs to be manually merged into the optimistic transaction. This is because buildOnyxDataForMoneyRequest() uses `Onyx.set()` for the transaction @@ -2335,7 +2377,7 @@ function getTrackExpenseInformation( let createdWorkspaceParams: CreateWorkspaceParams | undefined; if (isDraftReportLocal) { - const workspaceData = Policy.buildPolicyData(undefined, policy?.makeMeAdmin, policy?.name, policy?.id, chatReport?.reportID); + const workspaceData = buildPolicyData(undefined, policy?.makeMeAdmin, policy?.name, policy?.id, chatReport?.reportID); createdWorkspaceParams = workspaceData.params; optimisticData.push(...workspaceData.optimisticData); successData.push(...workspaceData.successData); @@ -2668,7 +2710,7 @@ function getUpdateMoneyRequestParams( let updatedMoneyRequestReport: OnyxTypes.OnyxInputOrEntry; if (!iouReport) { updatedMoneyRequestReport = null; - } else if ((isExpenseReport(iouReport) || isInvoiceReport(iouReport)) && typeof iouReport.total === 'number') { + } else if ((isExpenseReport(iouReport) || isInvoiceReportReportUtils(iouReport)) && typeof iouReport.total === 'number') { // For expense report, the amount is negative, so we should subtract total from diff updatedMoneyRequestReport = { ...iouReport, @@ -2748,7 +2790,7 @@ function getUpdateMoneyRequestParams( // Update recently used categories if the category is changed const hasModifiedCategory = 'category' in transactionChanges; if (hasModifiedCategory) { - const optimisticPolicyRecentlyUsedCategories = Category.buildOptimisticPolicyRecentlyUsedCategories(iouReport?.policyID, transactionChanges.category); + const optimisticPolicyRecentlyUsedCategories = buildOptimisticPolicyRecentlyUsedCategories(iouReport?.policyID, transactionChanges.category); if (optimisticPolicyRecentlyUsedCategories.length) { optimisticData.push({ onyxMethod: Onyx.METHOD.SET, @@ -2760,7 +2802,7 @@ function getUpdateMoneyRequestParams( // Update recently used currencies if the currency is changed if ('currency' in transactionChanges) { - const optimisticRecentlyUsedCurrencies = Policy.buildOptimisticRecentlyUsedCurrencies(transactionChanges.currency); + const optimisticRecentlyUsedCurrencies = buildOptimisticRecentlyUsedCurrencies(transactionChanges.currency); if (optimisticRecentlyUsedCurrencies.length) { optimisticData.push({ onyxMethod: Onyx.METHOD.SET, @@ -2773,7 +2815,7 @@ function getUpdateMoneyRequestParams( // Update recently used categories if the tag is changed const hasModifiedTag = 'tag' in transactionChanges; if (hasModifiedTag) { - const optimisticPolicyRecentlyUsedTags = Tag.buildOptimisticPolicyRecentlyUsedTags(iouReport?.policyID, transactionChanges.tag); + const optimisticPolicyRecentlyUsedTags = buildOptimisticPolicyRecentlyUsedTags(iouReport?.policyID, transactionChanges.tag); if (!isEmptyObject(optimisticPolicyRecentlyUsedTags)) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, @@ -3611,10 +3653,10 @@ function requestMoney(requestMoneyInformation: RequestMoneyInformation) { } = transactionParams; // If the report is iou or expense report, we should get the linked chat report to be passed to the getMoneyRequestInformation function - const isMoneyRequestReport = isMoneyRequestReport(report); - const currentChatReport = isMoneyRequestReport ? ReportUtils.getReportOrDraftReport(report?.chatReportID) : report; + const isMoneyRequestReport = isMoneyRequestReportReportUtils(report); + const currentChatReport = isMoneyRequestReport ? getReportOrDraftReport(report?.chatReportID) : report; const moneyRequestReportID = isMoneyRequestReport ? report?.reportID : ''; - const isMovingTransactionFromTrackExpense = IOUUtils.isMovingTransactionFromTrackExpense(action); + const isMovingTransactionFromTrackExpense = isMovingTransactionFromTrackExpenseIOUUtils(action); const { payerAccountID, @@ -3638,8 +3680,8 @@ function requestMoney(requestMoneyInformation: RequestMoneyInformation) { created, merchant, receipt, - isMovingTransactionFromTrackExpense && linkedTrackedExpenseReportAction && ReportActionsUtils.isMoneyRequestAction(linkedTrackedExpenseReportAction) - ? ReportActionsUtils.getOriginalMessage(linkedTrackedExpenseReportAction)?.IOUTransactionID + isMovingTransactionFromTrackExpense && linkedTrackedExpenseReportAction && isMoneyRequestAction(linkedTrackedExpenseReportAction) + ? getOriginalMessage(linkedTrackedExpenseReportAction)?.IOUTransactionID : undefined, category, tag, @@ -3723,10 +3765,10 @@ function requestMoney(requestMoneyInformation: RequestMoneyInformation) { } } - InteractionManager.runAfterInteractions(() => TransactionEdit.removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); + InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); Navigation.dismissModal(isSearchTopmostCentralPane() ? undefined : activeReportID); if (activeReportID) { - Report.notifyNewAction(activeReportID, payeeAccountID); + notifyNewAction(activeReportID, payeeAccountID); } } @@ -3780,7 +3822,7 @@ function sendInvoice( }; API.write(WRITE_COMMANDS.SEND_INVOICE, parameters, onyxData); - InteractionManager.runAfterInteractions(() => TransactionEdit.removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); + InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); if (isSearchTopmostCentralPane()) { Navigation.dismissModal(); @@ -3788,7 +3830,7 @@ function sendInvoice( Navigation.dismissModalWithReport(invoiceRoom); } - Report.notifyNewAction(invoiceRoom.reportID, receiver.accountID); + notifyNewAction(invoiceRoom.reportID, receiver.accountID); } /** @@ -3822,10 +3864,10 @@ function trackExpense( linkedTrackedExpenseReportID?: string, customUnitRateID?: string, ) { - const isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report); - const currentChatReport = isMoneyRequestReport ? ReportUtils.getReportOrDraftReport(report.chatReportID) : report; + const isMoneyRequestReport = isMoneyRequestReportReportUtils(report); + const currentChatReport = isMoneyRequestReport ? getReportOrDraftReport(report.chatReportID) : report; const moneyRequestReportID = isMoneyRequestReport ? report.reportID : ''; - const isMovingTransactionFromTrackExpense = IOUUtils.isMovingTransactionFromTrackExpense(action); + const isMovingTransactionFromTrackExpense = isMovingTransactionFromTrackExpenseIOUUtils(action); // Pass an open receipt so the distance expense will show a map with the route optimistically const trackedReceipt = validWaypoints ? {source: ReceiptGeneric as ReceiptSource, state: CONST.IOU.RECEIPT_STATE.OPEN} : receipt; @@ -3865,8 +3907,8 @@ function trackExpense( payeeAccountID, moneyRequestReportID, linkedTrackedExpenseReportAction, - isMovingTransactionFromTrackExpense && linkedTrackedExpenseReportAction && ReportActionsUtils.isMoneyRequestAction(linkedTrackedExpenseReportAction) - ? ReportActionsUtils.getOriginalMessage(linkedTrackedExpenseReportAction)?.IOUTransactionID + isMovingTransactionFromTrackExpense && linkedTrackedExpenseReportAction && isMoneyRequestAction(linkedTrackedExpenseReportAction) + ? getOriginalMessage(linkedTrackedExpenseReportAction)?.IOUTransactionID : undefined, ) ?? {}; const activeReportID = isMoneyRequestReport ? report.reportID : chatReport?.reportID; @@ -3976,7 +4018,7 @@ function trackExpense( API.write(WRITE_COMMANDS.TRACK_EXPENSE, parameters, onyxData); } } - InteractionManager.runAfterInteractions(() => TransactionEdit.removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); + InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); Navigation.dismissModal(isSearchTopmostCentralPane() ? undefined : activeReportID); if (action === CONST.IOU.ACTION.SHARE) { @@ -3987,7 +4029,7 @@ function trackExpense( Navigation.setNavigationActionToMicrotaskQueue(() => Navigation.navigate(ROUTES.ROOM_INVITE.getRoute(activeReportID ?? '-1', CONST.IOU.SHARE.ROLE.ACCOUNTANT))); } - Report.notifyNewAction(activeReportID ?? '', payeeAccountID); + notifyNewAction(activeReportID ?? '', payeeAccountID); } function getOrCreateOptimisticSplitChatReport(existingSplitChatReportID: string, participants: Participant[], participantAccountIDs: number[], currentUserAccountID: number) { @@ -3999,7 +4041,7 @@ function getOrCreateOptimisticSplitChatReport(existingSplitChatReportID: string, const allParticipantsAccountIDs = [...participantAccountIDs, currentUserAccountID]; if (!existingSplitChatReport) { - existingSplitChatReport = ReportUtils.getChatByParticipants(allParticipantsAccountIDs, undefined, participantAccountIDs.length > 1); + existingSplitChatReport = getChatByParticipants(allParticipantsAccountIDs, undefined, participantAccountIDs.length > 1); } // We found an existing chat report we are done... @@ -4010,7 +4052,7 @@ function getOrCreateOptimisticSplitChatReport(existingSplitChatReportID: string, // Create a Group Chat if we have multiple participants if (participants.length > 1) { - const splitChatReport = ReportUtils.buildOptimisticChatReport( + const splitChatReport = buildOptimisticChatReport( allParticipantsAccountIDs, '', CONST.REPORT.CHAT_TYPE.GROUP, @@ -4026,7 +4068,7 @@ function getOrCreateOptimisticSplitChatReport(existingSplitChatReportID: string, } // Otherwise, create a new 1:1 chat report - const splitChatReport = ReportUtils.buildOptimisticChatReport(participantAccountIDs); + const splitChatReport = buildOptimisticChatReport(participantAccountIDs); return {existingSplitChatReport: null, splitChatReport}; } @@ -4062,7 +4104,7 @@ function createSplitsAndOnyxData( taxCode = '', taxAmount = 0, ): SplitsAndOnyxData { - const currentUserEmailForIOUSplit = PhoneNumber.addSMSDomainIfPhoneNumber(currentUserLogin); + const currentUserEmailForIOUSplit = addSMSDomainIfPhoneNumber(currentUserLogin); const participantAccountIDs = participants.map((participant) => Number(participant.accountID)); const {splitChatReport, existingSplitChatReport} = getOrCreateOptimisticSplitChatReport(existingSplitChatReportID, participants, participantAccountIDs, currentUserAccountID); @@ -4102,8 +4144,8 @@ function createSplitsAndOnyxData( } // Note: The created action must be optimistically generated before the IOU action so there's no chance that the created action appears after the IOU action in the chat - const splitCreatedReportAction = ReportUtils.buildOptimisticCreatedReportAction(currentUserEmailForIOUSplit); - const splitIOUReportAction = ReportUtils.buildOptimisticIOUReportAction( + const splitCreatedReportAction = buildOptimisticCreatedReportAction(currentUserEmailForIOUSplit); + const splitIOUReportAction = buildOptimisticIOUReportAction( CONST.IOU.REPORT_ACTION_TYPE.SPLIT, amount, currency, @@ -4118,8 +4160,8 @@ function createSplitsAndOnyxData( ); splitChatReport.lastReadTime = DateUtils.getDBTime(); - splitChatReport.lastMessageText = ReportActionsUtils.getReportActionText(splitIOUReportAction); - splitChatReport.lastMessageHtml = ReportActionsUtils.getReportActionHtml(splitIOUReportAction); + splitChatReport.lastMessageText = getReportActionText(splitIOUReportAction); + splitChatReport.lastMessageHtml = getReportActionHtml(splitIOUReportAction); splitChatReport.lastActorAccountID = currentUserAccountID; splitChatReport.lastVisibleActionCreated = splitIOUReportAction.created; @@ -4245,17 +4287,17 @@ function createSplitsAndOnyxData( } // Loop through participants creating individual chats, iouReports and reportActionIDs as needed - const currentUserAmount = splitShares?.[currentUserAccountID]?.amount ?? IOUUtils.calculateAmount(participants.length, amount, currency, true); - const currentUserTaxAmount = IOUUtils.calculateAmount(participants.length, taxAmount, currency, true); + const currentUserAmount = splitShares?.[currentUserAccountID]?.amount ?? calculateAmount(participants.length, amount, currency, true); + const currentUserTaxAmount = calculateAmount(participants.length, taxAmount, currency, true); const splits: Split[] = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID, amount: currentUserAmount, taxAmount: currentUserTaxAmount}]; const hasMultipleParticipants = participants.length > 1; participants.forEach((participant) => { // In a case when a participant is a workspace, even when a current user is not an owner of the workspace - const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(participant); - const splitAmount = splitShares?.[participant.accountID ?? -1]?.amount ?? IOUUtils.calculateAmount(participants.length, amount, currency, false); - const splitTaxAmount = IOUUtils.calculateAmount(participants.length, taxAmount, currency, false); + const isPolicyExpenseChat = isPolicyExpenseChatReportUtils(participant); + const splitAmount = splitShares?.[participant.accountID ?? -1]?.amount ?? calculateAmount(participants.length, amount, currency, false); + const splitTaxAmount = calculateAmount(participants.length, taxAmount, currency, false); // To exclude someone from a split, the amount can be 0. The scenario for this is when creating a split from a group chat, we have remove the option to deselect users to exclude them. // We can input '0' next to someone we want to exclude. @@ -4265,7 +4307,7 @@ function createSplitsAndOnyxData( // In case the participant is a workspace, email & accountID should remain undefined and won't be used in the rest of this code // participant.login is undefined when the request is initiated from a group DM with an unknown user, so we need to add a default - const email = isOwnPolicyExpenseChat || isPolicyExpenseChat ? '' : PhoneNumber.addSMSDomainIfPhoneNumber(participant.login ?? '').toLowerCase(); + const email = isOwnPolicyExpenseChat || isPolicyExpenseChat ? '' : addSMSDomainIfPhoneNumber(participant.login ?? '').toLowerCase(); const accountID = isOwnPolicyExpenseChat || isPolicyExpenseChat ? 0 : Number(participant.accountID); if (email === currentUserEmailForIOUSplit) { return; @@ -4287,32 +4329,32 @@ function createSplitsAndOnyxData( oneOnOneChatReport = splitChatReport; shouldCreateOptimisticPersonalDetails = !existingSplitChatReport && !personalDetailExists; } else { - const existingChatReport = ReportUtils.getChatByParticipants([accountID, currentUserAccountID]); + const existingChatReport = getChatByParticipants([accountID, currentUserAccountID]); isNewOneOnOneChatReport = !existingChatReport; shouldCreateOptimisticPersonalDetails = isNewOneOnOneChatReport && !personalDetailExists; - oneOnOneChatReport = existingChatReport ?? ReportUtils.buildOptimisticChatReport([accountID, currentUserAccountID]); + oneOnOneChatReport = existingChatReport ?? buildOptimisticChatReport([accountID, currentUserAccountID]); } // STEP 2: Get existing IOU/Expense report and update its total OR build a new optimistic one let oneOnOneIOUReport: OneOnOneIOUReport = oneOnOneChatReport.iouReportID ? getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`] : null; - const shouldCreateNewOneOnOneIOUReport = ReportUtils.shouldCreateNewMoneyRequestReport(oneOnOneIOUReport, oneOnOneChatReport); + const shouldCreateNewOneOnOneIOUReport = shouldCreateNewMoneyRequestReportReportUtils(oneOnOneIOUReport, oneOnOneChatReport); if (!oneOnOneIOUReport || shouldCreateNewOneOnOneIOUReport) { oneOnOneIOUReport = isOwnPolicyExpenseChat - ? ReportUtils.buildOptimisticExpenseReport(oneOnOneChatReport.reportID, oneOnOneChatReport.policyID ?? '-1', currentUserAccountID, splitAmount, currency) - : ReportUtils.buildOptimisticIOUReport(currentUserAccountID, accountID, splitAmount, oneOnOneChatReport.reportID, currency); + ? buildOptimisticExpenseReport(oneOnOneChatReport.reportID, oneOnOneChatReport.policyID ?? '-1', currentUserAccountID, splitAmount, currency) + : buildOptimisticIOUReport(currentUserAccountID, accountID, splitAmount, oneOnOneChatReport.reportID, currency); } else if (isOwnPolicyExpenseChat) { if (typeof oneOnOneIOUReport?.total === 'number') { // Because of the Expense reports are stored as negative values, we subtract the total from the amount oneOnOneIOUReport.total -= splitAmount; } } else { - oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(oneOnOneIOUReport, currentUserAccountID, splitAmount, currency); + oneOnOneIOUReport = updateIOUOwnerAndTotal(oneOnOneIOUReport, currentUserAccountID, splitAmount, currency); } // STEP 3: Build optimistic transaction const oneOnOneTransaction = buildOptimisticTransaction( - ReportUtils.isExpenseReport(oneOnOneIOUReport) ? -splitAmount : splitAmount, + isExpenseReport(oneOnOneIOUReport) ? -splitAmount : splitAmount, currency, oneOnOneIOUReport.reportID, comment, @@ -4327,7 +4369,7 @@ function createSplitsAndOnyxData( category, tag, taxCode, - ReportUtils.isExpenseReport(oneOnOneIOUReport) ? -splitTaxAmount : splitTaxAmount, + isExpenseReport(oneOnOneIOUReport) ? -splitTaxAmount : splitTaxAmount, billable, ); @@ -4338,7 +4380,7 @@ function createSplitsAndOnyxData( // 4. Transaction Thread and the CREATED action for it // 5. REPORT_PREVIEW action for the chatReport const [oneOnOneCreatedActionForChat, oneOnOneCreatedActionForIOU, oneOnOneIOUAction, optimisticTransactionThread, optimisticCreatedActionForTransactionThread] = - ReportUtils.buildOptimisticMoneyRequestEntities( + buildOptimisticMoneyRequestEntities( oneOnOneIOUReport, CONST.IOU.REPORT_ACTION_TYPE.CREATE, splitAmount, @@ -4356,7 +4398,7 @@ function createSplitsAndOnyxData( accountID, // Disabling this line since participant.displayName can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - displayName: LocalePhoneNumber.formatPhoneNumber(participant.displayName || email), + displayName: formatPhoneNumber(participant.displayName || email), login: participant.login, isOptimisticPersonalDetail: true, }, @@ -4370,18 +4412,18 @@ function createSplitsAndOnyxData( let oneOnOneReportPreviewAction = getReportPreviewAction(oneOnOneChatReport.reportID, oneOnOneIOUReport.reportID); if (oneOnOneReportPreviewAction) { - oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction); + oneOnOneReportPreviewAction = updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction); } else { - oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport); + oneOnOneReportPreviewAction = buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport); } // Add category to optimistic policy recently used categories when a participant is a workspace - const optimisticPolicyRecentlyUsedCategories = isPolicyExpenseChat ? Category.buildOptimisticPolicyRecentlyUsedCategories(participant.policyID, category) : []; + const optimisticPolicyRecentlyUsedCategories = isPolicyExpenseChat ? buildOptimisticPolicyRecentlyUsedCategories(participant.policyID, category) : []; - const optimisticRecentlyUsedCurrencies = Policy.buildOptimisticRecentlyUsedCurrencies(currency); + const optimisticRecentlyUsedCurrencies = buildOptimisticRecentlyUsedCurrencies(currency); // Add tag to optimistic policy recently used tags when a participant is a workspace - const optimisticPolicyRecentlyUsedTags = isPolicyExpenseChat ? Tag.buildOptimisticPolicyRecentlyUsedTags(participant.policyID, tag) : {}; + const optimisticPolicyRecentlyUsedTags = isPolicyExpenseChat ? buildOptimisticPolicyRecentlyUsedTags(participant.policyID, tag) : {}; // STEP 5: Build Onyx Data const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest( @@ -4411,7 +4453,7 @@ function createSplitsAndOnyxData( const individualSplit = { email, accountID, - isOptimisticAccount: ReportUtils.isOptimisticPersonalDetail(accountID), + isOptimisticAccount: isOptimisticPersonalDetail(accountID), amount: splitAmount, iouReportID: oneOnOneIOUReport.reportID, chatReportID: oneOnOneChatReport.reportID, @@ -4544,10 +4586,10 @@ function splitBill({ }; API.write(WRITE_COMMANDS.SPLIT_BILL, parameters, onyxData); - InteractionManager.runAfterInteractions(() => TransactionEdit.removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); + InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); Navigation.dismissModal(isSearchTopmostCentralPane() ? undefined : existingSplitChatReportID); - Report.notifyNewAction(splitData.chatReportID, currentUserAccountID); + notifyNewAction(splitData.chatReportID, currentUserAccountID); } /** @@ -4612,10 +4654,10 @@ function splitBillAndOpenReport({ }; API.write(WRITE_COMMANDS.SPLIT_BILL_AND_OPEN_REPORT, parameters, onyxData); - InteractionManager.runAfterInteractions(() => TransactionEdit.removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); + InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); Navigation.dismissModal(isSearchTopmostCentralPane() ? undefined : splitData.chatReportID); - Report.notifyNewAction(splitData.chatReportID, currentUserAccountID); + notifyNewAction(splitData.chatReportID, currentUserAccountID); } type StartSplitBilActionParams = { @@ -4652,7 +4694,7 @@ function startSplitBill({ taxCode = '', taxAmount = 0, }: StartSplitBilActionParams) { - const currentUserEmailForIOUSplit = PhoneNumber.addSMSDomainIfPhoneNumber(currentUserLogin); + const currentUserEmailForIOUSplit = addSMSDomainIfPhoneNumber(currentUserLogin); const participantAccountIDs = participants.map((participant) => Number(participant.accountID)); const {splitChatReport, existingSplitChatReport} = getOrCreateOptimisticSplitChatReport(existingSplitChatReportID, participants, participantAccountIDs, currentUserAccountID); const isOwnPolicyExpenseChat = !!splitChatReport.isOwnPolicyExpenseChat; @@ -4682,8 +4724,8 @@ function startSplitBill({ ); // Note: The created action must be optimistically generated before the IOU action so there's no chance that the created action appears after the IOU action in the chat - const splitChatCreatedReportAction = ReportUtils.buildOptimisticCreatedReportAction(currentUserEmailForIOUSplit); - const splitIOUReportAction = ReportUtils.buildOptimisticIOUReportAction( + const splitChatCreatedReportAction = buildOptimisticCreatedReportAction(currentUserEmailForIOUSplit); + const splitIOUReportAction = buildOptimisticIOUReportAction( CONST.IOU.REPORT_ACTION_TYPE.SPLIT, 0, CONST.CURRENCY.USD, @@ -4698,8 +4740,8 @@ function startSplitBill({ ); splitChatReport.lastReadTime = DateUtils.getDBTime(); - splitChatReport.lastMessageText = ReportActionsUtils.getReportActionText(splitIOUReportAction); - splitChatReport.lastMessageHtml = ReportActionsUtils.getReportActionHtml(splitIOUReportAction); + splitChatReport.lastMessageText = getReportActionText(splitIOUReportAction); + splitChatReport.lastMessageHtml = getReportActionHtml(splitIOUReportAction); // If we have an existing splitChatReport (group chat or workspace) use it's pending fields, otherwise indicate that we are adding a chat if (!existingSplitChatReport) { @@ -4829,7 +4871,7 @@ function startSplitBill({ participants.forEach((participant) => { // Disabling this line since participant.login can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const email = participant.isOwnPolicyExpenseChat ? '' : PhoneNumber.addSMSDomainIfPhoneNumber(participant.login || participant.text || '').toLowerCase(); + const email = participant.isOwnPolicyExpenseChat ? '' : addSMSDomainIfPhoneNumber(participant.login || participant.text || '').toLowerCase(); const accountID = participant.isOwnPolicyExpenseChat ? 0 : Number(participant.accountID); if (email === currentUserEmailForIOUSplit) { return; @@ -4854,7 +4896,7 @@ function startSplitBill({ accountID, // Disabling this line since participant.displayName can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - displayName: LocalePhoneNumber.formatPhoneNumber(participant.displayName || email), + displayName: formatPhoneNumber(participant.displayName || email), // Disabling this line since participant.login can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing login: participant.login || participant.text, @@ -4873,14 +4915,14 @@ function startSplitBill({ }); participants.forEach((participant) => { - const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(participant); + const isPolicyExpenseChat = isPolicyExpenseChatReportUtils(participant); if (!isPolicyExpenseChat) { return; } - const optimisticPolicyRecentlyUsedCategories = Category.buildOptimisticPolicyRecentlyUsedCategories(participant.policyID, category); - const optimisticPolicyRecentlyUsedTags = Tag.buildOptimisticPolicyRecentlyUsedTags(participant.policyID, tag); - const optimisticRecentlyUsedCurrencies = Policy.buildOptimisticRecentlyUsedCurrencies(currency); + const optimisticPolicyRecentlyUsedCategories = buildOptimisticPolicyRecentlyUsedCategories(participant.policyID, category); + const optimisticPolicyRecentlyUsedTags = buildOptimisticPolicyRecentlyUsedTags(participant.policyID, tag); + const optimisticRecentlyUsedCurrencies = buildOptimisticRecentlyUsedCurrencies(currency); if (optimisticPolicyRecentlyUsedCategories.length > 0) { optimisticData.push({ @@ -4939,7 +4981,7 @@ function startSplitBill({ API.write(WRITE_COMMANDS.START_SPLIT_BILL, parameters, {optimisticData, successData, failureData}); Navigation.dismissModalWithReport(splitChatReport); - Report.notifyNewAction(splitChatReport.reportID ?? '-1', currentUserAccountID); + notifyNewAction(splitChatReport.reportID ?? '-1', currentUserAccountID); } /** Used for editing a split expense while it's still scanning or when SmartScan fails, it completes a split expense started by startSplitBill above. @@ -4951,7 +4993,7 @@ function startSplitBill({ * @param sessionEmail - email of the current user */ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportAction, updatedTransaction: OnyxEntry, sessionAccountID: number, sessionEmail: string) { - const currentUserEmailForIOUSplit = PhoneNumber.addSMSDomainIfPhoneNumber(sessionEmail); + const currentUserEmailForIOUSplit = addSMSDomainIfPhoneNumber(sessionEmail); const transactionID = updatedTransaction?.transactionID ?? '-1'; const unmodifiedTransaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; @@ -5020,8 +5062,8 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA const currency = updatedTransaction?.modifiedCurrency; // Exclude the current user when calculating the split amount, `calculateAmount` takes it into account - const splitAmount = IOUUtils.calculateAmount(splitParticipants.length - 1, amount ?? 0, currency ?? '', false); - const splitTaxAmount = IOUUtils.calculateAmount(splitParticipants.length - 1, updatedTransaction?.taxAmount ?? 0, currency ?? '', false); + const splitAmount = calculateAmount(splitParticipants.length - 1, amount ?? 0, currency ?? '', false); + const splitTaxAmount = calculateAmount(splitParticipants.length - 1, updatedTransaction?.taxAmount ?? 0, currency ?? '', false); const splits: Split[] = [{email: currentUserEmailForIOUSplit}]; splitParticipants.forEach((participant) => { @@ -5051,25 +5093,25 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA // The workspace chat reportID is saved in the splits array when starting a split expense with a workspace oneOnOneChatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.chatReportID}`]; } else { - const existingChatReport = ReportUtils.getChatByParticipants(participant.accountID ? [participant.accountID, sessionAccountID] : []); + const existingChatReport = getChatByParticipants(participant.accountID ? [participant.accountID, sessionAccountID] : []); isNewOneOnOneChatReport = !existingChatReport; - oneOnOneChatReport = existingChatReport ?? ReportUtils.buildOptimisticChatReport(participant.accountID ? [participant.accountID, sessionAccountID] : []); + oneOnOneChatReport = existingChatReport ?? buildOptimisticChatReport(participant.accountID ? [participant.accountID, sessionAccountID] : []); } let oneOnOneIOUReport: OneOnOneIOUReport = oneOnOneChatReport?.iouReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`] : null; - const shouldCreateNewOneOnOneIOUReport = ReportUtils.shouldCreateNewMoneyRequestReport(oneOnOneIOUReport, oneOnOneChatReport); + const shouldCreateNewOneOnOneIOUReport = shouldCreateNewMoneyRequestReportReportUtils(oneOnOneIOUReport, oneOnOneChatReport); if (!oneOnOneIOUReport || shouldCreateNewOneOnOneIOUReport) { oneOnOneIOUReport = isPolicyExpenseChat - ? ReportUtils.buildOptimisticExpenseReport(oneOnOneChatReport?.reportID ?? '-1', participant.policyID ?? '-1', sessionAccountID, splitAmount, currency ?? '') - : ReportUtils.buildOptimisticIOUReport(sessionAccountID, participant.accountID ?? -1, splitAmount, oneOnOneChatReport?.reportID ?? '-1', currency ?? ''); + ? buildOptimisticExpenseReport(oneOnOneChatReport?.reportID ?? '-1', participant.policyID ?? '-1', sessionAccountID, splitAmount, currency ?? '') + : buildOptimisticIOUReport(sessionAccountID, participant.accountID ?? -1, splitAmount, oneOnOneChatReport?.reportID ?? '-1', currency ?? ''); } else if (isPolicyExpenseChat) { if (typeof oneOnOneIOUReport?.total === 'number') { // Because of the Expense reports are stored as negative values, we subtract the total from the amount oneOnOneIOUReport.total -= splitAmount; } } else { - oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(oneOnOneIOUReport, sessionAccountID, splitAmount, currency ?? ''); + oneOnOneIOUReport = updateIOUOwnerAndTotal(oneOnOneIOUReport, sessionAccountID, splitAmount, currency ?? ''); } const oneOnOneTransaction = buildOptimisticTransaction( @@ -5093,7 +5135,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA ); const [oneOnOneCreatedActionForChat, oneOnOneCreatedActionForIOU, oneOnOneIOUAction, optimisticTransactionThread, optimisticCreatedActionForTransactionThread] = - ReportUtils.buildOptimisticMoneyRequestEntities( + buildOptimisticMoneyRequestEntities( oneOnOneIOUReport, CONST.IOU.REPORT_ACTION_TYPE.CREATE, splitAmount, @@ -5107,9 +5149,9 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA let oneOnOneReportPreviewAction = getReportPreviewAction(oneOnOneChatReport?.reportID ?? '-1', oneOnOneIOUReport?.reportID ?? '-1'); if (oneOnOneReportPreviewAction) { - oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction); + oneOnOneReportPreviewAction = updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction); } else { - oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport, '', oneOnOneTransaction); + oneOnOneReportPreviewAction = buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport, '', oneOnOneTransaction); } const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest( @@ -5165,7 +5207,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA taxCode: transactionTaxCode, taxAmount: transactionTaxAmount, billable: transactionBillable, - } = ReportUtils.getTransactionDetails(updatedTransaction) ?? {}; + } = getTransactionDetails(updatedTransaction) ?? {}; const parameters: CompleteSplitBillParams = { transactionID, @@ -5183,9 +5225,9 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA }; API.write(WRITE_COMMANDS.COMPLETE_SPLIT_BILL, parameters, {optimisticData, successData, failureData}); - InteractionManager.runAfterInteractions(() => TransactionEdit.removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); + InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); Navigation.dismissModal(isSearchTopmostCentralPane() ? undefined : chatReportID); - Report.notifyNewAction(chatReportID, sessionAccountID); + notifyNewAction(chatReportID, sessionAccountID); } function setDraftSplitTransaction(transactionID: string, transactionChanges: TransactionChanges = {}) { @@ -5233,8 +5275,8 @@ function createDistanceRequest( existingTransaction: OnyxEntry | undefined = undefined, ) { // If the report is an iou or expense report, we should get the linked chat report to be passed to the getMoneyRequestInformation function - const isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report); - const currentChatReport = isMoneyRequestReport ? ReportUtils.getReportOrDraftReport(report?.chatReportID) : report; + const isMoneyRequestReport = isMoneyRequestReportReportUtils(report); + const currentChatReport = isMoneyRequestReport ? getReportOrDraftReport(report?.chatReportID) : report; const moneyRequestReportID = isMoneyRequestReport ? report?.reportID : ''; const optimisticReceipt: Receipt = { @@ -5361,10 +5403,10 @@ function createDistanceRequest( }); API.write(WRITE_COMMANDS.CREATE_DISTANCE_REQUEST, parameters, onyxData); - InteractionManager.runAfterInteractions(() => TransactionEdit.removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); + InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); const activeReportID = isMoneyRequestReport ? report?.reportID ?? '-1' : parameters.chatReportID; Navigation.dismissModal(isSearchTopmostCentralPane() ? undefined : activeReportID); - Report.notifyNewAction(activeReportID, userAccountID); + notifyNewAction(activeReportID, userAccountID); } type UpdateMoneyRequestAmountAndCurrencyParams = { @@ -5401,7 +5443,7 @@ function updateMoneyRequestAmountAndCurrency({ const transactionThreadReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.parentReportID}`] ?? null; let data: UpdateMoneyRequestData; - if (ReportUtils.isTrackExpenseReport(transactionThreadReport) && ReportUtils.isSelfDM(parentReport)) { + if (isTrackExpenseReport(transactionThreadReport) && isSelfDM(parentReport)) { data = getUpdateTrackExpenseParams(transactionID, transactionThreadReportID, transactionChanges, policy); } else { data = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, policy, policyTagList ?? null, policyCategories ?? null); @@ -5420,7 +5462,7 @@ function updateMoneyRequestAmountAndCurrency({ function prepareToCleanUpMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) { // STEP 1: Get all collections we're updating const allReports = getAllReports(); - const iouReportID = ReportActionsUtils.isMoneyRequestAction(reportAction) ? ReportActionsUtils.getOriginalMessage(reportAction)?.IOUReportID : '-1'; + const iouReportID = isMoneyRequestAction(reportAction) ? getOriginalMessage(reportAction)?.IOUReportID : '-1'; const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReportID}`] ?? null; const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`]; // eslint-disable-next-line @typescript-eslint/no-non-null-assertion @@ -5494,13 +5536,13 @@ function prepareToCleanUpMoneyRequest(transactionID: string, reportAction: OnyxT updatedIOUReport.lastVisibleActionCreated = lastVisibleAction?.created; } - const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(iouReport?.reportID); + const hasNonReimbursableTransactions = hasNonReimbursableTransactionsReportUtils(iouReport?.reportID); const messageText = Localize.translateLocal(hasNonReimbursableTransactions ? 'iou.payerSpentAmount' : 'iou.payerOwesAmount', { - payer: ReportUtils.getPersonalDetailsForAccountID(updatedIOUReport?.managerID ?? -1).login ?? '', - amount: CurrencyUtils.convertToDisplayString(updatedIOUReport?.total, updatedIOUReport?.currency), + payer: getPersonalDetailsForAccountID(updatedIOUReport?.managerID ?? -1).login ?? '', + amount: convertToDisplayString(updatedIOUReport?.total, updatedIOUReport?.currency), }); - if (ReportActionsUtils.getReportActionMessage(updatedReportPreviewAction)) { + if (getReportActionMessage(updatedReportPreviewAction)) { if (Array.isArray(updatedReportPreviewAction?.message)) { const message = updatedReportPreviewAction.message.at(0); if (message) { @@ -5642,7 +5684,7 @@ function cleanUpMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repo { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`, - value: ReportUtils.getOutstandingChildRequest(updatedIOUReport), + value: getOutstandingChildRequest(updatedIOUReport), }, ); @@ -5668,10 +5710,10 @@ function cleanUpMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repo value: { hasOutstandingChildRequest: false, iouReportID: null, - lastMessageText: ReportActionsUtils.getLastVisibleMessage(iouReport?.chatReportID ?? '-1', canUserPerformWriteAction, { + lastMessageText: getLastVisibleMessage(iouReport?.chatReportID ?? '-1', canUserPerformWriteAction, { [reportPreviewAction?.reportActionID ?? '-1']: null, })?.lastMessageText, - lastVisibleActionCreated: ReportActionsUtils.getLastVisibleAction(iouReport?.chatReportID ?? '-1', canUserPerformWriteAction, { + lastVisibleActionCreated: getLastVisibleAction(iouReport?.chatReportID ?? '-1', canUserPerformWriteAction, { [reportPreviewAction?.reportActionID ?? '-1']: null, })?.created, }, @@ -5766,7 +5808,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`, - value: ReportUtils.getOutstandingChildRequest(updatedIOUReport), + value: getOutstandingChildRequest(updatedIOUReport), }, ); @@ -5791,9 +5833,8 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor value: { hasOutstandingChildRequest: false, iouReportID: null, - lastMessageText: ReportActionsUtils.getLastVisibleMessage(iouReport?.chatReportID ?? '-1', canUserPerformWriteAction, {[reportPreviewAction?.reportActionID ?? '-1']: null}) - ?.lastMessageText, - lastVisibleActionCreated: ReportActionsUtils.getLastVisibleAction(iouReport?.chatReportID ?? '-1', canUserPerformWriteAction, { + lastMessageText: getLastVisibleMessage(iouReport?.chatReportID ?? '-1', canUserPerformWriteAction, {[reportPreviewAction?.reportActionID ?? '-1']: null})?.lastMessageText, + lastVisibleActionCreated: getLastVisibleAction(iouReport?.chatReportID ?? '-1', canUserPerformWriteAction, { [reportPreviewAction?.reportActionID ?? '-1']: null, })?.created, }, @@ -5930,7 +5971,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor // STEP 3: Make the API request API.write(WRITE_COMMANDS.DELETE_MONEY_REQUEST, parameters, {optimisticData, successData, failureData}); - CachedPDFPaths.clearByKey(transactionID); + clearByKey(transactionID); return urlToNavigateBack; } @@ -5938,11 +5979,11 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor function deleteTrackExpense(chatReportID: string, transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) { // STEP 1: Get all collections we're updating const chatReport = getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`] ?? null; - if (!ReportUtils.isSelfDM(chatReport)) { + if (!isSelfDM(chatReport)) { return deleteMoneyRequest(transactionID, reportAction, isSingleTransactionView); } - const whisperAction = ReportActionsUtils.getTrackExpenseActionableWhisper(transactionID, chatReportID); + const whisperAction = getTrackExpenseActionableWhisper(transactionID, chatReportID); const actionableWhisperReportActionID = whisperAction?.reportActionID; const {parameters, optimisticData, successData, failureData, shouldDeleteTransactionThread} = getDeleteTrackExpenseInformation( chatReportID, @@ -5956,7 +5997,7 @@ function deleteTrackExpense(chatReportID: string, transactionID: string, reportA // STEP 6: Make the API request API.write(WRITE_COMMANDS.DELETE_MONEY_REQUEST, parameters, {optimisticData, successData, failureData}); - CachedPDFPaths.clearByKey(transactionID); + clearByKey(transactionID); // STEP 7: Navigate the user depending on which page they are on and which resources were deleted if (isSingleTransactionView && shouldDeleteTransactionThread) { @@ -5978,7 +6019,7 @@ function getSendMoneyParams( managerID: number, recipient: Participant, ): SendMoneyParamsData { - const recipientEmail = PhoneNumber.addSMSDomainIfPhoneNumber(recipient.login ?? ''); + const recipientEmail = addSMSDomainIfPhoneNumber(recipient.login ?? ''); const recipientAccountID = Number(recipient.accountID); const newIOUReportDetails = JSON.stringify({ amount, @@ -5989,13 +6030,13 @@ function getSendMoneyParams( idempotencyKey: Str.guid(), }); - let chatReport = !isEmptyObject(report) && report?.reportID ? report : ReportUtils.getChatByParticipants([recipientAccountID, managerID]); + let chatReport = !isEmptyObject(report) && report?.reportID ? report : getChatByParticipants([recipientAccountID, managerID]); let isNewChat = false; if (!chatReport) { - chatReport = ReportUtils.buildOptimisticChatReport([recipientAccountID, managerID]); + chatReport = buildOptimisticChatReport([recipientAccountID, managerID]); isNewChat = true; } - const optimisticIOUReport = ReportUtils.buildOptimisticIOUReport(recipientAccountID, managerID, amount, chatReport.reportID, currency, true); + const optimisticIOUReport = buildOptimisticIOUReport(recipientAccountID, managerID, amount, chatReport.reportID, currency, true); const optimisticTransaction = buildOptimisticTransaction(amount, currency, optimisticIOUReport.reportID, comment); const optimisticTransactionData: OnyxUpdate = { @@ -6005,7 +6046,7 @@ function getSendMoneyParams( }; const [optimisticCreatedActionForChat, optimisticCreatedActionForIOUReport, optimisticIOUReportAction, optimisticTransactionThread, optimisticCreatedActionForTransactionThread] = - ReportUtils.buildOptimisticMoneyRequestEntities( + buildOptimisticMoneyRequestEntities( optimisticIOUReport, CONST.IOU.REPORT_ACTION_TYPE.PAY, amount, @@ -6019,7 +6060,7 @@ function getSendMoneyParams( true, ); - const reportPreviewAction = ReportUtils.buildOptimisticReportPreview(chatReport, optimisticIOUReport); + const reportPreviewAction = buildOptimisticReportPreview(chatReport, optimisticIOUReport); // Change the method to set for new reports because it doesn't exist yet, is faster, // and we need the data to be available when we navigate to the chat page @@ -6058,8 +6099,8 @@ function getSendMoneyParams( key: `${ONYXKEYS.COLLECTION.REPORT}${optimisticIOUReport.reportID}`, value: { ...optimisticIOUReport, - lastMessageText: ReportActionsUtils.getReportActionText(optimisticIOUReportAction), - lastMessageHtml: ReportActionsUtils.getReportActionHtml(optimisticIOUReportAction), + lastMessageText: getReportActionText(optimisticIOUReportAction), + lastMessageHtml: getReportActionHtml(optimisticIOUReportAction), }, }; const optimisticTransactionThreadData: OnyxUpdate = { @@ -6307,12 +6348,12 @@ type OptimisticHoldReportExpenseActionID = { }; function getHoldReportActionsAndTransactions(reportID: string) { - const iouReportActions = ReportActionsUtils.getAllReportActions(reportID); + const iouReportActions = getAllReportActions(reportID); const holdReportActions: Array> = []; const holdTransactions: OnyxTypes.Transaction[] = []; Object.values(iouReportActions).forEach((action) => { - const transactionID = ReportActionsUtils.isMoneyRequestAction(action) ? ReportActionsUtils.getOriginalMessage(action)?.IOUTransactionID ?? null : null; + const transactionID = isMoneyRequestAction(action) ? getOriginalMessage(action)?.IOUTransactionID ?? null : null; const transaction = getTransaction(transactionID ?? '-1'); if (transaction?.comment?.hold) { @@ -6339,10 +6380,10 @@ function getReportFromHoldRequestsOnyxData( const firstHoldTransaction = holdTransactions.at(0); const newParentReportActionID = rand64(); - const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(chatReport); + const isPolicyExpenseChat = isPolicyExpenseChatReportUtils(chatReport); const holdTransactionAmount = holdTransactions.reduce((acc, transaction) => acc + getAmount(transaction), 0); const optimisticExpenseReport = isPolicyExpenseChat - ? ReportUtils.buildOptimisticExpenseReport( + ? buildOptimisticExpenseReport( chatReport.reportID, chatReport.policyID ?? iouReport?.policyID ?? '', recipient.accountID ?? 1, @@ -6351,7 +6392,7 @@ function getReportFromHoldRequestsOnyxData( false, newParentReportActionID, ) - : ReportUtils.buildOptimisticIOUReport( + : buildOptimisticIOUReport( iouReport?.ownerAccountID ?? -1, iouReport?.managerID ?? -1, holdTransactionAmount, @@ -6361,7 +6402,7 @@ function getReportFromHoldRequestsOnyxData( newParentReportActionID, ); - const optimisticExpenseReportPreview = ReportUtils.buildOptimisticReportPreview( + const optimisticExpenseReportPreview = buildOptimisticReportPreview( chatReport, optimisticExpenseReport, '', @@ -6376,7 +6417,7 @@ function getReportFromHoldRequestsOnyxData( const optimisticHoldReportExpenseActionIDs: OptimisticHoldReportExpenseActionID[] = []; holdReportActions.forEach((holdReportAction) => { - const originalMessage = ReportActionsUtils.getOriginalMessage(holdReportAction); + const originalMessage = getOriginalMessage(holdReportAction); deleteHoldReportActions[holdReportAction.reportActionID] = { message: [ @@ -6399,7 +6440,7 @@ function getReportFromHoldRequestsOnyxData( pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }; - const heldReport = ReportUtils.getReportOrDraftReport(holdReportAction.childReportID); + const heldReport = getReportOrDraftReport(holdReportAction.childReportID); if (heldReport) { optimisticHoldReportExpenseActionIDs.push({optimisticReportActionID: reportActionID, oldReportActionID: holdReportAction.reportActionID}); @@ -6531,24 +6572,24 @@ function getPayMoneyRequestParams( full: boolean, payAsBusiness?: boolean, ): PayMoneyRequestData { - const isInvoiceReport = ReportUtils.isInvoiceReport(iouReport); - const activePolicy = PolicyUtils.getPolicy(activePolicyID); + const isInvoiceReport = isInvoiceReportReportUtils(iouReport); + const activePolicy = getPolicy(activePolicyID); let payerPolicyID = activePolicyID; let chatReport = initialChatReport; let policyParams = {}; const optimisticData: OnyxUpdate[] = []; const successData: OnyxUpdate[] = []; const failureData: OnyxUpdate[] = []; - const shouldCreatePolicy = !activePolicy || !PolicyUtils.isPolicyAdmin(activePolicy) || !PolicyUtils.isPaidGroupPolicy(activePolicy); + const shouldCreatePolicy = !activePolicy || !isPolicyAdmin(activePolicy) || !isPaidGroupPolicy(activePolicy); - if (ReportUtils.isIndividualInvoiceRoom(chatReport) && payAsBusiness && shouldCreatePolicy) { - payerPolicyID = Policy.generatePolicyID(); + if (isIndividualInvoiceRoom(chatReport) && payAsBusiness && shouldCreatePolicy) { + payerPolicyID = generatePolicyID(); const { optimisticData: policyOptimisticData, failureData: policyFailureData, successData: policySuccessData, params, - } = Policy.buildPolicyData(currentUserEmail, true, undefined, payerPolicyID); + } = buildPolicyData(currentUserEmail, true, undefined, payerPolicyID); const {adminsChatReportID, adminsCreatedReportActionID, expenseChatReportID, expenseCreatedReportActionID, customUnitRateID, customUnitID, ownerEmail, policyName} = params; policyParams = { @@ -6568,21 +6609,21 @@ function getPayMoneyRequestParams( failureData.push(...policyFailureData, {onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.NVP_ACTIVE_POLICY_ID, value: activePolicyID ?? null}); } - if (ReportUtils.isIndividualInvoiceRoom(chatReport) && payAsBusiness && activePolicyID) { - const existingB2BInvoiceRoom = ReportUtils.getInvoiceChatByParticipants(chatReport.policyID ?? '', activePolicyID); + if (isIndividualInvoiceRoom(chatReport) && payAsBusiness && activePolicyID) { + const existingB2BInvoiceRoom = getInvoiceChatByParticipants(chatReport.policyID ?? '', activePolicyID); if (existingB2BInvoiceRoom) { chatReport = existingB2BInvoiceRoom; } } let total = (iouReport?.total ?? 0) - (iouReport?.nonReimbursableTotal ?? 0); - if (ReportUtils.hasHeldExpenses(iouReport?.reportID ?? '') && !full && !!iouReport?.unheldTotal) { + if (hasHeldExpensesReportUtils(iouReport?.reportID ?? '') && !full && !!iouReport?.unheldTotal) { total = iouReport?.unheldTotal; } - const optimisticIOUReportAction = ReportUtils.buildOptimisticIOUReportAction( + const optimisticIOUReportAction = buildOptimisticIOUReportAction( CONST.IOU.REPORT_ACTION_TYPE.PAY, - ReportUtils.isExpenseReport(iouReport) ? -total : total, + isExpenseReport(iouReport) ? -total : total, iouReport?.currency ?? '', '', [recipient], @@ -6597,13 +6638,13 @@ function getPayMoneyRequestParams( let optimisticReportPreviewAction = null; const reportPreviewAction = getReportPreviewAction(chatReport.reportID, iouReport?.reportID ?? ''); if (reportPreviewAction) { - optimisticReportPreviewAction = ReportUtils.updateReportPreview(iouReport, reportPreviewAction, true); + optimisticReportPreviewAction = updateReportPreview(iouReport, reportPreviewAction, true); } let currentNextStep = null; let optimisticNextStep = null; if (!isInvoiceReport) { currentNextStep = allNextSteps[`${ONYXKEYS.COLLECTION.NEXT_STEP}${iouReport?.reportID ?? ''}`] ?? null; - optimisticNextStep = NextStepUtils.buildNextStep(iouReport, CONST.REPORT.STATUS_NUM.REIMBURSED); + optimisticNextStep = buildNextStep(iouReport, CONST.REPORT.STATUS_NUM.REIMBURSED); } const optimisticChatReport = { @@ -6612,10 +6653,10 @@ function getPayMoneyRequestParams( lastVisibleActionCreated: optimisticIOUReportAction.created, hasOutstandingChildRequest: false, iouReportID: null, - lastMessageText: ReportActionsUtils.getReportActionText(optimisticIOUReportAction), - lastMessageHtml: ReportActionsUtils.getReportActionHtml(optimisticIOUReportAction), + lastMessageText: getReportActionText(optimisticIOUReportAction), + lastMessageHtml: getReportActionHtml(optimisticIOUReportAction), }; - if (ReportUtils.isIndividualInvoiceRoom(chatReport) && payAsBusiness && payerPolicyID) { + if (isIndividualInvoiceRoom(chatReport) && payAsBusiness && payerPolicyID) { optimisticChatReport.invoiceReceiver = { type: CONST.REPORT.INVOICE_RECEIVER_TYPE.BUSINESS, policyID: payerPolicyID, @@ -6643,8 +6684,8 @@ function getPayMoneyRequestParams( key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID ?? ''}`, value: { ...iouReport, - lastMessageText: ReportActionsUtils.getReportActionText(optimisticIOUReportAction), - lastMessageHtml: ReportActionsUtils.getReportActionHtml(optimisticIOUReportAction), + lastMessageText: getReportActionText(optimisticIOUReportAction), + lastMessageHtml: getReportActionHtml(optimisticIOUReportAction), hasOutstandingChildRequest: false, statusNum: CONST.REPORT.STATUS_NUM.REIMBURSED, pendingFields: { @@ -6813,20 +6854,20 @@ function sendMoneyElsewhere(report: OnyxEntry, amount: number, API.write(WRITE_COMMANDS.SEND_MONEY_ELSEWHERE, params, {optimisticData, successData, failureData}); Navigation.dismissModal(isSearchTopmostCentralPane() ? undefined : params.chatReportID); - Report.notifyNewAction(params.chatReportID, managerID); + notifyNewAction(params.chatReportID, managerID); } /** * @param managerID - Account ID of the person sending the money * @param recipient - The user receiving the money */ -function sendMoneyWithWallet(report: OnyxEntry, amount: number, currency: string, comment: string, managerID: number, recipient: Participant | ReportUtils.OptionData) { +function sendMoneyWithWallet(report: OnyxEntry, amount: number, currency: string, comment: string, managerID: number, recipient: Participant | OptionData) { const {params, optimisticData, successData, failureData} = getSendMoneyParams(report, amount, currency, comment, CONST.IOU.PAYMENT_TYPE.EXPENSIFY, managerID, recipient); API.write(WRITE_COMMANDS.SEND_MONEY_WITH_WALLET, params, {optimisticData, successData, failureData}); Navigation.dismissModal(isSearchTopmostCentralPane() ? undefined : params.chatReportID); - Report.notifyNewAction(params.chatReportID, managerID); + notifyNewAction(params.chatReportID, managerID); } function canApproveIOU( @@ -6836,25 +6877,25 @@ function canApproveIOU( chatReportRNVP?: OnyxTypes.ReportNameValuePairs, ) { // Only expense reports can be approved - const isPaidGroupPolicy = policy && PolicyUtils.isPaidGroupPolicy(policy); - if (!isPaidGroupPolicy) { + + if (!policy && isPaidGroupPolicy(policy)) { return false; } - const isOnSubmitAndClosePolicy = PolicyUtils.isSubmitAndClose(policy); + const isOnSubmitAndClosePolicy = isSubmitAndClose(policy); if (isOnSubmitAndClosePolicy) { return false; } const managerID = iouReport?.managerID ?? -1; const isCurrentUserManager = managerID === userAccountID; - const isOpenExpenseReport = ReportUtils.isOpenExpenseReport(iouReport); - const isApproved = ReportUtils.isReportApproved(iouReport); - const iouSettled = ReportUtils.isSettled(iouReport?.reportID); - const reportNameValuePairs = chatReportRNVP ?? ReportUtils.getReportNameValuePairs(iouReport?.reportID); - const isArchivedReport = ReportUtils.isArchivedRoom(iouReport, reportNameValuePairs); + const isOpenExpenseReport = isOpenExpenseReportReportUtils(iouReport); + const isApproved = isReportApproved(iouReport); + const iouSettled = isSettled(iouReport?.reportID); + const reportNameValuePairs = chatReportRNVP ?? getReportNameValuePairs(iouReport?.reportID); + const isArchivedReport = isArchivedRoom(iouReport, reportNameValuePairs); const allViolations = violations ?? allTransactionViolations; - const hasViolations = ReportUtils.hasViolations(iouReport?.reportID ?? '-1', allViolations); + const hasViolations = hasViolationsReportUtils(iouReport?.reportID ?? '-1', allViolations); let isTransactionBeingScanned = false; const reportTransactions = getAllReportTransactions(iouReport?.reportID); for (const transaction of reportTransactions) { @@ -6880,10 +6921,10 @@ function canIOUBePaid( chatReportRNVP?: OnyxTypes.ReportNameValuePairs, invoiceReceiverPolicy?: SearchPolicy, ) { - const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(chatReport); - const reportNameValuePairs = chatReportRNVP ?? ReportUtils.getReportNameValuePairs(chatReport?.reportID); - const isChatReportArchived = ReportUtils.isArchivedRoom(chatReport, reportNameValuePairs); - const iouSettled = ReportUtils.isSettled(iouReport); + const isPolicyExpenseChat = isPolicyExpenseChatReportUtils(chatReport); + const reportNameValuePairs = chatReportRNVP ?? getReportNameValuePairs(chatReport?.reportID); + const isChatReportArchived = isArchivedRoom(chatReport, reportNameValuePairs); + const iouSettled = isSettled(iouReport); if (isEmptyObject(iouReport)) { return false; @@ -6898,17 +6939,17 @@ function canIOUBePaid( } } - if (ReportUtils.isInvoiceReport(iouReport)) { + if (isInvoiceReportReportUtils(iouReport)) { if (iouSettled) { return false; } if (chatReport?.invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL) { return chatReport?.invoiceReceiver?.accountID === userAccountID; } - return (invoiceReceiverPolicy ?? PolicyUtils.getPolicy(chatReport?.invoiceReceiver?.policyID))?.role === CONST.POLICY.ROLE.ADMIN; + return (invoiceReceiverPolicy ?? getPolicy(chatReport?.invoiceReceiver?.policyID))?.role === CONST.POLICY.ROLE.ADMIN; } - const isPayer = ReportUtils.isPayer( + const isPayer = isPayerReportUtils( { email: currentUserEmail, accountID: userAccountID, @@ -6918,15 +6959,15 @@ function canIOUBePaid( policy, ); - const isOpenExpenseReport = isPolicyExpenseChat && ReportUtils.isOpenExpenseReport(iouReport); + const isOpenExpenseReport = isPolicyExpenseChat && isOpenExpenseReportReportUtils(iouReport); - const {reimbursableSpend} = ReportUtils.getMoneyRequestSpendBreakdown(iouReport); - const isAutoReimbursable = policy?.reimbursementChoice === CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_YES ? false : ReportUtils.canBeAutoReimbursed(iouReport, policy); + const {reimbursableSpend} = getMoneyRequestSpendBreakdown(iouReport); + const isAutoReimbursable = policy?.reimbursementChoice === CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_YES ? false : canBeAutoReimbursed(iouReport, policy); const allViolations = violations ?? allTransactionViolations; const shouldBeApproved = canApproveIOU(iouReport, policy, allViolations); - const hasViolations = ReportUtils.hasViolations(iouReport?.reportID ?? '-1', allViolations); + const hasViolations = hasViolationsReportUtils(iouReport?.reportID ?? '-1', allViolations); - const isPayAtEndExpenseReport = ReportUtils.isPayAtEndExpenseReport(iouReport?.reportID, transactions); + const isPayAtEndExpenseReport = isPayAtEndExpenseReportReportUtils(iouReport?.reportID, transactions); return ( isPayer && !isOpenExpenseReport && @@ -6945,8 +6986,8 @@ function getIOUReportActionToApproveOrPay(chatReport: OnyxEntry { - const iouReport = ReportUtils.getReportOrDraftReport(action.childReportID ?? '-1'); - const policy = PolicyUtils.getPolicy(iouReport?.policyID); + const iouReport = getReportOrDraftReport(action.childReportID ?? '-1'); + const policy = getPolicy(iouReport?.policyID); const shouldShowSettlementButton = canIOUBePaid(iouReport, chatReport, policy, undefined, allTransactionViolations) || canApproveIOU(iouReport, policy, allTransactionViolations); return action.childReportID?.toString() !== excludedIOUReportID && action.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW && shouldShowSettlementButton; }); @@ -6964,9 +7005,9 @@ function isLastApprover(approvalChain: string[]): boolean { } function getNextApproverAccountID(report: OnyxEntry) { - const policy = PolicyUtils.getPolicy(report?.policyID); - const approvalChain = ReportUtils.getApprovalChain(policy, report); - const submitToAccountID = PolicyUtils.getSubmitToAccountID(policy, report); + const policy = getPolicy(report?.policyID); + const approvalChain = getApprovalChain(policy, report); + const submitToAccountID = getSubmitToAccountID(policy, report); if (approvalChain.length === 0) { return submitToAccountID; @@ -6977,31 +7018,31 @@ function getNextApproverAccountID(report: OnyxEntry) { return submitToAccountID; } - return PersonalDetailsUtils.getAccountIDsByLogins([nextApproverEmail]).at(0); + return getAccountIDsByLogins([nextApproverEmail]).at(0); } function approveMoneyRequest(expenseReport: OnyxEntry, full?: boolean) { - if (expenseReport?.policyID && SubscriptionUtils.shouldRestrictUserBillableActions(expenseReport.policyID)) { + if (expenseReport?.policyID && shouldRestrictUserBillableActions(expenseReport.policyID)) { Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(expenseReport.policyID)); return; } const currentNextStep = allNextSteps[`${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport?.reportID}`] ?? null; let total = expenseReport?.total ?? 0; - const hasHeldExpenses = ReportUtils.hasHeldExpenses(expenseReport?.reportID); + const hasHeldExpenses = hasHeldExpensesReportUtils(expenseReport?.reportID); if (hasHeldExpenses && !full && !!expenseReport?.unheldTotal) { total = expenseReport?.unheldTotal; } - const optimisticApprovedReportAction = ReportUtils.buildOptimisticApprovedReportAction(total, expenseReport?.currency ?? '', expenseReport?.reportID ?? '-1'); + const optimisticApprovedReportAction = buildOptimisticApprovedReportAction(total, expenseReport?.currency ?? '', expenseReport?.reportID ?? '-1'); - const approvalChain = ReportUtils.getApprovalChain(PolicyUtils.getPolicy(expenseReport?.policyID), expenseReport); + const approvalChain = getApprovalChain(getPolicy(expenseReport?.policyID), expenseReport); const predictedNextStatus = isLastApprover(approvalChain) ? CONST.REPORT.STATUS_NUM.APPROVED : CONST.REPORT.STATUS_NUM.SUBMITTED; const predictedNextState = isLastApprover(approvalChain) ? CONST.REPORT.STATE_NUM.APPROVED : CONST.REPORT.STATE_NUM.SUBMITTED; const managerID = isLastApprover(approvalChain) ? expenseReport?.managerID : getNextApproverAccountID(expenseReport); - const optimisticNextStep = NextStepUtils.buildNextStep(expenseReport, predictedNextStatus); - const chatReport = ReportUtils.getReportOrDraftReport(expenseReport?.chatReportID); + const optimisticNextStep = buildNextStep(expenseReport, predictedNextStatus); + const chatReport = getReportOrDraftReport(expenseReport?.chatReportID); const optimisticReportActionsData: OnyxUpdate = { onyxMethod: Onyx.METHOD.MERGE, @@ -7018,8 +7059,8 @@ function approveMoneyRequest(expenseReport: OnyxEntry, full?: key: `${ONYXKEYS.COLLECTION.REPORT}${expenseReport?.reportID}`, value: { ...expenseReport, - lastMessageText: ReportActionsUtils.getReportActionText(optimisticApprovedReportAction), - lastMessageHtml: ReportActionsUtils.getReportActionHtml(optimisticApprovedReportAction), + lastMessageText: getReportActionText(optimisticApprovedReportAction), + lastMessageHtml: getReportActionHtml(optimisticApprovedReportAction), stateNum: predictedNextState, statusNum: predictedNextStatus, managerID, @@ -7094,7 +7135,7 @@ function approveMoneyRequest(expenseReport: OnyxEntry, full?: // Clear hold reason of all transactions if we approve all requests if (full && hasHeldExpenses) { - const heldTransactions = ReportUtils.getAllHeldTransactions(expenseReport?.reportID); + const heldTransactions = getAllHeldTransactionsReportUtils(expenseReport?.reportID); heldTransactions.forEach((heldTransaction) => { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, @@ -7149,8 +7190,8 @@ function unapproveExpenseReport(expenseReport: OnyxEntry) { const currentNextStep = allNextSteps[`${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`] ?? null; - const optimisticUnapprovedReportAction = ReportUtils.buildOptimisticUnapprovedReportAction(expenseReport.total ?? 0, expenseReport.currency ?? '', expenseReport.reportID); - const optimisticNextStep = NextStepUtils.buildNextStep(expenseReport, CONST.REPORT.STATUS_NUM.SUBMITTED); + const optimisticUnapprovedReportAction = buildOptimisticUnapprovedReportAction(expenseReport.total ?? 0, expenseReport.currency ?? '', expenseReport.reportID); + const optimisticNextStep = buildNextStep(expenseReport, CONST.REPORT.STATUS_NUM.SUBMITTED); const optimisticReportActionData: OnyxUpdate = { onyxMethod: Onyx.METHOD.MERGE, @@ -7167,8 +7208,8 @@ function unapproveExpenseReport(expenseReport: OnyxEntry) { key: `${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`, value: { ...expenseReport, - lastMessageText: ReportActionsUtils.getReportActionText(optimisticUnapprovedReportAction), - lastMessageHtml: ReportActionsUtils.getReportActionHtml(optimisticUnapprovedReportAction), + lastMessageText: getReportActionText(optimisticUnapprovedReportAction), + lastMessageHtml: getReportActionHtml(optimisticUnapprovedReportAction), stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, pendingFields: { @@ -7256,19 +7297,19 @@ function unapproveExpenseReport(expenseReport: OnyxEntry) { } function submitReport(expenseReport: OnyxTypes.Report) { - if (expenseReport.policyID && SubscriptionUtils.shouldRestrictUserBillableActions(expenseReport.policyID)) { + if (expenseReport.policyID && shouldRestrictUserBillableActions(expenseReport.policyID)) { Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(expenseReport.policyID)); return; } const currentNextStep = allNextSteps[`${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`] ?? null; - const parentReport = ReportUtils.getReportOrDraftReport(expenseReport.parentReportID); - const policy = PolicyUtils.getPolicy(expenseReport.policyID); + const parentReport = getReportOrDraftReport(expenseReport.parentReportID); + const policy = getPolicy(expenseReport.policyID); const isCurrentUserManager = currentUserPersonalDetails?.accountID === expenseReport.managerID; - const isSubmitAndClosePolicy = PolicyUtils.isSubmitAndClose(policy); + const isSubmitAndClosePolicy = isSubmitAndClose(policy); const adminAccountID = policy?.role === CONST.POLICY.ROLE.ADMIN ? currentUserPersonalDetails?.accountID : undefined; - const optimisticSubmittedReportAction = ReportUtils.buildOptimisticSubmittedReportAction(expenseReport?.total ?? 0, expenseReport.currency ?? '', expenseReport.reportID, adminAccountID); - const optimisticNextStep = NextStepUtils.buildNextStep(expenseReport, isSubmitAndClosePolicy ? CONST.REPORT.STATUS_NUM.CLOSED : CONST.REPORT.STATUS_NUM.SUBMITTED); + const optimisticSubmittedReportAction = buildOptimisticSubmittedReportAction(expenseReport?.total ?? 0, expenseReport.currency ?? '', expenseReport.reportID, adminAccountID); + const optimisticNextStep = buildNextStep(expenseReport, isSubmitAndClosePolicy ? CONST.REPORT.STATUS_NUM.CLOSED : CONST.REPORT.STATUS_NUM.SUBMITTED); const optimisticData: OnyxUpdate[] = !isSubmitAndClosePolicy ? [ @@ -7287,8 +7328,8 @@ function submitReport(expenseReport: OnyxTypes.Report) { key: `${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`, value: { ...expenseReport, - lastMessageText: ReportActionsUtils.getReportActionText(optimisticSubmittedReportAction), - lastMessageHtml: ReportActionsUtils.getReportActionHtml(optimisticSubmittedReportAction), + lastMessageText: getReportActionText(optimisticSubmittedReportAction), + lastMessageHtml: getReportActionHtml(optimisticSubmittedReportAction), stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, }, @@ -7378,7 +7419,7 @@ function submitReport(expenseReport: OnyxTypes.Report) { const parameters: SubmitReportParams = { reportID: expenseReport.reportID, - managerAccountID: PolicyUtils.getSubmitToAccountID(policy, expenseReport) ?? expenseReport.managerID, + managerAccountID: getSubmitToAccountID(policy, expenseReport) ?? expenseReport.managerID, reportActionID: optimisticSubmittedReportAction.reportActionID, }; @@ -7390,12 +7431,12 @@ function cancelPayment(expenseReport: OnyxEntry, chatReport: O return; } - const optimisticReportAction = ReportUtils.buildOptimisticCancelPaymentReportAction(expenseReport.reportID, -(expenseReport.total ?? 0), expenseReport.currency ?? ''); - const policy = PolicyUtils.getPolicy(chatReport.policyID); + const optimisticReportAction = buildOptimisticCancelPaymentReportAction(expenseReport.reportID, -(expenseReport.total ?? 0), expenseReport.currency ?? ''); + const policy = getPolicy(chatReport.policyID); const approvalMode = policy?.approvalMode ?? CONST.POLICY.APPROVAL_MODE.BASIC; const stateNum: ValueOf = approvalMode === CONST.POLICY.APPROVAL_MODE.OPTIONAL ? CONST.REPORT.STATE_NUM.SUBMITTED : CONST.REPORT.STATE_NUM.APPROVED; const statusNum: ValueOf = approvalMode === CONST.POLICY.APPROVAL_MODE.OPTIONAL ? CONST.REPORT.STATUS_NUM.CLOSED : CONST.REPORT.STATUS_NUM.APPROVED; - const optimisticNextStep = NextStepUtils.buildNextStep(expenseReport, statusNum); + const optimisticNextStep = buildNextStep(expenseReport, statusNum); const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, @@ -7412,8 +7453,8 @@ function cancelPayment(expenseReport: OnyxEntry, chatReport: O key: `${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`, value: { ...expenseReport, - lastMessageText: ReportActionsUtils.getReportActionText(optimisticReportAction), - lastMessageHtml: ReportActionsUtils.getReportActionHtml(optimisticReportAction), + lastMessageText: getReportActionText(optimisticReportAction), + lastMessageHtml: getReportActionHtml(optimisticReportAction), stateNum, statusNum, }, @@ -7494,7 +7535,7 @@ function cancelPayment(expenseReport: OnyxEntry, chatReport: O failureData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`, - value: NextStepUtils.buildNextStep(expenseReport, CONST.REPORT.STATUS_NUM.REIMBURSED), + value: buildNextStep(expenseReport, CONST.REPORT.STATUS_NUM.REIMBURSED), }); API.write( @@ -7521,9 +7562,9 @@ function completePaymentOnboarding(paymentSelected: ValueOf, full = true) { - if (chatReport.policyID && SubscriptionUtils.shouldRestrictUserBillableActions(chatReport.policyID)) { + if (chatReport.policyID && shouldRestrictUserBillableActions(chatReport.policyID)) { Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(chatReport.policyID)); return; } @@ -7734,14 +7775,14 @@ function replaceReceipt(transactionID: string, file: File, source: string) { */ function setMoneyRequestParticipantsFromReport(transactionID: string, report: OnyxEntry): Participant[] { // If the report is iou or expense report, we should get the chat report to set participant for request money - const chatReport = ReportUtils.isMoneyRequestReport(report) ? ReportUtils.getReportOrDraftReport(report?.chatReportID) : report; + const chatReport = isMoneyRequestReportReportUtils(report) ? getReportOrDraftReport(report?.chatReportID) : report; const currentUserAccountID = currentUserPersonalDetails?.accountID; - const shouldAddAsReport = !isEmptyObject(chatReport) && ReportUtils.isSelfDM(chatReport); + const shouldAddAsReport = !isEmptyObject(chatReport) && isSelfDM(chatReport); let participants: Participant[] = []; - if (ReportUtils.isPolicyExpenseChat(chatReport) || shouldAddAsReport) { - participants = [{accountID: 0, reportID: chatReport?.reportID, isPolicyExpenseChat: ReportUtils.isPolicyExpenseChat(chatReport), selected: true}]; - } else if (ReportUtils.isInvoiceRoom(chatReport)) { + if (isPolicyExpenseChatReportUtils(chatReport) || shouldAddAsReport) { + participants = [{accountID: 0, reportID: chatReport?.reportID, isPolicyExpenseChat: isPolicyExpenseChatReportUtils(chatReport), selected: true}]; + } else if (isInvoiceRoom(chatReport)) { participants = [ {reportID: chatReport?.reportID, selected: true}, { @@ -7815,7 +7856,7 @@ function setSplitShares(transaction: OnyxEntry, amount: n const isPayer = accountID === userAccountID; const participantsLength = newAccountIDs.includes(userAccountID) ? newAccountIDs.length - 1 : newAccountIDs.length; - const splitAmount = IOUUtils.calculateAmount(participantsLength, amount, currency, isPayer); + const splitAmount = calculateAmount(participantsLength, amount, currency, isPayer); acc[accountID] = { amount: splitAmount, isModified: false, @@ -7873,7 +7914,7 @@ function adjustRemainingSplitShares(transaction: NonNullable { - const splitAmount = IOUUtils.calculateAmount(unmodifiedSharesAccountIDs.length - 1, remainingTotal, transaction.currency, index === 0); + const splitAmount = calculateAmount(unmodifiedSharesAccountIDs.length - 1, remainingTotal, transaction.currency, index === 0); acc[accountID] = { amount: splitAmount, }; @@ -7888,12 +7929,12 @@ function adjustRemainingSplitShares(transaction: NonNullable, re function getIOUActionForTransactions(transactionIDList: string[], iouReportID: string): Array> { return Object.values(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReportID}`] ?? {})?.filter( (reportAction): reportAction is ReportAction => { - if (!ReportActionsUtils.isMoneyRequestAction(reportAction)) { + if (!isMoneyRequestAction(reportAction)) { return false; } - const message = ReportActionsUtils.getOriginalMessage(reportAction); + const message = getOriginalMessage(reportAction); if (!message?.IOUTransactionID) { return false; } @@ -8350,7 +8391,7 @@ function resolveDuplicates(params: TransactionMergeParams) { const iouActionList = getIOUActionForTransactions(params.transactionIDList, params.reportID); const transactionThreadReportIDList = iouActionList.map((action) => action?.childReportID); const orderedTransactionIDList = iouActionList.map((action) => { - const message = ReportActionsUtils.getOriginalMessage(action); + const message = getOriginalMessage(action); return message?.IOUTransactionID ?? ''; }); @@ -8360,7 +8401,7 @@ function resolveDuplicates(params: TransactionMergeParams) { const optimisticHoldTransactionActions: OnyxUpdate[] = []; const failureHoldTransactionActions: OnyxUpdate[] = []; transactionThreadReportIDList.forEach((transactionThreadReportID) => { - const createdReportAction = ReportUtils.buildOptimisticHoldReportAction(); + const createdReportAction = buildOptimisticHoldReportAction(); reportActionIDList.push(createdReportAction.reportActionID); const transactionID = getTransactionID(transactionThreadReportID ?? '-1'); optimisticHoldTransactionActions.push({ @@ -8400,7 +8441,7 @@ function resolveDuplicates(params: TransactionMergeParams) { }); const transactionThreadReportID = getIOUActionForTransactions([params.transactionID], params.reportID).at(0)?.childReportID; - const optimisticReportAction = ReportUtils.buildOptimisticDismissedViolationReportAction({ + const optimisticReportAction = buildOptimisticDismissedViolationReportAction({ reason: 'manual', violationName: CONST.VIOLATIONS.DUPLICATED_TRANSACTION, }); diff --git a/src/libs/actions/PriorityMode.ts b/src/libs/actions/PriorityMode.ts index 6d53cf809d0d..9a5fb2dfaab4 100644 --- a/src/libs/actions/PriorityMode.ts +++ b/src/libs/actions/PriorityMode.ts @@ -32,7 +32,7 @@ Onyx.connect({ * Debounce the prompt to promote focus mode as many reports updates could happen in a short burst */ // eslint-disable-next-line @typescript-eslint/no-use-before-define -const autoSwitchToFocusMode = debounce(tryFocusModeUpdate, 300, {leading: true}); +export const autoSwitchToFocusMode = debounce(tryFocusModeUpdate, 300, {leading: true}); let isLoadingReportData = true; Onyx.connect({ @@ -68,7 +68,7 @@ Onyx.connect({ }, }); -function resetHasReadRequiredDataFromStorage() { +export function resetHasReadRequiredDataFromStorage() { // Create a new promise and a new resolve function isReadyPromise = new Promise((resolve) => { resolveIsReadyPromise = resolve; @@ -127,5 +127,3 @@ function tryFocusModeUpdate() { Onyx.set(ONYXKEYS.FOCUS_MODE_NOTIFICATION, true); }); } - -export {resetHasReadRequiredDataFromStorage, autoSwitchToFocusMode}; diff --git a/src/libs/actions/Session/index.ts b/src/libs/actions/Session/index.ts index c126543c499b..d0865145d458 100644 --- a/src/libs/actions/Session/index.ts +++ b/src/libs/actions/Session/index.ts @@ -34,13 +34,12 @@ import * as MainQueue from '@libs/Network/MainQueue'; import * as NetworkStore from '@libs/Network/NetworkStore'; import NetworkConnection from '@libs/NetworkConnection'; import * as Pusher from '@libs/Pusher/pusher'; -import * as ReportUtils from '@libs/ReportUtils'; +import {getReportIDFromLink, parseReportRouteParams as parseReportRouteParamsReportUtils} from '@libs/ReportUtils'; import * as SessionUtils from '@libs/SessionUtils'; import {clearSoundAssetsCache} from '@libs/Sound'; import Timers from '@libs/Timers'; import {hideContextMenu} from '@pages/home/report/ContextMenu/ReportActionContextMenu'; -import {KEYS_TO_PRESERVE, openApp} from '@userActions/App'; -import * as App from '@userActions/App'; +import {KEYS_TO_PRESERVE, openApp, reconnectApp} from '@userActions/App'; import {KEYS_TO_PRESERVE_DELEGATE_ACCESS} from '@userActions/Delegate'; import * as Device from '@userActions/Device'; import * as PriorityMode from '@userActions/PriorityMode'; @@ -263,7 +262,7 @@ function signOutAndRedirectToSignIn(shouldResetToHome?: boolean, shouldStashSess } Navigation.navigate(ROUTES.SIGN_IN_MODAL); Linking.getInitialURL().then((url) => { - const reportID = ReportUtils.getReportIDFromLink(url); + const reportID = getReportIDFromLink(url); if (reportID) { Onyx.merge(ONYXKEYS.LAST_OPENED_PUBLIC_ROOM_ID, reportID); } @@ -539,10 +538,10 @@ function signInAfterTransitionFromOldDot(transitionURL: string) { ) .then(() => { if (clearOnyxOnStart === 'true') { - return App.openApp(); + return openApp(); } return getLastUpdateIDAppliedToClient().then((lastUpdateId) => { - return App.reconnectApp(lastUpdateId); + return reconnectApp(lastUpdateId); }); }) .catch((error) => { @@ -1134,11 +1133,11 @@ function signInWithValidateCodeAndNavigate(accountID: number, validateCode: stri */ const canAnonymousUserAccessRoute = (route: string) => { - const reportID = ReportUtils.getReportIDFromLink(route); + const reportID = getReportIDFromLink(route); if (reportID) { return true; } - const parsedReportRouteParams = ReportUtils.parseReportRouteParams(route); + const parsedReportRouteParams = parseReportRouteParamsReportUtils(route); let routeRemovedReportId = route; if ((parsedReportRouteParams as {reportID: string})?.reportID) { routeRemovedReportId = route.replace((parsedReportRouteParams as {reportID: string})?.reportID, ':reportID'); diff --git a/src/libs/actions/SignInRedirect.ts b/src/libs/actions/SignInRedirect.ts index 4d8b60265f29..2e5d1dd649c3 100644 --- a/src/libs/actions/SignInRedirect.ts +++ b/src/libs/actions/SignInRedirect.ts @@ -1,8 +1,8 @@ import Onyx from 'react-native-onyx'; -import * as ErrorUtils from '@libs/ErrorUtils'; +import {getMicroSecondOnyxErrorWithMessage} from '@libs/ErrorUtils'; import type {OnyxKey} from '@src/ONYXKEYS'; import ONYXKEYS from '@src/ONYXKEYS'; -import * as Policy from './Policy/Policy'; +import {clearAllPolicies} from './Policy/Policy'; let currentIsOffline: boolean | undefined; let currentShouldForceOffline: boolean | undefined; @@ -30,13 +30,13 @@ function clearStorageAndRedirect(errorMessage?: string): Promise { } return Onyx.clear(keysToPreserve).then(() => { - Policy.clearAllPolicies(); + clearAllPolicies(); if (!errorMessage) { return; } // `Onyx.clear` reinitializes the Onyx instance with initial values so use `Onyx.merge` instead of `Onyx.set` - Onyx.merge(ONYXKEYS.SESSION, {errors: ErrorUtils.getMicroSecondOnyxErrorWithMessage(errorMessage)}); + Onyx.merge(ONYXKEYS.SESSION, {errors: getMicroSecondOnyxErrorWithMessage(errorMessage)}); }); } From 4d0d4771d630bf1e28bc34cbe96a0f56d3bc7345 Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Mon, 2 Dec 2024 10:20:35 +0100 Subject: [PATCH 07/29] fix imports in OnyxUpdateManager --- metro.config.js | 1 - src/libs/actions/OnyxUpdateManager/index.ts | 32 ++++++++++----------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/metro.config.js b/metro.config.js index 3aaed6164d50..2405af23445b 100644 --- a/metro.config.js +++ b/metro.config.js @@ -27,7 +27,6 @@ const config = { transformer: { getTransformOptions: async () => ({ transform: { - experimentalImportSupport: false, inlineRequires: true, }, }), diff --git a/src/libs/actions/OnyxUpdateManager/index.ts b/src/libs/actions/OnyxUpdateManager/index.ts index 085e05b0a449..302110e3e6bf 100644 --- a/src/libs/actions/OnyxUpdateManager/index.ts +++ b/src/libs/actions/OnyxUpdateManager/index.ts @@ -2,15 +2,15 @@ import type {OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import * as ActiveClientManager from '@libs/ActiveClientManager'; import Log from '@libs/Log'; -import * as NetworkStore from '@libs/Network/NetworkStore'; -import * as SequentialQueue from '@libs/Network/SequentialQueue'; -import * as App from '@userActions/App'; +import {setAuthToken} from '@libs/Network/NetworkStore'; +import {unpause} from '@libs/Network/SequentialQueue'; +import {finalReconnectAppAfterActivatingReliableUpdates, getMissingOnyxUpdates} from '@userActions/App'; import updateSessionAuthTokens from '@userActions/Session/updateSessionAuthTokens'; import ONYXKEYS from '@src/ONYXKEYS'; import type {OnyxUpdatesFromServer, Session} from '@src/types/onyx'; import {isValidOnyxUpdateFromServer} from '@src/types/onyx/OnyxUpdatesFromServer'; -import * as OnyxUpdateManagerUtils from './utils'; -import * as DeferredOnyxUpdates from './utils/DeferredOnyxUpdates'; +import {validateAndApplyDeferredUpdates} from './utils'; +import {clear, enqueue, getMissingOnyxUpdatesQueryPromise, isEmpty, setMissingOnyxUpdatesQueryPromise} from './utils/DeferredOnyxUpdates'; // This file is in charge of looking at the updateIDs coming from the server and comparing them to the last updateID that the client has. // If the client is behind the server, then we need to @@ -50,7 +50,7 @@ const createQueryPromiseWrapper = () => let queryPromiseWrapper = createQueryPromiseWrapper(); const resetDeferralLogicVariables = () => { - DeferredOnyxUpdates.clear({shouldUnpauseSequentialQueue: false}); + clear({shouldUnpauseSequentialQueue: false}); }; // This function will reset the query variables, unpause the SequentialQueue and log an info to the user. @@ -60,7 +60,7 @@ function finalizeUpdatesAndResumeQueue() { resolveQueryPromiseWrapper(); queryPromiseWrapper = createQueryPromiseWrapper(); - DeferredOnyxUpdates.clear(); + clear(); } /** @@ -76,7 +76,7 @@ function handleOnyxUpdateGap(onyxUpdatesFromServer: OnyxEntry OnyxUpdateManagerUtils.validateAndApplyDeferredUpdates(clientLastUpdateID)), - ); + setMissingOnyxUpdatesQueryPromise(getMissingOnyxUpdates(lastUpdateIDFromClient, previousUpdateIDFromServer).then(() => validateAndApplyDeferredUpdates(clientLastUpdateID))); } - DeferredOnyxUpdates.getMissingOnyxUpdatesQueryPromise()?.finally(finalizeUpdatesAndResumeQueue); + getMissingOnyxUpdatesQueryPromise()?.finally(finalizeUpdatesAndResumeQueue); } function updateAuthTokenIfNecessary(onyxUpdatesFromServer: OnyxEntry): void { @@ -169,7 +167,7 @@ function updateAuthTokenIfNecessary(onyxUpdatesFromServer: OnyxEntry Date: Mon, 2 Dec 2024 12:54:17 +0100 Subject: [PATCH 08/29] fixing rest of dependecy cycles --- .../Search/ExpenseItemHeaderNarrow.tsx | 4 +- .../SelectionList/Search/UserInfoCell.tsx | 4 +- src/libs/SearchUIUtils.ts | 37 +++++++++---------- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/components/SelectionList/Search/ExpenseItemHeaderNarrow.tsx b/src/components/SelectionList/Search/ExpenseItemHeaderNarrow.tsx index 384262a78b15..d59d85c04957 100644 --- a/src/components/SelectionList/Search/ExpenseItemHeaderNarrow.tsx +++ b/src/components/SelectionList/Search/ExpenseItemHeaderNarrow.tsx @@ -7,7 +7,7 @@ import {PressableWithFeedback} from '@components/Pressable'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as SearchUIUtils from '@libs/SearchUIUtils'; +import {isCorrectSearchUserName} from '@libs/SearchUIUtils'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import type {SearchPersonalDetails, SearchTransactionAction} from '@src/types/onyx/SearchResults'; @@ -52,7 +52,7 @@ function ExpenseItemHeaderNarrow({ const theme = useTheme(); // It might happen that we are missing display names for `From` or `To`, we only display arrow icon if both names exist - const shouldDisplayArrowIcon = SearchUIUtils.isCorrectSearchUserName(participantFromDisplayName) && SearchUIUtils.isCorrectSearchUserName(participantToDisplayName); + const shouldDisplayArrowIcon = isCorrectSearchUserName(participantFromDisplayName) && isCorrectSearchUserName(participantToDisplayName); return ( diff --git a/src/components/SelectionList/Search/UserInfoCell.tsx b/src/components/SelectionList/Search/UserInfoCell.tsx index 4e71b97028bb..6a2fda42d247 100644 --- a/src/components/SelectionList/Search/UserInfoCell.tsx +++ b/src/components/SelectionList/Search/UserInfoCell.tsx @@ -4,7 +4,7 @@ import Avatar from '@components/Avatar'; import Text from '@components/Text'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as SearchUIUtils from '@libs/SearchUIUtils'; +import {isCorrectSearchUserName} from '@libs/SearchUIUtils'; import CONST from '@src/CONST'; import type {SearchPersonalDetails} from '@src/types/onyx/SearchResults'; @@ -18,7 +18,7 @@ function UserInfoCell({participant, displayName}: UserInfoCellProps) { const {isLargeScreenWidth} = useResponsiveLayout(); const avatarURL = participant?.avatar; - if (!SearchUIUtils.isCorrectSearchUserName(displayName)) { + if (!isCorrectSearchUserName(displayName)) { return null; } diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index e100fb885fff..080568dcbca3 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -12,14 +12,14 @@ import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type SearchResults from '@src/types/onyx/SearchResults'; import type {ListItemDataType, ListItemType, SearchDataTypes, SearchPersonalDetails, SearchReport, SearchTransaction, SearchTransactionAction} from '@src/types/onyx/SearchResults'; -import * as IOU from './actions/IOU'; -import * as CurrencyUtils from './CurrencyUtils'; +import {canApproveIOU, canIOUBePaid} from './actions/IOU'; +import {convertToDisplayString} from './CurrencyUtils'; import DateUtils from './DateUtils'; import {translateLocal} from './Localize'; import Navigation from './Navigation/Navigation'; -import * as ReportActionsUtils from './ReportActionsUtils'; -import * as ReportUtils from './ReportUtils'; -import * as TransactionUtils from './TransactionUtils'; +import {isDeletedAction} from './ReportActionsUtils'; +import {hasOnlyHeldExpenses, isAllowedToApproveExpenseReport, isClosedReport, isInvoiceReport, isMoneyRequestReport, isSettled} from './ReportUtils'; +import {getAmount, getCreated, getMerchant} from './TransactionUtils'; const columnNamesToSortingProperty = { [CONST.SEARCH.TABLE_COLUMNS.TO]: 'formattedTo' as const, @@ -63,9 +63,9 @@ function getTransactionItemCommonFormattedProperties( const formattedFrom = from?.displayName ?? from?.login ?? ''; const formattedTo = to?.displayName ?? to?.login ?? ''; - const formattedTotal = TransactionUtils.getAmount(transactionItem, isExpenseReport); + const formattedTotal = getAmount(transactionItem, isExpenseReport); const date = transactionItem?.modifiedCreated ? transactionItem.modifiedCreated : transactionItem?.created; - const merchant = TransactionUtils.getMerchant(transactionItem); + const merchant = getMerchant(transactionItem); const formattedMerchant = merchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT || merchant === CONST.TRANSACTION.DEFAULT_MERCHANT ? '' : merchant; return { @@ -146,7 +146,7 @@ function shouldShowYear(data: TransactionListItemType[] | ReportListItemType[] | if (isReportListItemType(item)) { // If the item is a ReportListItemType, iterate over its transactions and check them return item.transactions.some((transaction) => { - const transactionYear = new Date(TransactionUtils.getCreated(transaction)).getFullYear(); + const transactionYear = new Date(getCreated(transaction)).getFullYear(); return transactionYear !== currentYear; }); } @@ -159,7 +159,7 @@ function shouldShowYear(data: TransactionListItemType[] | ReportListItemType[] | for (const key in data) { if (isTransactionEntry(key)) { const item = data[key]; - const date = TransactionUtils.getCreated(item); + const date = getCreated(item); if (DateUtils.doesDateBelongToAPastYear(date)) { return true; @@ -185,7 +185,7 @@ function shouldShowYear(data: TransactionListItemType[] | ReportListItemType[] | function getIOUReportName(data: OnyxTypes.SearchResults['data'], reportItem: SearchReport) { const payerPersonalDetails = reportItem.managerID ? data.personalDetailsList?.[reportItem.managerID] : emptyPersonalDetails; const payerName = payerPersonalDetails?.displayName ?? payerPersonalDetails?.login ?? translateLocal('common.hidden'); - const formattedAmount = CurrencyUtils.convertToDisplayString(reportItem.total ?? 0, reportItem.currency ?? CONST.CURRENCY.USD); + const formattedAmount = convertToDisplayString(reportItem.total ?? 0, reportItem.currency ?? CONST.CURRENCY.USD); if (reportItem.action === CONST.SEARCH.ACTION_TYPES.VIEW) { return translateLocal('iou.payerOwesAmount', { payer: payerName, @@ -257,23 +257,23 @@ function getAction(data: OnyxTypes.SearchResults['data'], key: string): SearchTr const transaction = isTransaction ? data[key] : undefined; const report = isTransaction ? data[`${ONYXKEYS.COLLECTION.REPORT}${transaction?.reportID}`] : data[key]; - if (ReportUtils.isSettled(report)) { + if (isSettled(report)) { return CONST.SEARCH.ACTION_TYPES.PAID; } - if (ReportUtils.isClosedReport(report)) { + if (isClosedReport(report)) { return CONST.SEARCH.ACTION_TYPES.DONE; } // We don't need to run the logic if this is not a transaction or iou/expense report, so let's shortcircuit the logic for performance reasons - if (!ReportUtils.isMoneyRequestReport(report) || (isTransaction && !data[key].isFromOneTransactionReport)) { + if (!isMoneyRequestReport(report) || (isTransaction && !data[key].isFromOneTransactionReport)) { return CONST.SEARCH.ACTION_TYPES.VIEW; } const policy = data[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`] ?? {}; const invoiceReceiverPolicy = - ReportUtils.isInvoiceReport(report) && report?.invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.BUSINESS + isInvoiceReport(report) && report?.invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.BUSINESS ? data[`${ONYXKEYS.COLLECTION.POLICY}${report?.invoiceReceiver?.policyID}`] : undefined; @@ -288,14 +288,11 @@ function getAction(data: OnyxTypes.SearchResults['data'], key: string): SearchTr const chatReport = data[`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`] ?? {}; const chatReportRNVP = data[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report?.chatReportID}`] ?? undefined; - if ( - IOU.canIOUBePaid(report, chatReport, policy, allReportTransactions, false, chatReportRNVP, invoiceReceiverPolicy) && - !ReportUtils.hasOnlyHeldExpenses(report.reportID, allReportTransactions) - ) { + if (canIOUBePaid(report, chatReport, policy, allReportTransactions, false, chatReportRNVP, invoiceReceiverPolicy) && !hasOnlyHeldExpenses(report.reportID, allReportTransactions)) { return CONST.SEARCH.ACTION_TYPES.PAY; } - if (IOU.canApproveIOU(report, policy) && ReportUtils.isAllowedToApproveExpenseReport(report, undefined, policy)) { + if (canApproveIOU(report, policy) && isAllowedToApproveExpenseReport(report, undefined, policy)) { return CONST.SEARCH.ACTION_TYPES.APPROVE; } @@ -315,7 +312,7 @@ function getReportActionsSections(data: OnyxTypes.SearchResults['data']): Report const reportActions = data[key]; for (const reportAction of Object.values(reportActions)) { const from = data.personalDetailsList?.[reportAction.accountID]; - if (ReportActionsUtils.isDeletedAction(reportAction)) { + if (isDeletedAction(reportAction)) { // eslint-disable-next-line no-continue continue; } From f1c0869573ae855fefcdbb59a40e633d58304806 Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Fri, 6 Dec 2024 13:55:17 +0100 Subject: [PATCH 09/29] fix: import in Report.ts --- src/libs/actions/Report.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 24dcef4e78b6..04591a6510d7 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -99,6 +99,7 @@ import { completeShortMention, doesReportBelongToWorkspace, findLastAccessedReport, + findSelfDMReportID, formatReportLastMessageText, getChatByParticipants, getChildReportNotificationPreference, @@ -3914,8 +3915,8 @@ function prepareOnboardingOptimisticData( } if (engagementChoice === CONST.ONBOARDING_CHOICES.MANAGE_TEAM) { - const selfDMReportID = ReportUtils.findSelfDMReportID(); - const selfDMReport = ReportConnection.getReport(selfDMReportID ?? '-1'); + const selfDMReportID = findSelfDMReportID(); + const selfDMReport = getReport(selfDMReportID ?? '-1'); optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${selfDMReportID}`, From 31847ee4652fc9a930aad10952d8809c8b0eb974 Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Tue, 10 Dec 2024 10:32:19 +0100 Subject: [PATCH 10/29] fix: two cyclic dependecies --- .../createResponsiveStackNavigator/CustomRouter.ts | 2 +- .../syncBrowserHistory/index.web.ts | 2 +- .../Navigation/AppNavigator/getActionsFromPartialDiff.ts | 2 +- src/libs/Navigation/Navigation.ts | 4 ++-- src/libs/Navigation/NavigationRoot.tsx | 2 +- src/libs/Navigation/dismissModalWithReport.ts | 5 +++-- src/libs/Navigation/getStateFromPath.ts | 2 +- src/libs/Navigation/linkTo/index.ts | 2 +- src/libs/Navigation/linkingConfig/config.ts | 3 +-- .../Navigation/linkingConfig/getAdaptedStateFromPath.ts | 2 +- src/libs/Navigation/linkingConfig/index.ts | 7 ++++--- .../Navigation/linkingConfig/subscribe/index.native.ts | 5 +++-- src/libs/Navigation/linkingConfig/subscribe/index.ts | 3 ++- src/libs/Navigation/switchPolicyID.ts | 2 +- src/libs/ReportUtils.ts | 2 +- src/libs/actions/Welcome/OnboardingFlow.ts | 2 +- 16 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts index 842ad5c86854..3cbb5acb81e5 100644 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts @@ -5,7 +5,7 @@ import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import * as Localize from '@libs/Localize'; import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute'; import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute'; -import linkingConfig from '@libs/Navigation/linkingConfig'; +import {linkingConfig} from '@libs/Navigation/linkingConfig'; import getAdaptedStateFromPath from '@libs/Navigation/linkingConfig/getAdaptedStateFromPath'; import type {PlatformStackRouterOptions} from '@libs/Navigation/PlatformStackNavigation/types'; import type {NavigationPartialRoute, RootStackParamList, State} from '@libs/Navigation/types'; diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/syncBrowserHistory/index.web.ts b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/syncBrowserHistory/index.web.ts index e85ffded64c1..77431c8ca14b 100644 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/syncBrowserHistory/index.web.ts +++ b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/syncBrowserHistory/index.web.ts @@ -1,6 +1,6 @@ import type {ParamListBase, StackNavigationState} from '@react-navigation/native'; import {getPathFromState} from '@react-navigation/native'; -import linkingConfig from '@libs/Navigation/linkingConfig'; +import {linkingConfig} from '@libs/Navigation/linkingConfig'; function syncBrowserHistory(state: StackNavigationState) { // We reset the URL as the browser sets it in a way that doesn't match the navigation state diff --git a/src/libs/Navigation/AppNavigator/getActionsFromPartialDiff.ts b/src/libs/Navigation/AppNavigator/getActionsFromPartialDiff.ts index 9685f4fc0339..86998ef4e308 100644 --- a/src/libs/Navigation/AppNavigator/getActionsFromPartialDiff.ts +++ b/src/libs/Navigation/AppNavigator/getActionsFromPartialDiff.ts @@ -1,6 +1,6 @@ import {getActionFromState, StackActions} from '@react-navigation/native'; import type {NavigationAction} from '@react-navigation/native'; -import linkingConfig from '@libs/Navigation/linkingConfig'; +import {linkingConfig} from '@libs/Navigation/linkingConfig'; import NAVIGATORS from '@src/NAVIGATORS'; import type {GetPartialStateDiffReturnType} from './getPartialStateDiff'; diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index b5819bd5ba5a..adbf76a89063 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -16,13 +16,13 @@ import type {Screen} from '@src/SCREENS'; import type {Report} from '@src/types/onyx'; import originalCloseRHPFlow from './closeRHPFlow'; import originalDismissModal from './dismissModal'; -import originalDismissModalWithReport from './dismissModalWithReport'; +import {dismissModalWithReport as originalDismissModalWithReport} from './dismissModalWithReport'; import getTopmostBottomTabRoute from './getTopmostBottomTabRoute'; import getTopmostCentralPaneRoute from './getTopmostCentralPaneRoute'; import originalGetTopmostReportActionId from './getTopmostReportActionID'; import originalGetTopmostReportId from './getTopmostReportId'; import isReportOpenInRHP from './isReportOpenInRHP'; -import linkingConfig from './linkingConfig'; +import {linkingConfig} from './linkingConfig'; import getMatchingBottomTabRouteForState from './linkingConfig/getMatchingBottomTabRouteForState'; import linkTo from './linkTo'; import navigationRef from './navigationRef'; diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index cff9fd49fb7a..53e3e727fabc 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -23,7 +23,7 @@ import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import AppNavigator from './AppNavigator'; import getPolicyIDFromState from './getPolicyIDFromState'; -import linkingConfig from './linkingConfig'; +import {linkingConfig} from './linkingConfig'; import customGetPathFromState from './linkingConfig/customGetPathFromState'; import getAdaptedStateFromPath from './linkingConfig/getAdaptedStateFromPath'; import Navigation, {navigationRef} from './Navigation'; diff --git a/src/libs/Navigation/dismissModalWithReport.ts b/src/libs/Navigation/dismissModalWithReport.ts index 854b2e586caf..b7cf2881f870 100644 --- a/src/libs/Navigation/dismissModalWithReport.ts +++ b/src/libs/Navigation/dismissModalWithReport.ts @@ -15,7 +15,7 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject'; import getPolicyIDFromState from './getPolicyIDFromState'; import getStateFromPath from './getStateFromPath'; import getTopmostReportId from './getTopmostReportId'; -import linkingConfig from './linkingConfig'; +import {linkingConfig} from './linkingConfig'; import switchPolicyID from './switchPolicyID'; import type {RootStackParamList, StackNavigationAction, State} from './types'; @@ -77,4 +77,5 @@ function dismissModalWithReport(targetReport: OnyxEntry, navigationRef: } } -export default dismissModalWithReport; +// eslint-disable-next-line import/prefer-default-export +export {dismissModalWithReport}; diff --git a/src/libs/Navigation/getStateFromPath.ts b/src/libs/Navigation/getStateFromPath.ts index 50254bb3898d..58ec111575e8 100644 --- a/src/libs/Navigation/getStateFromPath.ts +++ b/src/libs/Navigation/getStateFromPath.ts @@ -1,7 +1,7 @@ import type {NavigationState, PartialState} from '@react-navigation/native'; import {getStateFromPath as RNGetStateFromPath} from '@react-navigation/native'; import type {Route} from '@src/ROUTES'; -import linkingConfig from './linkingConfig'; +import {linkingConfig} from './linkingConfig'; /** * @param path - The path to parse diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/linkTo/index.ts index 3ca41846d2b4..ebaf528e2460 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/linkTo/index.ts @@ -18,7 +18,7 @@ import getTopmostBottomTabRoute from '@navigation/getTopmostBottomTabRoute'; import getTopmostCentralPaneRoute from '@navigation/getTopmostCentralPaneRoute'; import getTopmostReportId from '@navigation/getTopmostReportId'; import isSideModalNavigator from '@navigation/isSideModalNavigator'; -import linkingConfig from '@navigation/linkingConfig'; +import {linkingConfig} from '@navigation/linkingConfig'; import getAdaptedStateFromPath from '@navigation/linkingConfig/getAdaptedStateFromPath'; import getMatchingBottomTabRouteForState from '@navigation/linkingConfig/getMatchingBottomTabRouteForState'; import getMatchingCentralPaneRouteForState from '@navigation/linkingConfig/getMatchingCentralPaneRouteForState'; diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index c9dd7f17ad86..a16a013e26e1 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -1552,5 +1552,4 @@ const normalizedConfigs = Object.keys(config.screens) return acc; }, {} as Record); -export {normalizedConfigs}; -export default config; +export {normalizedConfigs, config}; diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index b0fba017b367..c73635495c6a 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -16,7 +16,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {Screen} from '@src/SCREENS'; import SCREENS from '@src/SCREENS'; import CENTRAL_PANE_TO_RHP_MAPPING from './CENTRAL_PANE_TO_RHP_MAPPING'; -import config, {normalizedConfigs} from './config'; +import {config, normalizedConfigs} from './config'; import FULL_SCREEN_TO_RHP_MAPPING from './FULL_SCREEN_TO_RHP_MAPPING'; import getMatchingBottomTabRouteForState from './getMatchingBottomTabRouteForState'; import getMatchingCentralPaneRouteForState from './getMatchingCentralPaneRouteForState'; diff --git a/src/libs/Navigation/linkingConfig/index.ts b/src/libs/Navigation/linkingConfig/index.ts index 1f556aa67809..f733e3a32d68 100644 --- a/src/libs/Navigation/linkingConfig/index.ts +++ b/src/libs/Navigation/linkingConfig/index.ts @@ -1,11 +1,11 @@ /* eslint-disable @typescript-eslint/naming-convention */ import type {LinkingOptions} from '@react-navigation/native'; import type {RootStackParamList} from '@navigation/types'; -import config from './config'; +import {config} from './config'; import customGetPathFromState from './customGetPathFromState'; import getAdaptedStateFromPath from './getAdaptedStateFromPath'; import prefixes from './prefixes'; -import subscribe from './subscribe'; +import {subscribe} from './subscribe'; const linkingConfig: LinkingOptions = { getStateFromPath: (...args) => { @@ -20,4 +20,5 @@ const linkingConfig: LinkingOptions = { config, }; -export default linkingConfig; +// eslint-disable-next-line import/prefer-default-export +export {linkingConfig}; diff --git a/src/libs/Navigation/linkingConfig/subscribe/index.native.ts b/src/libs/Navigation/linkingConfig/subscribe/index.native.ts index 46720e9884e9..8f14032e7e33 100644 --- a/src/libs/Navigation/linkingConfig/subscribe/index.native.ts +++ b/src/libs/Navigation/linkingConfig/subscribe/index.native.ts @@ -4,7 +4,7 @@ import {findFocusedRoute, getStateFromPath} from '@react-navigation/native'; import extractPathFromURL from '@react-navigation/native/src/extractPathFromURL'; import {Linking} from 'react-native'; import Navigation from '@libs/Navigation/Navigation'; -import config from '@navigation/linkingConfig/config'; +import {config} from '@navigation/linkingConfig/config'; import prefixes from '@navigation/linkingConfig/prefixes'; import type {RootStackParamList} from '@navigation/types'; import type {Route} from '@src/ROUTES'; @@ -37,4 +37,5 @@ const subscribe: LinkingOptions['subscribe'] = (listener) => }; }; -export default subscribe; +// eslint-disable-next-line import/prefer-default-export +export {subscribe}; diff --git a/src/libs/Navigation/linkingConfig/subscribe/index.ts b/src/libs/Navigation/linkingConfig/subscribe/index.ts index 74ef4133cb55..7ccbb5252a2c 100644 --- a/src/libs/Navigation/linkingConfig/subscribe/index.ts +++ b/src/libs/Navigation/linkingConfig/subscribe/index.ts @@ -4,4 +4,5 @@ import type {RootStackParamList} from '@libs/Navigation/types'; // This field in linkingConfig is supported on native only. const subscribe: LinkingOptions['subscribe'] = undefined; -export default subscribe; +// eslint-disable-next-line import/prefer-default-export +export {subscribe}; diff --git a/src/libs/Navigation/switchPolicyID.ts b/src/libs/Navigation/switchPolicyID.ts index 144a56c7e522..420dbe5aba51 100644 --- a/src/libs/Navigation/switchPolicyID.ts +++ b/src/libs/Navigation/switchPolicyID.ts @@ -11,7 +11,7 @@ import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; import getStateFromPath from './getStateFromPath'; import getTopmostCentralPaneRoute from './getTopmostCentralPaneRoute'; -import linkingConfig from './linkingConfig'; +import {linkingConfig} from './linkingConfig'; import type {NavigationRoot, RootStackParamList, StackNavigationAction, State, SwitchPolicyIDParams} from './types'; type ActionPayloadParams = { diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 3427d9a776a4..a26ca0e08228 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -74,7 +74,7 @@ import * as Localize from './Localize'; import Log from './Log'; import {isEmailPublicDomain} from './LoginUtils'; import ModifiedExpenseMessage from './ModifiedExpenseMessage'; -import linkingConfig from './Navigation/linkingConfig'; +import {linkingConfig} from './Navigation/linkingConfig'; import Navigation from './Navigation/Navigation'; import {rand64} from './NumberUtils'; import Parser from './Parser'; diff --git a/src/libs/actions/Welcome/OnboardingFlow.ts b/src/libs/actions/Welcome/OnboardingFlow.ts index 5a1b4fc0474a..4e88b0f3b980 100644 --- a/src/libs/actions/Welcome/OnboardingFlow.ts +++ b/src/libs/actions/Welcome/OnboardingFlow.ts @@ -1,7 +1,7 @@ import {findFocusedRoute, getStateFromPath} from '@react-navigation/native'; import type {NavigationState, PartialState} from '@react-navigation/native'; import Onyx from 'react-native-onyx'; -import linkingConfig from '@libs/Navigation/linkingConfig'; +import {linkingConfig} from '@libs/Navigation/linkingConfig'; import getAdaptedStateFromPath from '@libs/Navigation/linkingConfig/getAdaptedStateFromPath'; import {navigationRef} from '@libs/Navigation/Navigation'; import type {RootStackParamList} from '@libs/Navigation/types'; From 47116155588053b844f171d1bfdfb18593813edd Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Wed, 11 Dec 2024 10:00:45 +0100 Subject: [PATCH 11/29] fix: tests --- src/libs/Network/SequentialQueue.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/Network/SequentialQueue.ts b/src/libs/Network/SequentialQueue.ts index 54094c4285aa..09d545d955e3 100644 --- a/src/libs/Network/SequentialQueue.ts +++ b/src/libs/Network/SequentialQueue.ts @@ -1,5 +1,5 @@ import Onyx from 'react-native-onyx'; -import {clear, deleteRequestsByIndices, endRequestAndRemoveFromQueue, getAll, processNextRequest, rollbackOngoingRequest, save, update} from '@libs/actions/PersistedRequests'; +import {deleteRequestsByIndices, endRequestAndRemoveFromQueue, getAll, processNextRequest, rollbackOngoingRequest, save, update} from '@libs/actions/PersistedRequests'; import {flushQueue, isEmpty} from '@libs/actions/QueuedOnyxUpdates'; import {isClientTheLeader} from '@libs/ActiveClientManager'; import Log from '@libs/Log'; @@ -100,7 +100,7 @@ function process(): Promise { Log.info('[SequentialQueue] Removing persisted request because it was processed successfully.', false, {request: requestToProcess}); endRequestAndRemoveFromQueue(requestToProcess); - clear(); + sequentialQueueRequestThrottle.clear(); return process(); }) .catch((error: RequestError) => { @@ -109,7 +109,7 @@ function process(): Promise { if (error.name === CONST.ERROR.REQUEST_CANCELLED || error.message === CONST.ERROR.DUPLICATE_RECORD) { Log.info("[SequentialQueue] Removing persisted request because it failed and doesn't need to be retried.", false, {error, request: requestToProcess}); endRequestAndRemoveFromQueue(requestToProcess); - clear(); + sequentialQueueRequestThrottle.clear(); return process(); } rollbackOngoingRequest(); @@ -120,7 +120,7 @@ function process(): Promise { Onyx.update(requestToProcess.failureData ?? []); Log.info('[SequentialQueue] Removing persisted request because it failed too many times.', false, {error, request: requestToProcess}); endRequestAndRemoveFromQueue(requestToProcess); - clear(); + sequentialQueueRequestThrottle.clear(); return process(); }); }); From fd30e2a7cd3eb345c5525ea2bb1a96d3c1f6d22d Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Thu, 12 Dec 2024 09:43:33 +0100 Subject: [PATCH 12/29] fix: resolve comments --- metro.config.js | 2 + package-lock.json | 8 ++-- package.json | 2 +- src/libs/API/index.ts | 12 +++--- src/libs/Middleware/Reauthentication.ts | 8 ++-- src/libs/Network/MainQueue.ts | 4 +- src/libs/Network/SequentialQueue.ts | 44 ++++++++++++--------- src/libs/Network/index.ts | 12 +++--- src/libs/ReportUtils.ts | 36 ++++++++--------- src/libs/SearchQueryUtils.ts | 4 +- src/libs/actions/IOU.ts | 24 +++++------ src/libs/actions/OnyxUpdateManager/index.ts | 20 ++++++---- src/types/onyx/SearchResults.ts | 1 - 13 files changed, 96 insertions(+), 81 deletions(-) diff --git a/metro.config.js b/metro.config.js index 2405af23445b..510142427d58 100644 --- a/metro.config.js +++ b/metro.config.js @@ -24,6 +24,8 @@ const config = { // When we run the e2e tests we want files that have the extension e2e.js to be resolved as source files sourceExts: [...(isE2ETesting ? e2eSourceExts : []), ...defaultSourceExts, 'jsx'], }, + // We are merging the default config from Expo and React Native and expo one is overriding the React Native one so inlineRequires is set to false so we want to set it to true + // for fix cycling dependencies and improve performance of app startup transformer: { getTransformOptions: async () => ({ transform: { diff --git a/package-lock.json b/package-lock.json index 3c09c86b7c60..385f1903f8ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "dependencies": { "@dotlottie/react-player": "^1.6.3", "@expensify/react-native-live-markdown": "0.1.187", - "@expo/metro-runtime": "4.0.0", + "@expo/metro-runtime": "~3.2.3", "@firebase/app": "^0.10.10", "@firebase/performance": "^0.6.8", "@formatjs/intl-datetimeformat": "^6.12.5", @@ -4729,9 +4729,9 @@ } }, "node_modules/@expo/metro-runtime": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@expo/metro-runtime/-/metro-runtime-4.0.0.tgz", - "integrity": "sha512-+zgCyuXqIzgZVN8h0g36sursGXBy3xqtJW9han7t/iR2HTTrrbEoep5ftW1a27bdSINU96ng+rSsPLbyHYeBvw==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@expo/metro-runtime/-/metro-runtime-3.2.3.tgz", + "integrity": "sha512-v5ji+fAGi7B9YavrxvekuF8gXEV/5fz0+PhaED5AaFDnbGB4IJIbpaiqK9nqZV1axjGZNQSw6Q8TsnFetCR3bQ==", "license": "MIT", "peerDependencies": { "react-native": "*" diff --git a/package.json b/package.json index b9c31bf86670..3c6ca5e63a43 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "dependencies": { "@dotlottie/react-player": "^1.6.3", "@expensify/react-native-live-markdown": "0.1.187", - "@expo/metro-runtime": "4.0.0", + "@expo/metro-runtime": "~3.2.3", "@firebase/app": "^0.10.10", "@firebase/performance": "^0.6.8", "@formatjs/intl-datetimeformat": "^6.12.5", diff --git a/src/libs/API/index.ts b/src/libs/API/index.ts index 458a2feffee3..73e84b03aab6 100644 --- a/src/libs/API/index.ts +++ b/src/libs/API/index.ts @@ -3,10 +3,10 @@ import Onyx from 'react-native-onyx'; import type {SetRequired} from 'type-fest'; import Log from '@libs/Log'; import {HandleUnusedOptimisticID, Logging, Pagination, Reauthentication, RecheckConnection, SaveResponseInOnyx} from '@libs/Middleware'; -import {push, waitForIdle} from '@libs/Network/SequentialQueue'; +import {push as pushToSequentialQueue, waitForIdle as waitForSequentialQueueIdle} from '@libs/Network/SequentialQueue'; import {getPusherSocketID} from '@libs/Pusher/pusher'; import {processWithMiddleware, use} from '@libs/Request'; -import {getLength} from '@userActions/PersistedRequests'; +import {getLength as getPersistedRequestsLength} from '@userActions/PersistedRequests'; import CONST from '@src/CONST'; import type OnyxRequest from '@src/types/onyx/Request'; import type {PaginatedRequest, PaginationConfig, RequestConflictResolver} from '@src/types/onyx/Request'; @@ -95,7 +95,7 @@ function prepareRequest( function processRequest(request: OnyxRequest, type: ApiRequestType): Promise { // Write commands can be saved and retried, so push it to the SequentialQueue if (type === CONST.API_REQUEST_TYPE.WRITE) { - push(request); + pushToSequentialQueue(request); return Promise.resolve(); } @@ -172,10 +172,10 @@ function makeRequestWithSideEffects( * write requests that use the same Onyx keys and haven't responded yet. */ function waitForWrites(command: TCommand) { - if (getLength() > 0) { - Log.info(`[API] '${command}' is waiting on ${getLength()} write commands`); + if (getPersistedRequestsLength() > 0) { + Log.info(`[API] '${command}' is waiting on ${getPersistedRequestsLength()} write commands`); } - return waitForIdle(); + return waitForSequentialQueueIdle(); } /** diff --git a/src/libs/Middleware/Reauthentication.ts b/src/libs/Middleware/Reauthentication.ts index deebfe4349b7..81860e3b5b49 100644 --- a/src/libs/Middleware/Reauthentication.ts +++ b/src/libs/Middleware/Reauthentication.ts @@ -1,7 +1,7 @@ import redirectToSignIn from '@libs/actions/SignInRedirect'; import {reauthenticate as reauthenticateLibs} from '@libs/Authentication'; import Log from '@libs/Log'; -import {replay} from '@libs/Network/MainQueue'; +import {replay as replayMainQueue} from '@libs/Network/MainQueue'; import {isAuthenticating as isAuthenticatingNetworkStore, isOffline, setIsAuthenticating} from '@libs/Network/NetworkStore'; import type {RequestError} from '@libs/Network/SequentialQueue'; import NetworkConnection from '@libs/NetworkConnection'; @@ -94,7 +94,7 @@ const Reauthentication: Middleware = (response, request, isFromSequentialQueue) // We are already authenticating and using the DeprecatedAPI so we will replay the request if (!apiRequestType && isAuthenticatingNetworkStore()) { - replay(request); + replayMainQueue(request); return data; } @@ -109,7 +109,7 @@ const Reauthentication: Middleware = (response, request, isFromSequentialQueue) return Promise.resolve(); } - replay(request); + replayMainQueue(request); return authenticateResponse; }) .catch(() => { @@ -118,7 +118,7 @@ const Reauthentication: Middleware = (response, request, isFromSequentialQueue) } // If we make it here, then our reauthenticate request could not be made due to a networking issue. The original request can be retried safely. - replay(request); + replayMainQueue(request); }); } diff --git a/src/libs/Network/MainQueue.ts b/src/libs/Network/MainQueue.ts index 95e4e260e153..3267c938fd94 100644 --- a/src/libs/Network/MainQueue.ts +++ b/src/libs/Network/MainQueue.ts @@ -1,7 +1,7 @@ import {processWithMiddleware} from '@libs/Request'; import type OnyxRequest from '@src/types/onyx/Request'; import {isAuthenticating, isOffline} from './NetworkStore'; -import {isRunning} from './SequentialQueue'; +import {isRunning as sequentialQueueIsRunning} from './SequentialQueue'; // Queue for network requests so we don't lose actions done by the user while offline let networkRequestQueue: OnyxRequest[] = []; @@ -12,7 +12,7 @@ let networkRequestQueue: OnyxRequest[] = []; function canMakeRequest(request: OnyxRequest): boolean { // Some requests are always made even when we are in the process of authenticating (typically because they require no authToken e.g. Log, BeginSignIn) // However, if we are in the process of authenticating we always want to queue requests until we are no longer authenticating. - return request.data?.forceNetworkRequest === true || (!isAuthenticating() && !isRunning()); + return request.data?.forceNetworkRequest === true || (!isAuthenticating() && !sequentialQueueIsRunning()); } function push(request: OnyxRequest) { diff --git a/src/libs/Network/SequentialQueue.ts b/src/libs/Network/SequentialQueue.ts index 09d545d955e3..eb8b80d9ba1d 100644 --- a/src/libs/Network/SequentialQueue.ts +++ b/src/libs/Network/SequentialQueue.ts @@ -1,5 +1,13 @@ import Onyx from 'react-native-onyx'; -import {deleteRequestsByIndices, endRequestAndRemoveFromQueue, getAll, processNextRequest, rollbackOngoingRequest, save, update} from '@libs/actions/PersistedRequests'; +import { + deleteRequestsByIndices as deletePersistedRequestsByIndices, + endRequestAndRemoveFromQueue as endPersistedRequestAndRemoveFromQueue, + getAll as getAllPersistedRequests, + processNextRequest as processNextPersistedRequest, + rollbackOngoingRequest as rollbackOngoingPersistedRequest, + save as savePersistedRequest, + update as updatePersistedRequest, +} from '@libs/actions/PersistedRequests'; import {flushQueue, isEmpty} from '@libs/actions/QueuedOnyxUpdates'; import {isClientTheLeader} from '@libs/ActiveClientManager'; import Log from '@libs/Log'; @@ -76,13 +84,13 @@ function process(): Promise { return Promise.resolve(); } - const persistedRequests = getAll(); + const persistedRequests = getAllPersistedRequests(); if (persistedRequests.length === 0) { Log.info('[SequentialQueue] Unable to process. No requests to process.'); return Promise.resolve(); } - const requestToProcess = processNextRequest(); + const requestToProcess = processNextPersistedRequest(); if (!requestToProcess) { Log.info('[SequentialQueue] Unable to process. No next request to handle.'); return Promise.resolve(); @@ -99,7 +107,7 @@ function process(): Promise { } Log.info('[SequentialQueue] Removing persisted request because it was processed successfully.', false, {request: requestToProcess}); - endRequestAndRemoveFromQueue(requestToProcess); + endPersistedRequestAndRemoveFromQueue(requestToProcess); sequentialQueueRequestThrottle.clear(); return process(); }) @@ -108,18 +116,18 @@ function process(): Promise { // Duplicate records don't need to be retried as they just mean the record already exists on the server if (error.name === CONST.ERROR.REQUEST_CANCELLED || error.message === CONST.ERROR.DUPLICATE_RECORD) { Log.info("[SequentialQueue] Removing persisted request because it failed and doesn't need to be retried.", false, {error, request: requestToProcess}); - endRequestAndRemoveFromQueue(requestToProcess); + endPersistedRequestAndRemoveFromQueue(requestToProcess); sequentialQueueRequestThrottle.clear(); return process(); } - rollbackOngoingRequest(); + rollbackOngoingPersistedRequest(); return sequentialQueueRequestThrottle .sleep(error, requestToProcess.command) .then(process) .catch(() => { Onyx.update(requestToProcess.failureData ?? []); Log.info('[SequentialQueue] Removing persisted request because it failed too many times.', false, {error, request: requestToProcess}); - endRequestAndRemoveFromQueue(requestToProcess); + endPersistedRequestAndRemoveFromQueue(requestToProcess); sequentialQueueRequestThrottle.clear(); return process(); }); @@ -140,7 +148,7 @@ function flush() { return; } - if (getAll().length === 0 && isEmpty()) { + if (getAllPersistedRequests().length === 0 && isEmpty()) { Log.info('[SequentialQueue] Unable to flush. No requests or queued Onyx updates to process.'); return; } @@ -163,20 +171,20 @@ function flush() { const connection = Onyx.connect({ key: ONYXKEYS.PERSISTED_REQUESTS, // We exceptionally opt out of reusing the connection here to avoid extra callback calls due to - // an existing connection already made in ts. + // an existing connection already made in PersistedRequests.ts. reuseConnection: false, callback: () => { Onyx.disconnect(connection); process().finally(() => { Log.info('[SequentialQueue] Finished processing queue.'); isSequentialQueueRunning = false; - if (isOffline() || getAll().length === 0) { + if (isOffline() || getAllPersistedRequests().length === 0) { resolveIsReadyPromise?.(); } currentRequestPromise = null; // The queue can be paused when we sync the data with backend so we should only update the Onyx data when the queue is empty - if (getAll().length === 0) { + if (getAllPersistedRequests().length === 0) { flushOnyxUpdatesQueue(); } }); @@ -193,7 +201,7 @@ function unpause() { return; } - const numberOfPersistedRequests = getAll().length || 0; + const numberOfPersistedRequests = getAllPersistedRequests().length || 0; Log.info(`[SequentialQueue] Unpausing the queue and flushing ${numberOfPersistedRequests} requests`); isQueuePaused = false; flush(); @@ -212,13 +220,13 @@ onReconnection(flush); function handleConflictActions(conflictAction: ConflictData, newRequest: OnyxRequest) { if (conflictAction.type === 'push') { - save(newRequest); + savePersistedRequest(newRequest); } else if (conflictAction.type === 'replace') { - update(conflictAction.index, conflictAction.request ?? newRequest); + updatePersistedRequest(conflictAction.index, conflictAction.request ?? newRequest); } else if (conflictAction.type === 'delete') { - deleteRequestsByIndices(conflictAction.indices); + deletePersistedRequestsByIndices(conflictAction.indices); if (conflictAction.pushNewRequest) { - save(newRequest); + savePersistedRequest(newRequest); } if (conflictAction.nextAction) { handleConflictActions(conflictAction.nextAction, newRequest); @@ -232,7 +240,7 @@ function push(newRequest: OnyxRequest) { const {checkAndFixConflictingRequest} = newRequest; if (checkAndFixConflictingRequest) { - const requests = getAll(); + const requests = getAllPersistedRequests(); const {conflictAction} = checkAndFixConflictingRequest(requests); Log.info(`[SequentialQueue] Conflict action for command ${newRequest.command} - ${conflictAction.type}:`); @@ -242,7 +250,7 @@ function push(newRequest: OnyxRequest) { handleConflictActions(conflictAction, newRequest); } else { // Add request to Persisted Requests so that it can be retried if it fails - save(newRequest); + savePersistedRequest(newRequest); } // If we are offline we don't need to trigger the queue to empty as it will happen when we come back online diff --git a/src/libs/Network/index.ts b/src/libs/Network/index.ts index 826bef76d12c..edca026b645d 100644 --- a/src/libs/Network/index.ts +++ b/src/libs/Network/index.ts @@ -3,18 +3,18 @@ import CONST from '@src/CONST'; import type {Request} from '@src/types/onyx'; import type Response from '@src/types/onyx/Response'; import pkg from '../../../package.json'; -import {process, push} from './MainQueue'; -import {flush} from './SequentialQueue'; +import {process as processMainQueue, push as pushToMainQueue} from './MainQueue'; +import {flush as flushSequentialQueue} from './SequentialQueue'; // React Native uses a number for the timer id, but Web/NodeJS uses a Timeout object let processQueueInterval: NodeJS.Timeout | number; // We must wait until the ActiveClientManager is ready so that we ensure only the "leader" tab processes any persisted requests ActiveClientManager.isReady().then(() => { - flush(); + flushSequentialQueue(); // Start main queue and process once every n ms delay - processQueueInterval = setInterval(process, CONST.NETWORK.PROCESS_REQUEST_DELAY_MS); + processQueueInterval = setInterval(processMainQueue, CONST.NETWORK.PROCESS_REQUEST_DELAY_MS); }); /** @@ -54,7 +54,7 @@ function post(command: string, data: Record = {}, type = CONST. request.reject = reject; // Add the request to a queue of actions to perform - push(request); + pushToMainQueue(request); // This check is mainly used to prevent API commands from triggering calls to MainQueue.process() from inside the context of a previous // call to MainQueue.process() e.g. calling a Log command without this would cause the requests in mainQueue to double process @@ -65,7 +65,7 @@ function post(command: string, data: Record = {}, type = CONST. } // Try to fire off the request as soon as it's queued so we don't add a delay to every queued command - process(); + processMainQueue(); }); } diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 7a1b64c99ef7..9c1908140e84 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -61,7 +61,7 @@ import type IconAsset from '@src/types/utils/IconAsset'; import * as IOU from './actions/IOU'; import {createDraftWorkspace} from './actions/Policy/Policy'; import * as store from './actions/ReimbursementAccount/store'; -import {isAnonymousUser as isAnonymousUserSessionUtils} from './actions/Session'; +import {isAnonymousUser as isAnonymousUserSession} from './actions/Session'; import * as CurrencyUtils from './CurrencyUtils'; import DateUtils from './DateUtils'; import {hasValidDraftComment} from './DraftCommentUtils'; @@ -143,7 +143,7 @@ import { isReversedTransaction, isRoomChangeLogAction, isSentMoneyReportAction, - isSplitBillAction, + isSplitBillAction as isSplitBillReportAction, isSubmittedAction, isSubmittedAndClosedAction, isThreadParentMessage, @@ -156,7 +156,6 @@ import { import {getAllReports} from './ReportConnection'; import { getAllReportTransactions, - getAmount, getAttendees, getBillable, getCardID, @@ -177,6 +176,7 @@ import { getTag, getTaxAmount, getTaxCode, + getAmount as getTransactionAmount, getWaypoints, hasMissingSmartscanFields as hasMissingSmartscanFieldsTransactionUtils, hasNoticeTypeViolation, @@ -3208,7 +3208,7 @@ function getTransactionDetails(transaction: OnyxInputOrEntry, creat const report = getReportOrDraftReport(transaction?.reportID); return { created: getFormattedCreated(transaction, createdDateFormat), - amount: getAmount(transaction, !isEmptyObject(report) && isExpenseReport(report)), + amount: getTransactionAmount(transaction, !isEmptyObject(report) && isExpenseReport(report)), attendees: getAttendees(transaction), taxAmount: getTaxAmount(transaction, !isEmptyObject(report) && isExpenseReport(report)), taxCode: getTaxCode(transaction), @@ -3584,7 +3584,7 @@ function getTransactionReportName(reportAction: OnyxEntry, return Localize.translateLocal(translationKey, {amount: formattedAmount, payer: ''}); } - const amount = getAmount(transaction, !isEmptyObject(iouReport) && isExpenseReport(iouReport)) ?? 0; + const amount = getTransactionAmount(transaction, !isEmptyObject(iouReport) && isExpenseReport(iouReport)) ?? 0; const formattedAmount = CurrencyUtils.convertToDisplayString(amount, getCurrency(transaction)) ?? ''; const isRequestSettled = isSettled(IOUReportID); const isApproved = isReportApproved(iouReport); @@ -7661,7 +7661,7 @@ function getIOUReportActionDisplayMessage(reportAction: OnyxEntry, amount: formattedAmount, }); } - if (isSplitBillAction(reportAction)) { + if (isSplitBillReportAction(reportAction)) { translationKey = 'iou.didSplitAmount'; } else if (isTrackExpenseAction(reportAction)) { translationKey = 'iou.trackedAmount'; @@ -7773,7 +7773,7 @@ function canEditPolicyDescription(policy: OnyxEntry): boolean { function getReportActionWithSmartscanError(reportActions: ReportAction[]): ReportAction | undefined { return reportActions.find((action) => { const isReportPreview = isReportPreviewAction(action); - const isSplitReportAction = isSplitBillAction(action); + const isSplitReportAction = isSplitBillReportAction(action); if (!isSplitReportAction && !isReportPreview) { return false; } @@ -7912,7 +7912,7 @@ function getNonHeldAndFullAmount(iouReport: OnyxEntry, shouldExcludeNonR * - The action is the thread's first chat */ function shouldDisableThread(reportAction: OnyxInputOrEntry, reportID: string, isThreadReportParentAction: boolean): boolean { - const isSplitBillActionLocal = isSplitBillAction(reportAction); + const isSplitBillAction = isSplitBillReportAction(reportAction); const isDeletedActionLocal = isDeletedAction(reportAction); const isReportPreviewActionLocal = isReportPreviewAction(reportAction); const isIOUAction = isMoneyRequestAction(reportAction); @@ -7922,7 +7922,7 @@ function shouldDisableThread(reportAction: OnyxInputOrEntry, repor return ( isActionDisabled || - isSplitBillActionLocal || + isSplitBillAction || (isDeletedActionLocal && !reportAction?.childVisibleActionCount) || (isArchivedReport && !reportAction?.childVisibleActionCount) || (isWhisperActionLocal && !isReportPreviewActionLocal && !isIOUAction) || @@ -8206,7 +8206,7 @@ function canLeaveChat(report: OnyxEntry, policy: OnyxEntry): boo return true; } - if (isPublicRoom(report) && isAnonymousUserSessionUtils()) { + if (isPublicRoom(report) && isAnonymousUserSession()) { return false; } diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index 3b16a63ceb5d..e9b3ef36f0ba 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -16,7 +16,7 @@ import {validateAmount} from './MoneyRequestUtils'; import * as PersonalDetailsUtils from './PersonalDetailsUtils'; import {getTagNamesFromTagsLists} from './PolicyUtils'; import {getReportName} from './ReportUtils'; -import {parse} from './SearchParser/searchParser'; +import {parse as parseSearchQuery} from './SearchParser/searchParser'; import {hashText} from './UserUtils'; import {isValidDate} from './ValidationUtils'; @@ -232,7 +232,7 @@ function getQueryHashes(query: SearchQueryJSON): {primaryHash: number; recentSea */ function buildSearchQueryJSON(query: SearchQueryString) { try { - const result = parse(query) as SearchQueryJSON; + const result = parseSearchQuery(query) as SearchQueryJSON; const flatFilters = getFilters(result); // Add the full input and hash to the results diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index c10a801842c2..51af7f4525c5 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -37,7 +37,7 @@ import {getMicroSecondOnyxErrorObject, getMicroSecondOnyxErrorWithTranslationKey import {readFileAsync} from '@libs/fileDownload/FileUtils'; import GoogleTagManager from '@libs/GoogleTagManager'; import { - calculateAmount, + calculateAmount as calculateIOUAmount, formatCurrentUserToAttendee, isMovingTransactionFromTrackExpense as isMovingTransactionFromTrackExpenseIOUUtils, navigateToStartMoneyRequestStep, @@ -160,7 +160,7 @@ import type {OnyxData} from '@src/types/onyx/Request'; import type {SearchPolicy, SearchReport, SearchTransaction} from '@src/types/onyx/SearchResults'; import type {Comment, Receipt, ReceiptSource, Routes, SplitShares, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; -import {clearByKey} from './CachedPDFPaths'; +import {clearByKey as clearPdfByOnyxKey} from './CachedPDFPaths'; import {buildOptimisticPolicyRecentlyUsedCategories} from './Policy/Category'; import {buildOptimisticRecentlyUsedCurrencies, buildPolicyData, generatePolicyID} from './Policy/Policy'; import {buildOptimisticPolicyRecentlyUsedTags} from './Policy/Tag'; @@ -4395,8 +4395,8 @@ function createSplitsAndOnyxData( } // Loop through participants creating individual chats, iouReports and reportActionIDs as needed - const currentUserAmount = splitShares?.[currentUserAccountID]?.amount ?? calculateAmount(participants.length, amount, currency, true); - const currentUserTaxAmount = calculateAmount(participants.length, taxAmount, currency, true); + const currentUserAmount = splitShares?.[currentUserAccountID]?.amount ?? calculateIOUAmount(participants.length, amount, currency, true); + const currentUserTaxAmount = calculateIOUAmount(participants.length, taxAmount, currency, true); const splits: Split[] = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID, amount: currentUserAmount, taxAmount: currentUserTaxAmount}]; @@ -4404,8 +4404,8 @@ function createSplitsAndOnyxData( participants.forEach((participant) => { // In a case when a participant is a workspace, even when a current user is not an owner of the workspace const isPolicyExpenseChat = isPolicyExpenseChatReportUtils(participant); - const splitAmount = splitShares?.[participant.accountID ?? -1]?.amount ?? calculateAmount(participants.length, amount, currency, false); - const splitTaxAmount = calculateAmount(participants.length, taxAmount, currency, false); + const splitAmount = splitShares?.[participant.accountID ?? -1]?.amount ?? calculateIOUAmount(participants.length, amount, currency, false); + const splitTaxAmount = calculateIOUAmount(participants.length, taxAmount, currency, false); // To exclude someone from a split, the amount can be 0. The scenario for this is when creating a split from a group chat, we have remove the option to deselect users to exclude them. // We can input '0' next to someone we want to exclude. @@ -5181,8 +5181,8 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA const currency = updatedTransaction?.modifiedCurrency; // Exclude the current user when calculating the split amount, `calculateAmount` takes it into account - const splitAmount = calculateAmount(splitParticipants.length - 1, amount ?? 0, currency ?? '', false); - const splitTaxAmount = calculateAmount(splitParticipants.length - 1, updatedTransaction?.taxAmount ?? 0, currency ?? '', false); + const splitAmount = calculateIOUAmount(splitParticipants.length - 1, amount ?? 0, currency ?? '', false); + const splitTaxAmount = calculateIOUAmount(splitParticipants.length - 1, updatedTransaction?.taxAmount ?? 0, currency ?? '', false); const splits: Split[] = [{email: currentUserEmailForIOUSplit}]; splitParticipants.forEach((participant) => { @@ -6164,7 +6164,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor // STEP 3: Make the API request API.write(WRITE_COMMANDS.DELETE_MONEY_REQUEST, parameters, {optimisticData, successData, failureData}); - clearByKey(transactionID); + clearPdfByOnyxKey(transactionID); return urlToNavigateBack; } @@ -6193,7 +6193,7 @@ function deleteTrackExpense(chatReportID: string, transactionID: string, reportA // STEP 6: Make the API request API.write(WRITE_COMMANDS.DELETE_MONEY_REQUEST, parameters, {optimisticData, successData, failureData}); - clearByKey(transactionID); + clearPdfByOnyxKey(transactionID); // STEP 7: Navigate the user depending on which page they are on and which resources were deleted return urlToNavigateBack; @@ -8094,7 +8094,7 @@ function setSplitShares(transaction: OnyxEntry, amount: n const isPayer = accountID === userAccountID; const participantsLength = newAccountIDs.includes(userAccountID) ? newAccountIDs.length - 1 : newAccountIDs.length; - const splitAmount = calculateAmount(participantsLength, amount, currency, isPayer); + const splitAmount = calculateIOUAmount(participantsLength, amount, currency, isPayer); acc[accountID] = { amount: splitAmount, isModified: false, @@ -8152,7 +8152,7 @@ function adjustRemainingSplitShares(transaction: NonNullable { - const splitAmount = calculateAmount(unmodifiedSharesAccountIDs.length - 1, remainingTotal, transaction.currency, index === 0); + const splitAmount = calculateIOUAmount(unmodifiedSharesAccountIDs.length - 1, remainingTotal, transaction.currency, index === 0); acc[accountID] = { amount: splitAmount, }; diff --git a/src/libs/actions/OnyxUpdateManager/index.ts b/src/libs/actions/OnyxUpdateManager/index.ts index 302110e3e6bf..71c4ba72911c 100644 --- a/src/libs/actions/OnyxUpdateManager/index.ts +++ b/src/libs/actions/OnyxUpdateManager/index.ts @@ -3,14 +3,20 @@ import Onyx from 'react-native-onyx'; import * as ActiveClientManager from '@libs/ActiveClientManager'; import Log from '@libs/Log'; import {setAuthToken} from '@libs/Network/NetworkStore'; -import {unpause} from '@libs/Network/SequentialQueue'; +import {unpause as unpauseSequentialQueue} from '@libs/Network/SequentialQueue'; import {finalReconnectAppAfterActivatingReliableUpdates, getMissingOnyxUpdates} from '@userActions/App'; import updateSessionAuthTokens from '@userActions/Session/updateSessionAuthTokens'; import ONYXKEYS from '@src/ONYXKEYS'; import type {OnyxUpdatesFromServer, Session} from '@src/types/onyx'; import {isValidOnyxUpdateFromServer} from '@src/types/onyx/OnyxUpdatesFromServer'; import {validateAndApplyDeferredUpdates} from './utils'; -import {clear, enqueue, getMissingOnyxUpdatesQueryPromise, isEmpty, setMissingOnyxUpdatesQueryPromise} from './utils/DeferredOnyxUpdates'; +import { + clear as clearDeferredOnyxUpdates, + enqueue as enqueueDeferredOnyxUpdates, + getMissingOnyxUpdatesQueryPromise, + isEmpty as isEmptyDeferredOnyxUpdates, + setMissingOnyxUpdatesQueryPromise, +} from './utils/DeferredOnyxUpdates'; // This file is in charge of looking at the updateIDs coming from the server and comparing them to the last updateID that the client has. // If the client is behind the server, then we need to @@ -50,7 +56,7 @@ const createQueryPromiseWrapper = () => let queryPromiseWrapper = createQueryPromiseWrapper(); const resetDeferralLogicVariables = () => { - clear({shouldUnpauseSequentialQueue: false}); + clearDeferredOnyxUpdates({shouldUnpauseSequentialQueue: false}); }; // This function will reset the query variables, unpause the SequentialQueue and log an info to the user. @@ -60,7 +66,7 @@ function finalizeUpdatesAndResumeQueue() { resolveQueryPromiseWrapper(); queryPromiseWrapper = createQueryPromiseWrapper(); - clear(); + clearDeferredOnyxUpdates(); } /** @@ -76,7 +82,7 @@ function handleOnyxUpdateGap(onyxUpdatesFromServer: OnyxEntry; -/** Model of report search result */ /** Model of report search result */ type SearchReport = { /** The ID of the report */ From f688e6cd4be3fdd95c9ca887841b709c4b64fc2a Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Thu, 12 Dec 2024 09:45:58 +0100 Subject: [PATCH 13/29] fix: resolve comment --- src/libs/SearchUIUtils.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index 080568dcbca3..1b2bfe0bcfe9 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -19,7 +19,7 @@ import {translateLocal} from './Localize'; import Navigation from './Navigation/Navigation'; import {isDeletedAction} from './ReportActionsUtils'; import {hasOnlyHeldExpenses, isAllowedToApproveExpenseReport, isClosedReport, isInvoiceReport, isMoneyRequestReport, isSettled} from './ReportUtils'; -import {getAmount, getCreated, getMerchant} from './TransactionUtils'; +import {getAmount as getTransactionAmount, getCreated as getTransactionCreatedDate, getMerchant as getTransactionMerchant} from './TransactionUtils'; const columnNamesToSortingProperty = { [CONST.SEARCH.TABLE_COLUMNS.TO]: 'formattedTo' as const, @@ -63,9 +63,9 @@ function getTransactionItemCommonFormattedProperties( const formattedFrom = from?.displayName ?? from?.login ?? ''; const formattedTo = to?.displayName ?? to?.login ?? ''; - const formattedTotal = getAmount(transactionItem, isExpenseReport); + const formattedTotal = getTransactionAmount(transactionItem, isExpenseReport); const date = transactionItem?.modifiedCreated ? transactionItem.modifiedCreated : transactionItem?.created; - const merchant = getMerchant(transactionItem); + const merchant = getTransactionMerchant(transactionItem); const formattedMerchant = merchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT || merchant === CONST.TRANSACTION.DEFAULT_MERCHANT ? '' : merchant; return { @@ -146,7 +146,7 @@ function shouldShowYear(data: TransactionListItemType[] | ReportListItemType[] | if (isReportListItemType(item)) { // If the item is a ReportListItemType, iterate over its transactions and check them return item.transactions.some((transaction) => { - const transactionYear = new Date(getCreated(transaction)).getFullYear(); + const transactionYear = new Date(getTransactionCreatedDate(transaction)).getFullYear(); return transactionYear !== currentYear; }); } @@ -159,7 +159,7 @@ function shouldShowYear(data: TransactionListItemType[] | ReportListItemType[] | for (const key in data) { if (isTransactionEntry(key)) { const item = data[key]; - const date = getCreated(item); + const date = getTransactionCreatedDate(item); if (DateUtils.doesDateBelongToAPastYear(date)) { return true; From 10d59cd13dae194743399e0670af3e63b0223c4d Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Thu, 12 Dec 2024 10:53:38 +0100 Subject: [PATCH 14/29] rerun of workflows --- src/libs/SearchUIUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index 2a355adc2457..48a3cef30ee1 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -177,7 +177,7 @@ function shouldShowYear(data: TransactionListItemType[] | ReportListItemType[] | } return false; } - +console.log('1'); /** * @private * Generates a display name for IOU reports considering the personal details of the payer and the transaction details. From c64f181f2e2868a4d391394e7dcbcc8372d08c78 Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Thu, 12 Dec 2024 10:53:53 +0100 Subject: [PATCH 15/29] revert commit --- src/libs/SearchUIUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index 48a3cef30ee1..2a355adc2457 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -177,7 +177,7 @@ function shouldShowYear(data: TransactionListItemType[] | ReportListItemType[] | } return false; } -console.log('1'); + /** * @private * Generates a display name for IOU reports considering the personal details of the payer and the transaction details. From e296606ac5a1dbecbd833283fceb6c3ad2f69932 Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Thu, 12 Dec 2024 11:15:15 +0100 Subject: [PATCH 16/29] fix: lint --- src/libs/SearchUIUtils.ts | 4 ++-- src/libs/actions/IOU.ts | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index 17ed87190b3c..4858c7c4f322 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -12,7 +12,7 @@ import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type SearchResults from '@src/types/onyx/SearchResults'; import type {ListItemDataType, ListItemType, SearchDataTypes, SearchPersonalDetails, SearchReport, SearchTransaction, SearchTransactionAction} from '@src/types/onyx/SearchResults'; -import {canApproveIOU, canIOUBePaid} from './actions/IOU'; +import {canApproveIOU, canIOUBePaid, canSubmitReport} from './actions/IOU'; import {convertToDisplayString} from './CurrencyUtils'; import DateUtils from './DateUtils'; import {translateLocal} from './Localize'; @@ -296,7 +296,7 @@ function getAction(data: OnyxTypes.SearchResults['data'], key: string): SearchTr return CONST.SEARCH.ACTION_TYPES.APPROVE; } - if (IOU.canSubmitReport(report, policy)) { + if (canSubmitReport(report, policy)) { return CONST.SEARCH.ACTION_TYPES.SUBMIT; } diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index ba933364d8d6..ac6839f761a4 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -166,7 +166,7 @@ import {clearByKey as clearPdfByOnyxKey} from './CachedPDFPaths'; import {buildOptimisticPolicyRecentlyUsedCategories} from './Policy/Category'; import {buildOptimisticRecentlyUsedCurrencies, buildPolicyData, generatePolicyID} from './Policy/Policy'; import {buildOptimisticPolicyRecentlyUsedTags} from './Policy/Tag'; -import {completeOnboarding, notifyNewAction} from './Report'; +import {completeOnboarding, getCurrentUserAccountID, notifyNewAction} from './Report'; import {getRecentWaypoints, sanitizeRecentWaypoints} from './Transaction'; import {removeDraftTransaction} from './TransactionEdit'; @@ -7238,9 +7238,9 @@ function canIOUBePaid( } function canSubmitReport(report: OnyxEntry | SearchReport, policy: OnyxEntry | SearchPolicy) { - const currentUserAccountID = Report.getCurrentUserAccountID(); - const isOpenExpenseReport = ReportUtils.isOpenExpenseReport(report); - const {reimbursableSpend} = ReportUtils.getMoneyRequestSpendBreakdown(report); + const currentUserAccountID = getCurrentUserAccountID(); + const isOpenExpenseReport = isOpenExpenseReportReportUtils(report); + const {reimbursableSpend} = getMoneyRequestSpendBreakdown(report); const isAdmin = policy?.role === CONST.POLICY.ROLE.ADMIN; // This logic differs from the one in MoneyRequestHeader From cb7bfbcb7ea4c15d420bbbe935db328c5d26f5e5 Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Tue, 17 Dec 2024 14:59:06 +0100 Subject: [PATCH 17/29] remove changes from package-lock.json --- package-lock.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index c1a8ed6728ed..67b834637133 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4734,7 +4734,6 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/@expo/metro-runtime/-/metro-runtime-3.2.3.tgz", "integrity": "sha512-v5ji+fAGi7B9YavrxvekuF8gXEV/5fz0+PhaED5AaFDnbGB4IJIbpaiqK9nqZV1axjGZNQSw6Q8TsnFetCR3bQ==", - "license": "MIT", "peerDependencies": { "react-native": "*" } From b736f160f9cb6b6c958784dfa4dbac93b4e73838 Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Wed, 18 Dec 2024 13:35:24 +0100 Subject: [PATCH 18/29] fix eslint problems --- src/ROUTES.ts | 2 +- .../API/parameters/ResolveDuplicatesParams.ts | 2 +- .../API/parameters/TransactionMergeParams.ts | 6 ++-- .../VerifyIdentityForBankAccountParams.ts | 2 +- src/libs/DistanceRequestUtils.ts | 21 ++++++------ src/libs/Navigation/dismissModalWithReport.ts | 2 +- src/libs/Navigation/linkTo/index.ts | 3 +- .../linkingConfig/getAdaptedStateFromPath.ts | 2 +- src/libs/PolicyUtils.ts | 17 +++++----- src/libs/ReportActionsUtils.ts | 4 +-- src/libs/ReportUtils.ts | 2 +- src/libs/SearchUIUtils.ts | 2 +- src/libs/TransactionUtils/index.ts | 32 +++++++++++-------- src/libs/actions/BankAccounts.ts | 2 +- src/libs/actions/IOU.ts | 4 +-- src/libs/actions/Policy/Category.ts | 2 +- src/libs/actions/Policy/Policy.ts | 24 ++++++++------ src/libs/actions/Policy/Tag.ts | 2 +- src/libs/actions/PriorityMode.ts | 2 +- .../TransactionDuplicate/Confirmation.tsx | 3 +- .../members/WorkspaceOwnerPaymentCardForm.tsx | 3 +- src/types/onyx/OriginalMessage.ts | 2 +- src/types/onyx/ReviewDuplicates.ts | 2 +- 23 files changed, 76 insertions(+), 67 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index b9544d81bece..7c8945caf37b 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -296,7 +296,7 @@ const ROUTES = { REPORT: 'r', REPORT_WITH_ID: { route: 'r/:reportID?/:reportActionID?', - getRoute: (reportID: string, reportActionID?: string, referrer?: string) => { + getRoute: (reportID: string | undefined, reportActionID?: string, referrer?: string) => { const baseRoute = reportActionID ? (`r/${reportID}/${reportActionID}` as const) : (`r/${reportID}` as const); const referrerParam = referrer ? `?referrer=${encodeURIComponent(referrer)}` : ''; return `${baseRoute}${referrerParam}` as const; diff --git a/src/libs/API/parameters/ResolveDuplicatesParams.ts b/src/libs/API/parameters/ResolveDuplicatesParams.ts index d225f227c0d7..66d013af8891 100644 --- a/src/libs/API/parameters/ResolveDuplicatesParams.ts +++ b/src/libs/API/parameters/ResolveDuplicatesParams.ts @@ -1,6 +1,6 @@ type ResolveDuplicatesParams = { /** The ID of the transaction that we want to keep */ - transactionID: string; + transactionID: string | undefined; /** The list of other duplicated transactions */ transactionIDList: string[]; diff --git a/src/libs/API/parameters/TransactionMergeParams.ts b/src/libs/API/parameters/TransactionMergeParams.ts index 9e2516e2637f..b4204ace72d2 100644 --- a/src/libs/API/parameters/TransactionMergeParams.ts +++ b/src/libs/API/parameters/TransactionMergeParams.ts @@ -1,6 +1,6 @@ type TransactionMergeParams = { - transactionID: string; - transactionIDList: string[]; + transactionID: string | undefined; + transactionIDList: Array; created: string; merchant: string; amount: number; @@ -11,7 +11,7 @@ type TransactionMergeParams = { reimbursable: boolean; tag: string; receiptID: number; - reportID: string; + reportID: string | undefined; }; export default TransactionMergeParams; diff --git a/src/libs/API/parameters/VerifyIdentityForBankAccountParams.ts b/src/libs/API/parameters/VerifyIdentityForBankAccountParams.ts index 6ef6b3712439..07ce9fa71b92 100644 --- a/src/libs/API/parameters/VerifyIdentityForBankAccountParams.ts +++ b/src/libs/API/parameters/VerifyIdentityForBankAccountParams.ts @@ -1,6 +1,6 @@ type VerifyIdentityForBankAccountParams = { bankAccountID: number; onfidoData: string; - policyID: string; + policyID: string | undefined; }; export default VerifyIdentityForBankAccountParams; diff --git a/src/libs/DistanceRequestUtils.ts b/src/libs/DistanceRequestUtils.ts index 620eb234e921..c3ab72079b27 100644 --- a/src/libs/DistanceRequestUtils.ts +++ b/src/libs/DistanceRequestUtils.ts @@ -292,17 +292,17 @@ function convertToDistanceInMeters(distance: number, unit: Unit): number { function getCustomUnitRateID(reportID: string) { const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; - const policy = getPolicy(report?.policyID ?? parentReport?.policyID ?? '-1'); - let customUnitRateID: string = CONST.CUSTOM_UNITS.FAKE_P2P_ID; + const policy = getPolicy(report?.policyID ?? parentReport?.policyID); + let customUnitRateID: string | undefined = CONST.CUSTOM_UNITS.FAKE_P2P_ID; if (isPolicyExpenseChat(report) || isPolicyExpenseChat(parentReport)) { const distanceUnit = Object.values(policy?.customUnits ?? {}).find((unit) => unit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE); - const lastSelectedDistanceRateID = lastSelectedDistanceRates?.[policy?.id ?? '-1'] ?? '-1'; - const lastSelectedDistanceRate = distanceUnit?.rates[lastSelectedDistanceRateID] ?? {}; - if (lastSelectedDistanceRate.enabled && lastSelectedDistanceRateID) { + const lastSelectedDistanceRateID = policy?.id ? lastSelectedDistanceRates?.[policy?.id] : undefined; + const lastSelectedDistanceRate = lastSelectedDistanceRateID ? distanceUnit?.rates[lastSelectedDistanceRateID] : {}; + if (lastSelectedDistanceRate?.enabled && lastSelectedDistanceRateID) { customUnitRateID = lastSelectedDistanceRateID; } else { - customUnitRateID = getDefaultMileageRate(policy)?.customUnitRateID ?? '-1'; + customUnitRateID = getDefaultMileageRate(policy)?.customUnitRateID; } } @@ -319,9 +319,9 @@ function getTaxableAmount(policy: OnyxEntry, customUnitRateID: string, d return 0; } const unit = distanceUnit?.attributes?.unit ?? CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES; - const rate = customUnitRate?.rate ?? 0; + const rate = customUnitRate?.rate ?? CONST.DEFAULT_NUMBER_ID; const amount = getDistanceRequestAmount(distance, unit, rate); - const taxClaimablePercentage = customUnitRate.attributes?.taxClaimablePercentage ?? 0; + const taxClaimablePercentage = customUnitRate.attributes?.taxClaimablePercentage ?? CONST.DEFAULT_NUMBER_ID; return amount * taxClaimablePercentage; } @@ -350,8 +350,9 @@ function getRate({ } const policyCurrency = policy?.outputCurrency ?? getPersonalPolicy()?.outputCurrency ?? CONST.CURRENCY.USD; const defaultMileageRate = getDefaultMileageRate(policy); - const customUnitRateID = getRateID(transaction) ?? ''; - const mileageRate = isCustomUnitRateIDForP2P(transaction) ? getRateForP2P(policyCurrency, transaction) : mileageRates?.[customUnitRateID] ?? defaultMileageRate; + const customUnitRateID = getRateID(transaction); + const customMileageRate = customUnitRateID ? mileageRates?.[customUnitRateID] : defaultMileageRate; + const mileageRate = isCustomUnitRateIDForP2P(transaction) ? getRateForP2P(policyCurrency, transaction) : customMileageRate; const unit = getDistanceUnit(useTransactionDistanceUnit ? transaction : undefined, mileageRate); return { ...mileageRate, diff --git a/src/libs/Navigation/dismissModalWithReport.ts b/src/libs/Navigation/dismissModalWithReport.ts index b7cf2881f870..a921a0b6216b 100644 --- a/src/libs/Navigation/dismissModalWithReport.ts +++ b/src/libs/Navigation/dismissModalWithReport.ts @@ -46,7 +46,7 @@ function dismissModalWithReport(targetReport: OnyxEntry, navigationRef: case SCREENS.CONCIERGE: // If we are not in the target report, we need to navigate to it after dismissing the modal if (targetReport?.reportID !== getTopmostReportId(state)) { - const reportState = getStateFromPath(ROUTES.REPORT_WITH_ID.getRoute(targetReport?.reportID ?? '-1')); + const reportState = getStateFromPath(ROUTES.REPORT_WITH_ID.getRoute(targetReport?.reportID)); const policyID = getPolicyIDFromState(state as State); const policyMemberAccountIDs = getPolicyEmployeeAccountIDs(policyID); const shouldOpenAllWorkspace = isEmptyObject(targetReport) ? true : !doesReportBelongToWorkspace(targetReport, policyMemberAccountIDs, policyID); diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/linkTo/index.ts index ebaf528e2460..93ae33a6f77e 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/linkTo/index.ts @@ -101,8 +101,7 @@ export default function linkTo(navigation: NavigationContainerRef)?.policyID ?? '') !== - ((matchingBottomTabRoute?.params as Record)?.policyID ?? ''); + (topmostBottomTabRoute?.params as Record)?.policyID !== (matchingBottomTabRoute?.params as Record)?.policyID; if (topmostBottomTabRoute && (topmostBottomTabRoute.name !== matchingBottomTabRoute.name || isNewPolicyID || isOpeningSearch)) { root.dispatch({ diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 456ced20b5fa..31b749d35106 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -347,7 +347,7 @@ function getAdaptedState(state: PartialState const matchingBottomTabRoute = getMatchingBottomTabRouteForState(state); routes.push(createBottomTabNavigator(matchingBottomTabRoute, policyID)); if (!isNarrowLayout) { - routes.push({name: SCREENS.REPORT, params: {reportID: reportAttachments.params?.reportID ?? '-1'}}); + routes.push({name: SCREENS.REPORT, params: {reportID: reportAttachments.params?.reportID}}); } routes.push(reportAttachments); diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 3e69a3b2f7b2..01df9fe190cb 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -197,7 +197,8 @@ function getPolicyBrickRoadIndicatorStatus(policy: OnyxEntry, isConnecti } function getPolicyRole(policy: OnyxInputOrEntry | SearchPolicy, currentUserLogin: string | undefined) { - return policy?.role ?? policy?.employeeList?.[currentUserLogin ?? '-1']?.role; + const currentUserRole = currentUserLogin ? policy?.employeeList?.[currentUserLogin]?.role : undefined; + return policy?.role ?? currentUserRole; } /** @@ -391,7 +392,7 @@ function isPaidGroupPolicy(policy: OnyxInputOrEntry | SearchPolicy): boo } function getOwnedPaidPolicies(policies: OnyxCollection | null, currentUserAccountID: number): Policy[] { - return Object.values(policies ?? {}).filter((policy): policy is Policy => isPolicyOwner(policy, currentUserAccountID ?? -1) && isPaidGroupPolicy(policy)); + return Object.values(policies ?? {}).filter((policy): policy is Policy => isPolicyOwner(policy, currentUserAccountID ?? CONST.DEFAULT_NUMBER_ID) && isPaidGroupPolicy(policy)); } function isControlPolicy(policy: OnyxEntry): boolean { @@ -400,7 +401,7 @@ function isControlPolicy(policy: OnyxEntry): boolean { function isTaxTrackingEnabled(isPolicyExpenseChat: boolean, policy: OnyxEntry, isDistanceRequest: boolean): boolean { const distanceUnit = getDistanceRateCustomUnit(policy); - const customUnitID = distanceUnit?.customUnitID ?? 0; + const customUnitID = distanceUnit?.customUnitID ?? CONST.DEFAULT_NUMBER_ID; const isPolicyTaxTrackingEnabled = isPolicyExpenseChat && policy?.tax?.trackingEnabled; const isTaxEnabledForDistance = isPolicyTaxTrackingEnabled && policy?.customUnits?.[customUnitID]?.attributes?.taxEnabled; @@ -538,7 +539,7 @@ function getDefaultApprover(policy: OnyxEntry | SearchPolicy): string { * Returns the accountID to whom the given expenseReport submits reports to in the given Policy. */ function getSubmitToAccountID(policy: OnyxEntry | SearchPolicy, expenseReport: OnyxEntry): number { - const employeeAccountID = expenseReport?.ownerAccountID ?? -1; + const employeeAccountID = expenseReport?.ownerAccountID ?? CONST.DEFAULT_NUMBER_ID; const employeeLogin = getLoginsByAccountIDs([employeeAccountID]).at(0) ?? ''; const defaultApprover = getDefaultApprover(policy); @@ -557,8 +558,8 @@ function getSubmitToAccountID(policy: OnyxEntry | SearchPolicy, expenseR return getAccountIDsByLogins([categoryAppover]).at(0) ?? -1; } - if (!tagApprover && getTagApproverRule(policy ?? '-1', tag)?.approver) { - tagApprover = getTagApproverRule(policy ?? '-1', tag)?.approver; + if (!tagApprover && getTagApproverRule(policy, tag)?.approver) { + tagApprover = getTagApproverRule(policy, tag)?.approver; } } @@ -709,7 +710,7 @@ function settingsPendingAction(settings?: string[], pendingFields?: PendingField } const key = Object.keys(pendingFields).find((setting) => settings.includes(setting)); - return pendingFields[key ?? '-1']; + return key ? pendingFields[key] : undefined; } function findSelectedVendorWithDefaultSelect(vendors: NetSuiteVendor[] | undefined, selectedVendorId: string | undefined) { @@ -1078,7 +1079,7 @@ function getWorkspaceAccountID(policyID: string) { if (!policy) { return 0; } - return policy.workspaceAccountID ?? 0; + return policy.workspaceAccountID ?? CONST.DEFAULT_NUMBER_ID; } function hasVBBA(policyID: string) { diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index dd17adbda338..c81131de6b12 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -929,8 +929,8 @@ function getLinkedTransactionID(reportActionOrID: string | OnyxEntry { currentUserEmail = val?.email ?? ''; - currentUserAccountID = val?.accountID ?? -1; + currentUserAccountID = val?.accountID ?? CONST.DEFAULT_NUMBER_ID; }, }); @@ -584,7 +584,7 @@ function getCategory(transaction: OnyxInputOrEntry): string { * Return the cardID from the transaction. */ function getCardID(transaction: Transaction): number { - return transaction?.cardID ?? -1; + return transaction?.cardID ?? CONST.DEFAULT_NUMBER_ID; } /** @@ -966,7 +966,7 @@ function getDefaultTaxCode(policy: OnyxEntry, transaction: OnyxEntry, transaction: OnyxEntry taxRate.code === (transaction?.taxCode ?? defaultTaxCode))?.modifiedName; } -function getTransaction(transactionID: string): OnyxEntry { +function getTransaction(transactionID: string | undefined): OnyxEntry { return allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; } @@ -1034,7 +1034,7 @@ type FieldsToChange = { reimbursable?: Array; }; -function removeSettledAndApprovedTransactions(transactionIDs: string[]) { +function removeSettledAndApprovedTransactions(transactionIDs: Array) { return transactionIDs.filter( (transactionID) => !isSettled(allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]?.reportID) && @@ -1060,7 +1060,11 @@ function removeSettledAndApprovedTransactions(transactionIDs: string[]) { * 6. It returns the 'keep' and 'change' objects. */ -function compareDuplicateTransactionFields(reviewingTransactionID: string, reportID: string, selectedTransactionID?: string): {keep: Partial; change: FieldsToChange} { +function compareDuplicateTransactionFields( + reviewingTransactionID: string | undefined, + reportID: string, + selectedTransactionID?: string, +): {keep: Partial; change: FieldsToChange} { const transactionViolations = allTransactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${reviewingTransactionID}`]; const duplicates = transactionViolations?.find((violation) => violation.name === CONST.VIOLATIONS.DUPLICATED_TRANSACTION)?.data?.duplicates ?? []; const transactions = removeSettledAndApprovedTransactions([reviewingTransactionID, ...duplicates]).map((item) => getTransaction(item)); @@ -1161,7 +1165,7 @@ function compareDuplicateTransactionFields(reviewingTransactionID: string, repor } } else if (fieldName === 'category') { const differentValues = getDifferentValues(transactions, keys); - const policyCategories = getPolicyCategoriesData(report?.policyID ?? '-1'); + const policyCategories = getPolicyCategoriesData(report?.policyID); const availableCategories = Object.values(policyCategories) .filter((category) => differentValues.includes(category.name) && category.enabled && category.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE) .map((e) => e.name); @@ -1172,7 +1176,7 @@ function compareDuplicateTransactionFields(reviewingTransactionID: string, repor keep[fieldName] = firstTransaction?.[keys[0]] ?? firstTransaction?.[keys[1]]; } } else if (fieldName === 'tag') { - const policyTags = getPolicyTagsData(report?.policyID ?? '-1'); + const policyTags = getPolicyTagsData(report?.policyID); const isMultiLevelTags = isMultiLevelTagsPolicyUtils(policyTags); if (isMultiLevelTags) { if (areAllFieldsEqualForKey || !policy?.areTagsEnabled) { @@ -1203,10 +1207,10 @@ function compareDuplicateTransactionFields(reviewingTransactionID: string, repor return {keep, change}; } -function getTransactionID(threadReportID: string): string { +function getTransactionID(threadReportID: string): string | undefined { const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${threadReportID}`]; - const parentReportAction = getReportAction(report?.parentReportID ?? '', report?.parentReportActionID ?? ''); - const IOUTransactionID = isMoneyRequestAction(parentReportAction) ? getOriginalMessage(parentReportAction)?.IOUTransactionID ?? '-1' : '-1'; + const parentReportAction = getReportAction(report?.parentReportID, report?.parentReportActionID); + const IOUTransactionID = isMoneyRequestAction(parentReportAction) ? getOriginalMessage(parentReportAction)?.IOUTransactionID : undefined; return IOUTransactionID; } @@ -1227,11 +1231,11 @@ function buildNewTransactionAfterReviewingDuplicates(reviewDuplicateTransaction: function buildTransactionsMergeParams(reviewDuplicates: OnyxEntry, originalTransaction: Partial): TransactionMergeParams { return { amount: -getAmount(originalTransaction as OnyxEntry, false), - reportID: originalTransaction?.reportID ?? '', - receiptID: originalTransaction?.receipt?.receiptID ?? 0, + reportID: originalTransaction?.reportID, + receiptID: originalTransaction?.receipt?.receiptID ?? CONST.DEFAULT_NUMBER_ID, currency: getCurrency(originalTransaction as OnyxEntry), created: getFormattedCreated(originalTransaction as OnyxEntry), - transactionID: reviewDuplicates?.transactionID ?? '', + transactionID: reviewDuplicates?.transactionID, transactionIDList: removeSettledAndApprovedTransactions(reviewDuplicates?.duplicates ?? []), billable: reviewDuplicates?.billable ?? false, reimbursable: reviewDuplicates?.reimbursable ?? false, diff --git a/src/libs/actions/BankAccounts.ts b/src/libs/actions/BankAccounts.ts index 804db83df33c..7e0ba5cc2a75 100644 --- a/src/libs/actions/BankAccounts.ts +++ b/src/libs/actions/BankAccounts.ts @@ -629,7 +629,7 @@ function verifyIdentityForBankAccount(bankAccountID: number, onfidoData: OnfidoD const parameters: VerifyIdentityForBankAccountParams = { bankAccountID, onfidoData: JSON.stringify(onfidoData), - policyID: policyID ?? '-1', + policyID, }; API.write(WRITE_COMMANDS.VERIFY_IDENTITY_FOR_BANK_ACCOUNT, parameters, getVBBADataForOnyx()); diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 3c1dd4218504..a42739871151 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -709,7 +709,7 @@ function setMoneyRequestReceipt(transactionID: string, source: string, filename: /** * Set custom unit rateID for the transaction draft */ -function setCustomUnitRateID(transactionID: string, customUnitRateID: string) { +function setCustomUnitRateID(transactionID: string, customUnitRateID: string | undefined) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {comment: {customUnit: {customUnitRateID}}}); } @@ -8509,7 +8509,7 @@ function getIOURequestPolicyID(transaction: OnyxEntry, re return workspaceSender?.policyID ?? report?.policyID ?? '-1'; } -function getIOUActionForTransactions(transactionIDList: string[], iouReportID: string): Array> { +function getIOUActionForTransactions(transactionIDList: Array, iouReportID: string | undefined): Array> { return Object.values(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReportID}`] ?? {})?.filter( (reportAction): reportAction is ReportAction => { if (!isMoneyRequestAction(reportAction)) { diff --git a/src/libs/actions/Policy/Category.ts b/src/libs/actions/Policy/Category.ts index 6108581e6c12..1b3267f59163 100644 --- a/src/libs/actions/Policy/Category.ts +++ b/src/libs/actions/Policy/Category.ts @@ -1366,7 +1366,7 @@ function setPolicyCategoryTax(policyID: string, categoryName: string, taxID: str API.write(WRITE_COMMANDS.SET_POLICY_CATEGORY_TAX, parameters, onyxData); } -function getPolicyCategoriesData(policyID: string) { +function getPolicyCategoriesData(policyID: string | undefined) { return allPolicyCategories?.[`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`] ?? {}; } diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index ceb539413947..595c9215aea7 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -196,7 +196,7 @@ Onyx.connect({ key: ONYXKEYS.SESSION, callback: (val) => { sessionEmail = val?.email ?? ''; - sessionAccountID = val?.accountID ?? -1; + sessionAccountID = val?.accountID ?? CONST.DEFAULT_NUMBER_ID; }, }); @@ -258,8 +258,8 @@ function hasInvoicingDetails(policy: OnyxEntry): boolean { * Returns a primary invoice workspace for the user */ function getInvoicePrimaryWorkspace(currentUserLogin: string | undefined): Policy | undefined { - if (PolicyUtils.canSendInvoiceFromWorkspace(activePolicyID ?? '-1')) { - return allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID ?? '-1'}`]; + if (PolicyUtils.canSendInvoiceFromWorkspace(activePolicyID)) { + return allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`]; } const activeAdminWorkspaces = PolicyUtils.getActiveAdminWorkspaces(allPolicies, currentUserLogin); return activeAdminWorkspaces.find((policy) => PolicyUtils.canSendInvoiceFromWorkspace(policy.id)); @@ -341,7 +341,7 @@ function deleteWorkspace(policyID: string, policyName: string) { stateNum: CONST.REPORT.STATE_NUM.APPROVED, statusNum: CONST.REPORT.STATUS_NUM.CLOSED, ...(!isInvoiceReceiverReport && { - oldPolicyName: allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]?.name ?? '', + oldPolicyName: allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]?.name, policyName: '', }), // eslint-disable-next-line @typescript-eslint/naming-convention @@ -810,7 +810,7 @@ function leaveWorkspace(policyID: string) { } function addBillingCardAndRequestPolicyOwnerChange( - policyID: string, + policyID: string | undefined, cardData: { cardNumber: string; cardYear: string; @@ -821,6 +821,10 @@ function addBillingCardAndRequestPolicyOwnerChange( currency: string; }, ) { + if (!policyID) { + return; + } + const {cardNumber, cardYear, cardMonth, cardCVV, addressName, addressZip, currency} = cardData; const optimisticData: OnyxUpdate[] = [ @@ -1862,7 +1866,7 @@ function buildPolicyData(policyOwnerEmail = '', makeMeAdmin = false, policyName failureData.push({ onyxMethod: Onyx.METHOD.SET, key: ONYXKEYS.NVP_ACTIVE_POLICY_ID, - value: activePolicyID ?? '', + value: activePolicyID, }); } @@ -2515,12 +2519,12 @@ function createWorkspaceFromIOUPayment(iouReport: OnyxEntry): WorkspaceF optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oldChatReportID}`, - value: {[reportPreview?.reportActionID ?? '-1']: null}, + value: reportPreview?.reportActionID ? {[reportPreview?.reportActionID]: null} : undefined, }); failureData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oldChatReportID}`, - value: {[reportPreview?.reportActionID ?? '-1']: reportPreview}, + value: reportPreview?.reportActionID ? {[reportPreview?.reportActionID]: reportPreview} : undefined, }); // To optimistically remove the GBR from the DM we need to update the hasOutstandingChildRequest param to false @@ -2562,11 +2566,11 @@ function createWorkspaceFromIOUPayment(iouReport: OnyxEntry): WorkspaceF failureData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${memberData.workspaceChatReportID}`, - value: {[reportPreview?.reportActionID ?? '-1']: null}, + value: reportPreview?.reportActionID ? {[reportPreview?.reportActionID]: null} : undefined, }); // Create the MOVED report action and add it to the DM chat which indicates to the user where the report has been moved - const movedReportAction = ReportUtils.buildOptimisticMovedReportAction(oldPersonalPolicyID ?? '-1', policyID, memberData.workspaceChatReportID, iouReportID, workspaceName); + const movedReportAction = ReportUtils.buildOptimisticMovedReportAction(oldPersonalPolicyID, policyID, memberData.workspaceChatReportID, iouReportID, workspaceName); optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oldChatReportID}`, diff --git a/src/libs/actions/Policy/Tag.ts b/src/libs/actions/Policy/Tag.ts index 9e5b38a1c8eb..9186e1478b36 100644 --- a/src/libs/actions/Policy/Tag.ts +++ b/src/libs/actions/Policy/Tag.ts @@ -1040,7 +1040,7 @@ function downloadTagsCSV(policyID: string, onDownloadFailed: () => void) { fileDownload(ApiUtils.getCommandURL({command: WRITE_COMMANDS.EXPORT_TAGS_CSV}), fileName, '', false, formData, CONST.NETWORK.METHOD.POST, onDownloadFailed); } -function getPolicyTagsData(policyID: string) { +function getPolicyTagsData(policyID: string | undefined) { return allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`] ?? {}; } diff --git a/src/libs/actions/PriorityMode.ts b/src/libs/actions/PriorityMode.ts index 0b186492ab94..95042697c911 100644 --- a/src/libs/actions/PriorityMode.ts +++ b/src/libs/actions/PriorityMode.ts @@ -114,7 +114,7 @@ function tryFocusModeUpdate() { return; } - if (!isValidReport(report) || !isReportParticipant(currentUserAccountID ?? -1, report)) { + if (!isValidReport(report) || !isReportParticipant(currentUserAccountID ?? CONST.DEFAULT_NUMBER_ID, report)) { return; } diff --git a/src/pages/TransactionDuplicate/Confirmation.tsx b/src/pages/TransactionDuplicate/Confirmation.tsx index 520a253469db..9337348fca22 100644 --- a/src/pages/TransactionDuplicate/Confirmation.tsx +++ b/src/pages/TransactionDuplicate/Confirmation.tsx @@ -76,7 +76,8 @@ function Confirmation() { ); const reportTransactionID = TransactionUtils.getTransactionID(report?.reportID ?? ''); - const doesTransactionBelongToReport = reviewDuplicates?.transactionID === reportTransactionID || reviewDuplicates?.duplicates.includes(reportTransactionID); + const doesTransactionIsDuplicate = reportTransactionID ? reviewDuplicates?.duplicates.includes(reportTransactionID) : false; + const doesTransactionBelongToReport = reviewDuplicates?.transactionID === reportTransactionID || doesTransactionIsDuplicate; // eslint-disable-next-line rulesdir/no-negated-variables const shouldShowNotFoundPage = diff --git a/src/pages/workspace/members/WorkspaceOwnerPaymentCardForm.tsx b/src/pages/workspace/members/WorkspaceOwnerPaymentCardForm.tsx index 2b317809c996..1f918dc72331 100644 --- a/src/pages/workspace/members/WorkspaceOwnerPaymentCardForm.tsx +++ b/src/pages/workspace/members/WorkspaceOwnerPaymentCardForm.tsx @@ -30,7 +30,7 @@ function WorkspaceOwnerPaymentCardForm({policy}: WorkspaceOwnerPaymentCardFormPr const styles = useThemeStyles(); const [shouldShowPaymentCardForm, setShouldShowPaymentCardForm] = useState(false); - const policyID = policy?.id ?? '-1'; + const policyID = policy?.id; const checkIfCanBeRendered = useCallback(() => { const changeOwnerErrors = Object.keys(policy?.errorFields?.changeOwner ?? {}); @@ -69,7 +69,6 @@ function WorkspaceOwnerPaymentCardForm({policy}: WorkspaceOwnerPaymentCardFormPr addressZip: values.addressZipCode, currency: values.currency, }; - PolicyActions.addBillingCardAndRequestPolicyOwnerChange(policyID, cardData); }, [policyID], diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index 0cb9a735aad4..1bae98f96d50 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -406,7 +406,7 @@ type OriginalMessageReimbursementDequeued = { /** Model of `moved` report action */ type OriginalMessageMoved = { /** ID of the old policy */ - fromPolicyID: string; + fromPolicyID: string | undefined; /** ID of the new policy */ toPolicyID: string; diff --git a/src/types/onyx/ReviewDuplicates.ts b/src/types/onyx/ReviewDuplicates.ts index 721275b198bc..d97798bcddb7 100644 --- a/src/types/onyx/ReviewDuplicates.ts +++ b/src/types/onyx/ReviewDuplicates.ts @@ -5,7 +5,7 @@ import type {Comment} from './Transaction'; */ type ReviewDuplicates = { /** Transactions ids which are duplicates of selected transcation */ - duplicates: string[]; + duplicates: Array; /** ID of transaction we want to keep */ transactionID: string; From b7729027c6ca6bfda7ead28cad373787be615ecc Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Wed, 18 Dec 2024 14:46:54 +0100 Subject: [PATCH 19/29] fix lint and ts problems --- src/ROUTES.ts | 6 +++ .../ReportActionItem/ReportPreview.tsx | 2 +- src/libs/OptionsListUtils.ts | 2 +- src/libs/ReportActionsUtils.ts | 42 +++++++++------- src/libs/ReportUtils.ts | 50 +++++++++++++------ src/libs/TransactionUtils/index.ts | 6 +-- .../TransactionDuplicate/Confirmation.tsx | 10 ++-- 7 files changed, 73 insertions(+), 45 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 7c8945caf37b..41d87ece730e 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -1162,15 +1162,21 @@ const ROUTES = { }, WORKSPACE_REPORT_FIELDS_LIST_VALUES: { route: 'settings/workspaces/:policyID/reportFields/listValues/:reportFieldID?', + // encodeURIComponent function is a JS built-in function and we cannot pass undefined here + // eslint-disable-next-line rulesdir/no-default-id-values getRoute: (policyID: string, reportFieldID?: string) => `settings/workspaces/${policyID}/reportFields/listValues/${encodeURIComponent(reportFieldID ?? '')}` as const, }, WORKSPACE_REPORT_FIELDS_ADD_VALUE: { route: 'settings/workspaces/:policyID/reportFields/addValue/:reportFieldID?', + // encodeURIComponent function is a JS built-in function and we cannot pass undefined here + // eslint-disable-next-line rulesdir/no-default-id-values getRoute: (policyID: string, reportFieldID?: string) => `settings/workspaces/${policyID}/reportFields/addValue/${encodeURIComponent(reportFieldID ?? '')}` as const, }, WORKSPACE_REPORT_FIELDS_VALUE_SETTINGS: { route: 'settings/workspaces/:policyID/reportFields/:valueIndex/:reportFieldID?', getRoute: (policyID: string, valueIndex: number, reportFieldID?: string) => + // encodeURIComponent function is a JS built-in function and we cannot pass undefined here + // eslint-disable-next-line rulesdir/no-default-id-values `settings/workspaces/${policyID}/reportFields/${valueIndex}/${encodeURIComponent(reportFieldID ?? '')}` as const, }, WORKSPACE_REPORT_FIELDS_EDIT_VALUE: { diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 65cdb4a7d00b..57361b0c9125 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -56,7 +56,7 @@ type ReportPreviewProps = { chatReportID: string; /** The active IOUReport, used for Onyx subscription */ - iouReportID: string; + iouReportID: string | undefined; /** The report's policyID, used for Onyx subscription */ policyID: string; diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index a7f738790f92..32b8ef0b88a4 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -1269,7 +1269,7 @@ function getValidOptions( if (reportPreviewAction) { const iouReportID = ReportActionUtils.getIOUReportIDFromReportActionPreview(reportPreviewAction); - const iouReportActions = allSortedReportActions[iouReportID] ?? []; + const iouReportActions = iouReportID ? allSortedReportActions[iouReportID] : []; const lastIOUAction = iouReportActions.find((iouAction) => iouAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU); if (lastIOUAction) { reportOption.lastIOUCreationDate = lastIOUAction.lastModified; diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index c81131de6b12..97e1d9bac798 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -287,7 +287,7 @@ function isWhisperActionTargetedToOthers(reportAction: OnyxInputOrEntry): reportAction is ReportAction { @@ -895,12 +895,12 @@ function getLastClosedReportAction(reportActions: OnyxEntry): Ony * 4. We will get the second last action from filtered actions because the last * action is always the created action */ -function getFirstVisibleReportActionID(sortedReportActions: ReportAction[] = [], isOffline = false): string { +function getFirstVisibleReportActionID(sortedReportActions: ReportAction[] = [], isOffline = false): string | undefined { if (!Array.isArray(sortedReportActions)) { return ''; } const sortedFilterReportActions = sortedReportActions.filter((action) => !isDeletedAction(action) || (action?.childVisibleActionCount ?? 0) > 0 || isOffline); - return sortedFilterReportActions.length > 1 ? sortedFilterReportActions.at(sortedFilterReportActions.length - 2)?.reportActionID ?? '-1' : ''; + return sortedFilterReportActions.length > 1 ? sortedFilterReportActions.at(sortedFilterReportActions.length - 2)?.reportActionID : ''; } /** @@ -921,7 +921,7 @@ function getLatestReportActionFromOnyxData(onyxData: OnyxUpdate[] | null): NonNu /** * Find the transaction associated with this reportAction, if one exists. */ -function getLinkedTransactionID(reportActionOrID: string | OnyxEntry, reportID?: string): string | null { +function getLinkedTransactionID(reportActionOrID: string | OnyxEntry | undefined, reportID?: string): string | null { const reportAction = typeof reportActionOrID === 'string' ? allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`]?.[reportActionOrID] : reportActionOrID; if (!reportAction || !isMoneyRequestAction(reportAction)) { return null; @@ -930,7 +930,7 @@ function getLinkedTransactionID(reportActionOrID: string | OnyxEntry): string { - return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW) ? getOriginalMessage(reportAction)?.linkedReportID ?? '-1' : '-1'; +function getIOUReportIDFromReportActionPreview(reportAction: OnyxEntry): string | undefined { + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW) ? getOriginalMessage(reportAction)?.linkedReportID : undefined; } /** @@ -1051,7 +1051,11 @@ const iouRequestTypes = new Set>([ * Gets the reportID for the transaction thread associated with a report by iterating over the reportActions and identifying the IOU report actions. * Returns a reportID if there is exactly one transaction thread for the report, and null otherwise. */ -function getOneTransactionThreadReportID(reportID: string, reportActions: OnyxEntry | ReportAction[], isOffline: boolean | undefined = undefined): string | undefined { +function getOneTransactionThreadReportID( + reportID: string | undefined, + reportActions: OnyxEntry | ReportAction[], + isOffline: boolean | undefined = undefined, +): string | undefined { // If the report is not an IOU, Expense report, or Invoice, it shouldn't be treated as one-transaction report. const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; if (report?.type !== CONST.REPORT.TYPE.IOU && report?.type !== CONST.REPORT.TYPE.EXPENSE && report?.type !== CONST.REPORT.TYPE.INVOICE) { @@ -1120,7 +1124,7 @@ function doesReportHaveVisibleActions(reportID: string, canUserPerformWriteActio return visibleReportActionsWithoutTaskSystemMessage.length > 0; } -function getAllReportActions(reportID: string): ReportActions { +function getAllReportActions(reportID: string | undefined): ReportActions { return allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? {}; } @@ -1494,7 +1498,7 @@ function isReportActionUnread(reportAction: OnyxEntry, lastReadTim */ function isCurrentActionUnread(report: OnyxEntry, reportAction: ReportAction): boolean { const lastReadTime = report?.lastReadTime ?? ''; - const sortedReportActions = getSortedReportActions(Object.values(getAllReportActions(report?.reportID ?? '-1'))); + const sortedReportActions = getSortedReportActions(Object.values(getAllReportActions(report?.reportID))); const currentActionIndex = sortedReportActions.findIndex((action) => action.reportActionID === reportAction.reportActionID); if (currentActionIndex === -1) { return false; @@ -1554,7 +1558,7 @@ function getDismissedViolationMessageText(originalMessage: ReportAction) { @@ -1571,7 +1575,7 @@ function didMessageMentionCurrentUser(reportAction: OnyxInputOrEntry'); + return accountIDsFromMessage.includes(currentUserAccountID ?? CONST.DEFAULT_NUMBER_ID) || emailsFromMessage.includes(currentEmail) || message.includes(''); } /** @@ -1586,9 +1590,9 @@ function wasActionTakenByCurrentUser(reportAction: OnyxInputOrEntry { const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; - const reportActions = getAllReportActions(report?.reportID ?? ''); + const reportActions = getAllReportActions(report?.reportID); const action = Object.values(reportActions ?? {})?.find((reportAction) => { - const IOUTransactionID = isMoneyRequestAction(reportAction) ? getOriginalMessage(reportAction)?.IOUTransactionID : -1; + const IOUTransactionID = isMoneyRequestAction(reportAction) ? getOriginalMessage(reportAction)?.IOUTransactionID : CONST.DEFAULT_NUMBER_ID; return IOUTransactionID === transactionID; }); return action; @@ -1631,7 +1635,7 @@ function getExportIntegrationActionFragments(reportAction: OnyxEntry '2022-11-14'; const base62ReportID = getBase62ReportID(Number(reportID)); @@ -1765,7 +1769,7 @@ function getRenamedAction(reportAction: OnyxEntry>) { const originalMessage = getOriginalMessage(reportAction); - const submittersNames = PersonalDetailsUtils.getPersonalDetailsByIDs(originalMessage?.submittersAccountIDs ?? [], currentUserAccountID ?? -1).map( + const submittersNames = PersonalDetailsUtils.getPersonalDetailsByIDs(originalMessage?.submittersAccountIDs ?? [], currentUserAccountID ?? CONST.DEFAULT_NUMBER_ID).map( ({displayName, login}) => displayName ?? login ?? 'Unknown Submitter', ); return Localize.translateLocal('workspaceActions.removedFromApprovalWorkflow', {submittersNames, count: submittersNames.length}); @@ -1792,9 +1796,9 @@ function getCardIssuedMessage(reportAction: OnyxEntry, shouldRende ? getOriginalMessage(reportAction) : undefined; - const assigneeAccountID = cardIssuedActionOriginalMessage?.assigneeAccountID ?? -1; - const cardID = cardIssuedActionOriginalMessage?.cardID ?? -1; - const assigneeDetails = PersonalDetailsUtils.getPersonalDetailsByIDs([assigneeAccountID], currentUserAccountID ?? -1).at(0); + const assigneeAccountID = cardIssuedActionOriginalMessage?.assigneeAccountID ?? CONST.DEFAULT_NUMBER_ID; + const cardID = cardIssuedActionOriginalMessage?.cardID ?? CONST.DEFAULT_NUMBER_ID; + const assigneeDetails = PersonalDetailsUtils.getPersonalDetailsByIDs([assigneeAccountID], currentUserAccountID ?? CONST.DEFAULT_NUMBER_ID).at(0); const isPolicyAdmin = PolicyUtils.isPolicyAdmin(PolicyUtils.getPolicy(policyID)); const assignee = shouldRenderHTML ? `` : assigneeDetails?.firstName ?? assigneeDetails?.login ?? ''; const navigateRoute = isPolicyAdmin ? ROUTES.EXPENSIFY_CARD_DETAILS.getRoute(policyID, String(cardID)) : ROUTES.SETTINGS_DOMAINCARD_DETAIL.getRoute(String(cardID)); diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index c71da3fbdb87..e2128a990826 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -893,7 +893,7 @@ function isDraftReport(reportID: string | undefined): boolean { /** * Returns the report */ -function getReport(reportID: string): OnyxEntry { +function getReport(reportID: string | undefined): OnyxEntry { return allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; } @@ -1145,7 +1145,7 @@ function isSettled(reportOrID: OnyxInputOrEntry | SearchReport | string /** * Whether the current user is the submitter of the report */ -function isCurrentUserSubmitter(reportID: string): boolean { +function isCurrentUserSubmitter(reportID: string | undefined): boolean { if (!allReports) { return false; } @@ -1832,7 +1832,7 @@ function hasOnlyNonReimbursableTransactions(iouReportID: string | undefined): bo /** * Checks if a report has only one transaction associated with it */ -function isOneTransactionReport(reportID: string): boolean { +function isOneTransactionReport(reportID: string | undefined): boolean { const reportActions = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? ([] as ReportAction[]); return getOneTransactionThreadReportID(reportID, reportActions) !== null; } @@ -1840,7 +1840,7 @@ function isOneTransactionReport(reportID: string): boolean { /* * Whether the report contains only one expense and the expense should be paid later */ -function isPayAtEndExpenseReport(reportID: string, transactions: Transaction[] | undefined): boolean { +function isPayAtEndExpenseReport(reportID: string | undefined, transactions: Transaction[] | undefined): boolean { if ((!!transactions && transactions.length !== 1) || !isOneTransactionReport(reportID)) { return false; } @@ -3511,7 +3511,7 @@ function getTransactionsWithReceipts(iouReportID: string | undefined): Transacti * or as soon as one receipt request is done scanning, we have at least one * "ready" expense, and we remove this indicator to show the partial report total. */ -function areAllRequestsBeingSmartScanned(iouReportID: string, reportPreviewAction: OnyxEntry): boolean { +function areAllRequestsBeingSmartScanned(iouReportID: string | undefined, reportPreviewAction: OnyxEntry): boolean { const transactionsWithReceipts = getTransactionsWithReceipts(iouReportID); // If we have more requests than requests with receipts, we have some manual requests if (getNumberOfMoneyRequests(reportPreviewAction) > transactionsWithReceipts.length) { @@ -3539,7 +3539,10 @@ function getLinkedTransaction(reportAction: OnyxEntry { if (!isMoneyRequestAction(action)) { @@ -3568,7 +3571,7 @@ function getReportActionWithMissingSmartscanFields(iouReportID: string): ReportA /** * Check if iouReportID has required missing fields */ -function shouldShowRBRForMissingSmartscanFields(iouReportID: string): boolean { +function shouldShowRBRForMissingSmartscanFields(iouReportID: string | undefined): boolean { return !!getReportActionWithMissingSmartscanFields(iouReportID); } @@ -6504,7 +6507,10 @@ function shouldDisplayViolationsRBRInLHN(report: OnyxEntry, transactionV /** * Checks to see if a report contains a violation */ -function hasViolations(reportID: string, transactionViolations: OnyxCollection, shouldShowInReview?: boolean): boolean { +function hasViolations(reportID: string | undefined, transactionViolations: OnyxCollection, shouldShowInReview?: boolean): boolean { + if (!reportID) { + return false; + } const transactions = reportsTransactions[reportID] ?? []; return transactions.some((transaction) => hasViolation(transaction.transactionID, transactionViolations, shouldShowInReview)); } @@ -6512,7 +6518,10 @@ function hasViolations(reportID: string, transactionViolations: OnyxCollection, shouldShowInReview?: boolean): boolean { +function hasWarningTypeViolations(reportID: string | undefined, transactionViolations: OnyxCollection, shouldShowInReview?: boolean): boolean { + if (!reportID) { + return false; + } const transactions = reportsTransactions[reportID] ?? []; return transactions.some((transaction) => hasWarningTypeViolation(transaction.transactionID, transactionViolations, shouldShowInReview)); } @@ -6520,12 +6529,18 @@ function hasWarningTypeViolations(reportID: string, transactionViolations: OnyxC /** * Checks to see if a report contains a violation of type `notice` */ -function hasNoticeTypeViolations(reportID: string, transactionViolations: OnyxCollection, shouldShowInReview?: boolean): boolean { +function hasNoticeTypeViolations(reportID: string | undefined, transactionViolations: OnyxCollection, shouldShowInReview?: boolean): boolean { + if (!reportID) { + return false; + } const transactions = reportsTransactions[reportID] ?? []; return transactions.some((transaction) => hasNoticeTypeViolation(transaction.transactionID, transactionViolations, shouldShowInReview)); } -function hasReportViolations(reportID: string) { +function hasReportViolations(reportID: string | undefined) { + if (!reportID) { + return false; + } const reportViolations = allReportsViolations?.[`${ONYXKEYS.COLLECTION.REPORT_VIOLATIONS}${reportID}`]; return Object.values(reportViolations ?? {}).some((violations) => !isEmptyObject(violations)); } @@ -8125,7 +8140,7 @@ function isAllowedToSubmitDraftExpenseReport(report: OnyxEntry): boolean /** * What missing payment method does this report action indicate, if any? */ -function getIndicatedMissingPaymentMethod(userWallet: OnyxEntry, reportId: string, reportAction: ReportAction): MissingPaymentMethod | undefined { +function getIndicatedMissingPaymentMethod(userWallet: OnyxEntry, reportId: string | undefined, reportAction: ReportAction): MissingPaymentMethod | undefined { const isSubmitterOfUnsettledReport = isCurrentUserSubmitter(reportId) && !isSettled(reportId); if (!isSubmitterOfUnsettledReport || !isReimbursementQueuedAction(reportAction)) { return undefined; @@ -8141,7 +8156,7 @@ function getIndicatedMissingPaymentMethod(userWallet: OnyxEntry, rep /** * Checks if report chat contains missing payment method */ -function hasMissingPaymentMethod(userWallet: OnyxEntry, iouReportID: string): boolean { +function hasMissingPaymentMethod(userWallet: OnyxEntry, iouReportID: string | undefined): boolean { const reportActions = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReportID}`] ?? {}; return Object.values(reportActions) .filter(Boolean) @@ -8173,7 +8188,10 @@ function getTripIDFromTransactionParentReport(transactionParentReport: OnyxEntry /** * Checks if report contains actions with errors */ -function hasActionsWithErrors(reportID: string): boolean { +function hasActionsWithErrors(reportID: string | undefined): boolean { + if (!reportID) { + return false; + } const reportActions = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? {}; return Object.values(reportActions) .filter(Boolean) @@ -8573,7 +8591,7 @@ function getApprovalChain(policy: OnyxEntry, expenseReport: OnyxEntry): boolean { /** * Check if transaction is on hold for the given transactionID */ -function isOnHoldByTransactionID(transactionID: string): boolean { +function isOnHoldByTransactionID(transactionID: string | undefined | null): boolean { if (!transactionID) { return false; } @@ -1062,7 +1062,7 @@ function removeSettledAndApprovedTransactions(transactionIDs: Array; change: FieldsToChange} { const transactionViolations = allTransactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${reviewingTransactionID}`]; @@ -1207,7 +1207,7 @@ function compareDuplicateTransactionFields( return {keep, change}; } -function getTransactionID(threadReportID: string): string | undefined { +function getTransactionID(threadReportID: string | undefined): string | undefined { const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${threadReportID}`]; const parentReportAction = getReportAction(report?.parentReportID, report?.parentReportActionID); const IOUTransactionID = isMoneyRequestAction(parentReportAction) ? getOriginalMessage(parentReportAction)?.IOUTransactionID : undefined; diff --git a/src/pages/TransactionDuplicate/Confirmation.tsx b/src/pages/TransactionDuplicate/Confirmation.tsx index 9337348fca22..1aadf9097d7a 100644 --- a/src/pages/TransactionDuplicate/Confirmation.tsx +++ b/src/pages/TransactionDuplicate/Confirmation.tsx @@ -39,8 +39,8 @@ function Confirmation() { const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const [reviewDuplicates, reviewDuplicatesResult] = useOnyx(ONYXKEYS.REVIEW_DUPLICATES); const transaction = useMemo(() => TransactionUtils.buildNewTransactionAfterReviewingDuplicates(reviewDuplicates), [reviewDuplicates]); - const transactionID = TransactionUtils.getTransactionID(route.params.threadReportID ?? ''); - const compareResult = TransactionUtils.compareDuplicateTransactionFields(transactionID, reviewDuplicates?.reportID ?? '-1'); + const transactionID = TransactionUtils.getTransactionID(route.params.threadReportID); + const compareResult = TransactionUtils.compareDuplicateTransactionFields(transactionID, reviewDuplicates?.reportID); const {goBack} = useReviewDuplicatesNavigation(Object.keys(compareResult.change ?? {}), 'confirmation', route.params.threadReportID, route.params.backTo); const [report, reportResult] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${route.params.threadReportID}`); const [iouReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${transaction?.reportID}`); @@ -54,12 +54,12 @@ function Confirmation() { const mergeDuplicates = useCallback(() => { IOU.mergeDuplicates(transactionsMergeParams); - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(reportAction?.childReportID ?? '-1')); + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(reportAction?.childReportID)); }, [reportAction?.childReportID, transactionsMergeParams]); const resolveDuplicates = useCallback(() => { IOU.resolveDuplicates(transactionsMergeParams); - Navigation.dismissModal(reportAction?.childReportID ?? '-1'); + Navigation.dismissModal(reportAction?.childReportID); }, [transactionsMergeParams, reportAction?.childReportID]); const contextValue = useMemo( @@ -75,7 +75,7 @@ function Confirmation() { [report, reportAction], ); - const reportTransactionID = TransactionUtils.getTransactionID(report?.reportID ?? ''); + const reportTransactionID = TransactionUtils.getTransactionID(report?.reportID); const doesTransactionIsDuplicate = reportTransactionID ? reviewDuplicates?.duplicates.includes(reportTransactionID) : false; const doesTransactionBelongToReport = reviewDuplicates?.transactionID === reportTransactionID || doesTransactionIsDuplicate; From bcb22a33d731947a97b7e003b4f1ac729d639022 Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Wed, 18 Dec 2024 15:42:32 +0100 Subject: [PATCH 20/29] ts fixes --- .../ReportActionItem/ReportPreview.tsx | 13 +++-- src/libs/OptionsListUtils.ts | 52 +++++++++++-------- src/libs/ReportActionsUtils.ts | 9 ++-- src/libs/ReportUtils.ts | 10 ++-- src/libs/TransactionUtils/index.ts | 6 +-- .../report/ContextMenu/ContextMenuActions.tsx | 5 +- .../types.ts | 2 +- src/types/onyx/ReportAction.ts | 2 +- 8 files changed, 56 insertions(+), 43 deletions(-) diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 57361b0c9125..3d216a1e7a41 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -103,7 +103,7 @@ function ReportPreview({ const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS); const [userWallet] = useOnyx(ONYXKEYS.USER_WALLET); const [invoiceReceiverPolicy] = useOnyx( - `${ONYXKEYS.COLLECTION.POLICY}${chatReport?.invoiceReceiver && 'policyID' in chatReport.invoiceReceiver ? chatReport.invoiceReceiver.policyID : -1}`, + `${ONYXKEYS.COLLECTION.POLICY}${chatReport?.invoiceReceiver && 'policyID' in chatReport.invoiceReceiver ? chatReport.invoiceReceiver.policyID : CONST.DEFAULT_NUMBER_ID}`, ); const theme = useTheme(); const styles = useThemeStyles(); @@ -144,10 +144,10 @@ function ReportPreview({ const shouldDisableApproveButton = shouldShowApproveButton && !ReportUtils.isAllowedToApproveExpenseReport(iouReport); const {nonHeldAmount, fullAmount, hasValidNonHeldAmount} = ReportUtils.getNonHeldAndFullAmount(iouReport, shouldShowPayButton); - const hasOnlyHeldExpenses = ReportUtils.hasOnlyHeldExpenses(iouReport?.reportID ?? ''); - const hasHeldExpenses = ReportUtils.hasHeldExpenses(iouReport?.reportID ?? ''); + const hasOnlyHeldExpenses = ReportUtils.hasOnlyHeldExpenses(iouReport?.reportID); + const hasHeldExpenses = ReportUtils.hasHeldExpenses(iouReport?.reportID); - const managerID = iouReport?.managerID ?? action.childManagerAccountID ?? 0; + const managerID = iouReport?.managerID ?? action.childManagerAccountID ?? CONST.DEFAULT_NUMBER_ID; const {totalDisplaySpend, reimbursableSpend} = ReportUtils.getMoneyRequestSpendBreakdown(iouReport); const iouSettled = ReportUtils.isSettled(iouReportID) || action?.childStatusNum === CONST.REPORT.STATUS_NUM.REIMBURSED; @@ -189,9 +189,8 @@ function ReportPreview({ const lastThreeReceipts = lastThreeTransactions.map((transaction) => ({...ReceiptUtils.getThumbnailAndImageURIs(transaction), transaction})); const showRTERViolationMessage = numberOfRequests === 1 && - TransactionUtils.hasPendingUI(allTransactions.at(0), TransactionUtils.getTransactionViolations(allTransactions.at(0)?.transactionID ?? '-1', transactionViolations)); - const shouldShowBrokenConnectionViolation = - numberOfRequests === 1 && TransactionUtils.shouldShowBrokenConnectionViolation(allTransactions.at(0)?.transactionID ?? '-1', iouReport, policy); + TransactionUtils.hasPendingUI(allTransactions.at(0), TransactionUtils.getTransactionViolations(allTransactions.at(0)?.transactionID, transactionViolations)); + const shouldShowBrokenConnectionViolation = numberOfRequests === 1 && TransactionUtils.shouldShowBrokenConnectionViolation(allTransactions.at(0)?.transactionID, iouReport, policy); let formattedMerchant = numberOfRequests === 1 ? TransactionUtils.getMerchant(allTransactions.at(0)) : null; const formattedDescription = numberOfRequests === 1 ? TransactionUtils.getDescription(allTransactions.at(0)) : null; diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 96eb9f37a5d8..b204b4d5f1d5 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -357,7 +357,7 @@ function isPersonalDetailsReady(personalDetails: OnyxEntry) * Get the participant option for a report. */ function getParticipantsOption(participant: ReportUtils.OptionData | Participant, personalDetails: OnyxEntry): Participant { - const detail = getPersonalDetailsForAccountIDs([participant.accountID ?? -1], personalDetails)[participant.accountID ?? -1]; + const detail = getPersonalDetailsForAccountIDs([participant.accountID ?? CONST.DEFAULT_NUMBER_ID], personalDetails)[participant.accountID ?? CONST.DEFAULT_NUMBER_ID]; // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const login = detail?.login || participant.login || ''; const displayName = LocalePhoneNumber.formatPhoneNumber(PersonalDetailsUtils.getDisplayNameOrDefault(detail, login || participant.text)); @@ -365,7 +365,7 @@ function getParticipantsOption(participant: ReportUtils.OptionData | Participant return { keyForList: String(detail?.accountID), login, - accountID: detail?.accountID ?? -1, + accountID: detail?.accountID ?? CONST.DEFAULT_NUMBER_ID, text: displayName, firstName: detail?.firstName ?? '', lastName: detail?.lastName ?? '', @@ -492,11 +492,11 @@ function getIOUReportIDOfLastAction(report: OnyxEntry): string | undefin * Get the last message text from the report directly or from other sources for special cases. */ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails: Partial | null, policy?: OnyxEntry): string { - const reportID = report?.reportID ?? '-1'; - const lastReportAction = lastVisibleReportActions[reportID] ?? null; + const reportID = report?.reportID; + const lastReportAction = reportID ? lastVisibleReportActions[reportID] : undefined; // some types of actions are filtered out for lastReportAction, in some cases we need to check the actual last action - const lastOriginalReportAction = lastReportActions[reportID] ?? null; + const lastOriginalReportAction = reportID ? lastReportActions[reportID] : undefined; let lastMessageTextFromReport = ''; if (report?.private_isArchived) { @@ -526,12 +526,14 @@ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails lastMessageTextFromReport = ReportUtils.formatReportLastMessageText(properSchemaForMoneyRequestMessage); } else if (ReportActionUtils.isReportPreviewAction(lastReportAction)) { const iouReport = ReportUtils.getReportOrDraftReport(ReportActionUtils.getIOUReportIDFromReportActionPreview(lastReportAction)); - const lastIOUMoneyReportAction = allSortedReportActions[iouReport?.reportID ?? '-1']?.find( - (reportAction, key): reportAction is ReportAction => - ReportActionUtils.shouldReportActionBeVisible(reportAction, key, ReportUtils.canUserPerformWriteAction(report)) && - reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && - ReportActionUtils.isMoneyRequestAction(reportAction), - ); + const lastIOUMoneyReportAction = iouReport?.reportID + ? allSortedReportActions[iouReport?.reportID]?.find( + (reportAction, key): reportAction is ReportAction => + ReportActionUtils.shouldReportActionBeVisible(reportAction, key, ReportUtils.canUserPerformWriteAction(report)) && + reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && + ReportActionUtils.isMoneyRequestAction(reportAction), + ) + : undefined; const reportPreviewMessage = ReportUtils.getReportPreviewMessage( !isEmptyObject(iouReport) ? iouReport : null, lastIOUMoneyReportAction, @@ -548,9 +550,9 @@ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails lastMessageTextFromReport = ReportUtils.getReimbursementDeQueuedActionMessage(lastReportAction, report, true); } else if (ReportActionUtils.isDeletedParentAction(lastReportAction) && ReportUtils.isChatReport(report)) { lastMessageTextFromReport = ReportUtils.getDeletedParentActionMessageForChatReport(lastReportAction); - } else if (ReportActionUtils.isPendingRemove(lastReportAction) && ReportActionUtils.isThreadParentMessage(lastReportAction, report?.reportID ?? '-1')) { + } else if (ReportActionUtils.isPendingRemove(lastReportAction) && ReportActionUtils.isThreadParentMessage(lastReportAction, report?.reportID)) { lastMessageTextFromReport = Localize.translateLocal('parentReportAction.hiddenMessage'); - } else if (ReportUtils.isReportMessageAttachment({text: report?.lastMessageText ?? '-1', html: report?.lastMessageHtml, translationKey: report?.lastMessageTranslationKey, type: ''})) { + } else if (ReportUtils.isReportMessageAttachment({text: report?.lastMessageText, html: report?.lastMessageHtml, translationKey: report?.lastMessageTranslationKey, type: ''})) { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing lastMessageTextFromReport = `[${Localize.translateLocal((report?.lastMessageTranslationKey || 'common.attachment') as TranslationPaths)}]`; } else if (ReportActionUtils.isModifiedExpenseAction(lastReportAction)) { @@ -691,7 +693,7 @@ function createOption( hasMultipleParticipants = personalDetailList.length > 1 || result.isChatRoom || result.isPolicyExpenseChat || ReportUtils.isGroupChat(report); subtitle = ReportUtils.getChatRoomSubtitle(report); - const lastActorDetails = personalDetailMap[report.lastActorAccountID ?? -1] ?? null; + const lastActorDetails = personalDetailMap[report.lastActorAccountID ?? CONST.DEFAULT_NUMBER_ID] ?? null; const lastActorDisplayName = getLastActorDisplayName(lastActorDetails, hasMultipleParticipants); const lastMessageTextFromReport = getLastMessageTextForReport(report, lastActorDetails); let lastMessageText = lastMessageTextFromReport; @@ -906,7 +908,13 @@ function createOptionList(personalDetails: OnyxEntry, repor const allPersonalDetailsOptions = Object.values(personalDetails ?? {}).map((personalDetail) => ({ item: personalDetail, - ...createOption([personalDetail?.accountID ?? -1], personalDetails, reportMapForAccountIDs[personalDetail?.accountID ?? -1], {}, {showPersonalDetails: true}), + ...createOption( + [personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID], + personalDetails, + reportMapForAccountIDs[personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID], + {}, + {showPersonalDetails: true}, + ), })); return { @@ -1120,7 +1128,7 @@ function getValidOptions( shouldBoldTitleByDefault = true, }: GetOptionsConfig = {}, ): Options { - const topmostReportId = Navigation.getTopmostReportId() ?? '-1'; + const topmostReportId = Navigation.getTopmostReportId(); // Filter out all the reports that shouldn't be displayed const filteredReportOptions = options.reports.filter((option) => { @@ -1234,7 +1242,7 @@ function getValidOptions( const shouldShowInvoiceRoom = includeInvoiceRooms && ReportUtils.isInvoiceRoom(reportOption.item) && - ReportUtils.isPolicyAdmin(reportOption.policyID ?? '', policies) && + ReportUtils.isPolicyAdmin(reportOption.policyID, policies) && !reportOption.private_isArchived && PolicyUtils.canSendInvoiceFromWorkspace(reportOption.policyID); @@ -1279,7 +1287,7 @@ function getValidOptions( if (reportPreviewAction) { const iouReportID = ReportActionUtils.getIOUReportIDFromReportActionPreview(reportPreviewAction); const iouReportActions = iouReportID ? allSortedReportActions[iouReportID] : []; - const lastIOUAction = iouReportActions.find((iouAction) => iouAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU); + const lastIOUAction = iouReportActions?.find((iouAction) => iouAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU); if (lastIOUAction) { reportOption.lastIOUCreationDate = lastIOUAction.lastModified; } @@ -1374,8 +1382,8 @@ function getIOUConfirmationOptionsFromPayeePersonalDetail(personalDetail: OnyxEn ], descriptiveText: amountText ?? '', login: personalDetail?.login ?? '', - accountID: personalDetail?.accountID ?? -1, - keyForList: String(personalDetail?.accountID ?? -1), + accountID: personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID, + keyForList: String(personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID), }; } @@ -1453,14 +1461,14 @@ function formatMemberForList(member: ReportUtils.OptionData): MemberForList { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing alternateText: member.alternateText || member.login || '', // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - keyForList: member.keyForList || String(accountID ?? -1) || '', + keyForList: member.keyForList || String(accountID ?? CONST.DEFAULT_NUMBER_ID) || '', isSelected: member.isSelected ?? false, isDisabled: member.isDisabled ?? false, accountID, login: member.login ?? '', icons: member.icons, pendingAction: member.pendingAction, - reportID: member.reportID ?? '-1', + reportID: member.reportID, }; } diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 97e1d9bac798..6c43251a6143 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -348,7 +348,7 @@ function isInviteOrRemovedAction( /** * Returns whether the comment is a thread parent message/the first message in a thread */ -function isThreadParentMessage(reportAction: OnyxEntry, reportID: string): boolean { +function isThreadParentMessage(reportAction: OnyxEntry, reportID: string | undefined): boolean { const {childType, childVisibleActionCount = 0, childReportID} = reportAction ?? {}; return childType === CONST.REPORT.TYPE.CHAT && (childVisibleActionCount > 0 || String(childReportID) === reportID); } @@ -789,12 +789,15 @@ function getLastVisibleAction(reportID: string, canUserPerformWriteAction?: bool return sortedReportActions.at(0); } -function formatLastMessageText(lastMessageText: string) { +function formatLastMessageText(lastMessageText: string | undefined) { const trimmedMessage = String(lastMessageText).trim(); // Add support for inline code containing only space characters // The message will appear as a blank space in the LHN - if ((trimmedMessage === '' && lastMessageText.length > 0) || (trimmedMessage === '?\u2026' && lastMessageText.length > CONST.REPORT.MIN_LENGTH_LAST_MESSAGE_WITH_ELLIPSIS)) { + if ( + (trimmedMessage === '' && (lastMessageText?.length ?? 0) > 0) || + (trimmedMessage === '?\u2026' && (lastMessageText?.length ?? 0) > CONST.REPORT.MIN_LENGTH_LAST_MESSAGE_WITH_ELLIPSIS) + ) { return ' '; } diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index d006136995c4..ba51bf955a5f 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1723,7 +1723,7 @@ function isPolicyExpenseChatAdmin(report: OnyxEntry, policies: OnyxColle /** * Checks if the current user is the admin of the policy. */ -function isPolicyAdmin(policyID: string, policies: OnyxCollection): boolean { +function isPolicyAdmin(policyID: string | undefined, policies: OnyxCollection): boolean { const policyRole = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]?.role; return policyRole === CONST.POLICY.ROLE.ADMIN; @@ -2088,7 +2088,7 @@ function canShowReportRecipientLocalTime(personalDetails: OnyxEntry): boolean { /** * Check if the report is the parent report of the currently viewed report or at least one child report has report action */ -function shouldHideReport(report: OnyxEntry, currentReportId: string): boolean { +function shouldHideReport(report: OnyxEntry, currentReportId: string | undefined): boolean { const currentReport = getReportOrDraftReport(currentReportId); const parentReport = getParentReport(!isEmptyObject(currentReport) ? currentReport : undefined); const reportActions = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report?.reportID}`] ?? {}; @@ -6652,7 +6652,7 @@ function hasReportErrorsOtherThanFailedReceipt(report: Report, doesReportHaveVio type ShouldReportBeInOptionListParams = { report: OnyxEntry; - currentReportId: string; + currentReportId: string | undefined; isInFocusMode: boolean; betas: OnyxEntry; policies: OnyxCollection; @@ -7889,7 +7889,7 @@ function hasHeldExpenses(iouReportID?: string, allReportTransactions?: SearchTra /** * Check if all expenses in the Report are on hold */ -function hasOnlyHeldExpenses(iouReportID: string, allReportTransactions?: SearchTransaction[]): boolean { +function hasOnlyHeldExpenses(iouReportID: string | undefined, allReportTransactions?: SearchTransaction[]): boolean { const reportTransactions = allReportTransactions ?? reportsTransactions[iouReportID ?? ''] ?? []; return reportTransactions.length > 0 && !reportTransactions.some((transaction) => !isOnHoldTransactionUtils(transaction)); } diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index 6f1f29f37671..185bce8aa3eb 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -707,7 +707,7 @@ function hasMissingSmartscanFields(transaction: OnyxInputOrEntry): /** * Get all transaction violations of the transaction with given tranactionID. */ -function getTransactionViolations(transactionID: string, transactionViolations: OnyxCollection | null): TransactionViolations | null { +function getTransactionViolations(transactionID: string | undefined, transactionViolations: OnyxCollection | null): TransactionViolations | null { return transactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transactionID] ?? null; } @@ -727,7 +727,7 @@ function hasPendingRTERViolation(transactionViolations?: TransactionViolations | /** * Check if there is broken connection violation. */ -function hasBrokenConnectionViolation(transactionID: string): boolean { +function hasBrokenConnectionViolation(transactionID: string | undefined): boolean { const violations = getTransactionViolations(transactionID, allTransactionViolations); return !!violations?.find( (violation) => @@ -739,7 +739,7 @@ function hasBrokenConnectionViolation(transactionID: string): boolean { /** * Check if user should see broken connection violation warning. */ -function shouldShowBrokenConnectionViolation(transactionID: string, report: OnyxEntry | SearchReport, policy: OnyxEntry): boolean { +function shouldShowBrokenConnectionViolation(transactionID: string | undefined, report: OnyxEntry | SearchReport, policy: OnyxEntry): boolean { return hasBrokenConnectionViolation(transactionID) && (!isPolicyAdmin(policy) || isOpenExpenseReport(report) || (isProcessingReport(report) && isInstantSubmitEnabled(policy))); } diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx index b8cdde2ecff3..11927b5bdea0 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx @@ -41,7 +41,10 @@ function getActionHtml(reportAction: OnyxInputOrEntry): string { } /** Sets the HTML string to Clipboard */ -function setClipboardMessage(content: string) { +function setClipboardMessage(content: string | undefined) { + if (!content) { + return; + } if (!Clipboard.canSetHtml()) { Clipboard.setString(Parser.htmlToMarkdown(content)); } else { diff --git a/src/pages/home/report/ReportActionItemMessageHeaderSender/types.ts b/src/pages/home/report/ReportActionItemMessageHeaderSender/types.ts index 44a27de119e6..68036c7247f4 100644 --- a/src/pages/home/report/ReportActionItemMessageHeaderSender/types.ts +++ b/src/pages/home/report/ReportActionItemMessageHeaderSender/types.ts @@ -2,7 +2,7 @@ import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; type ReportActionItemMessageHeaderSenderProps = { /** Text to display */ - fragmentText: string; + fragmentText: string | undefined; /** Users accountID */ accountID: number; diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts index 2c97fda0dc0a..2df1d904fca7 100644 --- a/src/types/onyx/ReportAction.ts +++ b/src/types/onyx/ReportAction.ts @@ -17,7 +17,7 @@ type Message = { type: string; /** The text content of the fragment. */ - text: string; + text: string | undefined; /** The html content of the fragment. */ html?: string; From b39b7aeb0b300490b686f2f4f8247a8bc11ebdfd Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Wed, 18 Dec 2024 15:45:46 +0100 Subject: [PATCH 21/29] adjusted check --- src/libs/OptionsListUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index b204b4d5f1d5..bb795c575bf4 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -1286,7 +1286,7 @@ function getValidOptions( if (reportPreviewAction) { const iouReportID = ReportActionUtils.getIOUReportIDFromReportActionPreview(reportPreviewAction); - const iouReportActions = iouReportID ? allSortedReportActions[iouReportID] : []; + const iouReportActions = iouReportID && allSortedReportActions[iouReportID] ? allSortedReportActions[iouReportID] : []; const lastIOUAction = iouReportActions?.find((iouAction) => iouAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU); if (lastIOUAction) { reportOption.lastIOUCreationDate = lastIOUAction.lastModified; From 1ac0ddab7819ccc010427b7cf65c5ca66eb4f459 Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Wed, 18 Dec 2024 15:52:08 +0100 Subject: [PATCH 22/29] fix lint --- src/libs/actions/Report.ts | 6 +++--- .../home/report/ContextMenu/ContextMenuActions.tsx | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index fbdf2a4fe1f3..5859271f4efb 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -842,7 +842,7 @@ function clearAvatarErrors(reportID: string) { * @param participantAccountIDList The list of accountIDs that are included in a new chat, not including the user creating it */ function openReport( - reportID: string, + reportID: string | undefined, reportActionID?: string, participantLoginList: string[] = [], newReportObject?: OptimisticChatReport, @@ -1394,8 +1394,8 @@ function readNewestAction(reportID: string, shouldResetUnreadMarker = false) { /** * Sets the last read time on a report */ -function markCommentAsUnread(reportID: string, reportActionCreated: string) { - if (reportID === '-1') { +function markCommentAsUnread(reportID: string | undefined, reportActionCreated: string) { + if (reportID === '-1' || !reportID) { Log.warn('7339cd6c-3263-4f89-98e5-730f0be15784 Invalid report passed to MarkCommentAsUnread. Not calling the API because it wil fail.'); return; } diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx index 11927b5bdea0..5155cf9419b8 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx @@ -196,11 +196,11 @@ const ContextMenuActions: ContextMenuAction[] = [ // is false, so we need to pass true here to override this condition. ReportActionComposeFocusManager.focus(true); }); - Report.navigateToAndOpenChildReport(reportAction?.childReportID ?? '-1', reportAction, originalReportID); + Report.navigateToAndOpenChildReport(reportAction?.childReportID, reportAction, originalReportID); }); return; } - Report.navigateToAndOpenChildReport(reportAction?.childReportID ?? '-1', reportAction, originalReportID); + Report.navigateToAndOpenChildReport(reportAction?.childReportID, reportAction, originalReportID); }, getDescription: () => {}, }, @@ -211,7 +211,7 @@ const ContextMenuActions: ContextMenuAction[] = [ successIcon: Expensicons.Checkmark, shouldShow: ({type, isUnreadChat}) => type === CONST.CONTEXT_MENU_TYPES.REPORT_ACTION || (type === CONST.CONTEXT_MENU_TYPES.REPORT && !isUnreadChat), onPress: (closePopover, {reportAction, reportID}) => { - const originalReportID = ReportUtils.getOriginalReportID(reportID, reportAction) ?? '-1'; + const originalReportID = ReportUtils.getOriginalReportID(reportID, reportAction); Report.markCommentAsUnread(originalReportID, reportAction?.created); if (closePopover) { hideContextMenu(true, ReportActionComposeFocusManager.focus); @@ -242,7 +242,7 @@ const ContextMenuActions: ContextMenuAction[] = [ onPress: (closePopover, {reportID, reportAction, draftMessage}) => { if (ReportActionsUtils.isMoneyRequestAction(reportAction)) { hideContextMenu(false); - const childReportID = reportAction?.childReportID ?? '-1'; + const childReportID = reportAction?.childReportID; Report.openReport(childReportID); Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(childReportID)); return; @@ -327,13 +327,13 @@ const ContextMenuActions: ContextMenuAction[] = [ if (closePopover) { hideContextMenu(false, () => { ReportActionComposeFocusManager.focus(); - Report.toggleSubscribeToChildReport(reportAction?.childReportID ?? '-1', reportAction, originalReportID, childReportNotificationPreference); + Report.toggleSubscribeToChildReport(reportAction?.childReportID, reportAction, originalReportID, childReportNotificationPreference); }); return; } ReportActionComposeFocusManager.focus(); - Report.toggleSubscribeToChildReport(reportAction?.childReportID ?? '-1', reportAction, originalReportID, childReportNotificationPreference); + Report.toggleSubscribeToChildReport(reportAction?.childReportID, reportAction, originalReportID, childReportNotificationPreference); }, getDescription: () => {}, }, From 21f10eb21b5f2afe1869b2454b59eddac79b8e66 Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Thu, 19 Dec 2024 12:48:20 +0100 Subject: [PATCH 23/29] fix resolve comments --- src/ROUTES.ts | 2 +- src/components/ReportActionItem/ReportPreview.tsx | 3 +++ src/libs/DistanceRequestUtils.ts | 4 ++-- src/libs/Navigation/dismissModalWithReport.ts | 2 +- src/libs/OptionsListUtils.ts | 2 +- src/libs/Permissions.ts | 2 +- src/pages/TransactionDuplicate/Confirmation.tsx | 3 +++ src/pages/home/report/ContextMenu/ContextMenuActions.tsx | 3 +++ src/pages/signin/SignInPage.tsx | 7 ++++++- src/types/onyx/ReportAction.ts | 2 +- 10 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index c2830ebe4dad..f48a5cae92f0 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -296,7 +296,7 @@ const ROUTES = { REPORT: 'r', REPORT_WITH_ID: { route: 'r/:reportID?/:reportActionID?', - getRoute: (reportID: string | undefined, reportActionID?: string, referrer?: string) => { + getRoute: (reportID: string, reportActionID?: string, referrer?: string) => { const baseRoute = reportActionID ? (`r/${reportID}/${reportActionID}` as const) : (`r/${reportID}` as const); const referrerParam = referrer ? `?referrer=${encodeURIComponent(referrer)}` : ''; return `${baseRoute}${referrerParam}` as const; diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 29ea5b7c85e6..20951c829ba0 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -476,6 +476,9 @@ function ReportPreview({ }, [isApproved, isApprovedAnimationRunning, thumbsUpScale]); const openReportFromPreview = useCallback(() => { + if (!iouReportID) { + return; + } Performance.markStart(CONST.TIMING.OPEN_REPORT_FROM_PREVIEW); Timing.start(CONST.TIMING.OPEN_REPORT_FROM_PREVIEW); Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(iouReportID)); diff --git a/src/libs/DistanceRequestUtils.ts b/src/libs/DistanceRequestUtils.ts index c3ab72079b27..8ec252711267 100644 --- a/src/libs/DistanceRequestUtils.ts +++ b/src/libs/DistanceRequestUtils.ts @@ -293,7 +293,7 @@ function getCustomUnitRateID(reportID: string) { const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; const policy = getPolicy(report?.policyID ?? parentReport?.policyID); - let customUnitRateID: string | undefined = CONST.CUSTOM_UNITS.FAKE_P2P_ID; + let customUnitRateID: string = CONST.CUSTOM_UNITS.FAKE_P2P_ID; if (isPolicyExpenseChat(report) || isPolicyExpenseChat(parentReport)) { const distanceUnit = Object.values(policy?.customUnits ?? {}).find((unit) => unit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE); @@ -302,7 +302,7 @@ function getCustomUnitRateID(reportID: string) { if (lastSelectedDistanceRate?.enabled && lastSelectedDistanceRateID) { customUnitRateID = lastSelectedDistanceRateID; } else { - customUnitRateID = getDefaultMileageRate(policy)?.customUnitRateID; + customUnitRateID = getDefaultMileageRate(policy)?.customUnitRateID ?? CONST.CUSTOM_UNITS.FAKE_P2P_ID; } } diff --git a/src/libs/Navigation/dismissModalWithReport.ts b/src/libs/Navigation/dismissModalWithReport.ts index a921a0b6216b..09f0070c59e4 100644 --- a/src/libs/Navigation/dismissModalWithReport.ts +++ b/src/libs/Navigation/dismissModalWithReport.ts @@ -45,7 +45,7 @@ function dismissModalWithReport(targetReport: OnyxEntry, navigationRef: case SCREENS.REPORT_AVATAR: case SCREENS.CONCIERGE: // If we are not in the target report, we need to navigate to it after dismissing the modal - if (targetReport?.reportID !== getTopmostReportId(state)) { + if (targetReport?.reportID && targetReport?.reportID !== getTopmostReportId(state)) { const reportState = getStateFromPath(ROUTES.REPORT_WITH_ID.getRoute(targetReport?.reportID)); const policyID = getPolicyIDFromState(state as State); const policyMemberAccountIDs = getPolicyEmployeeAccountIDs(policyID); diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index d81c3bc44fe8..c436aa963677 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -561,7 +561,7 @@ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails lastMessageTextFromReport = ReportUtils.getDeletedParentActionMessageForChatReport(lastReportAction); } else if (ReportActionUtils.isPendingRemove(lastReportAction) && ReportActionUtils.isThreadParentMessage(lastReportAction, report?.reportID)) { lastMessageTextFromReport = Localize.translateLocal('parentReportAction.hiddenMessage'); - } else if (ReportUtils.isReportMessageAttachment({text: report?.lastMessageText, html: report?.lastMessageHtml, translationKey: report?.lastMessageTranslationKey, type: ''})) { + } else if (ReportUtils.isReportMessageAttachment({text: report?.lastMessageText ?? '', html: report?.lastMessageHtml, translationKey: report?.lastMessageTranslationKey, type: ''})) { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing lastMessageTextFromReport = `[${Localize.translateLocal((report?.lastMessageTranslationKey || 'common.attachment') as TranslationPaths)}]`; } else if (ReportActionUtils.isModifiedExpenseAction(lastReportAction)) { diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts index bebd54698288..f8f4115caa31 100644 --- a/src/libs/Permissions.ts +++ b/src/libs/Permissions.ts @@ -6,7 +6,7 @@ import * as SessionUtils from './SessionUtils'; const isAccountIDEven = (accountID: number) => accountID % 2 === 0; function canUseAllBetas(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.ALL); + return true; } function canUseDefaultRooms(betas: OnyxEntry): boolean { diff --git a/src/pages/TransactionDuplicate/Confirmation.tsx b/src/pages/TransactionDuplicate/Confirmation.tsx index 1aadf9097d7a..a7d7072f34e7 100644 --- a/src/pages/TransactionDuplicate/Confirmation.tsx +++ b/src/pages/TransactionDuplicate/Confirmation.tsx @@ -53,6 +53,9 @@ function Confirmation() { const isReportOwner = iouReport?.ownerAccountID === currentUserPersonalDetails?.accountID; const mergeDuplicates = useCallback(() => { + if (!reportAction?.childReportID) { + return; + } IOU.mergeDuplicates(transactionsMergeParams); Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(reportAction?.childReportID)); }, [reportAction?.childReportID, transactionsMergeParams]); diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx index 5155cf9419b8..c180ba7e1889 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx @@ -243,6 +243,9 @@ const ContextMenuActions: ContextMenuAction[] = [ if (ReportActionsUtils.isMoneyRequestAction(reportAction)) { hideContextMenu(false); const childReportID = reportAction?.childReportID; + if (!childReportID) { + return; + } Report.openReport(childReportID); Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(childReportID)); return; diff --git a/src/pages/signin/SignInPage.tsx b/src/pages/signin/SignInPage.tsx index 9cd3166ac3a1..1c680a09c345 100644 --- a/src/pages/signin/SignInPage.tsx +++ b/src/pages/signin/SignInPage.tsx @@ -94,7 +94,7 @@ function getRenderOptions({ const isSAMLEnabled = !!account?.isSAMLEnabled; const isSAMLRequired = !!account?.isSAMLRequired; const hasEmailDeliveryFailure = !!account?.hasEmailDeliveryFailure; - const hasSMSDeliveryFailure = !!account?.smsDeliveryFailureStatus; + const hasSMSDeliveryFailure = !!account?.smsDeliveryFailureStatus?.hasSMSDeliveryFailure; // True, if the user has SAML required, and we haven't yet initiated SAML for their account const shouldInitiateSAMLLogin = hasAccount && hasLogin && isSAMLRequired && !hasInitiatedSAMLLogin && !!account.isLoading; @@ -112,6 +112,11 @@ function getRenderOptions({ const shouldShowLoginForm = !shouldShowAnotherLoginPageOpenedMessage && !hasLogin && !hasValidateCode; const shouldShowEmailDeliveryFailurePage = hasLogin && hasEmailDeliveryFailure && !shouldShowChooseSSOOrMagicCode && !shouldInitiateSAMLLogin; const shouldShowSMSDeliveryFailurePage = !!(hasLogin && hasSMSDeliveryFailure && !shouldShowChooseSSOOrMagicCode && !shouldInitiateSAMLLogin && account?.accountExists); + console.log('hasLogin', hasLogin); + console.log('hasSMSDeliveryFailure', hasSMSDeliveryFailure); + console.log('!shouldShowChooseSoorMagicCode', !shouldShowChooseSSOOrMagicCode); + console.log('account.accountExists', account?.accountExists); + console.log('shouldShowSMSDeliveryFailurePage', shouldShowSMSDeliveryFailurePage); const isUnvalidatedSecondaryLogin = hasLogin && !isPrimaryLogin && !account?.validated && !hasEmailDeliveryFailure && !hasSMSDeliveryFailure; const shouldShowValidateCodeForm = !shouldShouldSignUpWelcomeForm && diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts index 2df1d904fca7..2c97fda0dc0a 100644 --- a/src/types/onyx/ReportAction.ts +++ b/src/types/onyx/ReportAction.ts @@ -17,7 +17,7 @@ type Message = { type: string; /** The text content of the fragment. */ - text: string | undefined; + text: string; /** The html content of the fragment. */ html?: string; From 7a8f142949bd526d62e291a45b1ec0e55e96b958 Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Thu, 19 Dec 2024 13:41:46 +0100 Subject: [PATCH 24/29] remove unnecessary changes --- src/libs/Permissions.ts | 2 +- src/pages/signin/SignInPage.tsx | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts index f8f4115caa31..bebd54698288 100644 --- a/src/libs/Permissions.ts +++ b/src/libs/Permissions.ts @@ -6,7 +6,7 @@ import * as SessionUtils from './SessionUtils'; const isAccountIDEven = (accountID: number) => accountID % 2 === 0; function canUseAllBetas(betas: OnyxEntry): boolean { - return true; + return !!betas?.includes(CONST.BETAS.ALL); } function canUseDefaultRooms(betas: OnyxEntry): boolean { diff --git a/src/pages/signin/SignInPage.tsx b/src/pages/signin/SignInPage.tsx index 1c680a09c345..9cd3166ac3a1 100644 --- a/src/pages/signin/SignInPage.tsx +++ b/src/pages/signin/SignInPage.tsx @@ -94,7 +94,7 @@ function getRenderOptions({ const isSAMLEnabled = !!account?.isSAMLEnabled; const isSAMLRequired = !!account?.isSAMLRequired; const hasEmailDeliveryFailure = !!account?.hasEmailDeliveryFailure; - const hasSMSDeliveryFailure = !!account?.smsDeliveryFailureStatus?.hasSMSDeliveryFailure; + const hasSMSDeliveryFailure = !!account?.smsDeliveryFailureStatus; // True, if the user has SAML required, and we haven't yet initiated SAML for their account const shouldInitiateSAMLLogin = hasAccount && hasLogin && isSAMLRequired && !hasInitiatedSAMLLogin && !!account.isLoading; @@ -112,11 +112,6 @@ function getRenderOptions({ const shouldShowLoginForm = !shouldShowAnotherLoginPageOpenedMessage && !hasLogin && !hasValidateCode; const shouldShowEmailDeliveryFailurePage = hasLogin && hasEmailDeliveryFailure && !shouldShowChooseSSOOrMagicCode && !shouldInitiateSAMLLogin; const shouldShowSMSDeliveryFailurePage = !!(hasLogin && hasSMSDeliveryFailure && !shouldShowChooseSSOOrMagicCode && !shouldInitiateSAMLLogin && account?.accountExists); - console.log('hasLogin', hasLogin); - console.log('hasSMSDeliveryFailure', hasSMSDeliveryFailure); - console.log('!shouldShowChooseSoorMagicCode', !shouldShowChooseSSOOrMagicCode); - console.log('account.accountExists', account?.accountExists); - console.log('shouldShowSMSDeliveryFailurePage', shouldShowSMSDeliveryFailurePage); const isUnvalidatedSecondaryLogin = hasLogin && !isPrimaryLogin && !account?.validated && !hasEmailDeliveryFailure && !hasSMSDeliveryFailure; const shouldShowValidateCodeForm = !shouldShouldSignUpWelcomeForm && From c7f3bdc3ce0a944a38dff459232011787034f4bc Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Thu, 19 Dec 2024 15:30:14 +0100 Subject: [PATCH 25/29] fix: another cycle dependecy --- src/libs/processReportIDDeeplink/getReportIDFromUrl.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/processReportIDDeeplink/getReportIDFromUrl.ts b/src/libs/processReportIDDeeplink/getReportIDFromUrl.ts index 6763b5a45085..7300f22ab008 100644 --- a/src/libs/processReportIDDeeplink/getReportIDFromUrl.ts +++ b/src/libs/processReportIDDeeplink/getReportIDFromUrl.ts @@ -1,9 +1,9 @@ -import * as ReportUtils from '@libs/ReportUtils'; +import {parseReportRouteParams} from '@libs/ReportUtils'; export default function getReportIDFromUrl(url: string): string { const currentParams = new URLSearchParams(url); const currentExitToRoute = currentParams.get('exitTo') ?? ''; - const {reportID} = ReportUtils.parseReportRouteParams(currentExitToRoute); + const {reportID} = parseReportRouteParams(currentExitToRoute); return reportID; } From b8d497504a359ab09f3168291d052dc5498aceae Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Fri, 20 Dec 2024 14:51:40 +0100 Subject: [PATCH 26/29] adjusted types --- src/types/onyx/ReviewDuplicates.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/onyx/ReviewDuplicates.ts b/src/types/onyx/ReviewDuplicates.ts index d97798bcddb7..721275b198bc 100644 --- a/src/types/onyx/ReviewDuplicates.ts +++ b/src/types/onyx/ReviewDuplicates.ts @@ -5,7 +5,7 @@ import type {Comment} from './Transaction'; */ type ReviewDuplicates = { /** Transactions ids which are duplicates of selected transcation */ - duplicates: Array; + duplicates: string[]; /** ID of transaction we want to keep */ transactionID: string; From b90ad7be14b02b6de3835f6dd16da6653e4c0740 Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Fri, 20 Dec 2024 15:17:33 +0100 Subject: [PATCH 27/29] fixes --- src/libs/actions/IOU.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index c6e8b7ace7a4..ecf0a751aebf 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -688,7 +688,7 @@ function setMoneyRequestCategory(transactionID: string, category: string, policy return; } const transaction = allTransactionDrafts[`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`]; - const {categoryTaxCode, categoryTaxAmount} = TransactionUtils.getCategoryTaxCodeAndAmount(category, transaction, PolicyUtils.getPolicy(policyID)); + const {categoryTaxCode, categoryTaxAmount} = getCategoryTaxCodeAndAmount(category, transaction, getPolicy(policyID)); if (categoryTaxCode && categoryTaxAmount !== undefined) { setMoneyRequestTaxRate(transactionID, categoryTaxCode); setMoneyRequestTaxAmount(transactionID, categoryTaxAmount); From cdeecced826845c5586718e751c2ee5aa3bd0d2c Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Thu, 2 Jan 2025 10:57:34 +0100 Subject: [PATCH 28/29] fix lint problems --- src/libs/actions/IOU.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index f348adce1479..efd75fbe2833 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -137,7 +137,6 @@ import { getCurrency, getMerchant, getTransaction, - getTransactionID, getUpdatedTransaction, hasReceipt as hasReceiptTransactionUtils, isDistanceRequest as isDistanceRequestTransactionUtils, @@ -7904,7 +7903,7 @@ function cancelPayment(expenseReport: OnyxEntry, chatReport: O {optimisticData, successData, failureData}, ); Navigation.dismissModal(); - Report.notifyNewAction(expenseReport.reportID, userAccountID); + notifyNewAction(expenseReport.reportID, userAccountID); } /** From 6f446dadc97dbdae83d8e2168e3c452e86f2bafd Mon Sep 17 00:00:00 2001 From: kubabutkiewicz Date: Mon, 13 Jan 2025 18:18:24 +0100 Subject: [PATCH 29/29] incorporate new eslint rules to forbid namespace imports --- .eslintrc.changed.js | 27 ++ .../ReportActionItem/ReportPreview.tsx | 179 +++++++---- src/libs/PolicyUtils.ts | 14 +- src/libs/ReportActionsUtils.ts | 121 ++++--- src/libs/ReportUtils.ts | 247 +++++++------- src/libs/SearchQueryUtils.ts | 6 +- src/libs/actions/App.ts | 12 +- src/libs/actions/Report.ts | 32 +- .../report/ContextMenu/ContextMenuActions.tsx | 303 +++++++++++------- .../members/WorkspaceOwnerPaymentCardForm.tsx | 18 +- 10 files changed, 542 insertions(+), 417 deletions(-) diff --git a/.eslintrc.changed.js b/.eslintrc.changed.js index 55472b10ea86..f5aff2debc8a 100644 --- a/.eslintrc.changed.js +++ b/.eslintrc.changed.js @@ -7,6 +7,17 @@ module.exports = { rules: { 'deprecation/deprecation': 'error', 'rulesdir/no-default-id-values': 'error', + 'no-restricted-syntax': [ + 'error', + { + selector: 'ImportNamespaceSpecifier[parent.source.value=/^@libs/]', + message: 'Namespace imports from @libs are not allowed. Use named imports instead. Example: import { method } from "@libs/module"', + }, + { + selector: 'ImportNamespaceSpecifier[parent.source.value=/^@userActions/]', + message: 'Namespace imports from @userActions are not allowed. Use named imports instead. Example: import { action } from "@userActions/module"', + }, + ], }, overrides: [ { @@ -24,5 +35,21 @@ module.exports = { 'rulesdir/no-default-id-values': 'off', }, }, + { + files: ['**/libs/**/*.{ts,tsx}'], + rules: { + 'no-restricted-syntax': [ + 'error', + { + selector: 'ImportNamespaceSpecifier[parent.source.value=/^\\.\\./]', + message: 'Namespace imports are not allowed. Use named imports instead. Example: import { method } from "../libs/module"', + }, + { + selector: 'ImportNamespaceSpecifier[parent.source.value=/^\\./]', + message: 'Namespace imports are not allowed. Use named imports instead. Example: import { method } from "./libs/module"', + }, + ], + }, + }, ], }; diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 596b610bbdfc..6b2ed42181b0 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -23,20 +23,66 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import {getCurrentUserAccountID} from '@libs/actions/Report'; import ControlSelection from '@libs/ControlSelection'; -import * as CurrencyUtils from '@libs/CurrencyUtils'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; +import {convertToDisplayString} from '@libs/CurrencyUtils'; +import {canUseTouchScreen} from '@libs/DeviceCapabilities'; import HapticFeedback from '@libs/HapticFeedback'; import Navigation from '@libs/Navigation/Navigation'; import Performance from '@libs/Performance'; -import * as PolicyUtils from '@libs/PolicyUtils'; -import * as ReceiptUtils from '@libs/ReceiptUtils'; -import * as ReportActionsUtils from '@libs/ReportActionsUtils'; -import * as ReportUtils from '@libs/ReportUtils'; +import {getConnectedIntegration} from '@libs/PolicyUtils'; +import {getThumbnailAndImageURIs} from '@libs/ReceiptUtils'; +import {getReportActionText} from '@libs/ReportActionsUtils'; +import { + areAllRequestsBeingSmartScanned as areAllRequestsBeingSmartScannedReportUtils, + canBeExported, + getArchiveReason, + getBankAccountRoute, + getDisplayNameForParticipant, + getInvoicePayerName, + getMoneyRequestSpendBreakdown, + getNonHeldAndFullAmount, + getPolicyName, + getTransactionsWithReceipts, + hasActionsWithErrors, + hasHeldExpenses as hasHeldExpensesReportUtils, + hasMissingInvoiceBankAccount, + hasMissingPaymentMethod, + hasMissingSmartscanFields as hasMissingSmartscanFieldsReportUtils, + hasNonReimbursableTransactions as hasNonReimbursableTransactionsReportUtils, + hasNoticeTypeViolations, + hasOnlyHeldExpenses as hasOnlyHeldExpensesReportUtils, + hasOnlyTransactionsWithPendingRoutes as hasOnlyTransactionsWithPendingRoutesReportUtils, + hasReportViolations, + hasUpdatedTotal, + hasViolations, + hasWarningTypeViolations, + isAllowedToApproveExpenseReport, + isAllowedToSubmitDraftExpenseReport, + isArchivedRoomWithID, + isInvoiceReport as isInvoiceReportUtils, + isInvoiceRoom as isInvoiceRoomReportUtils, + isOpenExpenseReport as isOpenExpenseReportUtils, + isPayAtEndExpenseReport, + isPolicyExpenseChat as isPolicyExpenseChatReportUtils, + isReportApproved, + isReportOwner, + isSettled, +} from '@libs/ReportUtils'; import StringUtils from '@libs/StringUtils'; -import * as TransactionUtils from '@libs/TransactionUtils'; +import { + getAllReportTransactions, + getDescription, + getMerchant, + getTransactionViolations, + hasPendingUI, + isCardTransaction, + isPartialMerchant, + isPending, + isReceiptBeingScanned, + shouldShowBrokenConnectionViolation as shouldShowBrokenConnectionViolationTransactionUtils, +} from '@libs/TransactionUtils'; import type {ContextMenuAnchor} from '@pages/home/report/ContextMenu/ReportActionContextMenu'; import variables from '@styles/variables'; -import * as IOU from '@userActions/IOU'; +import {approveMoneyRequest, canApproveIOU, canIOUBePaid as canIOUBePaidIOUActions, payInvoice, payMoneyRequest, submitReport} from '@userActions/IOU'; import Timing from '@userActions/Timing'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; @@ -109,14 +155,14 @@ function ReportPreview({ const styles = useThemeStyles(); const {translate} = useLocalize(); const {isOffline} = useNetwork(); - const allTransactions = useMemo(() => TransactionUtils.getAllReportTransactions(iouReportID, transactions), [iouReportID, transactions]); + const allTransactions = useMemo(() => getAllReportTransactions(iouReportID, transactions), [iouReportID, transactions]); const {hasMissingSmartscanFields, areAllRequestsBeingSmartScanned, hasOnlyTransactionsWithPendingRoutes, hasNonReimbursableTransactions} = useMemo( () => ({ - hasMissingSmartscanFields: ReportUtils.hasMissingSmartscanFields(iouReportID), - areAllRequestsBeingSmartScanned: ReportUtils.areAllRequestsBeingSmartScanned(iouReportID, action), - hasOnlyTransactionsWithPendingRoutes: ReportUtils.hasOnlyTransactionsWithPendingRoutes(iouReportID), - hasNonReimbursableTransactions: ReportUtils.hasNonReimbursableTransactions(iouReportID), + hasMissingSmartscanFields: hasMissingSmartscanFieldsReportUtils(iouReportID), + areAllRequestsBeingSmartScanned: areAllRequestsBeingSmartScannedReportUtils(iouReportID, action), + hasOnlyTransactionsWithPendingRoutes: hasOnlyTransactionsWithPendingRoutesReportUtils(iouReportID), + hasNonReimbursableTransactions: hasNonReimbursableTransactionsReportUtils(iouReportID), }), // When transactions get updated these status may have changed, so that is a case where we also want to run this. // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps @@ -131,7 +177,7 @@ function ReportPreview({ const getCanIOUBePaid = useCallback( (onlyShowPayElsewhere = false, shouldCheckApprovedState = true) => - IOU.canIOUBePaid(iouReport, chatReport, policy, allTransactions, onlyShowPayElsewhere, undefined, undefined, shouldCheckApprovedState), + canIOUBePaidIOUActions(iouReport, chatReport, policy, allTransactions, onlyShowPayElsewhere, undefined, undefined, shouldCheckApprovedState), [iouReport, chatReport, policy, allTransactions], ); @@ -139,25 +185,25 @@ function ReportPreview({ const canIOUBePaidAndApproved = useMemo(() => getCanIOUBePaid(false, false), [getCanIOUBePaid]); const onlyShowPayElsewhere = useMemo(() => !canIOUBePaid && getCanIOUBePaid(true), [canIOUBePaid, getCanIOUBePaid]); const shouldShowPayButton = isPaidAnimationRunning || canIOUBePaid || onlyShowPayElsewhere; - const shouldShowApproveButton = useMemo(() => IOU.canApproveIOU(iouReport, policy), [iouReport, policy]) || isApprovedAnimationRunning; + const shouldShowApproveButton = useMemo(() => canApproveIOU(iouReport, policy), [iouReport, policy]) || isApprovedAnimationRunning; - const shouldDisableApproveButton = shouldShowApproveButton && !ReportUtils.isAllowedToApproveExpenseReport(iouReport); + const shouldDisableApproveButton = shouldShowApproveButton && !isAllowedToApproveExpenseReport(iouReport); - const {nonHeldAmount, fullAmount, hasValidNonHeldAmount} = ReportUtils.getNonHeldAndFullAmount(iouReport, shouldShowPayButton); - const hasOnlyHeldExpenses = ReportUtils.hasOnlyHeldExpenses(iouReport?.reportID); - const hasHeldExpenses = ReportUtils.hasHeldExpenses(iouReport?.reportID); + const {nonHeldAmount, fullAmount, hasValidNonHeldAmount} = getNonHeldAndFullAmount(iouReport, shouldShowPayButton); + const hasOnlyHeldExpenses = hasOnlyHeldExpensesReportUtils(iouReport?.reportID); + const hasHeldExpenses = hasHeldExpensesReportUtils(iouReport?.reportID); const managerID = iouReport?.managerID ?? action.childManagerAccountID ?? CONST.DEFAULT_NUMBER_ID; - const {totalDisplaySpend, reimbursableSpend} = ReportUtils.getMoneyRequestSpendBreakdown(iouReport); + const {totalDisplaySpend, reimbursableSpend} = getMoneyRequestSpendBreakdown(iouReport); - const iouSettled = ReportUtils.isSettled(iouReportID) || action?.childStatusNum === CONST.REPORT.STATUS_NUM.REIMBURSED; + const iouSettled = isSettled(iouReportID) || action?.childStatusNum === CONST.REPORT.STATUS_NUM.REIMBURSED; const previewMessageOpacity = useSharedValue(1); const previewMessageStyle = useAnimatedStyle(() => ({ opacity: previewMessageOpacity.get(), })); const checkMarkScale = useSharedValue(iouSettled ? 1 : 0); - const isApproved = ReportUtils.isReportApproved(iouReport, action); + const isApproved = isReportApproved(iouReport, action); const thumbsUpScale = useSharedValue(isApproved ? 1 : 0); const thumbsUpStyle = useAnimatedStyle(() => ({ ...styles.defaultCheckmarkWrapper, @@ -165,36 +211,34 @@ function ReportPreview({ })); const moneyRequestComment = action?.childLastMoneyRequestComment ?? ''; - const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(chatReport); - const isInvoiceRoom = ReportUtils.isInvoiceRoom(chatReport); - const isOpenExpenseReport = isPolicyExpenseChat && ReportUtils.isOpenExpenseReport(iouReport); + const isPolicyExpenseChat = isPolicyExpenseChatReportUtils(chatReport); + const isInvoiceRoom = isInvoiceRoomReportUtils(chatReport); + const isOpenExpenseReport = isPolicyExpenseChat && isOpenExpenseReportUtils(iouReport); - const canAllowSettlement = ReportUtils.hasUpdatedTotal(iouReport, policy); + const canAllowSettlement = hasUpdatedTotal(iouReport, policy); const numberOfRequests = allTransactions.length; - const transactionsWithReceipts = ReportUtils.getTransactionsWithReceipts(iouReportID); - const numberOfScanningReceipts = transactionsWithReceipts.filter((transaction) => TransactionUtils.isReceiptBeingScanned(transaction)).length; - const numberOfPendingRequests = transactionsWithReceipts.filter((transaction) => TransactionUtils.isPending(transaction) && TransactionUtils.isCardTransaction(transaction)).length; + const transactionsWithReceipts = getTransactionsWithReceipts(iouReportID); + const numberOfScanningReceipts = transactionsWithReceipts.filter((transaction) => isReceiptBeingScanned(transaction)).length; + const numberOfPendingRequests = transactionsWithReceipts.filter((transaction) => isPending(transaction) && isCardTransaction(transaction)).length; const hasReceipts = transactionsWithReceipts.length > 0; const isScanning = hasReceipts && areAllRequestsBeingSmartScanned; const hasErrors = (hasMissingSmartscanFields && !iouSettled) || // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - ReportUtils.hasViolations(iouReportID, transactionViolations, true) || - ReportUtils.hasNoticeTypeViolations(iouReportID, transactionViolations, true) || - ReportUtils.hasWarningTypeViolations(iouReportID, transactionViolations, true) || - (ReportUtils.isReportOwner(iouReport) && ReportUtils.hasReportViolations(iouReportID)) || - ReportUtils.hasActionsWithErrors(iouReportID); + hasViolations(iouReportID, transactionViolations, true) || + hasNoticeTypeViolations(iouReportID, transactionViolations, true) || + hasWarningTypeViolations(iouReportID, transactionViolations, true) || + (isReportOwner(iouReport) && hasReportViolations(iouReportID)) || + hasActionsWithErrors(iouReportID); const lastThreeTransactions = allTransactions.slice(-3); - const lastThreeReceipts = lastThreeTransactions.map((transaction) => ({...ReceiptUtils.getThumbnailAndImageURIs(transaction), transaction})); - const showRTERViolationMessage = - numberOfRequests === 1 && - TransactionUtils.hasPendingUI(allTransactions.at(0), TransactionUtils.getTransactionViolations(allTransactions.at(0)?.transactionID, transactionViolations)); - const shouldShowBrokenConnectionViolation = numberOfRequests === 1 && TransactionUtils.shouldShowBrokenConnectionViolation(allTransactions.at(0)?.transactionID, iouReport, policy); - let formattedMerchant = numberOfRequests === 1 ? TransactionUtils.getMerchant(allTransactions.at(0)) : null; - const formattedDescription = numberOfRequests === 1 ? TransactionUtils.getDescription(allTransactions.at(0)) : null; - - if (TransactionUtils.isPartialMerchant(formattedMerchant ?? '')) { + const lastThreeReceipts = lastThreeTransactions.map((transaction) => ({...getThumbnailAndImageURIs(transaction), transaction})); + const showRTERViolationMessage = numberOfRequests === 1 && hasPendingUI(allTransactions.at(0), getTransactionViolations(allTransactions.at(0)?.transactionID, transactionViolations)); + const shouldShowBrokenConnectionViolation = numberOfRequests === 1 && shouldShowBrokenConnectionViolationTransactionUtils(allTransactions.at(0)?.transactionID, iouReport, policy); + let formattedMerchant = numberOfRequests === 1 ? getMerchant(allTransactions.at(0)) : null; + const formattedDescription = numberOfRequests === 1 ? getDescription(allTransactions.at(0)) : null; + + if (isPartialMerchant(formattedMerchant ?? '')) { formattedMerchant = null; } @@ -207,7 +251,7 @@ function ReportPreview({ !shouldShowBrokenConnectionViolation && (iouReport?.ownerAccountID === currentUserAccountID || isAdmin || iouReport?.managerID === currentUserAccountID); - const shouldDisableSubmitButton = shouldShowSubmitButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(iouReport); + const shouldDisableSubmitButton = shouldShowSubmitButton && !isAllowedToSubmitDraftExpenseReport(iouReport); // The submit button should be success green colour only if the user is submitter and the policy does not have Scheduled Submit turned on const isWaitingForSubmissionFromCurrentUser = useMemo( @@ -240,15 +284,15 @@ function ReportPreview({ setRequestType(CONST.IOU.REPORT_ACTION_TYPE.PAY); if (isDelegateAccessRestricted) { setIsNoDelegateAccessMenuVisible(true); - } else if (ReportUtils.hasHeldExpenses(iouReport?.reportID)) { + } else if (hasHeldExpensesReportUtils(iouReport?.reportID)) { setIsHoldMenuVisible(true); } else if (chatReport && iouReport) { setIsPaidAnimationRunning(true); HapticFeedback.longPress(); - if (ReportUtils.isInvoiceReport(iouReport)) { - IOU.payInvoice(type, chatReport, iouReport, payAsBusiness); + if (isInvoiceReportUtils(iouReport)) { + payInvoice(type, chatReport, iouReport, payAsBusiness); } else { - IOU.payMoneyRequest(type, chatReport, iouReport); + payMoneyRequest(type, chatReport, iouReport); } } }, @@ -259,12 +303,12 @@ function ReportPreview({ setRequestType(CONST.IOU.REPORT_ACTION_TYPE.APPROVE); if (isDelegateAccessRestricted) { setIsNoDelegateAccessMenuVisible(true); - } else if (ReportUtils.hasHeldExpenses(iouReport?.reportID)) { + } else if (hasHeldExpensesReportUtils(iouReport?.reportID)) { setIsHoldMenuVisible(true); } else { setIsApprovedAnimationRunning(true); HapticFeedback.longPress(); - IOU.approveMoneyRequest(iouReport, true); + approveMoneyRequest(iouReport, true); } }; @@ -274,16 +318,16 @@ function ReportPreview({ } // We shouldn't display the nonHeldAmount as the default option if it's not valid since we cannot pay partially in this case - if (ReportUtils.hasHeldExpenses(iouReport?.reportID) && canAllowSettlement && hasValidNonHeldAmount) { + if (hasHeldExpensesReportUtils(iouReport?.reportID) && canAllowSettlement && hasValidNonHeldAmount) { return nonHeldAmount; } - return CurrencyUtils.convertToDisplayString(reimbursableSpend, iouReport?.currency); + return convertToDisplayString(reimbursableSpend, iouReport?.currency); }; const getDisplayAmount = (): string => { if (totalDisplaySpend) { - return CurrencyUtils.convertToDisplayString(totalDisplaySpend, iouReport?.currency); + return convertToDisplayString(totalDisplaySpend, iouReport?.currency); } if (isScanning) { return translate('iou.receiptScanning', {count: numberOfScanningReceipts}); @@ -294,7 +338,7 @@ function ReportPreview({ // If iouReport is not available, get amount from the action message (Ex: "Domain20821's Workspace owes $33.00" or "paid ₫60" or "paid -₫60 elsewhere") let displayAmount = ''; - const actionMessage = ReportActionsUtils.getReportActionText(action); + const actionMessage = getReportActionText(action); const splits = actionMessage.split(' '); splits.forEach((split) => { @@ -327,11 +371,11 @@ function ReportPreview({ let payerOrApproverName; if (isPolicyExpenseChat) { - payerOrApproverName = ReportUtils.getPolicyName(chatReport, undefined, policy); + payerOrApproverName = getPolicyName(chatReport, undefined, policy); } else if (isInvoiceRoom) { - payerOrApproverName = ReportUtils.getInvoicePayerName(chatReport, invoiceReceiverPolicy); + payerOrApproverName = getInvoicePayerName(chatReport, invoiceReceiverPolicy); } else { - payerOrApproverName = ReportUtils.getDisplayNameForParticipant(managerID, true); + payerOrApproverName = getDisplayNameForParticipant(managerID, true); } if (isApproved) { @@ -342,7 +386,7 @@ function ReportPreview({ paymentVerb = 'iou.payerPaid'; } else if (hasNonReimbursableTransactions) { paymentVerb = 'iou.payerSpent'; - payerOrApproverName = ReportUtils.getDisplayNameForParticipant(chatReport?.ownerAccountID, true); + payerOrApproverName = getDisplayNameForParticipant(chatReport?.ownerAccountID, true); } return translate(paymentVerb, {payer: payerOrApproverName}); }, [ @@ -360,12 +404,11 @@ function ReportPreview({ translate, ]); - const bankAccountRoute = ReportUtils.getBankAccountRoute(chatReport); + const bankAccountRoute = getBankAccountRoute(chatReport); const shouldShowSettlementButton = (shouldShowPayButton || shouldShowApproveButton) && !showRTERViolationMessage && !shouldShowBrokenConnectionViolation; - const shouldPromptUserToAddBankAccount = - (ReportUtils.hasMissingPaymentMethod(userWallet, iouReportID) || ReportUtils.hasMissingInvoiceBankAccount(iouReportID)) && !ReportUtils.isSettled(iouReportID); + const shouldPromptUserToAddBankAccount = (hasMissingPaymentMethod(userWallet, iouReportID) || hasMissingInvoiceBankAccount(iouReportID)) && !isSettled(iouReportID); const shouldShowRBR = hasErrors && !iouSettled; /* @@ -382,9 +425,9 @@ function ReportPreview({ const shouldShowScanningSubtitle = (numberOfScanningReceipts === 1 && numberOfRequests === 1) || (numberOfScanningReceipts >= 1 && Number(nonHeldAmount) === 0); const shouldShowPendingSubtitle = numberOfPendingRequests === 1 && numberOfRequests === 1; - const isPayAtEndExpense = ReportUtils.isPayAtEndExpenseReport(iouReportID, allTransactions); - const isArchivedReport = ReportUtils.isArchivedRoomWithID(iouReportID); - const [archiveReason] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReportID}`, {selector: ReportUtils.getArchiveReason}); + const isPayAtEndExpense = isPayAtEndExpenseReport(iouReportID, allTransactions); + const isArchivedReport = isArchivedRoomWithID(iouReportID); + const [archiveReason] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReportID}`, {selector: getArchiveReason}); const getPendingMessageProps: () => PendingMessageProps = () => { if (isPayAtEndExpense) { @@ -441,9 +484,9 @@ function ReportPreview({ /* * Manual export */ - const connectedIntegration = PolicyUtils.getConnectedIntegration(policy); + const connectedIntegration = getConnectedIntegration(policy); - const shouldShowExportIntegrationButton = !shouldShowPayButton && !shouldShowSubmitButton && connectedIntegration && isAdmin && ReportUtils.canBeExported(iouReport); + const shouldShowExportIntegrationButton = !shouldShowPayButton && !shouldShowSubmitButton && connectedIntegration && isAdmin && canBeExported(iouReport); useEffect(() => { if (!isPaidAnimationRunning || isApprovedAnimationRunning) { @@ -493,7 +536,7 @@ function ReportPreview({ DeviceCapabilities.canUseTouchScreen() && ControlSelection.block()} + onPressIn={() => canUseTouchScreen() && ControlSelection.block()} onPressOut={() => ControlSelection.unblock()} onLongPress={(event) => showContextMenuForReport(event, contextMenuAnchor, chatReportID, action, checkIfContextMenuActive)} shouldUseHapticsOnLongPress @@ -621,7 +664,7 @@ function ReportPreview({