From 996ee26a0463376fc95539227a607b2cd5d18850 Mon Sep 17 00:00:00 2001 From: Viktoryia Kliushun Date: Thu, 28 Dec 2023 12:16:50 +0100 Subject: [PATCH 01/68] Migrate Onyx.connect methods to TS --- src/ONYXKEYS.ts | 3 +++ src/libs/actions/{IOU.js => IOU.ts} | 42 +++++++++++++++-------------- src/types/onyx/Transaction.ts | 4 ++- src/types/onyx/index.ts | 3 ++- 4 files changed, 30 insertions(+), 22 deletions(-) rename src/libs/actions/{IOU.js => IOU.ts} (99%) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 53cd37e71f67..f19320a8bbc6 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -457,6 +457,9 @@ type OnyxValues = { [ONYXKEYS.COLLECTION.REPORT_USER_IS_LEAVING_ROOM]: boolean; [ONYXKEYS.COLLECTION.SECURITY_GROUP]: OnyxTypes.SecurityGroup; [ONYXKEYS.COLLECTION.TRANSACTION]: OnyxTypes.Transaction; + [ONYXKEYS.COLLECTION.TRANSACTION_DRAFT]: OnyxTypes.TransactionDraft; + [ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT]: OnyxTypes.TransactionDraft; + [ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS]: OnyxTypes.TransactionViolation; [ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS]: OnyxTypes.RecentlyUsedTags; [ONYXKEYS.COLLECTION.SELECTED_TAB]: string; [ONYXKEYS.COLLECTION.PRIVATE_NOTES_DRAFT]: string; diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.ts similarity index 99% rename from src/libs/actions/IOU.js rename to src/libs/actions/IOU.ts index d43fefca20bc..dec566ee977a 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.ts @@ -2,7 +2,7 @@ import {format} from 'date-fns'; import Str from 'expensify-common/lib/str'; import lodashGet from 'lodash/get'; import lodashHas from 'lodash/has'; -import Onyx from 'react-native-onyx'; +import Onyx, {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import OnyxUtils from 'react-native-onyx/lib/utils'; import _ from 'underscore'; import ReceiptGeneric from '@assets/images/receipt-generic.png'; @@ -24,31 +24,33 @@ import * as UserUtils from '@libs/UserUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import * as OnyxTypes from '@src/types/onyx'; +import {EmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; import * as Report from './Report'; -let betas; +let betas: OnyxTypes.Beta[] = []; Onyx.connect({ key: ONYXKEYS.BETAS, - callback: (val) => (betas = val || []), + callback: (val) => (betas = val ?? []), }); -let allPersonalDetails; +let allPersonalDetails: OnyxTypes.PersonalDetailsList = {}; Onyx.connect({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (val) => { - allPersonalDetails = val || {}; + allPersonalDetails = val ?? {}; }, }); -let allReports; +let allReports: OnyxCollection = null; Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT, waitForCollectionCallback: true, callback: (val) => (allReports = val), }); -let allTransactions; +let allTransactions: Record = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.TRANSACTION, waitForCollectionCallback: true, @@ -62,16 +64,16 @@ Onyx.connect({ }, }); -let allTransactionDrafts = {}; +let allTransactionDrafts: Record = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.TRANSACTION_DRAFT, waitForCollectionCallback: true, callback: (val) => { - allTransactionDrafts = val || {}; + allTransactionDrafts = val ?? {}; }, }); -let allTransactionViolations; +let allTransactionViolations: Record = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, waitForCollectionCallback: true, @@ -85,43 +87,43 @@ Onyx.connect({ }, }); -let allDraftSplitTransactions; +let allDraftSplitTransactions: Record = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT, waitForCollectionCallback: true, callback: (val) => { - allDraftSplitTransactions = val || {}; + allDraftSplitTransactions = val ?? {}; }, }); -let allNextSteps = {}; +let allNextSteps: Record = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.NEXT_STEP, waitForCollectionCallback: true, callback: (val) => { - allNextSteps = val || {}; + allNextSteps = val ?? {}; }, }); -let userAccountID = ''; +let userAccountID = -1; let currentUserEmail = ''; Onyx.connect({ key: ONYXKEYS.SESSION, callback: (val) => { - currentUserEmail = lodashGet(val, 'email', ''); - userAccountID = lodashGet(val, 'accountID', ''); + currentUserEmail = val?.email ?? ''; + userAccountID = val?.accountID ?? -1; }, }); -let currentUserPersonalDetails = {}; +let currentUserPersonalDetails: OnyxTypes.PersonalDetails | EmptyObject = {}; Onyx.connect({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (val) => { - currentUserPersonalDetails = lodashGet(val, userAccountID, {}); + currentUserPersonalDetails = val?.[userAccountID] ?? {}; }, }); -let currentDate = ''; +let currentDate: OnyxEntry = ''; Onyx.connect({ key: ONYXKEYS.CURRENT_DATE, callback: (val) => { diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 53bfc36a4e47..8b79966451ed 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -96,5 +96,7 @@ type Transaction = { originalCurrency?: string; }; +type TransactionDraft = Partial; + export default Transaction; -export type {WaypointCollection, Comment, Receipt, Waypoint}; +export type {WaypointCollection, Comment, Receipt, Waypoint, TransactionDraft}; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 3d4eef500f1d..3a59959364c5 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -46,7 +46,7 @@ import ScreenShareRequest from './ScreenShareRequest'; import SecurityGroup from './SecurityGroup'; import Session from './Session'; import Task from './Task'; -import Transaction from './Transaction'; +import Transaction, {TransactionDraft} from './Transaction'; import {TransactionViolation, ViolationName} from './TransactionViolation'; import User from './User'; import UserLocation from './UserLocation'; @@ -115,6 +115,7 @@ export type { Session, Task, Transaction, + TransactionDraft, TransactionViolation, User, UserLocation, From b7af44adc59140a9d227fedd6c11990b494fd93f Mon Sep 17 00:00:00 2001 From: Viktoryia Kliushun Date: Thu, 28 Dec 2023 12:26:48 +0100 Subject: [PATCH 02/68] Migrate simple functions --- src/libs/actions/IOU.ts | 140 +++++++--------------------------- src/types/onyx/IOU.ts | 4 + src/types/onyx/Transaction.ts | 2 + 3 files changed, 33 insertions(+), 113 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index dec566ee977a..f62799066d62 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/naming-convention */ import {format} from 'date-fns'; import Str from 'expensify-common/lib/str'; import lodashGet from 'lodash/get'; @@ -25,6 +26,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import * as OnyxTypes from '@src/types/onyx'; +import {Participant} from '@src/types/onyx/IOU'; import {EmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; import * as Report from './Report'; @@ -165,106 +167,55 @@ function startMoneyRequest_temporaryForRefactor(reportID, isFromGlobalCreate, io }); } -/** - * @param {String} transactionID - */ -function clearMoneyRequest(transactionID) { +function clearMoneyRequest(transactionID: string) { Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, null); } -/** - * @param {String} transactionID - * @param {Number} amount - * @param {String} currency - */ -function setMoneyRequestAmount_temporaryForRefactor(transactionID, amount, currency) { +function setMoneyRequestAmount_temporaryForRefactor(transactionID: string, amount: number, currency: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {amount, currency}); } -/** - * @param {String} transactionID - * @param {String} created - */ -function setMoneyRequestCreated_temporaryForRefactor(transactionID, created) { +function setMoneyRequestCreated_temporaryForRefactor(transactionID: string, created: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {created}); } -/** - * @param {String} transactionID - * @param {String} currency - */ -function setMoneyRequestCurrency_temporaryForRefactor(transactionID, currency) { +function setMoneyRequestCurrency_temporaryForRefactor(transactionID: string, currency: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {currency}); } -/** - * @param {String} transactionID - * @param {String} comment - */ -function setMoneyRequestDescription_temporaryForRefactor(transactionID, comment) { +function setMoneyRequestDescription_temporaryForRefactor(transactionID: string, comment: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {comment: {comment: comment.trim()}}); } -/** - * @param {String} transactionID - * @param {String} merchant - */ -function setMoneyRequestMerchant_temporaryForRefactor(transactionID, merchant) { +function setMoneyRequestMerchant_temporaryForRefactor(transactionID: string, merchant: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {merchant: merchant.trim()}); } -/** - * @param {String} transactionID - * @param {String} category - */ -function setMoneyRequestCategory_temporaryForRefactor(transactionID, category) { +function setMoneyRequestCategory_temporaryForRefactor(transactionID: string, category: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {category}); } -/* - * @param {String} transactionID - */ -function resetMoneyRequestCategory_temporaryForRefactor(transactionID) { +function resetMoneyRequestCategory_temporaryForRefactor(transactionID: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {category: null}); } -/* - * @param {String} transactionID - * @param {String} tag - */ -function setMoneyRequestTag_temporaryForRefactor(transactionID, tag) { +function setMoneyRequestTag_temporaryForRefactor(transactionID: string, tag: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {tag}); } -/* - * @param {String} transactionID - */ -function resetMoneyRequestTag_temporaryForRefactor(transactionID) { +function resetMoneyRequestTag_temporaryForRefactor(transactionID: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {tag: null}); } -/** - * @param {String} transactionID - * @param {Boolean} billable - */ -function setMoneyRequestBillable_temporaryForRefactor(transactionID, billable) { +function setMoneyRequestBillable_temporaryForRefactor(transactionID: string, billable: boolean) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {billable}); } -/** - * @param {String} transactionID - * @param {Object[]} participants - */ -function setMoneyRequestParticipants_temporaryForRefactor(transactionID, participants) { +function setMoneyRequestParticipants_temporaryForRefactor(transactionID: string, participants: Participant[]) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {participants}); } -/** - * @param {String} transactionID - * @param {String} source - * @param {String} filename - */ -function setMoneyRequestReceipt_temporaryForRefactor(transactionID, source, filename) { +function setMoneyRequestReceipt_temporaryForRefactor(transactionID: string, source: string, filename: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {receipt: {source}, filename}); } @@ -3214,60 +3165,37 @@ function setMoneyRequestParticipantsFromReport(transactionID, report) { /** * Initialize money request info and navigate to the MoneyRequest page - * @param {String} iouType - * @param {String} reportID */ -function startMoneyRequest(iouType, reportID = '') { +function startMoneyRequest(iouType: string, reportID = '') { resetMoneyRequestInfo(`${iouType}${reportID}`); Navigation.navigate(ROUTES.MONEY_REQUEST.getRoute(iouType, reportID)); } -/** - * @param {String} id - */ -function setMoneyRequestId(id) { +function setMoneyRequestId(id: string) { Onyx.merge(ONYXKEYS.IOU, {id}); } -/** - * @param {Number} amount - */ -function setMoneyRequestAmount(amount) { +function setMoneyRequestAmount(amount: number) { Onyx.merge(ONYXKEYS.IOU, {amount}); } -/** - * @param {String} created - */ -function setMoneyRequestCreated(created) { +function setMoneyRequestCreated(created: string) { Onyx.merge(ONYXKEYS.IOU, {created}); } -/** - * @param {String} currency - */ -function setMoneyRequestCurrency(currency) { +function setMoneyRequestCurrency(currency: string) { Onyx.merge(ONYXKEYS.IOU, {currency}); } -/** - * @param {String} comment - */ -function setMoneyRequestDescription(comment) { +function setMoneyRequestDescription(comment: string) { Onyx.merge(ONYXKEYS.IOU, {comment: comment.trim()}); } -/** - * @param {String} merchant - */ -function setMoneyRequestMerchant(merchant) { +function setMoneyRequestMerchant(merchant: string) { Onyx.merge(ONYXKEYS.IOU, {merchant: merchant.trim()}); } -/** - * @param {String} category - */ -function setMoneyRequestCategory(category) { +function setMoneyRequestCategory(category: string) { Onyx.merge(ONYXKEYS.IOU, {category}); } @@ -3275,10 +3203,7 @@ function resetMoneyRequestCategory() { Onyx.merge(ONYXKEYS.IOU, {category: ''}); } -/* - * @param {String} tag - */ -function setMoneyRequestTag(tag) { +function setMoneyRequestTag(tag: string) { Onyx.merge(ONYXKEYS.IOU, {tag}); } @@ -3286,26 +3211,15 @@ function resetMoneyRequestTag() { Onyx.merge(ONYXKEYS.IOU, {tag: ''}); } -/** - * @param {Boolean} billable - */ -function setMoneyRequestBillable(billable) { +function setMoneyRequestBillable(billable: boolean) { Onyx.merge(ONYXKEYS.IOU, {billable}); } -/** - * @param {Object[]} participants - * @param {Boolean} isSplitRequest - */ -function setMoneyRequestParticipants(participants, isSplitRequest) { +function setMoneyRequestParticipants(participants: Participant[], isSplitRequest: boolean) { Onyx.merge(ONYXKEYS.IOU, {participants, isSplitRequest}); } -/** - * @param {String} receiptPath - * @param {String} receiptFilename - */ -function setMoneyRequestReceipt(receiptPath, receiptFilename) { +function setMoneyRequestReceipt(receiptPath: string, receiptFilename: string) { Onyx.merge(ONYXKEYS.IOU, {receiptPath, receiptFilename, merchant: ''}); } diff --git a/src/types/onyx/IOU.ts b/src/types/onyx/IOU.ts index a89b0d4530ef..e6a0d861e989 100644 --- a/src/types/onyx/IOU.ts +++ b/src/types/onyx/IOU.ts @@ -13,6 +13,7 @@ type IOU = { /** Selected Currency Code of the current IOU */ currency?: string; comment?: string; + category?: string; merchant?: string; created?: string; receiptPath?: string; @@ -20,6 +21,9 @@ type IOU = { transactionID?: string; participants?: Participant[]; tag?: string; + billable?: boolean; + isSplitRequest?: boolean; }; export default IOU; +export type {Participant}; diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 8b79966451ed..bed682822add 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -1,5 +1,6 @@ import {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; +import {Participant} from './IOU'; import * as OnyxCommon from './OnyxCommon'; import RecentWaypoint from './RecentWaypoint'; @@ -70,6 +71,7 @@ type Transaction = { modifiedWaypoints?: WaypointCollection; // Used during the creation flow before the transaction is saved to the server and helps dictate where the user is navigated to when pressing the back button on the confirmation step participantsAutoAssigned?: boolean; + participants?: Participant[]; pendingAction: OnyxCommon.PendingAction; receipt?: Receipt; reportID: string; From 519852e6437f81d8153d03e481d7ccab9f359305 Mon Sep 17 00:00:00 2001 From: Viktoryia Kliushun Date: Thu, 28 Dec 2023 12:38:31 +0100 Subject: [PATCH 03/68] Migrate startMoneyRequest_temporaryForRefactor and resetMoneyRequestInfo functions --- src/libs/actions/IOU.ts | 19 ++++++++++++------- src/types/onyx/Transaction.ts | 4 +++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index f62799066d62..5fcfc13fe6c9 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -5,6 +5,7 @@ import lodashGet from 'lodash/get'; import lodashHas from 'lodash/has'; import Onyx, {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import OnyxUtils from 'react-native-onyx/lib/utils'; +import {ValueOf} from 'type-fest'; import _ from 'underscore'; import ReceiptGeneric from '@assets/images/receipt-generic.png'; import * as API from '@libs/API'; @@ -27,10 +28,13 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import * as OnyxTypes from '@src/types/onyx'; import {Participant} from '@src/types/onyx/IOU'; +import {Comment} from '@src/types/onyx/Transaction'; import {EmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; import * as Report from './Report'; +type IOURequestType = ValueOf; + let betas: OnyxTypes.Beta[] = []; Onyx.connect({ key: ONYXKEYS.BETAS, @@ -135,15 +139,16 @@ Onyx.connect({ /** * Initialize money request info - * @param {String} reportID to attach the transaction to - * @param {Boolean} isFromGlobalCreate - * @param {String} [iouRequestType] one of manual/scan/distance + * @param reportID to attach the transaction to + * @param isFromGlobalCreate + * @param [iouRequestType] one of manual/scan/distance */ -function startMoneyRequest_temporaryForRefactor(reportID, isFromGlobalCreate, iouRequestType = CONST.IOU.REQUEST_TYPE.MANUAL) { +function startMoneyRequest_temporaryForRefactor(reportID: string, isFromGlobalCreate: boolean, iouRequestType: IOURequestType = CONST.IOU.REQUEST_TYPE.MANUAL) { // Generate a brand new transactionID const newTransactionID = CONST.IOU.OPTIMISTIC_TRANSACTION_ID; + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- currentDate can be an empty string const created = currentDate || format(new Date(), 'yyyy-MM-dd'); - const comment = {}; + const comment: Comment = {}; // Add initial empty waypoints when starting a distance request if (iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE) { @@ -221,14 +226,14 @@ function setMoneyRequestReceipt_temporaryForRefactor(transactionID: string, sour /** * Reset money request info from the store with its initial value - * @param {String} id */ function resetMoneyRequestInfo(id = '') { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- currentDate can be an empty string const created = currentDate || format(new Date(), CONST.DATE.FNS_FORMAT_STRING); Onyx.merge(ONYXKEYS.IOU, { id, amount: 0, - currency: lodashGet(currentUserPersonalDetails, 'localCurrencyCode', CONST.CURRENCY.USD), + currency: currentUserPersonalDetails?.localCurrencyCode ?? CONST.CURRENCY.USD, comment: '', participants: [], merchant: CONST.TRANSACTION.DEFAULT_MERCHANT, diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index bed682822add..34068a6d12d9 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -98,7 +98,9 @@ type Transaction = { originalCurrency?: string; }; -type TransactionDraft = Partial; +type TransactionDraft = Partial & { + isFromGlobalCreate?: boolean; +}; export default Transaction; export type {WaypointCollection, Comment, Receipt, Waypoint, TransactionDraft}; From e5f8cc337ccbf4b1a3a6e90cad83d23a8a999fd9 Mon Sep 17 00:00:00 2001 From: Viktoryia Kliushun Date: Thu, 28 Dec 2023 13:39:45 +0100 Subject: [PATCH 04/68] Migrate buildOnyxDataForMoneyRequest function --- src/libs/ErrorUtils.ts | 2 +- src/libs/ReportUtils.ts | 2 +- src/libs/actions/IOU.ts | 243 ++++++++++++++++++++++++---------------- 3 files changed, 147 insertions(+), 100 deletions(-) diff --git a/src/libs/ErrorUtils.ts b/src/libs/ErrorUtils.ts index 46bdd510f5c4..8d3cc4b83fab 100644 --- a/src/libs/ErrorUtils.ts +++ b/src/libs/ErrorUtils.ts @@ -38,7 +38,7 @@ function getAuthenticateErrorMessage(response: Response): keyof TranslationFlatO * Method used to get an error object with microsecond as the key. * @param error - error key or message to be saved */ -function getMicroSecondOnyxError(error: string): Record { +function getMicroSecondOnyxError(error: string | null): Record { return {[DateUtils.getMicroseconds()]: error}; } diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 81bbf1df6273..b72b36a5caca 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4368,4 +4368,4 @@ export { shouldAutoFocusOnKeyPress, }; -export type {ExpenseOriginalMessage, OptionData, OptimisticChatReport}; +export type {ExpenseOriginalMessage, OptionData, OptimisticChatReport, OptimisticCreatedReportAction, OptimisticIOUReportAction}; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 5fcfc13fe6c9..e9e6bc394b16 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -3,7 +3,7 @@ import {format} from 'date-fns'; import Str from 'expensify-common/lib/str'; import lodashGet from 'lodash/get'; import lodashHas from 'lodash/has'; -import Onyx, {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import Onyx, {OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import OnyxUtils from 'react-native-onyx/lib/utils'; import {ValueOf} from 'type-fest'; import _ from 'underscore'; @@ -21,6 +21,7 @@ import * as OptionsListUtils from '@libs/OptionsListUtils'; import Permissions from '@libs/Permissions'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; +import {OptimisticCreatedReportAction, OptimisticIOUReportAction} from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import * as UserUtils from '@libs/UserUtils'; import CONST from '@src/CONST'; @@ -28,11 +29,18 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import * as OnyxTypes from '@src/types/onyx'; import {Participant} from '@src/types/onyx/IOU'; +import ReportAction from '@src/types/onyx/ReportAction'; import {Comment} from '@src/types/onyx/Transaction'; import {EmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; import * as Report from './Report'; +// TODO: Remove this once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. +type OptimisticPolicyRecentlyUsedCategories = string[]; + +// TODO: Remove this once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. +type OptimisticPolicyRecentlyUsedTags = Record; + type IOURequestType = ValueOf; let betas: OnyxTypes.Beta[] = []; @@ -249,63 +257,100 @@ function resetMoneyRequestInfo(id = '') { } function buildOnyxDataForMoneyRequest( - chatReport, - iouReport, - transaction, - chatCreatedAction, - iouCreatedAction, - iouAction, - optimisticPersonalDetailListAction, - reportPreviewAction, - optimisticPolicyRecentlyUsedCategories, - optimisticPolicyRecentlyUsedTags, - isNewChatReport, - isNewIOUReport, -) { - const optimisticData = [ - { - // Use 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 - onyxMethod: isNewChatReport ? Onyx.METHOD.SET : Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, - value: { - ...chatReport, - lastReadTime: DateUtils.getDBTime(), - lastMessageTranslationKey: '', - iouReportID: iouReport.reportID, - ...(isNewChatReport ? {pendingFields: {createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}} : {}), - }, - }, - { - onyxMethod: isNewIOUReport ? Onyx.METHOD.SET : Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, - value: { - ...iouReport, - lastMessageText: iouAction.message[0].text, - lastMessageHtml: iouAction.message[0].html, - ...(isNewIOUReport ? {pendingFields: {createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}} : {}), - }, - }, + chatReport: OnyxTypes.Report, + iouReport: OnyxTypes.Report, + transaction: OnyxTypes.Transaction, + chatCreatedAction: OptimisticCreatedReportAction, + iouCreatedAction: OptimisticCreatedReportAction, + iouAction: OptimisticIOUReportAction, + optimisticPersonalDetailListAction: OnyxTypes.PersonalDetailsList | undefined, + reportPreviewAction: ReportAction, + optimisticPolicyRecentlyUsedCategories: OptimisticPolicyRecentlyUsedCategories, + optimisticPolicyRecentlyUsedTags: OptimisticPolicyRecentlyUsedTags, + isNewChatReport: boolean, + isNewIOUReport: boolean, +): OnyxUpdate[][] { + const optimisticData: OnyxUpdate[] = [ + isNewChatReport + ? { + // Use 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 + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`, + value: { + ...chatReport, + lastReadTime: DateUtils.getDBTime(), + lastMessageTranslationKey: '', + iouReportID: iouReport?.reportID, + pendingFields: {createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}, + }, + } + : { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`, + value: { + ...chatReport, + lastReadTime: DateUtils.getDBTime(), + lastMessageTranslationKey: '', + iouReportID: iouReport?.reportID, + }, + }, + isNewIOUReport + ? { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, + value: { + ...iouReport, + lastMessageText: iouAction.message?.[0].text, + lastMessageHtml: iouAction.message?.[0].html, + pendingFields: {createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}, + }, + } + : { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, + value: { + ...iouReport, + lastMessageText: iouAction.message?.[0].text, + lastMessageHtml: iouAction.message?.[0].html, + }, + }, { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`, value: transaction, }, - { - onyxMethod: isNewChatReport ? Onyx.METHOD.SET : Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, - value: { - ...(isNewChatReport ? {[chatCreatedAction.reportActionID]: chatCreatedAction} : {}), - [reportPreviewAction.reportActionID]: reportPreviewAction, - }, - }, - { - onyxMethod: isNewIOUReport ? Onyx.METHOD.SET : Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`, - value: { - ...(isNewIOUReport ? {[iouCreatedAction.reportActionID]: iouCreatedAction} : {}), - [iouAction.reportActionID]: iouAction, - }, - }, + isNewChatReport + ? { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, + value: { + [chatCreatedAction.reportActionID]: chatCreatedAction, + [reportPreviewAction.reportActionID]: reportPreviewAction, + }, + } + : { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, + value: { + [reportPreviewAction.reportActionID]: reportPreviewAction, + }, + }, + isNewIOUReport + ? { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`, + value: { + [iouCreatedAction.reportActionID]: iouCreatedAction as OnyxTypes.ReportAction, + [iouAction.reportActionID]: iouAction as OnyxTypes.ReportAction, + }, + } + : { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`, + value: { + [iouAction.reportActionID]: iouAction as OnyxTypes.ReportAction, + }, + }, // Remove the temporary transaction used during the creation flow { @@ -315,7 +360,7 @@ function buildOnyxDataForMoneyRequest( }, ]; - if (!_.isEmpty(optimisticPolicyRecentlyUsedCategories)) { + if (optimisticPolicyRecentlyUsedCategories.length) { optimisticData.push({ onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${iouReport.policyID}`, @@ -323,7 +368,7 @@ function buildOnyxDataForMoneyRequest( }); } - if (!_.isEmpty(optimisticPolicyRecentlyUsedTags)) { + if (Object.keys(optimisticPolicyRecentlyUsedTags).length) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${iouReport.policyID}`, @@ -331,7 +376,7 @@ function buildOnyxDataForMoneyRequest( }); } - if (!_.isEmpty(optimisticPersonalDetailListAction)) { + if (optimisticPersonalDetailListAction && Object.keys(optimisticPersonalDetailListAction).length) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, @@ -339,31 +384,31 @@ function buildOnyxDataForMoneyRequest( }); } - const successData = [ - ...(isNewChatReport - ? [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, - value: { - pendingFields: null, - errorFields: null, - }, - }, - ] - : []), - ...(isNewIOUReport - ? [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, - value: { - pendingFields: null, - errorFields: null, - }, - }, - ] - : []), + const successData: OnyxUpdate[] = []; + + if (isNewChatReport) { + successData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, + value: { + pendingFields: null, + errorFields: null, + }, + }); + } + + if (isNewIOUReport) { + successData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, + value: { + pendingFields: null, + errorFields: null, + }, + }); + } + + successData.push( { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`, @@ -408,9 +453,9 @@ function buildOnyxDataForMoneyRequest( }, }, }, - ]; + ); - const failureData = [ + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, @@ -427,20 +472,22 @@ function buildOnyxDataForMoneyRequest( : {}), }, }, - ...(isNewIOUReport - ? [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, - value: { - pendingFields: null, - errorFields: { - createChat: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'), - }, - }, - }, - ] - : []), + ]; + + if (isNewIOUReport) { + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, + value: { + pendingFields: null, + errorFields: { + createChat: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'), + }, + }, + }); + } + + failureData.push( { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`, @@ -499,7 +546,7 @@ function buildOnyxDataForMoneyRequest( }), }, }, - ]; + ); return [optimisticData, successData, failureData]; } From 98a1e6bb49ed2cfe18bd777c3806a37a3a54db36 Mon Sep 17 00:00:00 2001 From: Viktoryia Kliushun Date: Thu, 28 Dec 2023 15:40:05 +0100 Subject: [PATCH 05/68] Migrate getMoneyRequestInformation function --- src/libs/IOUUtils.ts | 3 +- src/libs/ReportUtils.ts | 47 +++------------ src/libs/actions/IOU.ts | 107 +++++++++++++++------------------ src/libs/actions/Policy.js | 8 +-- src/types/onyx/IOU.ts | 11 ++++ src/types/onyx/ReportAction.ts | 2 + src/types/onyx/Transaction.ts | 1 + 7 files changed, 74 insertions(+), 105 deletions(-) diff --git a/src/libs/IOUUtils.ts b/src/libs/IOUUtils.ts index edfb9e3691d0..786a91ce3227 100644 --- a/src/libs/IOUUtils.ts +++ b/src/libs/IOUUtils.ts @@ -1,4 +1,3 @@ -import {OnyxEntry} from 'react-native-onyx'; import {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; @@ -74,7 +73,7 @@ function calculateAmount(numberOfParticipants: number, total: number, currency: * * @param isDeleting - whether the user is deleting the request */ -function updateIOUOwnerAndTotal(iouReport: OnyxEntry, actorAccountID: number, amount: number, currency: string, isDeleting = false): OnyxEntry { +function updateIOUOwnerAndTotal(iouReport: Report, actorAccountID: number, amount: number, currency: string, isDeleting = false): Report { if (currency !== iouReport?.currency) { return iouReport; } diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index b72b36a5caca..68fb91c7f3e9 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -14,6 +14,7 @@ import {ParentNavigationSummaryParams, TranslationPaths} from '@src/languages/ty import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import {Beta, Login, PersonalDetails, PersonalDetailsList, Policy, Report, ReportAction, Session, Transaction} from '@src/types/onyx'; +import {Participant} from '@src/types/onyx/IOU'; import {Errors, Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; import {IOUMessage, OriginalMessageActionName, OriginalMessageCreated} from '@src/types/onyx/OriginalMessage'; import {NotificationPreference} from '@src/types/onyx/Report'; @@ -60,20 +61,6 @@ type ExpenseOriginalMessage = { oldBillable?: string; }; -type Participant = { - accountID: number; - alternateText: string; - firstName: string; - icons: Icon[]; - keyForList: string; - lastName: string; - login: string; - phoneNumber: string; - searchText: string; - selected: boolean; - text: string; -}; - type SpendBreakdown = { nonReimbursableSpend: number; reimbursableSpend: number; @@ -135,27 +122,6 @@ type OptimisticIOUReportAction = Pick< | 'whisperedToAccountIDs' >; -type OptimisticReportPreview = Pick< - ReportAction, - | 'actionName' - | 'reportActionID' - | 'pendingAction' - | 'originalMessage' - | 'message' - | 'created' - | 'actorAccountID' - | 'childMoneyRequestCount' - | 'childLastMoneyRequestComment' - | 'childRecentReceiptTransactionIDs' - | 'childReportID' - | 'whisperedToAccountIDs' -> & {reportID?: string; accountID?: number}; - -type UpdateReportPreview = Pick< - ReportAction, - 'created' | 'message' | 'childLastMoneyRequestComment' | 'childMoneyRequestCount' | 'childRecentReceiptTransactionIDs' | 'whisperedToAccountIDs' ->; - type ReportRouteParams = { reportID: string; isSubReportPageRoute: boolean; @@ -2607,7 +2573,7 @@ function buildOptimisticIOUReportAction( comment: string, participants: Participant[], transactionID: string, - paymentType: DeepValueOf, + paymentType: DeepValueOf | undefined, iouReportID = '', isSettlingUp = false, isSendMoneyFlow = false, @@ -2801,7 +2767,7 @@ function buildOptimisticReportPreview( comment = '', transaction: OnyxEntry = null, childReportID?: string, -): OptimisticReportPreview { +): ReportAction { const hasReceipt = TransactionUtils.hasReceipt(transaction); const isReceiptBeingScanned = hasReceipt && TransactionUtils.isReceiptBeingScanned(transaction); const message = getReportPreviewMessage(iouReport); @@ -2812,7 +2778,7 @@ function buildOptimisticReportPreview( actionName: CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, originalMessage: { - linkedReportID: iouReport?.reportID, + linkedReportID: iouReport?.reportID ?? '', }, message: [ { @@ -2887,7 +2853,7 @@ function updateReportPreview( isPayRequest = false, comment = '', transaction: OnyxEntry = null, -): UpdateReportPreview { +): ReportAction { const hasReceipt = TransactionUtils.hasReceipt(transaction); const recentReceiptTransactions = reportPreviewAction?.childRecentReceiptTransactionIDs ?? {}; const transactionsToKeep = TransactionUtils.getRecentTransactions(recentReceiptTransactions); @@ -2904,7 +2870,8 @@ function updateReportPreview( const message = getReportPreviewMessage(iouReport, reportPreviewAction); return { - ...reportPreviewAction, + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style + ...(reportPreviewAction as ReportAction), created: DateUtils.getDBTime(), message: [ { diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index e9e6bc394b16..831859f5d9c4 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -30,7 +30,8 @@ import ROUTES from '@src/ROUTES'; import * as OnyxTypes from '@src/types/onyx'; import {Participant} from '@src/types/onyx/IOU'; import ReportAction from '@src/types/onyx/ReportAction'; -import {Comment} from '@src/types/onyx/Transaction'; +import {OnyxData} from '@src/types/onyx/Request'; +import {Comment, Receipt} from '@src/types/onyx/Transaction'; import {EmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; import * as Report from './Report'; @@ -43,6 +44,19 @@ type OptimisticPolicyRecentlyUsedTags = Record; type IOURequestType = ValueOf; +type MoneyRequestInformation = { + payerAccountID: number; + payerEmail: string; + iouReport: OnyxTypes.Report; + chatReport: OnyxTypes.Report; + transaction: OnyxTypes.Transaction; + iouAction: OptimisticIOUReportAction; + createdChatReportActionID: string; + createdIOUReportActionID: string; + reportPreviewAction: OnyxTypes.ReportAction; + onyxData: OnyxData; +}; + let betas: OnyxTypes.Beta[] = []; Onyx.connect({ key: ONYXKEYS.BETAS, @@ -554,63 +568,35 @@ function buildOnyxDataForMoneyRequest( /** * Gathers all the data needed to make a money request. It attempts to find existing reports, iouReports, and receipts. If it doesn't find them, then * it creates optimistic versions of them and uses those instead - * - * @param {Object} report - * @param {Object} participant - * @param {String} comment - * @param {Number} amount - * @param {String} currency - * @param {String} created - * @param {String} merchant - * @param {Number} [payeeAccountID] - * @param {String} [payeeEmail] - * @param {Object} [receipt] - * @param {String} [existingTransactionID] - * @param {String} [category] - * @param {String} [tag] - * @param {Boolean} [billable] - * @returns {Object} data - * @returns {String} data.payerEmail - * @returns {Object} data.iouReport - * @returns {Object} data.chatReport - * @returns {Object} data.transaction - * @returns {Object} data.iouAction - * @returns {Object} data.createdChatReportActionID - * @returns {Object} data.createdIOUReportActionID - * @returns {Object} data.reportPreviewAction - * @returns {Object} data.onyxData - * @returns {Object} data.onyxData.optimisticData - * @returns {Object} data.onyxData.successData - * @returns {Object} data.onyxData.failureData */ function getMoneyRequestInformation( - report, - participant, - comment, - amount, - currency, - created, - merchant, + report: OnyxTypes.Report, + participant: Participant, + comment: string, + amount: number, + currency: string, + created: string, + merchant: string, payeeAccountID = userAccountID, payeeEmail = currentUserEmail, - receipt = undefined, - existingTransactionID = undefined, - category = undefined, - tag = undefined, - billable = undefined, -) { - const payerEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login); + receipt?: Receipt, + existingTransactionID?: string, + category?: string, + tag?: string, + billable?: boolean, +): MoneyRequestInformation { + const payerEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login ?? ''); const payerAccountID = Number(participant.accountID); const isPolicyExpenseChat = participant.isPolicyExpenseChat; // STEP 1: Get existing chat report OR build a new optimistic one let isNewChatReport = false; - let chatReport = lodashGet(report, 'reportID', null) ? report : null; + let chatReport = report?.reportID ? report : null; // 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) { - chatReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${participant.reportID}`]; + chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.reportID}`] ?? null; } if (!chatReport) { @@ -625,11 +611,11 @@ function getMoneyRequestInformation( // STEP 2: Get existing IOU report and update its total OR build a new optimistic one const isNewIOUReport = !chatReport.iouReportID || ReportUtils.hasIOUWaitingOnCurrentUserBankAccount(chatReport); - let iouReport = isNewIOUReport ? null : allReports[`${ONYXKEYS.COLLECTION.REPORT}${chatReport.iouReportID}`]; + let iouReport = isNewIOUReport ? null : allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReport.iouReportID}`]; // If the linked expense report on paid policy is not draft, we need to create a new draft expense report if (isPolicyExpenseChat && iouReport) { - const policyType = ReportUtils.getPolicy(iouReport.policyID).type || ''; + const policyType = ReportUtils.getPolicy(iouReport.policyID ?? '').type || ''; const isFromPaidPolicy = policyType === CONST.POLICY.TYPE.TEAM || policyType === CONST.POLICY.TYPE.CORPORATE; if (isFromPaidPolicy && !ReportUtils.isDraftExpenseReport(iouReport)) { iouReport = null; @@ -640,23 +626,25 @@ function getMoneyRequestInformation( if (isPolicyExpenseChat) { iouReport = {...iouReport}; - // Because of the Expense reports are stored as negative values, we substract the total from the amount - iouReport.total -= amount; + if (iouReport.total) { + // Because of the Expense reports are stored as negative values, we substract the total from the amount + iouReport.total -= amount; + } } else { iouReport = IOUUtils.updateIOUOwnerAndTotal(iouReport, payeeAccountID, amount, currency); } } else { iouReport = isPolicyExpenseChat - ? ReportUtils.buildOptimisticExpenseReport(chatReport.reportID, chatReport.policyID, payeeAccountID, amount, currency) + ? ReportUtils.buildOptimisticExpenseReport(chatReport.reportID, chatReport.policyID ?? '', payeeAccountID, amount, currency) : ReportUtils.buildOptimisticIOUReport(payeeAccountID, payerAccountID, amount, chatReport.reportID, currency); } // STEP 3: Build optimistic receipt and transaction - const receiptObject = {}; + const receiptObject: Receipt = {}; let filename; - if (receipt && receipt.source) { + if (receipt?.source) { receiptObject.source = receipt.source; - receiptObject.state = receipt.state || CONST.IOU.RECEIPT_STATE.SCANREADY; + receiptObject.state = receipt.state ?? CONST.IOU.RECEIPT_STATE.SCANREADY; filename = receipt.name; } let optimisticTransaction = TransactionUtils.buildOptimisticTransaction( @@ -676,9 +664,9 @@ function getMoneyRequestInformation( billable, ); - const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, category); + const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, category) as OptimisticPolicyRecentlyUsedCategories; - const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport.policyID, tag); + const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport.policyID, tag) as OptimisticPolicyRecentlyUsedTags; // 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 @@ -687,7 +675,7 @@ function getMoneyRequestInformation( // to remind me to do this. const existingTransaction = allTransactionDrafts[`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`]; if (existingTransaction && existingTransaction.iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE) { - optimisticTransaction = OnyxUtils.fastMerge(existingTransaction, optimisticTransaction); + optimisticTransaction = OnyxUtils.fastMerge(existingTransaction, optimisticTransaction) as OnyxTypes.Transaction; } // STEP 4: Build optimistic reportActions. We need: @@ -706,7 +694,7 @@ function getMoneyRequestInformation( comment, [participant], optimisticTransaction.transactionID, - '', + undefined, iouReport.reportID, false, false, @@ -733,6 +721,7 @@ function getMoneyRequestInformation( [payerAccountID]: { accountID: payerAccountID, avatar: UserUtils.getDefaultAvatarURL(payerAccountID), + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing displayName: LocalePhoneNumber.formatPhoneNumber(participant.displayName || payerEmail), login: participant.login, isOptimisticPersonalDetail: true, @@ -763,8 +752,8 @@ function getMoneyRequestInformation( chatReport, transaction: optimisticTransaction, iouAction, - createdChatReportActionID: isNewChatReport ? optimisticCreatedActionForChat.reportActionID : 0, - createdIOUReportActionID: isNewIOUReport ? optimisticCreatedActionForIOU.reportActionID : 0, + createdChatReportActionID: isNewChatReport ? optimisticCreatedActionForChat.reportActionID : '', + createdIOUReportActionID: isNewIOUReport ? optimisticCreatedActionForIOU.reportActionID : '', reportPreviewAction, onyxData: { optimisticData, diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index f33e6637e2de..0ff1b75315c7 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -1475,8 +1475,8 @@ function dismissAddedWithPrimaryLoginMessages(policyID) { } /** - * @param {String} policyID - * @param {String} category + * @param {String | undefined} policyID + * @param {String | undefined} category * @returns {Object} */ function buildOptimisticPolicyRecentlyUsedCategories(policyID, category) { @@ -1490,8 +1490,8 @@ function buildOptimisticPolicyRecentlyUsedCategories(policyID, category) { } /** - * @param {String} policyID - * @param {String} tag + * @param {String | undefined} policyID + * @param {String | undefined} tag * @returns {Object} */ function buildOptimisticPolicyRecentlyUsedTags(policyID, tag) { diff --git a/src/types/onyx/IOU.ts b/src/types/onyx/IOU.ts index e6a0d861e989..4558e5a99c08 100644 --- a/src/types/onyx/IOU.ts +++ b/src/types/onyx/IOU.ts @@ -1,3 +1,5 @@ +import {Icon} from './OnyxCommon'; + type Participant = { accountID: number; login?: string; @@ -5,6 +7,15 @@ type Participant = { isOwnPolicyExpenseChat?: boolean; selected?: boolean; reportID?: string; + displayName?: string; + alternateText: string; + firstName: string; + icons: Icon[]; + keyForList: string; + lastName: string; + phoneNumber: string; + searchText: string; + text: string; }; type IOU = { diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts index a881b63fbb95..a9adc66a7806 100644 --- a/src/types/onyx/ReportAction.ts +++ b/src/types/onyx/ReportAction.ts @@ -139,6 +139,8 @@ type ReportActionBase = { /** Type of child report */ childType?: string; + accountID?: number; + childOldestFourEmails?: string; childOldestFourAccountIDs?: string; childCommenterCount?: number; diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 34068a6d12d9..a40acda79c91 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -39,6 +39,7 @@ type Geometry = { type Receipt = { receiptID?: number; path?: string; + name?: string; source?: string; state?: ValueOf; }; From 19035e5ab44357977b65cbdab8338f119c77a7ac Mon Sep 17 00:00:00 2001 From: Viktoryia Kliushun Date: Thu, 28 Dec 2023 15:47:31 +0100 Subject: [PATCH 06/68] Fix failing Money request --- src/libs/actions/IOU.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 831859f5d9c4..04e07ef4b2ef 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -51,8 +51,8 @@ type MoneyRequestInformation = { chatReport: OnyxTypes.Report; transaction: OnyxTypes.Transaction; iouAction: OptimisticIOUReportAction; - createdChatReportActionID: string; - createdIOUReportActionID: string; + createdChatReportActionID: string | number; + createdIOUReportActionID: string | number; reportPreviewAction: OnyxTypes.ReportAction; onyxData: OnyxData; }; @@ -752,8 +752,8 @@ function getMoneyRequestInformation( chatReport, transaction: optimisticTransaction, iouAction, - createdChatReportActionID: isNewChatReport ? optimisticCreatedActionForChat.reportActionID : '', - createdIOUReportActionID: isNewIOUReport ? optimisticCreatedActionForIOU.reportActionID : '', + createdChatReportActionID: isNewChatReport ? optimisticCreatedActionForChat.reportActionID : 0, + createdIOUReportActionID: isNewIOUReport ? optimisticCreatedActionForIOU.reportActionID : 0, reportPreviewAction, onyxData: { optimisticData, From ad41a6053698949e0f5c08bfb2805ffbc0cacc54 Mon Sep 17 00:00:00 2001 From: Viktoryia Kliushun Date: Thu, 28 Dec 2023 17:43:37 +0100 Subject: [PATCH 07/68] Migrate createDistanceRequest and requestMoney functions --- src/libs/ReportUtils.ts | 2 +- src/libs/actions/IOU.ts | 199 +++++++++++++++++++--------------- src/types/onyx/Transaction.ts | 3 +- 3 files changed, 114 insertions(+), 90 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 68fb91c7f3e9..57c5d7b8fc42 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -974,7 +974,7 @@ function isOneOnOneChat(report: OnyxEntry): boolean { /** * Get the report given a reportID */ -function getReport(reportID: string | undefined): OnyxEntry | EmptyObject { +function getReport(reportID: string | undefined): Report | EmptyObject { /** * Using typical string concatenation here due to performance issues * with template literals. diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 04e07ef4b2ef..017f51c4e510 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -31,8 +31,8 @@ import * as OnyxTypes from '@src/types/onyx'; import {Participant} from '@src/types/onyx/IOU'; import ReportAction from '@src/types/onyx/ReportAction'; import {OnyxData} from '@src/types/onyx/Request'; -import {Comment, Receipt} from '@src/types/onyx/Transaction'; -import {EmptyObject} from '@src/types/utils/EmptyObject'; +import {Comment, Receipt, WaypointCollection} from '@src/types/onyx/Transaction'; +import {EmptyObject, isEmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; import * as Report from './Report'; @@ -570,7 +570,7 @@ function buildOnyxDataForMoneyRequest( * it creates optimistic versions of them and uses those instead */ function getMoneyRequestInformation( - report: OnyxTypes.Report, + report: OnyxTypes.Report | EmptyObject, participant: Participant, comment: string, amount: number, @@ -591,7 +591,7 @@ function getMoneyRequestInformation( // STEP 1: Get existing chat report OR build a new optimistic one let isNewChatReport = false; - let chatReport = report?.reportID ? report : null; + let chatReport = !isEmptyObject(report) && report?.reportID ? report : null; // 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 @@ -765,25 +765,25 @@ function getMoneyRequestInformation( /** * Requests money based on a distance (eg. mileage from a map) - * - * @param {Object} report - * @param {Object} participant - * @param {String} comment - * @param {String} created - * @param {String} [category] - * @param {String} [tag] - * @param {Number} amount - * @param {String} currency - * @param {String} merchant - * @param {Boolean} [billable] - * @param {Obejct} validWaypoints */ -function createDistanceRequest(report, participant, comment, created, category, tag, amount, currency, merchant, billable, validWaypoints) { +function createDistanceRequest( + report: OnyxTypes.Report, + participant: Participant, + comment: string, + created: string, + category: string | undefined, + tag: string | undefined, + amount: number, + currency: string, + merchant: string, + billable: boolean | undefined, + validWaypoints: WaypointCollection, +) { // 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.getReport(report.chatReportID) : report; - const optimisticReceipt = { + const optimisticReceipt: Receipt = { source: ReceiptGeneric, state: CONST.IOU.RECEIPT_STATE.OPEN, }; @@ -803,25 +803,40 @@ function createDistanceRequest(report, participant, comment, created, category, tag, billable, ); - API.write( - 'CreateDistanceRequest', - { - comment, - iouReportID: iouReport.reportID, - chatReportID: chatReport.reportID, - transactionID: transaction.transactionID, - reportActionID: iouAction.reportActionID, - createdChatReportActionID, - createdIOUReportActionID, - reportPreviewReportActionID: reportPreviewAction.reportActionID, - waypoints: JSON.stringify(validWaypoints), - created, - category, - tag, - billable, - }, - onyxData, - ); + + type CreateDistanceRequestParams = { + comment: string; + iouReportID: string; + chatReportID: string; + transactionID: string; + reportActionID: string; + createdChatReportActionID: string | number; + createdIOUReportActionID: string | number; + reportPreviewReportActionID: string; + waypoints: string; + created: string; + category?: string; + tag?: string; + billable?: boolean; + }; + + const parameters: CreateDistanceRequestParams = { + comment, + iouReportID: iouReport.reportID, + chatReportID: chatReport.reportID, + transactionID: transaction.transactionID, + reportActionID: iouAction.reportActionID, + createdChatReportActionID, + createdIOUReportActionID, + reportPreviewReportActionID: reportPreviewAction.reportActionID, + waypoints: JSON.stringify(validWaypoints), + created, + category, + tag, + billable, + }; + + API.write('CreateDistanceRequest', parameters, onyxData); Navigation.dismissModal(isMoneyRequestReport ? report.reportID : chatReport.reportID); Report.notifyNewAction(chatReport.reportID, userAccountID); } @@ -1039,34 +1054,22 @@ function updateDistanceRequest(transactionID, transactionThreadReportID, transac /** * Request money from another user * - * @param {Object} report - * @param {Number} amount - always in the smallest unit of the currency - * @param {String} currency - * @param {String} created - * @param {String} merchant - * @param {String} payeeEmail - * @param {Number} payeeAccountID - * @param {Object} participant - * @param {String} comment - * @param {Object} [receipt] - * @param {String} [category] - * @param {String} [tag] - * @param {Boolean} [billable] + * @param amount - always in the smallest unit of the currency */ function requestMoney( - report, - amount, - currency, - created, - merchant, - payeeEmail, - payeeAccountID, - participant, - comment, - receipt = undefined, - category = undefined, - tag = undefined, - billable = undefined, + report: OnyxTypes.Report, + amount: number, + currency: string, + created: string, + merchant: string, + payeeEmail: string, + payeeAccountID: number, + participant: Participant, + comment: string, + receipt: Receipt, + category?: string, + tag?: string, + billable?: boolean, ) { // 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); @@ -1075,31 +1078,51 @@ function requestMoney( getMoneyRequestInformation(currentChatReport, participant, comment, amount, currency, created, merchant, payeeAccountID, payeeEmail, receipt, undefined, category, tag, billable); const activeReportID = isMoneyRequestReport ? report.reportID : chatReport.reportID; - API.write( - 'RequestMoney', - { - debtorEmail: payerEmail, - debtorAccountID: payerAccountID, - amount, - currency, - comment, - created, - merchant, - iouReportID: iouReport.reportID, - chatReportID: chatReport.reportID, - transactionID: transaction.transactionID, - reportActionID: iouAction.reportActionID, - createdChatReportActionID, - createdIOUReportActionID, - reportPreviewReportActionID: reportPreviewAction.reportActionID, - receipt, - receiptState: lodashGet(receipt, 'state'), - category, - tag, - billable, - }, - onyxData, - ); + type RequestMoneyParams = { + debtorEmail: string; + debtorAccountID: number; + amount: number; + currency: string; + comment: string; + created: string; + merchant: string; + iouReportID: string; + chatReportID: string; + transactionID: string; + reportActionID: string; + createdChatReportActionID: string | number; + createdIOUReportActionID: string | number; + reportPreviewReportActionID: string; + receipt: Receipt; + receiptState?: ValueOf; + category?: string; + tag?: string; + billable?: boolean; + }; + + const parameters: RequestMoneyParams = { + debtorEmail: payerEmail, + debtorAccountID: payerAccountID, + amount, + currency, + comment, + created, + merchant, + iouReportID: iouReport.reportID, + chatReportID: chatReport.reportID, + transactionID: transaction.transactionID, + reportActionID: iouAction.reportActionID, + createdChatReportActionID, + createdIOUReportActionID, + reportPreviewReportActionID: reportPreviewAction.reportActionID, + receipt, + receiptState: receipt?.state, + category, + tag, + billable, + }; + + API.write('RequestMoney', parameters, onyxData); resetMoneyRequestInfo(); Navigation.dismissModal(activeReportID); Report.notifyNewAction(activeReportID, payeeAccountID); diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index a40acda79c91..126a12bcb3f8 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -1,3 +1,4 @@ +import {ImageSourcePropType} from 'react-native'; import {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; import {Participant} from './IOU'; @@ -40,7 +41,7 @@ type Receipt = { receiptID?: number; path?: string; name?: string; - source?: string; + source?: ImageSourcePropType; state?: ValueOf; }; From 578cc507525b69a9661df8c395179be9caf44e37 Mon Sep 17 00:00:00 2001 From: Viktoryia Kliushun Date: Fri, 29 Dec 2023 13:10:32 +0100 Subject: [PATCH 08/68] Migrate startSplitBill function --- src/libs/ReportUtils.ts | 2 + src/libs/TransactionUtils.ts | 6 +- src/libs/actions/IOU.ts | 120 ++++++++++++++++++++-------------- src/types/onyx/IOU.ts | 1 + src/types/onyx/Transaction.ts | 20 +++++- 5 files changed, 95 insertions(+), 54 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 57c5d7b8fc42..93c4f5870720 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -159,6 +159,7 @@ type OptimisticChatReport = Pick< Report, | 'type' | 'chatType' + | 'chatReportID' | 'isOwnPolicyExpenseChat' | 'isPinned' | 'lastActorAccountID' @@ -170,6 +171,7 @@ type OptimisticChatReport = Pick< | 'notificationPreference' | 'oldPolicyName' | 'ownerAccountID' + | 'pendingFields' | 'parentReportActionID' | 'parentReportID' | 'participantAccountIDs' diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index 6905a542fa5b..e3d36484056a 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -4,16 +4,12 @@ import {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import {RecentWaypoint, ReportAction, Transaction} from '@src/types/onyx'; -import {Comment, Receipt, Waypoint, WaypointCollection} from '@src/types/onyx/Transaction'; +import {Comment, Receipt, TransactionChanges, Waypoint, WaypointCollection} from '@src/types/onyx/Transaction'; import {EmptyObject} from '@src/types/utils/EmptyObject'; import {isCorporateCard, isExpensifyCard} from './CardUtils'; import DateUtils from './DateUtils'; import * as NumberUtils from './NumberUtils'; -type AdditionalTransactionChanges = {comment?: string; waypoints?: WaypointCollection}; - -type TransactionChanges = Partial & AdditionalTransactionChanges; - let allTransactions: OnyxCollection = {}; Onyx.connect({ diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 017f51c4e510..8d016fbda0f9 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -31,7 +31,7 @@ import * as OnyxTypes from '@src/types/onyx'; import {Participant} from '@src/types/onyx/IOU'; import ReportAction from '@src/types/onyx/ReportAction'; import {OnyxData} from '@src/types/onyx/Request'; -import {Comment, Receipt, WaypointCollection} from '@src/types/onyx/Transaction'; +import {Comment, Receipt, Split, WaypointCollection} from '@src/types/onyx/Transaction'; import {EmptyObject, isEmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; import * as Report from './Report'; @@ -1573,27 +1573,29 @@ function splitBillAndOpenReport(participants, currentUserLogin, currentUserAccou /** Used exclusively for starting a split bill request that contains a receipt, the split request will be completed once the receipt is scanned * or user enters details manually. * - * @param {Array} participants - * @param {String} currentUserLogin - * @param {Number} currentUserAccountID - * @param {String} comment - * @param {String} category - * @param {String} tag - * @param {Object} receipt - * @param {String} existingSplitChatReportID - Either a group DM or a workspace chat + * @param existingSplitChatReportID - Either a group DM or a workspace chat */ -function startSplitBill(participants, currentUserLogin, currentUserAccountID, comment, category, tag, receipt, existingSplitChatReportID = '') { +function startSplitBill( + participants: Participant[], + currentUserLogin: string, + currentUserAccountID: number, + comment: string, + category: string, + tag: string, + receipt: Receipt, + existingSplitChatReportID = '', +) { const currentUserEmailForIOUSplit = OptionsListUtils.addSMSDomainIfPhoneNumber(currentUserLogin); - const participantAccountIDs = _.map(participants, (participant) => Number(participant.accountID)); + const participantAccountIDs = participants.map((participant) => Number(participant.accountID)); const existingSplitChatReport = existingSplitChatReportID || participants[0].reportID - ? allReports[`${ONYXKEYS.COLLECTION.REPORT}${existingSplitChatReportID || participants[0].reportID}`] + ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${existingSplitChatReportID || participants[0].reportID}`] : ReportUtils.getChatByParticipants(participantAccountIDs); - const splitChatReport = existingSplitChatReport || ReportUtils.buildOptimisticChatReport(participantAccountIDs); - const isOwnPolicyExpenseChat = splitChatReport.isOwnPolicyExpenseChat || false; + const splitChatReport = existingSplitChatReport ?? ReportUtils.buildOptimisticChatReport(participantAccountIDs); + const isOwnPolicyExpenseChat = !!splitChatReport.isOwnPolicyExpenseChat || false; const {name: filename, source, state = CONST.IOU.RECEIPT_STATE.SCANREADY} = receipt; - const receiptObject = {state, source}; + const receiptObject: Receipt = {state, source}; // ReportID is -2 (aka "deleted") on the group transaction const splitTransaction = TransactionUtils.buildOptimisticTransaction( @@ -1618,7 +1620,7 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co comment, participants, splitTransaction.transactionID, - '', + undefined, '', false, false, @@ -1627,8 +1629,8 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co ); splitChatReport.lastReadTime = DateUtils.getDBTime(); - splitChatReport.lastMessageText = splitIOUReportAction.message[0].text; - splitChatReport.lastMessageHtml = splitIOUReportAction.message[0].html; + splitChatReport.lastMessageText = splitIOUReportAction.message?.[0].text; + splitChatReport.lastMessageHtml = splitIOUReportAction.message?.[0].html; // 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) { @@ -1637,7 +1639,7 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co }; } - const optimisticData = [ + const optimisticData: OnyxUpdate[] = [ { // Use 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 @@ -1645,14 +1647,22 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co key: `${ONYXKEYS.COLLECTION.REPORT}${splitChatReport.reportID}`, value: splitChatReport, }, - { - onyxMethod: existingSplitChatReport ? Onyx.METHOD.MERGE : Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`, - value: { - ...(existingSplitChatReport ? {} : {[splitChatCreatedReportAction.reportActionID]: splitChatCreatedReportAction}), - [splitIOUReportAction.reportActionID]: splitIOUReportAction, - }, - }, + existingSplitChatReport + ? { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`, + value: { + [splitIOUReportAction.reportActionID]: splitIOUReportAction as OnyxTypes.ReportAction, + }, + } + : { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`, + value: { + [splitChatCreatedReportAction.reportActionID]: splitChatCreatedReportAction, + [splitIOUReportAction.reportActionID]: splitIOUReportAction as OnyxTypes.ReportAction, + }, + }, { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${splitTransaction.transactionID}`, @@ -1660,7 +1670,7 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co }, ]; - const successData = [ + const successData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`, @@ -1684,7 +1694,7 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co }); } - const failureData = [ + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${splitTransaction.transactionID}`, @@ -1730,9 +1740,10 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co ); } - const splits = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID}]; + const splits: Split[] = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID}]; - _.each(participants, (participant) => { + participants.forEach((participant) => { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const email = participant.isOwnPolicyExpenseChat ? '' : OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login || participant.text).toLowerCase(); const accountID = participant.isOwnPolicyExpenseChat ? 0 : Number(participant.accountID); if (email === currentUserEmailForIOUSplit) { @@ -1757,7 +1768,9 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co [accountID]: { accountID, avatar: UserUtils.getDefaultAvatarURL(accountID), + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing displayName: LocalePhoneNumber.formatPhoneNumber(participant.displayName || email), + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing login: participant.login || participant.text, isOptimisticPersonalDetail: true, }, @@ -1782,26 +1795,37 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co }, }); - API.write( - 'StartSplitBill', - { - chatReportID: splitChatReport.reportID, - reportActionID: splitIOUReportAction.reportActionID, - transactionID: splitTransaction.transactionID, - splits: JSON.stringify(splits), - receipt, - comment, - category, - tag, - isFromGroupDM: !existingSplitChatReport, - ...(existingSplitChatReport ? {} : {createdReportActionID: splitChatCreatedReportAction.reportActionID}), - }, - {optimisticData, successData, failureData}, - ); + type StartSplitBillParams = { + chatReportID: string; + reportActionID: string; + transactionID: string; + splits: string; + receipt: Receipt; + comment: string; + category: string; + tag: string; + isFromGroupDM: boolean; + createdReportActionID?: string; + }; + + const parameters: StartSplitBillParams = { + chatReportID: splitChatReport.reportID, + reportActionID: splitIOUReportAction.reportActionID, + transactionID: splitTransaction.transactionID, + splits: JSON.stringify(splits), + receipt, + comment, + category, + tag, + isFromGroupDM: !existingSplitChatReport, + ...(existingSplitChatReport ? {} : {createdReportActionID: splitChatCreatedReportAction.reportActionID}), + }; + + API.write('StartSplitBill', parameters, {optimisticData, successData, failureData}); resetMoneyRequestInfo(); Navigation.dismissModal(splitChatReport.reportID); - Report.notifyNewAction(splitChatReport.chatReportID, currentUserAccountID); + Report.notifyNewAction(splitChatReport.chatReportID ?? '', currentUserAccountID); } /** Used for editing a split bill while it's still scanning or when SmartScan fails, it completes a split bill started by startSplitBill above. diff --git a/src/types/onyx/IOU.ts b/src/types/onyx/IOU.ts index 4558e5a99c08..98d04fb2ea9e 100644 --- a/src/types/onyx/IOU.ts +++ b/src/types/onyx/IOU.ts @@ -7,6 +7,7 @@ type Participant = { isOwnPolicyExpenseChat?: boolean; selected?: boolean; reportID?: string; + policyID?: string; displayName?: string; alternateText: string; firstName: string; diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 126a12bcb3f8..d7acd8851341 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -20,6 +20,19 @@ type Waypoint = { }; type WaypointCollection = Record; + +type UserSplit = { + email: string; + accountID: number; +}; + +type WorkspaceSplit = { + policyID?: string; + chatReportID: string; +}; + +type Split = UserSplit | WorkspaceSplit; + type Comment = { comment?: string; waypoints?: WaypointCollection; @@ -28,6 +41,7 @@ type Comment = { customUnit?: Record; source?: string; originalTransactionID?: string; + splits?: Split[]; }; type GeometryType = 'LineString'; @@ -104,5 +118,9 @@ type TransactionDraft = Partial & { isFromGlobalCreate?: boolean; }; +type AdditionalTransactionChanges = {comment?: string; waypoints?: WaypointCollection}; + +type TransactionChanges = Partial & AdditionalTransactionChanges; + export default Transaction; -export type {WaypointCollection, Comment, Receipt, Waypoint, TransactionDraft}; +export type {WaypointCollection, Comment, Receipt, Waypoint, TransactionDraft, TransactionChanges, Split}; From 8f0418d24e9e603a8d9c11d7fe0dfd993297afd4 Mon Sep 17 00:00:00 2001 From: Viktoryia Kliushun Date: Fri, 29 Dec 2023 16:32:29 +0100 Subject: [PATCH 09/68] Replace Split type with Participant --- src/libs/actions/IOU.ts | 11 ++++++----- src/types/onyx/IOU.ts | 20 +++++++++++--------- src/types/onyx/Transaction.ts | 16 ++-------------- 3 files changed, 19 insertions(+), 28 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 07a172192021..193793744548 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -3,6 +3,7 @@ import {format} from 'date-fns'; import Str from 'expensify-common/lib/str'; import lodashGet from 'lodash/get'; import lodashHas from 'lodash/has'; +import {ImageSourcePropType} from 'react-native'; import Onyx, {OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import OnyxUtils from 'react-native-onyx/lib/utils'; import {ValueOf} from 'type-fest'; @@ -31,7 +32,7 @@ import * as OnyxTypes from '@src/types/onyx'; import {Participant} from '@src/types/onyx/IOU'; import ReportAction from '@src/types/onyx/ReportAction'; import {OnyxData} from '@src/types/onyx/Request'; -import {Comment, Receipt, Split, WaypointCollection} from '@src/types/onyx/Transaction'; +import {Comment, Receipt, WaypointCollection} from '@src/types/onyx/Transaction'; import {EmptyObject, isEmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; import * as Report from './Report'; @@ -243,7 +244,7 @@ function setMoneyRequestParticipants_temporaryForRefactor(transactionID: string, Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {participants}); } -function setMoneyRequestReceipt_temporaryForRefactor(transactionID: string, source: string, filename: string) { +function setMoneyRequestReceipt_temporaryForRefactor(transactionID: string, source: ImageSourcePropType, filename: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {receipt: {source}, filename}); } @@ -1741,11 +1742,11 @@ function startSplitBill( ); } - const splits: Split[] = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID}]; + const splits: Participant[] = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID}]; participants.forEach((participant) => { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const email = participant.isOwnPolicyExpenseChat ? '' : OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login || participant.text).toLowerCase(); + const email = participant.isOwnPolicyExpenseChat ? '' : OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login || participant.text || '').toLowerCase(); const accountID = participant.isOwnPolicyExpenseChat ? 0 : Number(participant.accountID); if (email === currentUserEmailForIOUSplit) { return; @@ -1760,7 +1761,7 @@ function startSplitBill( return; } - const participantPersonalDetails = allPersonalDetails[participant.accountID]; + const participantPersonalDetails = allPersonalDetails[participant?.accountID ?? -1]; if (!participantPersonalDetails) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, diff --git a/src/types/onyx/IOU.ts b/src/types/onyx/IOU.ts index 98d04fb2ea9e..5647bd31d3ef 100644 --- a/src/types/onyx/IOU.ts +++ b/src/types/onyx/IOU.ts @@ -1,22 +1,24 @@ import {Icon} from './OnyxCommon'; type Participant = { - accountID: number; + accountID?: number; login?: string; + email?: string; isPolicyExpenseChat?: boolean; + chatReportID?: string; isOwnPolicyExpenseChat?: boolean; selected?: boolean; reportID?: string; policyID?: string; displayName?: string; - alternateText: string; - firstName: string; - icons: Icon[]; - keyForList: string; - lastName: string; - phoneNumber: string; - searchText: string; - text: string; + alternateText?: string; + firstName?: string; + icons?: Icon[]; + keyForList?: string; + lastName?: string; + phoneNumber?: string; + searchText?: string; + text?: string; }; type IOU = { diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index d7acd8851341..ad8b2e20d1d6 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -21,18 +21,6 @@ type Waypoint = { type WaypointCollection = Record; -type UserSplit = { - email: string; - accountID: number; -}; - -type WorkspaceSplit = { - policyID?: string; - chatReportID: string; -}; - -type Split = UserSplit | WorkspaceSplit; - type Comment = { comment?: string; waypoints?: WaypointCollection; @@ -41,7 +29,7 @@ type Comment = { customUnit?: Record; source?: string; originalTransactionID?: string; - splits?: Split[]; + splits?: Participant[]; }; type GeometryType = 'LineString'; @@ -123,4 +111,4 @@ type AdditionalTransactionChanges = {comment?: string; waypoints?: WaypointColle type TransactionChanges = Partial & AdditionalTransactionChanges; export default Transaction; -export type {WaypointCollection, Comment, Receipt, Waypoint, TransactionDraft, TransactionChanges, Split}; +export type {WaypointCollection, Comment, Receipt, Waypoint, TransactionDraft, TransactionChanges}; From 417e173cb1022398210c0b508f0e89594f5a74dc Mon Sep 17 00:00:00 2001 From: Viktoryia Kliushun Date: Fri, 29 Dec 2023 16:58:57 +0100 Subject: [PATCH 10/68] Migrate completeSplitBill function --- src/libs/ReportUtils.ts | 4 +- src/libs/actions/IOU.ts | 124 ++++++++++++++++++++++------------------ src/types/onyx/IOU.ts | 6 ++ 3 files changed, 76 insertions(+), 58 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 1e71d58563b3..791a64312589 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2644,8 +2644,8 @@ function buildOptimisticIOUReportAction( originalMessage.participantAccountIDs = currentUserAccountID ? [currentUserAccountID] : []; } else { originalMessage.participantAccountIDs = currentUserAccountID - ? [currentUserAccountID, ...participants.map((participant) => participant.accountID)] - : participants.map((participant) => participant.accountID); + ? [currentUserAccountID, ...participants.map((participant) => participant.accountID ?? -1)] + : participants.map((participant) => participant.accountID ?? -1); } } diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 193793744548..c745a7b0b865 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1832,19 +1832,19 @@ function startSplitBill( /** Used for editing a split bill while it's still scanning or when SmartScan fails, it completes a split bill started by startSplitBill above. * - * @param {number} chatReportID - The group chat or workspace reportID - * @param {Object} reportAction - The split action that lives in the chatReport above - * @param {Object} updatedTransaction - The updated **draft** split transaction - * @param {Number} sessionAccountID - accountID of the current user - * @param {String} sessionEmail - email of the current user + * @param chatReportID - The group chat or workspace reportID + * @param reportAction - The split action that lives in the chatReport above + * @param updatedTransaction - The updated **draft** split transaction + * @param sessionAccountID - accountID of the current user + * @param sessionEmail - email of the current user */ -function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessionAccountID, sessionEmail) { +function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportAction, updatedTransaction: OnyxTypes.Transaction, sessionAccountID: number, sessionEmail: string) { const currentUserEmailForIOUSplit = OptionsListUtils.addSMSDomainIfPhoneNumber(sessionEmail); const {transactionID} = updatedTransaction; const unmodifiedTransaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; // Save optimistic updated transaction and action - const optimisticData = [ + const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, @@ -1867,7 +1867,7 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessi }, ]; - const successData = [ + const successData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, @@ -1876,11 +1876,11 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessi { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`, - value: null, + value: {pendingAction: null}, }, ]; - const failureData = [ + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, @@ -1901,25 +1901,25 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessi }, ]; - const splitParticipants = updatedTransaction.comment.splits; + const splitParticipants = updatedTransaction.comment.splits ?? []; const {modifiedAmount: amount, modifiedCurrency: currency} = updatedTransaction; // Exclude the current user when calculating the split amount, `calculateAmount` takes it into account - const splitAmount = IOUUtils.calculateAmount(splitParticipants.length - 1, amount, currency, false); + const splitAmount = IOUUtils.calculateAmount(splitParticipants.length - 1, amount ?? 0, currency ?? '', false); - const splits = [{email: currentUserEmailForIOUSplit}]; - _.each(splitParticipants, (participant) => { + const splits: Participant[] = [{email: currentUserEmailForIOUSplit}]; + splitParticipants.forEach((participant) => { // Skip creating the transaction for the current user if (participant.email === currentUserEmailForIOUSplit) { return; } - const isPolicyExpenseChat = !_.isEmpty(participant.policyID); + const isPolicyExpenseChat = !!participant.policyID; if (!isPolicyExpenseChat) { // In case this is still the optimistic accountID saved in the splits array, return early as we cannot know // if there is an existing chat between the split creator and this participant // Instead, we will rely on Auth generating the report IDs and the user won't see any optimistic chats or reports created - const participantPersonalDetails = allPersonalDetails[participant.accountID] || {}; + const participantPersonalDetails: OnyxTypes.PersonalDetails | EmptyObject = allPersonalDetails[participant?.accountID ?? -1] || {}; if (!participantPersonalDetails || participantPersonalDetails.isOptimisticPersonalDetail) { splits.push({ email: participant.email, @@ -1928,36 +1928,38 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessi } } - let oneOnOneChatReport; + let oneOnOneChatReport: OnyxTypes.Report | null; let isNewOneOnOneChatReport = false; if (isPolicyExpenseChat) { // The workspace chat reportID is saved in the splits array when starting a split bill with a workspace - oneOnOneChatReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${participant.chatReportID}`]; + oneOnOneChatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.chatReportID}`] ?? null; } else { - const existingChatReport = ReportUtils.getChatByParticipants([participant.accountID]); + const existingChatReport = ReportUtils.getChatByParticipants(participant.accountID ? [participant.accountID] : []); isNewOneOnOneChatReport = !existingChatReport; - oneOnOneChatReport = existingChatReport || ReportUtils.buildOptimisticChatReport([participant.accountID]); + oneOnOneChatReport = existingChatReport || ReportUtils.buildOptimisticChatReport(participant.accountID ? [participant.accountID] : []); } - let oneOnOneIOUReport = oneOnOneChatReport.iouReportID ? lodashGet(allReports, `${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`, undefined) : undefined; + let oneOnOneIOUReport = oneOnOneChatReport?.iouReportID ? lodashGet(allReports, `${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`, undefined) : undefined; const shouldCreateNewOneOnOneIOUReport = _.isUndefined(oneOnOneIOUReport) || (isPolicyExpenseChat && ReportUtils.isControlPolicyExpenseReport(oneOnOneIOUReport) && ReportUtils.isReportApproved(oneOnOneIOUReport)); if (shouldCreateNewOneOnOneIOUReport) { oneOnOneIOUReport = isPolicyExpenseChat - ? ReportUtils.buildOptimisticExpenseReport(oneOnOneChatReport.reportID, participant.policyID, sessionAccountID, splitAmount, currency) - : ReportUtils.buildOptimisticIOUReport(sessionAccountID, participant.accountID, splitAmount, oneOnOneChatReport.reportID, currency); + ? ReportUtils.buildOptimisticExpenseReport(oneOnOneChatReport?.reportID ?? '', participant.policyID ?? '', sessionAccountID, splitAmount, currency ?? '') + : ReportUtils.buildOptimisticIOUReport(sessionAccountID, participant.accountID ?? -1, splitAmount, oneOnOneChatReport?.reportID ?? '', currency ?? ''); } else if (isPolicyExpenseChat) { - // Because of the Expense reports are stored as negative values, we subtract the total from the amount - oneOnOneIOUReport.total -= splitAmount; + if (oneOnOneIOUReport?.total) { + // 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 = IOUUtils.updateIOUOwnerAndTotal(oneOnOneIOUReport as OnyxTypes.Report, sessionAccountID, splitAmount, currency ?? ''); } const oneOnOneTransaction = TransactionUtils.buildOptimisticTransaction( isPolicyExpenseChat ? -splitAmount : splitAmount, - currency, - oneOnOneIOUReport.reportID, + currency ?? '', + oneOnOneIOUReport?.reportID ?? '', updatedTransaction.comment.comment, updatedTransaction.modifiedCreated, CONST.IOU.TYPE.SPLIT, @@ -1972,31 +1974,31 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessi const oneOnOneIOUAction = ReportUtils.buildOptimisticIOUReportAction( CONST.IOU.REPORT_ACTION_TYPE.CREATE, splitAmount, - currency, - updatedTransaction.comment.comment, + currency ?? '', + updatedTransaction.comment.comment ?? '', [participant], oneOnOneTransaction.transactionID, - '', - oneOnOneIOUReport.reportID, + undefined, + oneOnOneIOUReport?.reportID, ); - let oneOnOneReportPreviewAction = ReportActionsUtils.getReportPreviewAction(oneOnOneChatReport.reportID, oneOnOneIOUReport.reportID); + let oneOnOneReportPreviewAction = ReportActionsUtils.getReportPreviewAction(oneOnOneChatReport?.reportID ?? '', oneOnOneIOUReport?.reportID ?? ''); if (oneOnOneReportPreviewAction) { - oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction); + oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport ?? null, oneOnOneReportPreviewAction); } else { - oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport, '', oneOnOneTransaction); + oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport ?? null, '', oneOnOneTransaction); } const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest( - oneOnOneChatReport, - oneOnOneIOUReport, + oneOnOneChatReport as OnyxTypes.Report, + oneOnOneIOUReport as OnyxTypes.Report, oneOnOneTransaction, oneOnOneCreatedActionForChat, oneOnOneCreatedActionForIOU, oneOnOneIOUAction, {}, oneOnOneReportPreviewAction, - {}, + [], {}, isNewOneOnOneChatReport, shouldCreateNewOneOnOneIOUReport, @@ -2006,8 +2008,8 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessi email: participant.email, accountID: participant.accountID, policyID: participant.policyID, - iouReportID: oneOnOneIOUReport.reportID, - chatReportID: oneOnOneChatReport.reportID, + iouReportID: oneOnOneIOUReport?.reportID, + chatReportID: oneOnOneChatReport?.reportID, transactionID: oneOnOneTransaction.transactionID, reportActionID: oneOnOneIOUAction.reportActionID, createdChatReportActionID: oneOnOneCreatedActionForChat.reportActionID, @@ -2028,23 +2030,33 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessi comment: transactionComment, category: transactionCategory, tag: transactionTag, - } = ReportUtils.getTransactionDetails(updatedTransaction); + } = ReportUtils.getTransactionDetails(updatedTransaction) ?? {}; - API.write( - 'CompleteSplitBill', - { - transactionID, - amount: transactionAmount, - currency: transactionCurrency, - created: transactionCreated, - merchant: transactionMerchant, - comment: transactionComment, - category: transactionCategory, - tag: transactionTag, - splits: JSON.stringify(splits), - }, - {optimisticData, successData, failureData}, - ); + type CompleteSplitBillParams = { + transactionID: string; + amount?: number; + currency?: string; + created?: string; + merchant?: string; + comment?: string; + category?: string; + tag?: string; + splits: string; + }; + + const parameters: CompleteSplitBillParams = { + transactionID, + amount: transactionAmount, + currency: transactionCurrency, + created: transactionCreated, + merchant: transactionMerchant, + comment: transactionComment, + category: transactionCategory, + tag: transactionTag, + splits: JSON.stringify(splits), + }; + + API.write('CompleteSplitBill', parameters, {optimisticData, successData, failureData}); Navigation.dismissModal(chatReportID); Report.notifyNewAction(chatReportID, sessionAccountID); } diff --git a/src/types/onyx/IOU.ts b/src/types/onyx/IOU.ts index 5647bd31d3ef..f3cc20975fb7 100644 --- a/src/types/onyx/IOU.ts +++ b/src/types/onyx/IOU.ts @@ -6,6 +6,9 @@ type Participant = { email?: string; isPolicyExpenseChat?: boolean; chatReportID?: string; + iouReportID?: string; + transactionID?: string; + reportActionID?: string; isOwnPolicyExpenseChat?: boolean; selected?: boolean; reportID?: string; @@ -19,6 +22,9 @@ type Participant = { phoneNumber?: string; searchText?: string; text?: string; + createdChatReportActionID?: string; + createdIOUReportActionID?: string; + reportPreviewReportActionID?: string; }; type IOU = { From ecdd7ddd037ecbcab52fed56556c0366eb01f413 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 2 Jan 2024 13:31:57 +0100 Subject: [PATCH 11/68] Migrate getIOUReportID, navigateToNextPage and setMoneyRequestParticipantsFromReport functions --- src/libs/ReportUtils.ts | 4 +-- src/libs/actions/IOU.ts | 62 ++++++++++++++++++----------------------- 2 files changed, 29 insertions(+), 37 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 99c7814c94cd..6e951ad472be 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -395,7 +395,7 @@ Onyx.connect({ }, }); -function getChatType(report: OnyxEntry): ValueOf | undefined { +function getChatType(report: OnyxEntry | EmptyObject): ValueOf | undefined { return report?.chatType; } @@ -619,7 +619,7 @@ function isUserCreatedPolicyRoom(report: OnyxEntry): boolean { /** * Whether the provided report is a Policy Expense chat. */ -function isPolicyExpenseChat(report: OnyxEntry): boolean { +function isPolicyExpenseChat(report: OnyxEntry | EmptyObject): boolean { return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT || (report?.isPolicyExpenseChat ?? false); } diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 91cf73ce8bfa..6e9e01dc5b96 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ +import {StackScreenProps} from '@react-navigation/stack'; import {format} from 'date-fns'; import Str from 'expensify-common/lib/str'; import lodashGet from 'lodash/get'; @@ -25,9 +26,11 @@ import * as ReportUtils from '@libs/ReportUtils'; import {OptimisticCreatedReportAction, OptimisticIOUReportAction} from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import * as UserUtils from '@libs/UserUtils'; +import type {MoneyRequestNavigatorParamList} from '@navigation/types'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import SCREENS from '@src/SCREENS'; import * as OnyxTypes from '@src/types/onyx'; import {Participant} from '@src/types/onyx/IOU'; import ReportAction from '@src/types/onyx/ReportAction'; @@ -43,6 +46,11 @@ type OptimisticPolicyRecentlyUsedCategories = string[]; // TODO: Remove this once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. type OptimisticPolicyRecentlyUsedTags = Record; +type MoneyRequestRoute = StackScreenProps< + MoneyRequestNavigatorParamList, + typeof SCREENS.MONEY_REQUEST.CATEGORY | typeof SCREENS.MONEY_REQUEST.TAG | typeof SCREENS.MONEY_REQUEST.CONFIRMATION +>['route']; + type IOURequestType = ValueOf; type MoneyRequestInformation = { @@ -3260,19 +3268,17 @@ function replaceReceipt(transactionID, receipt, filePath) { /** * Finds the participants for an IOU based on the attached report - * @param {String} transactionID of the transaction to set the participants of - * @param {Object} report attached to the transaction + * @param transactionID of the transaction to set the participants of + * @param report attached to the transaction */ -function setMoneyRequestParticipantsFromReport(transactionID, report) { +function setMoneyRequestParticipantsFromReport(transactionID: string, report: OnyxTypes.Report) { // 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.getReport(report.chatReportID) : report; const currentUserAccountID = currentUserPersonalDetails.accountID; - const participants = ReportUtils.isPolicyExpenseChat(chatReport) + const participants: Participant[] = ReportUtils.isPolicyExpenseChat(chatReport) ? [{reportID: chatReport.reportID, isPolicyExpenseChat: true, selected: true}] - : _.chain(chatReport.participantAccountIDs) - .filter((accountID) => currentUserAccountID !== accountID) - .map((accountID) => ({accountID, selected: true})) - .value(); + : (chatReport.participantAccountIDs ?? []).filter((accountID) => currentUserAccountID !== accountID).map((accountID) => ({accountID, selected: true})); + Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {participants, participantsAutoAssigned: true}); } @@ -3328,7 +3334,7 @@ function setMoneyRequestBillable(billable: boolean) { Onyx.merge(ONYXKEYS.IOU, {billable}); } -function setMoneyRequestParticipants(participants: Participant[], isSplitRequest: boolean) { +function setMoneyRequestParticipants(participants: Participant[], isSplitRequest?: boolean) { Onyx.merge(ONYXKEYS.IOU, {participants, isSplitRequest}); } @@ -3347,16 +3353,10 @@ function setUpDistanceTransaction() { /** * Navigates to the next IOU page based on where the IOU request was started - * - * @param {Object} iou - * @param {String} iouType - * @param {Object} report - * @param {String} report.reportID - * @param {String} path */ -function navigateToNextPage(iou, iouType, report, path = '') { - const moneyRequestID = `${iouType}${report.reportID || ''}`; - const shouldReset = iou.id !== moneyRequestID && !_.isEmpty(report.reportID); +function navigateToNextPage(iou: OnyxEntry, iouType: string, report?: OnyxTypes.Report, path = '') { + const moneyRequestID = `${iouType}${report?.reportID ?? ''}`; + const shouldReset = iou?.id !== moneyRequestID && !!report?.reportID; // If the money request ID in Onyx does not match the ID from params, we want to start a new request // with the ID from params. We need to clear the participants in case the new request is initiated from FAB. @@ -3365,24 +3365,21 @@ function navigateToNextPage(iou, iouType, report, path = '') { } // If we're adding a receipt, that means the user came from the confirmation page and we need to navigate back to it. - if (path.slice(1) === ROUTES.MONEY_REQUEST_RECEIPT.getRoute(iouType, report.reportID)) { - Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report.reportID)); + if (path.slice(1) === ROUTES.MONEY_REQUEST_RECEIPT.getRoute(iouType, report?.reportID)) { + Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report?.reportID)); return; } // If a request is initiated on a report, skip the participants selection step and navigate to the confirmation page. - if (report.reportID) { + if (report?.reportID) { // 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.getReport(report.chatReportID) : report; // Reinitialize the participants when the money request ID in Onyx does not match the ID from params - if (_.isEmpty(iou.participants) || shouldReset) { + if (!iou?.participants?.length || shouldReset) { const currentUserAccountID = currentUserPersonalDetails.accountID; - const participants = ReportUtils.isPolicyExpenseChat(chatReport) + const participants: Participant[] = ReportUtils.isPolicyExpenseChat(chatReport) ? [{reportID: chatReport.reportID, isPolicyExpenseChat: true, selected: true}] - : _.chain(chatReport.participantAccountIDs) - .filter((accountID) => currentUserAccountID !== accountID) - .map((accountID) => ({accountID, selected: true})) - .value(); + : (chatReport.participantAccountIDs ?? []).filter((accountID) => currentUserAccountID !== accountID).map((accountID) => ({accountID, selected: true})); setMoneyRequestParticipants(participants); resetMoneyRequestCategory(); resetMoneyRequestTag(); @@ -3397,15 +3394,10 @@ function navigateToNextPage(iou, iouType, report, path = '') { * When the money request or split bill creation flow is initialized via FAB, the reportID is not passed as a navigation * parameter. * Gets a report id from the first participant of the IOU object stored in Onyx. - * @param {Object} iou - * @param {Array} iou.participants - * @param {Object} route - * @param {Object} route.params - * @param {String} [route.params.reportID] - * @returns {String} */ -function getIOUReportID(iou, route) { - return lodashGet(route, 'params.reportID') || lodashGet(iou, 'participants.0.reportID', ''); +function getIOUReportID(iou?: OnyxTypes.IOU, route?: MoneyRequestRoute): string { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + return route?.params.reportID || iou?.participants?.[0]?.reportID || ''; } export { From 016c19eab622a9fdfc81a63f7b286f713f31bce5 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 2 Jan 2024 15:38:33 +0100 Subject: [PATCH 12/68] Migrate approveMoneyRequest, submitReport, detachReceipt, replaceReceipt functions --- src/libs/actions/IOU.ts | 167 +++++++++++++++++++++------------------ src/types/onyx/Report.ts | 3 + 2 files changed, 94 insertions(+), 76 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 6e9e01dc5b96..bdfbef57c995 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -3005,35 +3005,35 @@ function sendMoneyWithWallet(report, amount, currency, comment, managerID, recip Report.notifyNewAction(params.chatReportID, managerID); } -function approveMoneyRequest(expenseReport) { - const currentNextStep = lodashGet(allNextSteps, `${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`, null); +function approveMoneyRequest(expenseReport: OnyxTypes.Report) { + const currentNextStep = allNextSteps[`${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`] ?? null; - const optimisticApprovedReportAction = ReportUtils.buildOptimisticApprovedReportAction(expenseReport.total, expenseReport.currency, expenseReport.reportID); + const optimisticApprovedReportAction = ReportUtils.buildOptimisticApprovedReportAction(expenseReport.total ?? 0, expenseReport.currency ?? '', expenseReport.reportID); - const optimisticReportActionsData = { + const optimisticReportActionsData: OnyxUpdate = { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`, value: { [optimisticApprovedReportAction.reportActionID]: { - ...optimisticApprovedReportAction, + ...(optimisticApprovedReportAction as OnyxTypes.ReportAction), pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }, }, }; - const optimisticIOUReportData = { + const optimisticIOUReportData: OnyxUpdate = { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`, value: { ...expenseReport, - lastMessageText: optimisticApprovedReportAction.message[0].text, - lastMessageHtml: optimisticApprovedReportAction.message[0].html, + lastMessageText: optimisticApprovedReportAction.message?.[0].text, + lastMessageHtml: optimisticApprovedReportAction.message?.[0].html, stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, statusNum: CONST.REPORT.STATUS.APPROVED, }, }; - const optimisticData = [optimisticIOUReportData, optimisticReportActionsData]; + const optimisticData: OnyxUpdate[] = [optimisticIOUReportData, optimisticReportActionsData]; - const successData = [ + const successData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`, @@ -3045,19 +3045,19 @@ function approveMoneyRequest(expenseReport) { }, ]; - const failureData = [ + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`, value: { - [expenseReport.reportActionID]: { + [expenseReport.reportActionID ?? '']: { errors: ErrorUtils.getMicroSecondOnyxError('iou.error.other'), }, }, }, ]; - if (!_.isNull(currentNextStep)) { + if (currentNextStep) { optimisticData.push({ onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`, @@ -3070,25 +3070,32 @@ function approveMoneyRequest(expenseReport) { }); } - API.write('ApproveMoneyRequest', {reportID: expenseReport.reportID, approvedReportActionID: optimisticApprovedReportAction.reportActionID}, {optimisticData, successData, failureData}); + type ApproveMoneyRequestParams = { + reportID: string; + approvedReportActionID: string; + }; + + const parameters: ApproveMoneyRequestParams = { + reportID: expenseReport.reportID, + approvedReportActionID: optimisticApprovedReportAction.reportActionID, + }; + + API.write('ApproveMoneyRequest', parameters, {optimisticData, successData, failureData}); } -/** - * @param {Object} expenseReport - */ -function submitReport(expenseReport) { - const currentNextStep = lodashGet(allNextSteps, `${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`, null); +function submitReport(expenseReport: OnyxTypes.Report) { + const currentNextStep = allNextSteps[`${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`] ?? null; - const optimisticSubmittedReportAction = ReportUtils.buildOptimisticSubmittedReportAction(expenseReport.total, expenseReport.currency, expenseReport.reportID); + const optimisticSubmittedReportAction = ReportUtils.buildOptimisticSubmittedReportAction(expenseReport?.total ?? 0, expenseReport.currency ?? '', expenseReport.reportID); const parentReport = ReportUtils.getReport(expenseReport.parentReportID); - const optimisticData = [ + const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`, value: { [optimisticSubmittedReportAction.reportActionID]: { - ...optimisticSubmittedReportAction, + ...(optimisticSubmittedReportAction as OnyxTypes.ReportAction), pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }, }, @@ -3105,22 +3112,21 @@ function submitReport(expenseReport) { statusNum: CONST.REPORT.STATUS.SUBMITTED, }, }, - ...(parentReport.reportID - ? [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${parentReport.reportID}`, - value: { - ...parentReport, - hasOutstandingChildRequest: false, - iouReportID: null, - }, - }, - ] - : []), ]; - const successData = [ + if (parentReport.reportID) { + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${parentReport.reportID}`, + value: { + ...parentReport, + hasOutstandingChildRequest: false, + iouReportID: null, + }, + }); + } + + const successData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`, @@ -3132,12 +3138,12 @@ function submitReport(expenseReport) { }, ]; - const failureData = [ + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`, value: { - [expenseReport.reportActionID]: { + [expenseReport.reportActionID ?? '']: { errors: ErrorUtils.getMicroSecondOnyxError('iou.error.other'), }, }, @@ -3150,21 +3156,20 @@ function submitReport(expenseReport) { stateNum: CONST.REPORT.STATE_NUM.OPEN, }, }, - ...(parentReport.reportID - ? [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${parentReport.reportID}`, - value: { - hasOutstandingChildRequest: parentReport.hasOutstandingChildRequest, - iouReportID: expenseReport.reportID, - }, - }, - ] - : []), ]; - if (!_.isNull(currentNextStep)) { + if (parentReport.reportID) { + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${parentReport.reportID}`, + value: { + hasOutstandingChildRequest: parentReport.hasOutstandingChildRequest, + iouReportID: expenseReport.reportID, + }, + }); + } + + if (currentNextStep) { optimisticData.push({ onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`, @@ -3177,15 +3182,19 @@ function submitReport(expenseReport) { }); } - API.write( - 'SubmitReport', - { - reportID: expenseReport.reportID, - managerAccountID: expenseReport.managerID, - reportActionID: optimisticSubmittedReportAction.reportActionID, - }, - {optimisticData, successData, failureData}, - ); + type SubmitReportParams = { + reportID: string; + managerAccountID?: number; + reportActionID: string; + }; + + const parameters: SubmitReportParams = { + reportID: expenseReport.reportID, + managerAccountID: expenseReport.managerID, + reportActionID: optimisticSubmittedReportAction.reportActionID, + }; + + API.write('SubmitReport', parameters, {optimisticData, successData, failureData}); } /** @@ -3206,11 +3215,12 @@ function payMoneyRequest(paymentType, chatReport, iouReport) { Navigation.dismissModal(chatReport.reportID); } -function detachReceipt(transactionID) { - const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] || {}; +function detachReceipt(transactionID: string) { + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style + const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] as OnyxTypes.Transaction; const newTransaction = {...transaction, filename: '', receipt: {}}; - const optimisticData = [ + const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, @@ -3218,7 +3228,7 @@ function detachReceipt(transactionID) { }, ]; - const failureData = [ + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, @@ -3229,16 +3239,11 @@ function detachReceipt(transactionID) { API.write('DetachReceipt', {transactionID}, {optimisticData, failureData}); } -/** - * @param {String} transactionID - * @param {Object} receipt - * @param {String} filePath - */ -function replaceReceipt(transactionID, receipt, filePath) { - const transaction = lodashGet(allTransactions, 'transactionID', {}); - const oldReceipt = lodashGet(transaction, 'receipt', {}); +function replaceReceipt(transactionID: string, receipt: Receipt, filePath: ImageSourcePropType) { + const transaction = allTransactions.transactionID; + const oldReceipt = transaction?.receipt ?? {}; - const optimisticData = [ + const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, @@ -3252,18 +3257,28 @@ function replaceReceipt(transactionID, receipt, filePath) { }, ]; - const failureData = [ + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, value: { receipt: oldReceipt, - filename: transaction.filename, + filename: transaction?.filename, }, }, ]; - API.write('ReplaceReceipt', {transactionID, receipt}, {optimisticData, failureData}); + type ReplaceReceiptParams = { + transactionID: string; + receipt: Receipt; + }; + + const parameters: ReplaceReceiptParams = { + transactionID, + receipt, + }; + + API.write('ReplaceReceipt', parameters, {optimisticData, failureData}); } /** diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts index b274025908f5..b13421e48047 100644 --- a/src/types/onyx/Report.ts +++ b/src/types/onyx/Report.ts @@ -80,6 +80,9 @@ type Report = { /** ID of the report */ reportID: string; + /** ID of the report action */ + reportActionID?: string; + /** ID of the chat report */ chatReportID?: string; From 012cd769b43e4d37e4535c12c516f0b25fce20c8 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 2 Jan 2024 16:16:26 +0100 Subject: [PATCH 13/68] Migrate createSplitsAndOnyxData function --- src/libs/ReportUtils.ts | 5 +- src/libs/actions/IOU.ts | 137 ++++++++++++++++++++++++---------------- src/types/onyx/IOU.ts | 4 ++ 3 files changed, 90 insertions(+), 56 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 6e951ad472be..2ea861b6372d 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -161,6 +161,7 @@ type OptimisticChatReport = Pick< | 'type' | 'chatType' | 'chatReportID' + | 'iouReportID' | 'isOwnPolicyExpenseChat' | 'isPinned' | 'lastActorAccountID' @@ -395,7 +396,7 @@ Onyx.connect({ }, }); -function getChatType(report: OnyxEntry | EmptyObject): ValueOf | undefined { +function getChatType(report: OnyxEntry | Participant | EmptyObject): ValueOf | undefined { return report?.chatType; } @@ -619,7 +620,7 @@ function isUserCreatedPolicyRoom(report: OnyxEntry): boolean { /** * Whether the provided report is a Policy Expense chat. */ -function isPolicyExpenseChat(report: OnyxEntry | EmptyObject): boolean { +function isPolicyExpenseChat(report: OnyxEntry | Participant | EmptyObject): boolean { return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT || (report?.isPolicyExpenseChat ?? false); } diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index bdfbef57c995..cbbefc6e6729 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -23,7 +23,7 @@ import * as OptionsListUtils from '@libs/OptionsListUtils'; import Permissions from '@libs/Permissions'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; -import {OptimisticCreatedReportAction, OptimisticIOUReportAction} from '@libs/ReportUtils'; +import {OptimisticChatReport, OptimisticCreatedReportAction, OptimisticIOUReportAction} from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import * as UserUtils from '@libs/UserUtils'; import type {MoneyRequestNavigatorParamList} from '@navigation/types'; @@ -66,6 +66,20 @@ type MoneyRequestInformation = { onyxData: OnyxData; }; +type SplitData = { + chatReportID: string; + transactionID: string; + reportActionID: string; + policyID?: string; + createdReportActionID?: string; +}; + +type SplitsAndOnyxData = { + splitData: SplitData; + splits: Participant[]; + onyxData: OnyxData; +}; + let betas: OnyxTypes.Beta[] = []; Onyx.connect({ key: ONYXKEYS.BETAS, @@ -1149,25 +1163,26 @@ function requestMoney( * {email: 'user2', amount: 100, iouReportID: '100', chatReportID: '110', transactionID: '120', reportActionID: '130'}, * {email: 'user3', amount: 100, iouReportID: '200', chatReportID: '210', transactionID: '220', reportActionID: '230'} * ] - * @param {Array} participants - * @param {String} currentUserLogin - * @param {Number} currentUserAccountID - * @param {Number} amount - always in the smallest unit of the currency - * @param {String} comment - * @param {String} currency - * @param {String} merchant - * @param {String} category - * @param {String} tag - * @param {String} existingSplitChatReportID - the report ID where the split bill happens, could be a group chat or a workspace chat - * - * @return {Object} + * @param amount - always in the smallest unit of the currency + * @param existingSplitChatReportID - the report ID where the split bill happens, could be a group chat or a workspace chat */ -function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, merchant, category, tag, existingSplitChatReportID = '') { +function createSplitsAndOnyxData( + participants: Participant[], + currentUserLogin: string, + currentUserAccountID: number, + amount: number, + comment: string, + currency: string, + merchant: string, + category: string, + tag: string, + existingSplitChatReportID = '', +): SplitsAndOnyxData { const currentUserEmailForIOUSplit = OptionsListUtils.addSMSDomainIfPhoneNumber(currentUserLogin); - const participantAccountIDs = _.map(participants, (participant) => Number(participant.accountID)); + const participantAccountIDs = participants.map((participant) => Number(participant.accountID)); const existingSplitChatReport = existingSplitChatReportID || participants[0].reportID - ? allReports[`${ONYXKEYS.COLLECTION.REPORT}${existingSplitChatReportID || participants[0].reportID}`] + ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${existingSplitChatReportID || participants[0].reportID}`] : ReportUtils.getChatByParticipants(participantAccountIDs); const splitChatReport = existingSplitChatReport || ReportUtils.buildOptimisticChatReport(participantAccountIDs); const isOwnPolicyExpenseChat = splitChatReport.isOwnPolicyExpenseChat; @@ -1197,7 +1212,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco comment, participants, splitTransaction.transactionID, - '', + undefined, '', false, false, @@ -1206,8 +1221,8 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco ); splitChatReport.lastReadTime = DateUtils.getDBTime(); - splitChatReport.lastMessageText = splitIOUReportAction.message[0].text; - splitChatReport.lastMessageHtml = splitIOUReportAction.message[0].html; + splitChatReport.lastMessageText = splitIOUReportAction.message?.[0].text; + splitChatReport.lastMessageHtml = splitIOUReportAction.message?.[0].html; // 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) { @@ -1216,7 +1231,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco }; } - const optimisticData = [ + const optimisticData: OnyxUpdate[] = [ { // Use 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 @@ -1224,14 +1239,22 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco key: `${ONYXKEYS.COLLECTION.REPORT}${splitChatReport.reportID}`, value: splitChatReport, }, - { - onyxMethod: existingSplitChatReport ? Onyx.METHOD.MERGE : Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`, - value: { - ...(existingSplitChatReport ? {} : {[splitCreatedReportAction.reportActionID]: splitCreatedReportAction}), - [splitIOUReportAction.reportActionID]: splitIOUReportAction, - }, - }, + existingSplitChatReport + ? { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`, + value: { + [splitIOUReportAction.reportActionID]: splitIOUReportAction as OnyxTypes.ReportAction, + }, + } + : { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`, + value: { + [splitCreatedReportAction.reportActionID]: splitCreatedReportAction as OnyxTypes.ReportAction, + [splitIOUReportAction.reportActionID]: splitIOUReportAction as OnyxTypes.ReportAction, + }, + }, { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${splitTransaction.transactionID}`, @@ -1239,7 +1262,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco }, ]; - const successData = [ + const successData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`, @@ -1256,7 +1279,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`, - value: null, + value: {pendingAction: null}, }, ]; @@ -1268,7 +1291,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco }); } - const failureData = [ + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${splitTransaction.transactionID}`, @@ -1279,7 +1302,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`, - value: null, + value: {pendingAction: null}, }, ]; @@ -1318,10 +1341,10 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco // Loop through participants creating individual chats, iouReports and reportActionIDs as needed const splitAmount = IOUUtils.calculateAmount(participants.length, amount, currency, false); - const splits = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID, amount: IOUUtils.calculateAmount(participants.length, amount, currency, true)}]; + const splits: Participant[] = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID, amount: IOUUtils.calculateAmount(participants.length, amount, currency, true)}]; const hasMultipleParticipants = participants.length > 1; - _.each(participants, (participant) => { + 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); @@ -1335,7 +1358,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco // STEP 1: Get existing chat report OR build a new optimistic one // If we only have one participant and the request was initiated from the global create menu, i.e. !existingGroupChatReportID, the oneOnOneChatReport is the groupChatReport - let oneOnOneChatReport; + let oneOnOneChatReport: OptimisticChatReport; let isNewOneOnOneChatReport = false; let shouldCreateOptimisticPersonalDetails = false; const personalDetailExists = lodashHas(allPersonalDetails, accountID); @@ -1363,20 +1386,22 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco if (shouldCreateNewOneOnOneIOUReport) { oneOnOneIOUReport = isOwnPolicyExpenseChat - ? ReportUtils.buildOptimisticExpenseReport(oneOnOneChatReport.reportID, oneOnOneChatReport.policyID, currentUserAccountID, splitAmount, currency) + ? ReportUtils.buildOptimisticExpenseReport(oneOnOneChatReport.reportID, oneOnOneChatReport.policyID ?? '', currentUserAccountID, splitAmount, currency) : ReportUtils.buildOptimisticIOUReport(currentUserAccountID, accountID, splitAmount, oneOnOneChatReport.reportID, currency); } else if (isOwnPolicyExpenseChat) { - // Because of the Expense reports are stored as negative values, we subtract the total from the amount - oneOnOneIOUReport.total -= splitAmount; + if (oneOnOneIOUReport?.total) { + // 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 = IOUUtils.updateIOUOwnerAndTotal(oneOnOneIOUReport as OnyxTypes.Report, currentUserAccountID, splitAmount, currency); } // STEP 3: Build optimistic transaction const oneOnOneTransaction = TransactionUtils.buildOptimisticTransaction( - ReportUtils.isExpenseReport(oneOnOneIOUReport) ? -splitAmount : splitAmount, + ReportUtils.isExpenseReport(oneOnOneIOUReport as OnyxTypes.Report) ? -splitAmount : splitAmount, currency, - oneOnOneIOUReport.reportID, + oneOnOneIOUReport?.reportID ?? '', comment, '', CONST.IOU.TYPE.SPLIT, @@ -1405,8 +1430,8 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco comment, [participant], oneOnOneTransaction.transactionID, - '', - oneOnOneIOUReport.reportID, + undefined, + oneOnOneIOUReport?.reportID ?? '', undefined, undefined, undefined, @@ -1415,7 +1440,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco ); // Add optimistic personal details for new participants - const oneOnOnePersonalDetailListAction = shouldCreateOptimisticPersonalDetails + const oneOnOnePersonalDetailListAction: OnyxTypes.PersonalDetailsList | undefined = shouldCreateOptimisticPersonalDetails ? { [accountID]: { accountID, @@ -1427,23 +1452,27 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco } : undefined; - let oneOnOneReportPreviewAction = ReportActionsUtils.getReportPreviewAction(oneOnOneChatReport.reportID, oneOnOneIOUReport.reportID); + let oneOnOneReportPreviewAction = ReportActionsUtils.getReportPreviewAction(oneOnOneChatReport.reportID, oneOnOneIOUReport?.reportID ?? ''); if (oneOnOneReportPreviewAction) { - oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction); + oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport as OnyxTypes.Report, oneOnOneReportPreviewAction); } else { - oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport); + oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport as OnyxTypes.Report); } // Add category to optimistic policy recently used categories when a participant is a workspace - const optimisticPolicyRecentlyUsedCategories = isPolicyExpenseChat ? Policy.buildOptimisticPolicyRecentlyUsedCategories(participant.policyID, category) : []; + const optimisticPolicyRecentlyUsedCategories: OptimisticPolicyRecentlyUsedCategories = isPolicyExpenseChat + ? (Policy.buildOptimisticPolicyRecentlyUsedCategories(participant.policyID, category) as OptimisticPolicyRecentlyUsedCategories) + : []; // Add tag to optimistic policy recently used tags when a participant is a workspace - const optimisticPolicyRecentlyUsedTags = isPolicyExpenseChat ? Policy.buildOptimisticPolicyRecentlyUsedTags(participant.policyID, tag) : {}; + const optimisticPolicyRecentlyUsedTags: OptimisticPolicyRecentlyUsedTags = isPolicyExpenseChat + ? (Policy.buildOptimisticPolicyRecentlyUsedTags(participant.policyID, tag) as OptimisticPolicyRecentlyUsedTags) + : {}; // STEP 5: Build Onyx Data const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest( oneOnOneChatReport, - oneOnOneIOUReport, + oneOnOneIOUReport as OnyxTypes.Report, oneOnOneTransaction, oneOnOneCreatedActionForChat, oneOnOneCreatedActionForIOU, @@ -1453,14 +1482,14 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco optimisticPolicyRecentlyUsedCategories, optimisticPolicyRecentlyUsedTags, isNewOneOnOneChatReport, - shouldCreateNewOneOnOneIOUReport, + !!shouldCreateNewOneOnOneIOUReport, ); const individualSplit = { email, accountID, amount: splitAmount, - iouReportID: oneOnOneIOUReport.reportID, + iouReportID: oneOnOneIOUReport?.reportID, chatReportID: oneOnOneChatReport.reportID, transactionID: oneOnOneTransaction.transactionID, reportActionID: oneOnOneIOUAction.reportActionID, @@ -1475,14 +1504,14 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco failureData.push(...oneOnOneFailureData); }); - const splitData = { + const splitData: SplitData = { chatReportID: splitChatReport.reportID, transactionID: splitTransaction.transactionID, reportActionID: splitIOUReportAction.reportActionID, policyID: splitChatReport.policyID, }; - if (_.isEmpty(existingSplitChatReport)) { + if (!existingSplitChatReport) { splitData.createdReportActionID = splitCreatedReportAction.reportActionID; } diff --git a/src/types/onyx/IOU.ts b/src/types/onyx/IOU.ts index f3cc20975fb7..4f9989d347a6 100644 --- a/src/types/onyx/IOU.ts +++ b/src/types/onyx/IOU.ts @@ -1,3 +1,5 @@ +import {ValueOf} from 'type-fest'; +import CONST from '@src/CONST'; import {Icon} from './OnyxCommon'; type Participant = { @@ -10,6 +12,8 @@ type Participant = { transactionID?: string; reportActionID?: string; isOwnPolicyExpenseChat?: boolean; + chatType?: ValueOf; + amount?: number; selected?: boolean; reportID?: string; policyID?: string; From 4711e1cd99dfae34ccb59c3de37a10b4f8f6a44c Mon Sep 17 00:00:00 2001 From: VickyStash Date: Thu, 4 Jan 2024 12:41:09 +0100 Subject: [PATCH 14/68] Migrate getReceiptError function; fix type imports after merging main --- src/libs/ErrorUtils.ts | 16 +++- src/libs/PolicyUtils.ts | 2 +- src/libs/ReportUtils.ts | 2 +- src/libs/actions/IOU.ts | 150 +++++++++++++++++----------------- src/types/onyx/OnyxCommon.ts | 9 +- src/types/onyx/Transaction.ts | 1 + src/types/onyx/index.ts | 3 +- 7 files changed, 97 insertions(+), 86 deletions(-) diff --git a/src/libs/ErrorUtils.ts b/src/libs/ErrorUtils.ts index 3160427ee81f..cd2b04f27782 100644 --- a/src/libs/ErrorUtils.ts +++ b/src/libs/ErrorUtils.ts @@ -1,10 +1,17 @@ +import type {ImageSourcePropType} from 'react-native'; import CONST from '@src/CONST'; import type {TranslationFlatObject, TranslationPaths} from '@src/languages/types'; -import type {ErrorFields, Errors} from '@src/types/onyx/OnyxCommon'; +import type {ErrorFields, SimpleErrors} from '@src/types/onyx/OnyxCommon'; import type Response from '@src/types/onyx/Response'; import DateUtils from './DateUtils'; import * as Localize from './Localize'; +type ErrorObject = Record; + +type MicroSecondOnyxError = Record; + +type MicroSecondOnyxErrorObject = Record; + function getAuthenticateErrorMessage(response: Response): keyof TranslationFlatObject { switch (response.jsonCode) { case CONST.JSON_CODE.UNABLE_TO_RETRY: @@ -38,7 +45,7 @@ function getAuthenticateErrorMessage(response: Response): keyof TranslationFlatO * Method used to get an error object with microsecond as the key. * @param error - error key or message to be saved */ -function getMicroSecondOnyxError(error: string | null): Record { +function getMicroSecondOnyxError(error: string | null): MicroSecondOnyxError { return {[DateUtils.getMicroseconds()]: error}; } @@ -46,12 +53,12 @@ function getMicroSecondOnyxError(error: string | null): Record): Record> { +function getMicroSecondOnyxErrorObject(error: ErrorObject): MicroSecondOnyxErrorObject { return {[DateUtils.getMicroseconds()]: error}; } type OnyxDataWithErrors = { - errors?: Errors; + errors?: SimpleErrors; }; function getLatestErrorMessage(onyxData: TOnyxData): string { @@ -120,3 +127,4 @@ function addErrorMessage(errors: ErrorsList, inpu } export {getAuthenticateErrorMessage, getMicroSecondOnyxError, getMicroSecondOnyxErrorObject, getLatestErrorMessage, getLatestErrorField, getEarliestErrorField, addErrorMessage}; +export type {MicroSecondOnyxErrorObject, MicroSecondOnyxError}; diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 0cab97299324..f50923aa0ecb 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -198,7 +198,7 @@ function isPendingDeletePolicy(policy: OnyxEntry): boolean { return policy?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE; } -function isPaidGroupPolicy(policy: OnyxEntry): boolean { +function isPaidGroupPolicy(policy: OnyxEntry | EmptyObject): boolean { return policy?.type === CONST.POLICY.TYPE.TEAM || policy?.type === CONST.POLICY.TYPE.CORPORATE; } diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 0ba456608680..56d074a0ade8 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -16,7 +16,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Beta, Login, PersonalDetails, PersonalDetailsList, Policy, Report, ReportAction, ReportMetadata, Session, Transaction} from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; -import {Errors, Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; +import type {Errors, Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; import type {IOUMessage, OriginalMessageActionName, OriginalMessageCreated} from '@src/types/onyx/OriginalMessage'; import type {Status} from '@src/types/onyx/PersonalDetails'; import type {NotificationPreference} from '@src/types/onyx/Report'; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index c92c7dec4b76..dc92c1b9043b 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1,19 +1,21 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {StackScreenProps} from '@react-navigation/stack'; +import type {StackScreenProps} from '@react-navigation/stack'; import {format} from 'date-fns'; import Str from 'expensify-common/lib/str'; import lodashGet from 'lodash/get'; import lodashHas from 'lodash/has'; import {ImageSourcePropType} from 'react-native'; -import Onyx, {OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx'; +import Onyx from 'react-native-onyx'; +import type {OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import OnyxUtils from 'react-native-onyx/lib/utils'; -import {ValueOf} from 'type-fest'; +import type {ValueOf} from 'type-fest'; import _ from 'underscore'; import ReceiptGeneric from '@assets/images/receipt-generic.png'; import * as API from '@libs/API'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import DateUtils from '@libs/DateUtils'; import * as ErrorUtils from '@libs/ErrorUtils'; +import type {MicroSecondOnyxError, MicroSecondOnyxErrorObject} from '@libs/ErrorUtils'; import * as IOUUtils from '@libs/IOUUtils'; import * as LocalePhoneNumber from '@libs/LocalePhoneNumber'; import * as Localize from '@libs/Localize'; @@ -24,20 +26,21 @@ import Permissions from '@libs/Permissions'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; -import {OptimisticChatReport, OptimisticCreatedReportAction, OptimisticIOUReportAction} from '@libs/ReportUtils'; +import type {OptimisticChatReport, OptimisticCreatedReportAction, OptimisticIOUReportAction} from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import * as UserUtils from '@libs/UserUtils'; import type {MoneyRequestNavigatorParamList} from '@navigation/types'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import SCREENS from '@src/SCREENS'; -import * as OnyxTypes from '@src/types/onyx'; -import {Participant} from '@src/types/onyx/IOU'; -import ReportAction from '@src/types/onyx/ReportAction'; -import {OnyxData} from '@src/types/onyx/Request'; -import {Comment, Receipt, WaypointCollection} from '@src/types/onyx/Transaction'; -import {EmptyObject, isEmptyObject} from '@src/types/utils/EmptyObject'; +import type SCREENS from '@src/SCREENS'; +import type * as OnyxTypes from '@src/types/onyx'; +import type {Participant} from '@src/types/onyx/IOU'; +import type ReportAction from '@src/types/onyx/ReportAction'; +import type {OnyxData} from '@src/types/onyx/Request'; +import type {Comment, Receipt, WaypointCollection} from '@src/types/onyx/Transaction'; +import type {EmptyObject} from '@src/types/utils/EmptyObject'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; import * as Report from './Report'; @@ -186,7 +189,6 @@ Onyx.connect({ /** * Initialize money request info * @param reportID to attach the transaction to - * @param isFromGlobalCreate * @param [iouRequestType] one of manual/scan/distance */ function startMoneyRequest_temporaryForRefactor(reportID: string, isFromGlobalCreate: boolean, iouRequestType: IOURequestType = CONST.IOU.REQUEST_TYPE.MANUAL) { @@ -297,14 +299,9 @@ function resetMoneyRequestInfo(id = '') { /** * Helper function to get the receipt error for money requests, or the generic error if there's no receipt - * - * @param {Object} receipt - * @param {String} filename - * @param {Boolean} [isScanRequest] - * @returns {Object} */ -function getReceiptError(receipt, filename, isScanRequest = true) { - return _.isEmpty(receipt) || !isScanRequest +function getReceiptError(receipt?: Receipt, filename?: string, isScanRequest = true): MicroSecondOnyxError | MicroSecondOnyxErrorObject { + return isEmptyObject(receipt) || !isScanRequest ? ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage') : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: receipt.source, filename}); } @@ -325,7 +322,7 @@ function buildOnyxDataForMoneyRequest( hasOutstandingChildRequest = false, ): OnyxUpdate[][] { const isScanRequest = TransactionUtils.isScanRequest(transaction); - const optimisticData = [ + const optimisticData: OnyxUpdate[] = [ { // Use 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 onyxMethod: isNewChatReport ? Onyx.METHOD.SET : Onyx.METHOD.MERGE, @@ -344,8 +341,8 @@ function buildOnyxDataForMoneyRequest( key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, value: { ...iouReport, - lastMessageText: iouAction.message[0].text, - lastMessageHtml: iouAction.message[0].html, + lastMessageText: iouAction.message?.[0].text, + lastMessageHtml: iouAction.message?.[0].html, pendingFields: { ...(isNewIOUReport ? {createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD} : {preview: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}), }, @@ -421,19 +418,20 @@ function buildOnyxDataForMoneyRequest( }); } - const successData = [ - ...(isNewChatReport - ? [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, - value: { - pendingFields: null, - errorFields: null, - }, - }, - ] - : []), + const successData: OnyxUpdate[] = []; + + if (isNewChatReport) { + successData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, + value: { + pendingFields: null, + errorFields: null, + }, + }); + } + + successData.push( { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, @@ -457,11 +455,11 @@ function buildOnyxDataForMoneyRequest( value: { ...(isNewChatReport ? { - [chatCreatedAction.reportActionID]: { - pendingAction: null, - errors: null, - }, - } + [chatCreatedAction.reportActionID]: { + pendingAction: null, + errors: null, + }, + } : {}), [reportPreviewAction.reportActionID]: { pendingAction: null, @@ -474,11 +472,11 @@ function buildOnyxDataForMoneyRequest( value: { ...(isNewIOUReport ? { - [iouCreatedAction.reportActionID]: { - pendingAction: null, - errors: null, - }, - } + [iouCreatedAction.reportActionID]: { + pendingAction: null, + errors: null, + }, + } : {}), [iouAction.reportActionID]: { pendingAction: null, @@ -486,9 +484,9 @@ function buildOnyxDataForMoneyRequest( }, }, }, - ]; + ); - const failureData = [ + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, @@ -498,10 +496,10 @@ function buildOnyxDataForMoneyRequest( pendingFields: null, ...(isNewChatReport ? { - errorFields: { - createChat: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'), - }, - } + errorFields: { + createChat: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'), + }, + } : {}), }, }, @@ -538,19 +536,19 @@ function buildOnyxDataForMoneyRequest( value: { ...(isNewChatReport ? { - [chatCreatedAction.reportActionID]: { - errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt.filename, isScanRequest), - }, - [reportPreviewAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError(null), - }, - } + [chatCreatedAction.reportActionID]: { + errors: getReceiptError(transaction?.receipt, transaction.filename ?? transaction.receipt?.filename, isScanRequest), + }, + [reportPreviewAction.reportActionID]: { + errors: ErrorUtils.getMicroSecondOnyxError(null), + }, + } : { - [reportPreviewAction.reportActionID]: { - created: reportPreviewAction.created, - errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt.filename, isScanRequest), - }, - }), + [reportPreviewAction.reportActionID]: { + created: reportPreviewAction.created, + errors: getReceiptError(transaction?.receipt, transaction.filename ?? transaction.receipt?.filename, isScanRequest), + }, + }), }, }, { @@ -559,18 +557,18 @@ function buildOnyxDataForMoneyRequest( value: { ...(isNewIOUReport ? { - [iouCreatedAction.reportActionID]: { - errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt.filename, isScanRequest), - }, - [iouAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError(null), - }, - } + [iouCreatedAction.reportActionID]: { + errors: getReceiptError(transaction.receipt, transaction.filename ?? transaction.receipt?.filename, isScanRequest), + }, + [iouAction.reportActionID]: { + errors: ErrorUtils.getMicroSecondOnyxError(null), + }, + } : { - [iouAction.reportActionID]: { - errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt.filename, isScanRequest), - }, - }), + [iouAction.reportActionID]: { + errors: getReceiptError(transaction.receipt, transaction.filename ?? transaction.receipt?.filename, isScanRequest), + }, + }), }, }, ]; @@ -630,7 +628,7 @@ function getMoneyRequestInformation( let needsToBeManuallySubmitted = false; let isFromPaidPolicy = false; if (isPolicyExpenseChat) { - const policy = ReportUtils.getPolicy(chatReport.policyID); + const policy = ReportUtils.getPolicy(chatReport.policyID ?? ''); isFromPaidPolicy = PolicyUtils.isPaidGroupPolicy(policy); // If the scheduled submit is turned off on the policy, user needs to manually submit the report which is indicated by GBR in LHN @@ -645,7 +643,7 @@ function getMoneyRequestInformation( if (iouReport) { if (isPolicyExpenseChat) { iouReport = {...iouReport}; - if (lodashGet(iouReport, 'currency') === currency) { + if (iouReport?.currency === currency && iouReport.total) { // Because of the Expense reports are stored as negative values, we substract the total from the amount iouReport.total -= amount; } diff --git a/src/types/onyx/OnyxCommon.ts b/src/types/onyx/OnyxCommon.ts index b26dc167ed44..60a3fc5b89df 100644 --- a/src/types/onyx/OnyxCommon.ts +++ b/src/types/onyx/OnyxCommon.ts @@ -1,4 +1,5 @@ import type {ValueOf} from 'type-fest'; +import type {MicroSecondOnyxError, MicroSecondOnyxErrorObject} from '@libs/ErrorUtils'; import type {AvatarSource} from '@libs/UserUtils'; import type CONST from '@src/CONST'; @@ -6,9 +7,11 @@ type PendingAction = ValueOf; type PendingFields = Record; -type ErrorFields = Record; +type SimpleErrors = Record; -type Errors = Record; +type ErrorFields = Record; + +type Errors = SimpleErrors | MicroSecondOnyxError | MicroSecondOnyxErrorObject; type AvatarType = typeof CONST.ICON_TYPE_AVATAR | typeof CONST.ICON_TYPE_WORKSPACE; @@ -29,4 +32,4 @@ type Icon = { fallbackIcon?: AvatarSource; }; -export type {Icon, PendingAction, PendingFields, ErrorFields, Errors, AvatarType}; +export type {Icon, PendingAction, PendingFields, ErrorFields, Errors, AvatarType, SimpleErrors}; diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 28fd451d002e..7f83c1de12c3 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -44,6 +44,7 @@ type Receipt = { path?: string; name?: string; source?: ImageSourcePropType; + filename?: string; state?: ValueOf; }; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index bf59c7520364..46de2b23bf32 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -56,7 +56,8 @@ import type ScreenShareRequest from './ScreenShareRequest'; import type SecurityGroup from './SecurityGroup'; import type Session from './Session'; import type Task from './Task'; -import type Transaction, {TransactionDraft} from './Transaction'; +import type Transaction from './Transaction'; +import type {TransactionDraft} from './Transaction'; import type {TransactionViolation, ViolationName} from './TransactionViolation'; import type User from './User'; import type UserLocation from './UserLocation'; From 372785bf1e756dda69023922023c917a3a17e8bb Mon Sep 17 00:00:00 2001 From: VickyStash Date: Thu, 4 Jan 2024 14:14:17 +0100 Subject: [PATCH 15/68] Migrate splitBill and splitBillAndOpenReport functions --- src/libs/actions/IOU.ts | 179 +++++++++++++++++++--------------- src/types/onyx/Transaction.ts | 21 +++- 2 files changed, 120 insertions(+), 80 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index dc92c1b9043b..94f2ec59ad9c 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -38,7 +38,7 @@ import type * as OnyxTypes from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; import type ReportAction from '@src/types/onyx/ReportAction'; import type {OnyxData} from '@src/types/onyx/Request'; -import type {Comment, Receipt, WaypointCollection} from '@src/types/onyx/Transaction'; +import type {Comment, Receipt, TaxRate, WaypointCollection} from '@src/types/onyx/Transaction'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; @@ -581,7 +581,7 @@ function buildOnyxDataForMoneyRequest( * it creates optimistic versions of them and uses those instead */ function getMoneyRequestInformation( - report: OnyxTypes.Report | EmptyObject, + report: OnyxEntry | EmptyObject, participant: Participant, comment: string, amount: number, @@ -1527,18 +1527,21 @@ function createSplitsAndOnyxData( } /** - * @param {Array} participants - * @param {String} currentUserLogin - * @param {Number} currentUserAccountID - * @param {Number} amount - always in smallest currency unit - * @param {String} comment - * @param {String} currency - * @param {String} merchant - * @param {String} category - * @param {String} tag - * @param {String} existingSplitChatReportID - Either a group DM or a workspace chat + * @param amount - always in smallest currency unit + * @param existingSplitChatReportID - Either a group DM or a workspace chat */ -function splitBill(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, merchant, category, tag, existingSplitChatReportID = '') { +function splitBill( + participants: Participant[], + currentUserLogin: string, + currentUserAccountID: number, + amount: number, + comment: string, + currency: string, + merchant: string, + category: string, + tag: string, + existingSplitChatReportID = '', +) { const {splitData, splits, onyxData} = createSplitsAndOnyxData( participants, currentUserLogin, @@ -1551,24 +1554,38 @@ function splitBill(participants, currentUserLogin, currentUserAccountID, amount, tag, existingSplitChatReportID, ); - API.write( - 'SplitBill', - { - reportID: splitData.chatReportID, - amount, - splits: JSON.stringify(splits), - currency, - comment, - category, - merchant, - tag, - transactionID: splitData.transactionID, - reportActionID: splitData.reportActionID, - createdReportActionID: splitData.createdReportActionID, - policyID: splitData.policyID, - }, - onyxData, - ); + + type SplitBillParams = { + reportID: string; + amount: number; + splits: string; + comment: string; + currency: string; + merchant: string; + category: string; + tag: string; + transactionID: string; + reportActionID: string; + createdReportActionID?: string; + policyID?: string; + }; + + const parameters: SplitBillParams = { + reportID: splitData.chatReportID, + amount, + splits: JSON.stringify(splits), + currency, + comment, + category, + merchant, + tag, + transactionID: splitData.transactionID, + reportActionID: splitData.reportActionID, + createdReportActionID: splitData.createdReportActionID, + policyID: splitData.policyID, + }; + + API.write('SplitBill', parameters, onyxData); resetMoneyRequestInfo(); Navigation.dismissModal(); @@ -1576,37 +1593,52 @@ function splitBill(participants, currentUserLogin, currentUserAccountID, amount, } /** - * @param {Array} participants - * @param {String} currentUserLogin - * @param {Number} currentUserAccountID - * @param {Number} amount - always in smallest currency unit - * @param {String} comment - * @param {String} currency - * @param {String} merchant - * @param {String} category - * @param {String} tag + * @param amount - always in smallest currency unit */ -function splitBillAndOpenReport(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, merchant, category, tag) { +function splitBillAndOpenReport( + participants: Participant[], + currentUserLogin: string, + currentUserAccountID: number, + amount: number, + comment: string, + currency: string, + merchant: string, + category: string, + tag: string, +) { const {splitData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, merchant, category, tag); - API.write( - 'SplitBillAndOpenReport', - { - reportID: splitData.chatReportID, - amount, - splits: JSON.stringify(splits), - currency, - merchant, - comment, - category, - tag, - transactionID: splitData.transactionID, - reportActionID: splitData.reportActionID, - createdReportActionID: splitData.createdReportActionID, - policyID: splitData.policyID, - }, - onyxData, - ); + type SplitBillAndOpenReport = { + reportID: string; + amount: number; + splits: string; + currency: string; + merchant: string; + comment: string; + category: string; + tag: string; + transactionID: string; + reportActionID: string; + createdReportActionID?: string; + policyID?: string; + }; + + const parameters: SplitBillAndOpenReport = { + reportID: splitData.chatReportID, + amount, + splits: JSON.stringify(splits), + currency, + merchant, + comment, + category, + tag, + transactionID: splitData.transactionID, + reportActionID: splitData.reportActionID, + createdReportActionID: splitData.createdReportActionID, + policyID: splitData.policyID, + }; + + API.write('SplitBillAndOpenReport', parameters, onyxData); resetMoneyRequestInfo(); Navigation.dismissModal(splitData.chatReportID); @@ -3148,7 +3180,7 @@ function submitReport(expenseReport: OnyxTypes.Report) { }, ]; - if (parentReport.reportID) { + if (parentReport?.reportID) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${parentReport.reportID}`, @@ -3193,7 +3225,7 @@ function submitReport(expenseReport: OnyxTypes.Report) { }, ]; - if (parentReport.reportID) { + if (parentReport?.reportID) { failureData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${parentReport.reportID}`, @@ -3326,8 +3358,8 @@ function setMoneyRequestParticipantsFromReport(transactionID: string, report: On const chatReport = ReportUtils.isMoneyRequestReport(report) ? ReportUtils.getReport(report.chatReportID) : report; const currentUserAccountID = currentUserPersonalDetails.accountID; const participants: Participant[] = ReportUtils.isPolicyExpenseChat(chatReport) - ? [{reportID: chatReport.reportID, isPolicyExpenseChat: true, selected: true}] - : (chatReport.participantAccountIDs ?? []).filter((accountID) => currentUserAccountID !== accountID).map((accountID) => ({accountID, selected: true})); + ? [{reportID: chatReport?.reportID, isPolicyExpenseChat: true, selected: true}] + : (chatReport?.participantAccountIDs ?? []).filter((accountID) => currentUserAccountID !== accountID).map((accountID) => ({accountID, selected: true})); Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {participants, participantsAutoAssigned: true}); } @@ -3380,26 +3412,15 @@ function resetMoneyRequestTag() { Onyx.merge(ONYXKEYS.IOU, {tag: ''}); } -/** - * @param {String} transactionID - * @param {Object} taxRate - */ -function setMoneyRequestTaxRate(transactionID, taxRate) { +function setMoneyRequestTaxRate(transactionID: string, taxRate: TaxRate) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {taxRate}); } -/** - * @param {String} transactionID - * @param {Number} taxAmount - */ -function setMoneyRequestTaxAmount(transactionID, taxAmount) { +function setMoneyRequestTaxAmount(transactionID: string, taxAmount: number) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {taxAmount}); } -/** - * @param {Boolean} billable - */ -function setMoneyRequestBillable(billable) { +function setMoneyRequestBillable(billable: boolean) { Onyx.merge(ONYXKEYS.IOU, {billable}); } @@ -3447,8 +3468,8 @@ function navigateToNextPage(iou: OnyxEntry, iouType: string, repo if (!iou?.participants?.length || shouldReset) { const currentUserAccountID = currentUserPersonalDetails.accountID; const participants: Participant[] = ReportUtils.isPolicyExpenseChat(chatReport) - ? [{reportID: chatReport.reportID, isPolicyExpenseChat: true, selected: true}] - : (chatReport.participantAccountIDs ?? []).filter((accountID) => currentUserAccountID !== accountID).map((accountID) => ({accountID, selected: true})); + ? [{reportID: chatReport?.reportID, isPolicyExpenseChat: true, selected: true}] + : (chatReport?.participantAccountIDs ?? []).filter((accountID) => currentUserAccountID !== accountID).map((accountID) => ({accountID, selected: true})); setMoneyRequestParticipants(participants); resetMoneyRequestCategory(); resetMoneyRequestTag(); diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 7f83c1de12c3..986ed8b46d0a 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -55,6 +55,21 @@ type Route = { type Routes = Record; +type TaxRateData = { + name: string; + value: string; + code?: string; +}; + +type TaxRate = { + text: string; + keyForList: string; + searchText: string; + tooltipText: string; + isDisabled?: boolean; + data?: TaxRateData; +}; + type Transaction = { amount: number; billable: boolean; @@ -105,6 +120,10 @@ type Transaction = { type TransactionDraft = Partial & { isFromGlobalCreate?: boolean; + taxRate?: TaxRate; + + /** Calculated tax amount based on selected tax rate */ + taxAmount?: number; }; type AdditionalTransactionChanges = {comment?: string; waypoints?: WaypointCollection}; @@ -112,4 +131,4 @@ type AdditionalTransactionChanges = {comment?: string; waypoints?: WaypointColle type TransactionChanges = Partial & AdditionalTransactionChanges; export default Transaction; -export type {WaypointCollection, Comment, Receipt, Waypoint, TransactionDraft, TransactionChanges}; +export type {WaypointCollection, Comment, Receipt, Waypoint, TransactionDraft, TransactionChanges, TaxRate}; From 4e7fab0fdc150b97e5dc987a552c912000201785 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Thu, 4 Jan 2024 15:42:07 +0100 Subject: [PATCH 16/68] Migrate getUpdateMoneyRequestParams function --- src/libs/ReportUtils.ts | 12 ++-- src/libs/actions/IOU.ts | 132 +++++++++++++++++++++------------- src/types/onyx/Transaction.ts | 8 ++- 3 files changed, 94 insertions(+), 58 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 56d074a0ade8..60cba5cacfcc 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -21,7 +21,7 @@ import type {IOUMessage, OriginalMessageActionName, OriginalMessageCreated} from import type {Status} from '@src/types/onyx/PersonalDetails'; import type {NotificationPreference} from '@src/types/onyx/Report'; import type {Message, ReportActionBase, ReportActions} from '@src/types/onyx/ReportAction'; -import type {Receipt, WaypointCollection} from '@src/types/onyx/Transaction'; +import type {Receipt, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; import type DeepValueOf from '@src/types/utils/DeepValueOf'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject, isNotEmptyObject} from '@src/types/utils/EmptyObject'; @@ -250,7 +250,7 @@ type TransactionDetails = amount: number; currency: string; merchant: string; - waypoints?: WaypointCollection; + waypoints?: WaypointCollection | string; comment: string; category: string; billable: boolean; @@ -2090,7 +2090,7 @@ function getReportPreviewMessage( * * At the moment, we only allow changing one transaction field at a time. */ -function getModifiedExpenseOriginalMessage(oldTransaction: OnyxEntry, transactionChanges: ExpenseOriginalMessage, isFromExpenseReport: boolean): ExpenseOriginalMessage { +function getModifiedExpenseOriginalMessage(oldTransaction: OnyxEntry, transactionChanges: TransactionChanges, isFromExpenseReport: boolean): ExpenseOriginalMessage { const originalMessage: ExpenseOriginalMessage = {}; // 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 @@ -2856,9 +2856,9 @@ function buildOptimisticReportPreview( * Builds an optimistic modified expense action with a randomly generated reportActionID. */ function buildOptimisticModifiedExpenseReportAction( - transactionThread: OnyxEntry, + transactionThread: OnyxEntry, oldTransaction: OnyxEntry, - transactionChanges: ExpenseOriginalMessage, + transactionChanges: TransactionChanges, isFromExpenseReport: boolean, ): OptimisticModifiedExpenseReportAction { const originalMessage = getModifiedExpenseOriginalMessage(oldTransaction, transactionChanges, isFromExpenseReport); @@ -4413,4 +4413,4 @@ export { shouldDisableThread, }; -export type {ExpenseOriginalMessage, OptionData, OptimisticChatReport, OptimisticCreatedReportAction, OptimisticIOUReportAction}; +export type {ExpenseOriginalMessage, OptionData, OptimisticChatReport, OptimisticCreatedReportAction, OptimisticIOUReportAction, TransactionDetails}; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 94f2ec59ad9c..ad04d0a7bbd9 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -26,7 +26,7 @@ import Permissions from '@libs/Permissions'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; -import type {OptimisticChatReport, OptimisticCreatedReportAction, OptimisticIOUReportAction} from '@libs/ReportUtils'; +import type {OptimisticChatReport, OptimisticCreatedReportAction, OptimisticIOUReportAction, TransactionDetails} from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import * as UserUtils from '@libs/UserUtils'; import type {MoneyRequestNavigatorParamList} from '@navigation/types'; @@ -38,7 +38,7 @@ import type * as OnyxTypes from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; import type ReportAction from '@src/types/onyx/ReportAction'; import type {OnyxData} from '@src/types/onyx/Request'; -import type {Comment, Receipt, TaxRate, WaypointCollection} from '@src/types/onyx/Transaction'; +import type {Comment, Receipt, TaxRate, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; @@ -84,6 +84,17 @@ type SplitsAndOnyxData = { onyxData: OnyxData; }; +type UpdateMoneyRequestParams = Partial & { + reportID?: string; + transactionID: string; + reportActionID?: string; +}; + +type UpdateMoneyRequestData = { + params: UpdateMoneyRequestParams; + onyxData: OnyxData; +}; + let betas: OnyxTypes.Beta[] = []; Onyx.connect({ key: ONYXKEYS.BETAS, @@ -864,44 +875,55 @@ function createDistanceRequest( } /** - * @param {String} transactionID - * @param {String} transactionThreadReportID - * @param {Object} transactionChanges - * @param {String} [transactionChanges.created] Present when updated the date field - * @param {Boolean} onlyIncludeChangedFields - * When 'true', then the returned params will only include the transaction details for the fields that were changed. - * When `false`, then the returned params will include all the transaction details, regardless of which fields were changed. - * This setting is necessary while the UpdateDistanceRequest API is refactored to be fully 1:1:1 in https://github.com/Expensify/App/issues/28358 - * @returns {object} + * @param transactionChanges + * @param [transactionChanges.created] Present when updated the date field + * @param onlyIncludeChangedFields + * When 'true', then the returned params will only include the transaction details for the fields that were changed. + * When `false`, then the returned params will include all the transaction details, regardless of which fields were changed. + * This setting is necessary while the UpdateDistanceRequest API is refactored to be fully 1:1:1 in https://github.com/Expensify/App/issues/28358 */ -function getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, onlyIncludeChangedFields) { - const optimisticData = []; - const successData = []; - const failureData = []; +function getUpdateMoneyRequestParams( + transactionID: string, + transactionThreadReportID: string, + transactionChanges: TransactionChanges, + onlyIncludeChangedFields: boolean, +): UpdateMoneyRequestData { + const optimisticData: OnyxUpdate[] = []; + const successData: OnyxUpdate[] = []; + const failureData: OnyxUpdate[] = []; // Step 1: Set any "pending fields" (ones updated while the user was offline) to have error messages in the failureData - const pendingFields = _.mapObject(transactionChanges, () => CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE); - const clearedPendingFields = _.mapObject(transactionChanges, () => null); - const errorFields = _.mapObject(pendingFields, () => ({ - [DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.genericEditFailureMessage'), - })); + const pendingFields = Object.fromEntries(Object.keys(transactionChanges).map((key) => [key, CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE])); + 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'), + }, + ]), + ); // Step 2: Get all the collections being updated - const transactionThread = allReports[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`]; - const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; - const iouReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${transactionThread.parentReportID}`]; + 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 updatedTransaction = TransactionUtils.getUpdatedTransaction(transaction, transactionChanges, isFromExpenseReport); + const updatedTransaction = transaction ? TransactionUtils.getUpdatedTransaction(transaction, transactionChanges, isFromExpenseReport) : null; const transactionDetails = ReportUtils.getTransactionDetails(updatedTransaction); - // This needs to be a JSON string since we're sending this to the MapBox API - transactionDetails.waypoints = JSON.stringify(transactionDetails.waypoints); + if (transactionDetails?.waypoints) { + // This needs to be a JSON string since we're sending this to the MapBox API + transactionDetails.waypoints = JSON.stringify(transactionDetails.waypoints); + } - const dataToIncludeInParams = onlyIncludeChangedFields ? _.pick(transactionDetails, _.keys(transactionChanges)) : transactionDetails; + const dataToIncludeInParams: Partial = onlyIncludeChangedFields + ? (Object.fromEntries(Object.entries(transactionDetails ?? {}).filter(([key]) => Object.keys(transactionChanges).includes(key))) as Partial) + : transactionDetails; - const params = { + const params: UpdateMoneyRequestParams = { ...dataToIncludeInParams, - reportID: iouReport.reportID, + reportID: iouReport?.reportID, transactionID, }; @@ -909,29 +931,29 @@ function getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, t // We don't create a modified report action if we're updating the waypoints, // since there isn't actually any optimistic data we can create for them and the report action is created on the server // with the response from the MapBox API - if (!_.has(transactionChanges, 'waypoints')) { + if (!('waypoints' in transactionChanges)) { const updatedReportAction = ReportUtils.buildOptimisticModifiedExpenseReportAction(transactionThread, transaction, transactionChanges, isFromExpenseReport); params.reportActionID = updatedReportAction.reportActionID; optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread?.reportID}`, value: { - [updatedReportAction.reportActionID]: updatedReportAction, + [updatedReportAction.reportActionID]: updatedReportAction as OnyxTypes.ReportAction, }, }); successData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread?.reportID}`, value: { [updatedReportAction.reportActionID]: {pendingAction: null}, }, }); failureData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread?.reportID}`, value: { - [updatedReportAction.reportActionID]: updatedReportAction, + [updatedReportAction.reportActionID]: updatedReportAction as OnyxTypes.ReportAction, }, }); @@ -939,23 +961,25 @@ function getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, t // Should only update if the transaction matches the currency of the report, else we wait for the update // from the server with the currency conversion let updatedMoneyRequestReport = {...iouReport}; - if (updatedTransaction.currency === iouReport.currency && updatedTransaction.modifiedAmount) { + if (updatedTransaction?.currency === iouReport?.currency && updatedTransaction?.modifiedAmount) { const diff = TransactionUtils.getAmount(transaction, true) - TransactionUtils.getAmount(updatedTransaction, true); - if (ReportUtils.isExpenseReport(iouReport)) { + if (ReportUtils.isExpenseReport(iouReport) && typeof updatedMoneyRequestReport.total === 'number') { updatedMoneyRequestReport.total += diff; } else { - updatedMoneyRequestReport = IOUUtils.updateIOUOwnerAndTotal(iouReport, updatedReportAction.actorAccountID, diff, TransactionUtils.getCurrency(transaction), false); + updatedMoneyRequestReport = iouReport + ? IOUUtils.updateIOUOwnerAndTotal(iouReport, updatedReportAction.actorAccountID ?? -1, diff, TransactionUtils.getCurrency(transaction), false) + : {}; } updatedMoneyRequestReport.cachedTotal = CurrencyUtils.convertToDisplayString(updatedMoneyRequestReport.total, updatedTransaction.currency); optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, value: updatedMoneyRequestReport, }); successData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, value: {pendingAction: null}, }); } @@ -968,30 +992,36 @@ function getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, t value: { ...updatedTransaction, pendingFields, - isLoading: _.has(transactionChanges, 'waypoints'), + isLoading: 'waypoints' in transactionChanges, errorFields: null, }, }); // Update recently used categories if the category is changed - if (_.has(transactionChanges, 'category')) { - const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, transactionChanges.category); - if (!_.isEmpty(optimisticPolicyRecentlyUsedCategories)) { + if ('category' in transactionChanges) { + const optimisticPolicyRecentlyUsedCategories: OptimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories( + iouReport?.policyID, + transactionChanges.category, + ) as OptimisticPolicyRecentlyUsedCategories; + if (optimisticPolicyRecentlyUsedCategories.length) { optimisticData.push({ onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${iouReport.policyID}`, + key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${iouReport?.policyID}`, value: optimisticPolicyRecentlyUsedCategories, }); } } // Update recently used categories if the tag is changed - if (_.has(transactionChanges, 'tag')) { - const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport.policyID, transactionChanges.tag); + if ('tag' in transactionChanges) { + const optimisticPolicyRecentlyUsedTags: OptimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags( + iouReport?.policyID, + transactionChanges.tag, + ) as OptimisticPolicyRecentlyUsedTags; if (!_.isEmpty(optimisticPolicyRecentlyUsedTags)) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${iouReport.policyID}`, + key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${iouReport?.policyID}`, value: optimisticPolicyRecentlyUsedTags, }); } @@ -1008,7 +1038,7 @@ function getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, t }, }); - if (_.has(transactionChanges, 'waypoints')) { + if ('waypoints' in transactionChanges) { // Delete the draft transaction when editing waypoints when the server responds successfully and there are no errors successData.push({ onyxMethod: Onyx.METHOD.SET, @@ -1031,8 +1061,8 @@ function getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, t // Reset the iouReport to it's original state failureData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, - value: iouReport, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, + value: iouReport as OnyxTypes.Report, }); return { diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 986ed8b46d0a..3875e70aff48 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -116,6 +116,7 @@ type Transaction = { /** If the transaction was made in a foreign currency, we send the original amount and currency */ originalAmount?: number; originalCurrency?: string; + isLoading?: boolean; }; type TransactionDraft = Partial & { @@ -126,7 +127,12 @@ type TransactionDraft = Partial & { taxAmount?: number; }; -type AdditionalTransactionChanges = {comment?: string; waypoints?: WaypointCollection}; +type AdditionalTransactionChanges = { + comment?: string; + waypoints?: WaypointCollection; + oldAmount?: number; + oldCurrency?: string; +}; type TransactionChanges = Partial & AdditionalTransactionChanges; From cdcb7d5b7b83572a0cbbeecb87e1b3259d9b074b Mon Sep 17 00:00:00 2001 From: VickyStash Date: Thu, 4 Jan 2024 15:51:47 +0100 Subject: [PATCH 17/68] Migrate updateMoneyRequestDate, updateDistanceRequest, editMoneyRequest, updateMoneyRequestAmountAndCurrency functions --- src/libs/ReportUtils.ts | 34 ++++++++++++++++------------------ src/libs/actions/IOU.ts | 34 ++++++---------------------------- 2 files changed, 22 insertions(+), 46 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 60cba5cacfcc..a4dadc25b469 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -244,23 +244,21 @@ type OptimisticTaskReport = Pick< | 'lastVisibleActionCreated' >; -type TransactionDetails = - | { - created: string; - amount: number; - currency: string; - merchant: string; - waypoints?: WaypointCollection | string; - comment: string; - category: string; - billable: boolean; - tag: string; - mccGroup?: ValueOf; - cardID: number; - originalAmount: number; - originalCurrency: string; - } - | undefined; +type TransactionDetails = { + created: string; + amount: number; + currency: string; + merchant: string; + waypoints?: WaypointCollection | string; + comment: string; + category: string; + billable: boolean; + tag: string; + mccGroup?: ValueOf; + cardID: number; + originalAmount: number; + originalCurrency: string; +}; type OptimisticIOUReport = Pick< Report, @@ -1787,7 +1785,7 @@ function getMoneyRequestReportName(report: OnyxEntry, policy: OnyxEntry< * into a flat object. Used for displaying transactions and sending them in API commands */ -function getTransactionDetails(transaction: OnyxEntry, createdDateFormat: string = CONST.DATE.FNS_FORMAT_STRING): TransactionDetails { +function getTransactionDetails(transaction: OnyxEntry, createdDateFormat: string = CONST.DATE.FNS_FORMAT_STRING): TransactionDetails | undefined { if (!transaction) { return; } diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index ad04d0a7bbd9..114174d11e34 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -917,7 +917,7 @@ function getUpdateMoneyRequestParams( transactionDetails.waypoints = JSON.stringify(transactionDetails.waypoints); } - const dataToIncludeInParams: Partial = onlyIncludeChangedFields + const dataToIncludeInParams: Partial | undefined = onlyIncludeChangedFields ? (Object.fromEntries(Object.entries(transactionDetails ?? {}).filter(([key]) => Object.keys(transactionChanges).includes(key))) as Partial) : transactionDetails; @@ -1073,13 +1073,9 @@ function getUpdateMoneyRequestParams( /** * Updates the created date of a money request - * - * @param {String} transactionID - * @param {String} transactionThreadReportID - * @param {String} val */ -function updateMoneyRequestDate(transactionID, transactionThreadReportID, val) { - const transactionChanges = { +function updateMoneyRequestDate(transactionID: string, transactionThreadReportID: string, val: string) { + const transactionChanges: TransactionChanges = { created: val, }; const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true); @@ -1089,16 +1085,8 @@ function updateMoneyRequestDate(transactionID, transactionThreadReportID, val) { /** * Edits an existing distance request * - * @param {String} transactionID - * @param {String} transactionThreadReportID - * @param {Object} transactionChanges - * @param {String} [transactionChanges.created] - * @param {Number} [transactionChanges.amount] - * @param {Object} [transactionChanges.comment] - * @param {Object} [transactionChanges.waypoints] - * */ -function updateDistanceRequest(transactionID, transactionThreadReportID, transactionChanges) { +function updateDistanceRequest(transactionID: string, transactionThreadReportID: string, transactionChanges: TransactionChanges) { const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, false); API.write('UpdateDistanceRequest', params, onyxData); } @@ -2415,12 +2403,7 @@ function editRegularMoneyRequest(transactionID, transactionThreadReportID, trans ); } -/** - * @param {object} transaction - * @param {String} transactionThreadReportID - * @param {Object} transactionChanges - */ -function editMoneyRequest(transaction, transactionThreadReportID, transactionChanges) { +function editMoneyRequest(transaction: OnyxTypes.Transaction, transactionThreadReportID: string, transactionChanges: TransactionChanges) { if (TransactionUtils.isDistanceRequest(transaction)) { updateDistanceRequest(transaction.transactionID, transactionThreadReportID, transactionChanges); } else { @@ -2430,13 +2413,8 @@ function editMoneyRequest(transaction, transactionThreadReportID, transactionCha /** * Updates the amount and currency fields of a money request - * - * @param {String} transactionID - * @param {String} transactionThreadReportID - * @param {String} currency - * @param {Number} amount */ -function updateMoneyRequestAmountAndCurrency(transactionID, transactionThreadReportID, currency, amount) { +function updateMoneyRequestAmountAndCurrency(transactionID: string, transactionThreadReportID: string, currency: string, amount: number) { const transactionChanges = { amount, currency, From c71ae90e0502c4fcc707bf6410c8522b5626f7b6 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Thu, 4 Jan 2024 16:31:58 +0100 Subject: [PATCH 18/68] Migrate setDraftSplitTransaction, editRegularMoneyRequest functions --- src/libs/actions/IOU.ts | 197 +++++++++++++++++++++------------------- 1 file changed, 103 insertions(+), 94 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 114174d11e34..41074a802b16 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -4,7 +4,7 @@ import {format} from 'date-fns'; import Str from 'expensify-common/lib/str'; import lodashGet from 'lodash/get'; import lodashHas from 'lodash/has'; -import {ImageSourcePropType} from 'react-native'; +import type {ImageSourcePropType} from 'react-native'; import Onyx from 'react-native-onyx'; import type {OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import OnyxUtils from 'react-native-onyx/lib/utils'; @@ -39,7 +39,7 @@ import type {Participant} from '@src/types/onyx/IOU'; import type ReportAction from '@src/types/onyx/ReportAction'; import type {OnyxData} from '@src/types/onyx/Request'; import type {Comment, Receipt, TaxRate, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; -import type {EmptyObject} from '@src/types/utils/EmptyObject'; +import {EmptyObject, isNotEmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; import * as Report from './Report'; @@ -1206,7 +1206,7 @@ function createSplitsAndOnyxData( existingSplitChatReportID || participants[0].reportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${existingSplitChatReportID || participants[0].reportID}`] : ReportUtils.getChatByParticipants(participantAccountIDs); - const splitChatReport = existingSplitChatReport || ReportUtils.buildOptimisticChatReport(participantAccountIDs); + const splitChatReport = existingSplitChatReport ?? ReportUtils.buildOptimisticChatReport(participantAccountIDs); const isOwnPolicyExpenseChat = splitChatReport.isOwnPolicyExpenseChat; const splitTransaction = TransactionUtils.buildOptimisticTransaction( @@ -2152,38 +2152,29 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA Report.notifyNewAction(chatReportID, sessionAccountID); } -/** - * @param {String} transactionID - * @param {Object} transactionChanges - */ -function setDraftSplitTransaction(transactionID, transactionChanges = {}) { +function setDraftSplitTransaction(transactionID: string, transactionChanges: TransactionChanges = {}) { let draftSplitTransaction = allDraftSplitTransactions[`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`]; if (!draftSplitTransaction) { draftSplitTransaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; } - const updatedTransaction = TransactionUtils.getUpdatedTransaction(draftSplitTransaction, transactionChanges, false, false); + const updatedTransaction = TransactionUtils.getUpdatedTransaction(draftSplitTransaction as OnyxTypes.Transaction, transactionChanges, false, false); Onyx.merge(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`, updatedTransaction); } -/** - * @param {String} transactionID - * @param {Number} transactionThreadReportID - * @param {Object} transactionChanges - */ -function editRegularMoneyRequest(transactionID, transactionThreadReportID, transactionChanges) { +function editRegularMoneyRequest(transactionID: string, transactionThreadReportID: string, transactionChanges: TransactionChanges) { // STEP 1: Get all collections we're updating - const transactionThread = allReports[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`]; + const transactionThread = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; - const iouReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${transactionThread.parentReportID}`]; - const chatReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${iouReport.chatReportID}`]; + const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThread?.parentReportID}`] ?? null; + const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`] ?? null; const isFromExpenseReport = ReportUtils.isExpenseReport(iouReport); // STEP 2: Build new modified expense report action. const updatedReportAction = ReportUtils.buildOptimisticModifiedExpenseReportAction(transactionThread, transaction, transactionChanges, isFromExpenseReport); - const updatedTransaction = TransactionUtils.getUpdatedTransaction(transaction, transactionChanges, isFromExpenseReport); + const updatedTransaction = TransactionUtils.getUpdatedTransaction(transaction as OnyxTypes.Transaction, transactionChanges, isFromExpenseReport); // STEP 3: Compute the IOU total and update the report preview message so LHN amount owed is correct // Should only update if the transaction matches the currency of the report, else we wait for the update @@ -2191,20 +2182,22 @@ function editRegularMoneyRequest(transactionID, transactionThreadReportID, trans let updatedMoneyRequestReport = {...iouReport}; const updatedChatReport = {...chatReport}; const diff = TransactionUtils.getAmount(transaction, true) - TransactionUtils.getAmount(updatedTransaction, true); - if (updatedTransaction.currency === iouReport.currency && updatedTransaction.modifiedAmount && diff !== 0) { - if (ReportUtils.isExpenseReport(iouReport)) { + if (updatedTransaction?.currency === iouReport?.currency && updatedTransaction?.modifiedAmount && diff !== 0) { + if (ReportUtils.isExpenseReport(iouReport) && updatedMoneyRequestReport.total) { updatedMoneyRequestReport.total += diff; } else { - updatedMoneyRequestReport = IOUUtils.updateIOUOwnerAndTotal(iouReport, updatedReportAction.actorAccountID, diff, TransactionUtils.getCurrency(transaction), false); + updatedMoneyRequestReport = iouReport + ? IOUUtils.updateIOUOwnerAndTotal(iouReport, updatedReportAction.actorAccountID ?? -1, diff, TransactionUtils.getCurrency(transaction), false) + : {}; } updatedMoneyRequestReport.cachedTotal = CurrencyUtils.convertToDisplayString(updatedMoneyRequestReport.total, updatedTransaction.currency); // Update the last message of the IOU report const lastMessage = ReportUtils.getIOUReportActionMessage( - iouReport.reportID, + iouReport?.reportID ?? '', CONST.IOU.REPORT_ACTION_TYPE.CREATE, - updatedMoneyRequestReport.total, + updatedMoneyRequestReport.total ?? 0, '', updatedTransaction.currency, '', @@ -2214,9 +2207,9 @@ function editRegularMoneyRequest(transactionID, transactionThreadReportID, trans updatedMoneyRequestReport.lastMessageHtml = lastMessage[0].html; // Update the last message of the chat report - const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(iouReport); + const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(iouReport?.reportID); // There was an error before - wrong value was sent const messageText = Localize.translateLocal(hasNonReimbursableTransactions ? 'iou.payerSpentAmount' : 'iou.payerOwesAmount', { - payer: ReportUtils.getPersonalDetailsForAccountID(updatedMoneyRequestReport.managerID).login || '', + payer: ReportUtils.getPersonalDetailsForAccountID(updatedMoneyRequestReport.managerID ?? -1).login || '', amount: CurrencyUtils.convertToDisplayString(updatedMoneyRequestReport.total, updatedMoneyRequestReport.currency), }); updatedChatReport.lastMessageText = messageText; @@ -2227,12 +2220,12 @@ function editRegularMoneyRequest(transactionID, transactionThreadReportID, trans // STEP 4: Compose the optimistic data const currentTime = DateUtils.getDBTime(); - const optimisticData = [ + const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread?.reportID}`, value: { - [updatedReportAction.reportActionID]: updatedReportAction, + [updatedReportAction.reportActionID]: updatedReportAction as OnyxTypes.ReportAction, }, }, { @@ -2242,12 +2235,12 @@ function editRegularMoneyRequest(transactionID, transactionThreadReportID, trans }, { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, value: updatedMoneyRequestReport, }, { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.chatReportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`, value: updatedChatReport, }, { @@ -2258,58 +2251,62 @@ function editRegularMoneyRequest(transactionID, transactionThreadReportID, trans lastVisibleActionCreated: currentTime, }, }, - ...(!isScanning - ? [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`, - value: { - [transactionThread.parentReportActionID]: { - whisperedToAccountIDs: [], - }, - }, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.parentReportID}`, - value: { - [iouReport.parentReportActionID]: { - whisperedToAccountIDs: [], - }, - }, - }, - ] - : []), ]; + if (!isScanning) { + optimisticData.push( + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.reportID}`, + value: { + [transactionThread?.parentReportActionID ?? '']: { + whisperedToAccountIDs: [], + }, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.parentReportID}`, + value: { + [iouReport?.parentReportActionID ?? '']: { + whisperedToAccountIDs: [], + }, + }, + }, + ); + } + // Update recently used categories if the category is changed - if (_.has(transactionChanges, 'category')) { - const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, transactionChanges.category); - if (!_.isEmpty(optimisticPolicyRecentlyUsedCategories)) { + if ('category' in transactionChanges) { + const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories( + iouReport?.policyID, + transactionChanges.category, + ) as OptimisticPolicyRecentlyUsedCategories; + if (optimisticPolicyRecentlyUsedCategories.length) { optimisticData.push({ onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${iouReport.policyID}`, + key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${iouReport?.policyID}`, value: optimisticPolicyRecentlyUsedCategories, }); } } // Update recently used categories if the tag is changed - if (_.has(transactionChanges, 'tag')) { - const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport.policyID, transactionChanges.tag); - if (!_.isEmpty(optimisticPolicyRecentlyUsedTags)) { + if ('tag' in transactionChanges) { + const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport?.policyID, transactionChanges.tag) as OptimisticPolicyRecentlyUsedTags; + if (isNotEmptyObject(optimisticPolicyRecentlyUsedTags)) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${iouReport.policyID}`, + key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${iouReport?.policyID}`, value: optimisticPolicyRecentlyUsedTags, }); } } - const successData = [ + const successData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread?.reportID}`, value: { [updatedReportAction.reportActionID]: {pendingAction: null}, }, @@ -2332,15 +2329,15 @@ function editRegularMoneyRequest(transactionID, transactionThreadReportID, trans }, { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, value: {pendingAction: null}, }, ]; - const failureData = [ + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread?.reportID}`, value: { [updatedReportAction.reportActionID]: { errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericEditFailureMessage'), @@ -2352,55 +2349,67 @@ function editRegularMoneyRequest(transactionID, transactionThreadReportID, trans key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, value: { ...transaction, - modifiedCreated: transaction.modifiedCreated ? transaction.modifiedCreated : null, - modifiedAmount: transaction.modifiedAmount ? transaction.modifiedAmount : null, - modifiedCurrency: transaction.modifiedCurrency ? transaction.modifiedCurrency : null, - modifiedMerchant: transaction.modifiedMerchant ? transaction.modifiedMerchant : null, - modifiedWaypoints: transaction.modifiedWaypoints ? transaction.modifiedWaypoints : null, + modifiedCreated: transaction?.modifiedCreated ? transaction.modifiedCreated : null, + modifiedAmount: transaction?.modifiedAmount ? transaction.modifiedAmount : null, + modifiedCurrency: transaction?.modifiedCurrency ? transaction.modifiedCurrency : null, + modifiedMerchant: transaction?.modifiedMerchant ? transaction.modifiedMerchant : null, + modifiedWaypoints: transaction?.modifiedWaypoints ? transaction.modifiedWaypoints : null, pendingFields: null, }, }, { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, value: { ...iouReport, - cachedTotal: iouReport.cachedTotal ? iouReport.cachedTotal : null, + cachedTotal: iouReport?.cachedTotal ? iouReport?.cachedTotal : null, }, }, { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.chatReportID}`, - value: chatReport, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`, + value: chatReport as OnyxTypes.Report, }, { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`, value: { - lastReadTime: transactionThread.lastReadTime, - lastVisibleActionCreated: transactionThread.lastVisibleActionCreated, + lastReadTime: transactionThread?.lastReadTime, + lastVisibleActionCreated: transactionThread?.lastVisibleActionCreated, }, }, ]; // STEP 6: Call the API endpoint - const {created, amount, currency, comment, merchant, category, billable, tag} = ReportUtils.getTransactionDetails(updatedTransaction); - API.write( - 'EditMoneyRequest', - { - transactionID, - reportActionID: updatedReportAction.reportActionID, - created, - amount, - currency, - comment, - merchant, - category, - billable, - tag, - }, - {optimisticData, successData, failureData}, - ); + const {created, amount, currency, comment, merchant, category, billable, tag} = ReportUtils.getTransactionDetails(updatedTransaction) ?? {}; + + type EditMoneyRequestParams = { + transactionID: string; + reportActionID: string; + created?: string; + amount?: number; + currency?: string; + comment?: string; + merchant?: string; + category?: string; + billable?: boolean; + tag?: string; + }; + + const parameters: EditMoneyRequestParams = { + transactionID, + reportActionID: updatedReportAction.reportActionID, + created, + amount, + currency, + comment, + merchant, + category, + billable, + tag, + }; + + API.write('EditMoneyRequest', parameters, {optimisticData, successData, failureData}); } function editMoneyRequest(transaction: OnyxTypes.Transaction, transactionThreadReportID: string, transactionChanges: TransactionChanges) { From 9aad84a4a6cc0ce9e1672880345f4aa31a4ee9d9 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Thu, 4 Jan 2024 17:21:41 +0100 Subject: [PATCH 19/68] Migrate getSendMoneyParams function --- src/libs/actions/IOU.ts | 136 +++++++++++++++++++++++----------------- 1 file changed, 79 insertions(+), 57 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 41074a802b16..ac41becf0e1c 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -39,8 +39,9 @@ import type {Participant} from '@src/types/onyx/IOU'; import type ReportAction from '@src/types/onyx/ReportAction'; import type {OnyxData} from '@src/types/onyx/Request'; import type {Comment, Receipt, TaxRate, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; -import {EmptyObject, isNotEmptyObject} from '@src/types/utils/EmptyObject'; -import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import DeepValueOf from '@src/types/utils/DeepValueOf'; +import type {EmptyObject} from '@src/types/utils/EmptyObject'; +import {isEmptyObject, isNotEmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; import * as Report from './Report'; @@ -95,6 +96,26 @@ type UpdateMoneyRequestData = { onyxData: OnyxData; }; +type PaymentMethodType = DeepValueOf; + +type SendMoneyParams = { + iouReportID: string; + chatReportID: string; + reportActionID: string; + paymentMethodType: PaymentMethodType; + transactionID: string; + newIOUReportDetails: string; + createdReportActionID: string; + reportPreviewReportActionID: string; +}; + +type SendMoneyParamsData = { + params: SendMoneyParams; + optimisticData: OnyxUpdate[]; + successData: OnyxUpdate[]; + failureData: OnyxUpdate[]; +}; + let betas: OnyxTypes.Beta[] = []; Onyx.connect({ key: ONYXKEYS.BETAS, @@ -2693,17 +2714,20 @@ function deleteMoneyRequest(transactionID, reportAction, isSingleTransactionView } /** - * @param {Object} report - * @param {Number} amount - * @param {String} currency - * @param {String} comment - * @param {String} paymentMethodType - * @param {String} managerID - Account ID of the person sending the money - * @param {Object} recipient - The user receiving the money + * @param managerID - Account ID of the person sending the money + * @param recipient - The user receiving the money * @returns {Object} */ -function getSendMoneyParams(report, amount, currency, comment, paymentMethodType, managerID, recipient) { - const recipientEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(recipient.login); +function getSendMoneyParams( + report: OnyxTypes.Report, + amount: number, + currency: string, + comment: string, + paymentMethodType: PaymentMethodType, + managerID: number, + recipient: Participant, +): SendMoneyParamsData { + const recipientEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(recipient.login ?? ''); const recipientAccountID = Number(recipient.accountID); const newIOUReportDetails = JSON.stringify({ amount, @@ -2726,7 +2750,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType const optimisticIOUReport = ReportUtils.buildOptimisticIOUReport(recipientAccountID, managerID, amount, chatReport.reportID, currency, true); const optimisticTransaction = TransactionUtils.buildOptimisticTransaction(amount, currency, optimisticIOUReport.reportID, comment); - const optimisticTransactionData = { + const optimisticTransactionData: OnyxUpdate = { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${optimisticTransaction.transactionID}`, value: optimisticTransaction, @@ -2749,36 +2773,49 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType const reportPreviewAction = ReportUtils.buildOptimisticReportPreview(chatReport, optimisticIOUReport); - // First, add data that will be used in all cases - const optimisticChatReportData = { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, - value: { - ...chatReport, - lastReadTime: DateUtils.getDBTime(), - lastVisibleActionCreated: reportPreviewAction.created, - }, - }; - const optimisticIOUReportData = { + // 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 + let optimisticChatReportData: OnyxUpdate = isNewChat + ? { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, + value: { + ...chatReport, + // Set and clear pending fields on the chat report + pendingFields: {createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}, + lastReadTime: DateUtils.getDBTime(), + lastVisibleActionCreated: reportPreviewAction.created, + }, + } + : { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, + value: { + ...chatReport, + lastReadTime: DateUtils.getDBTime(), + lastVisibleActionCreated: reportPreviewAction.created, + }, + }; + const optimisticIOUReportData: OnyxUpdate = { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.REPORT}${optimisticIOUReport.reportID}`, value: { ...optimisticIOUReport, - lastMessageText: optimisticIOUReportAction.message[0].text, - lastMessageHtml: optimisticIOUReportAction.message[0].html, + lastMessageText: optimisticIOUReportAction.message?.[0].text, + lastMessageHtml: optimisticIOUReportAction.message?.[0].html, }, }; - const optimisticIOUReportActionsData = { + const optimisticIOUReportActionsData: OnyxUpdate = { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${optimisticIOUReport.reportID}`, value: { [optimisticIOUReportAction.reportActionID]: { - ...optimisticIOUReportAction, + ...(optimisticIOUReportAction as OnyxTypes.ReportAction), pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }, }, }; - const optimisticChatReportActionsData = { + const optimisticChatReportActionsData: OnyxUpdate = { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { @@ -2786,7 +2823,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType }, }; - const successData = [ + const successData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${optimisticIOUReport.reportID}`, @@ -2812,7 +2849,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType }, ]; - const failureData = [ + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${optimisticTransaction.transactionID}`, @@ -2822,26 +2859,19 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType }, ]; - let optimisticPersonalDetailListData = {}; + let optimisticPersonalDetailListData: OnyxUpdate | EmptyObject = {}; // Now, let's add the data we need just when we are creating a new chat report if (isNewChat) { - // 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 - optimisticChatReportData.onyxMethod = Onyx.METHOD.SET; - optimisticIOUReportData.onyxMethod = Onyx.METHOD.SET; - - // Set and clear pending fields on the chat report - optimisticChatReportData.value.pendingFields = {createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}; successData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: optimisticChatReportData.key, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, value: {pendingFields: null}, }); failureData.push( { onyxMethod: Onyx.METHOD.MERGE, - key: optimisticChatReportData.key, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, value: { errorFields: { createChat: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'), @@ -2887,8 +2917,8 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType }); } - const optimisticData = [optimisticChatReportData, optimisticIOUReportData, optimisticChatReportActionsData, optimisticIOUReportActionsData, optimisticTransactionData]; - if (!_.isEmpty(optimisticPersonalDetailListData)) { + const optimisticData: OnyxUpdate[] = [optimisticChatReportData, optimisticIOUReportData, optimisticChatReportActionsData, optimisticIOUReportActionsData, optimisticTransactionData]; + if (isNotEmptyObject(optimisticPersonalDetailListData)) { optimisticData.push(optimisticPersonalDetailListData); } @@ -2900,7 +2930,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType paymentMethodType, transactionID: optimisticTransaction.transactionID, newIOUReportDetails, - createdReportActionID: isNewChat ? optimisticCreatedAction.reportActionID : 0, + createdReportActionID: isNewChat ? optimisticCreatedAction.reportActionID : '', reportPreviewReportActionID: reportPreviewAction.reportActionID, }, optimisticData, @@ -3052,14 +3082,10 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho } /** - * @param {Object} report - * @param {Number} amount - * @param {String} currency - * @param {String} comment - * @param {String} managerID - Account ID of the person sending the money - * @param {Object} recipient - The user receiving the money + * @param managerID - Account ID of the person sending the money + * @param recipient - The user receiving the money */ -function sendMoneyElsewhere(report, amount, currency, comment, managerID, recipient) { +function sendMoneyElsewhere(report: OnyxTypes.Report, amount: number, currency: string, comment: string, managerID: number, recipient: Participant) { const {params, optimisticData, successData, failureData} = getSendMoneyParams(report, amount, currency, comment, CONST.IOU.PAYMENT_TYPE.ELSEWHERE, managerID, recipient); API.write('SendMoneyElsewhere', params, {optimisticData, successData, failureData}); @@ -3070,14 +3096,10 @@ function sendMoneyElsewhere(report, amount, currency, comment, managerID, recipi } /** - * @param {Object} report - * @param {Number} amount - * @param {String} currency - * @param {String} comment - * @param {String} managerID - Account ID of the person sending the money - * @param {Object} recipient - The user receiving the money + * @param managerID - Account ID of the person sending the money + * @param recipient - The user receiving the money */ -function sendMoneyWithWallet(report, amount, currency, comment, managerID, recipient) { +function sendMoneyWithWallet(report: OnyxTypes.Report, amount: number, currency: string, comment: string, managerID: number, recipient: Participant) { const {params, optimisticData, successData, failureData} = getSendMoneyParams(report, amount, currency, comment, CONST.IOU.PAYMENT_TYPE.EXPENSIFY, managerID, recipient); API.write('SendMoneyWithWallet', params, {optimisticData, successData, failureData}); From 63576708f951cd44fa6750572fac4b7e2d12eed7 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 8 Jan 2024 09:34:52 +0100 Subject: [PATCH 20/68] Migrate deleteMoneyRequest function --- src/libs/actions/IOU.ts | 366 ++++++++++++++++++++++------------------ 1 file changed, 205 insertions(+), 161 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index ac41becf0e1c..43b6a06890a5 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -36,12 +36,13 @@ import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; +import type {IOUMessage} from '@src/types/onyx/OriginalMessage'; import type ReportAction from '@src/types/onyx/ReportAction'; import type {OnyxData} from '@src/types/onyx/Request'; import type {Comment, Receipt, TaxRate, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; -import DeepValueOf from '@src/types/utils/DeepValueOf'; +import type DeepValueOf from '@src/types/utils/DeepValueOf'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; -import {isEmptyObject, isNotEmptyObject} from '@src/types/utils/EmptyObject'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; import * as Report from './Report'; @@ -1083,6 +1084,7 @@ function getUpdateMoneyRequestParams( failureData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style value: iouReport as OnyxTypes.Report, }); @@ -1393,8 +1395,8 @@ 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 ? '' : OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login || '').toLowerCase(); - const accountID = isOwnPolicyExpenseChat || isPolicyExpenseChat ? 0 : Number(participant.accountID); + const email = !!isOwnPolicyExpenseChat || isPolicyExpenseChat ? '' : OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login ?? '').toLowerCase(); + const accountID = !!isOwnPolicyExpenseChat || isPolicyExpenseChat ? 0 : Number(participant.accountID); if (email === currentUserEmailForIOUSplit) { return; } @@ -1418,7 +1420,7 @@ function createSplitsAndOnyxData( const existingChatReport = ReportUtils.getChatByParticipants([accountID]); isNewOneOnOneChatReport = !existingChatReport; shouldCreateOptimisticPersonalDetails = isNewOneOnOneChatReport && !personalDetailExists; - oneOnOneChatReport = existingChatReport || ReportUtils.buildOptimisticChatReport([accountID]); + oneOnOneChatReport = existingChatReport ?? ReportUtils.buildOptimisticChatReport([accountID]); } // STEP 2: Get existing IOU/Expense report and update its total OR build a new optimistic one @@ -1437,11 +1439,13 @@ function createSplitsAndOnyxData( oneOnOneIOUReport.total -= splitAmount; } } else { + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(oneOnOneIOUReport as OnyxTypes.Report, currentUserAccountID, splitAmount, currency); } // STEP 3: Build optimistic transaction const oneOnOneTransaction = TransactionUtils.buildOptimisticTransaction( + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style ReportUtils.isExpenseReport(oneOnOneIOUReport as OnyxTypes.Report) ? -splitAmount : splitAmount, currency, oneOnOneIOUReport?.reportID ?? '', @@ -1497,8 +1501,10 @@ function createSplitsAndOnyxData( let oneOnOneReportPreviewAction = ReportActionsUtils.getReportPreviewAction(oneOnOneChatReport.reportID, oneOnOneIOUReport?.reportID ?? ''); if (oneOnOneReportPreviewAction) { + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport as OnyxTypes.Report, oneOnOneReportPreviewAction); } else { + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport as OnyxTypes.Report); } @@ -1515,6 +1521,7 @@ function createSplitsAndOnyxData( // STEP 5: Build Onyx Data const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest( oneOnOneChatReport, + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style oneOnOneIOUReport as OnyxTypes.Report, oneOnOneTransaction, oneOnOneCreatedActionForChat, @@ -2031,7 +2038,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA // In case this is still the optimistic accountID saved in the splits array, return early as we cannot know // if there is an existing chat between the split creator and this participant // Instead, we will rely on Auth generating the report IDs and the user won't see any optimistic chats or reports created - const participantPersonalDetails: OnyxTypes.PersonalDetails | EmptyObject = allPersonalDetails[participant?.accountID ?? -1] || {}; + const participantPersonalDetails: OnyxTypes.PersonalDetails | EmptyObject = allPersonalDetails[participant?.accountID ?? -1] ?? {}; if (!participantPersonalDetails || participantPersonalDetails.isOptimisticPersonalDetail) { splits.push({ email: participant.email, @@ -2048,7 +2055,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA } else { const existingChatReport = ReportUtils.getChatByParticipants(participant.accountID ? [participant.accountID] : []); isNewOneOnOneChatReport = !existingChatReport; - oneOnOneChatReport = existingChatReport || ReportUtils.buildOptimisticChatReport(participant.accountID ? [participant.accountID] : []); + oneOnOneChatReport = existingChatReport ?? ReportUtils.buildOptimisticChatReport(participant.accountID ? [participant.accountID] : []); } let oneOnOneIOUReport = oneOnOneChatReport?.iouReportID ? lodashGet(allReports, `${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`, undefined) : undefined; @@ -2065,6 +2072,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA oneOnOneIOUReport.total -= splitAmount; } } else { + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(oneOnOneIOUReport as OnyxTypes.Report, sessionAccountID, splitAmount, currency ?? ''); } @@ -2102,7 +2110,9 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA } const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest( + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style oneOnOneChatReport as OnyxTypes.Report, + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style oneOnOneIOUReport as OnyxTypes.Report, oneOnOneTransaction, oneOnOneCreatedActionForChat, @@ -2195,6 +2205,7 @@ function editRegularMoneyRequest(transactionID: string, transactionThreadReportI // STEP 2: Build new modified expense report action. const updatedReportAction = ReportUtils.buildOptimisticModifiedExpenseReportAction(transactionThread, transaction, transactionChanges, isFromExpenseReport); + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style const updatedTransaction = TransactionUtils.getUpdatedTransaction(transaction as OnyxTypes.Transaction, transactionChanges, isFromExpenseReport); // STEP 3: Compute the IOU total and update the report preview message so LHN amount owed is correct @@ -2230,7 +2241,7 @@ function editRegularMoneyRequest(transactionID: string, transactionThreadReportI // Update the last message of the chat report const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(iouReport?.reportID); // There was an error before - wrong value was sent const messageText = Localize.translateLocal(hasNonReimbursableTransactions ? 'iou.payerSpentAmount' : 'iou.payerOwesAmount', { - payer: ReportUtils.getPersonalDetailsForAccountID(updatedMoneyRequestReport.managerID ?? -1).login || '', + payer: ReportUtils.getPersonalDetailsForAccountID(updatedMoneyRequestReport.managerID ?? -1).login ?? '', amount: CurrencyUtils.convertToDisplayString(updatedMoneyRequestReport.total, updatedMoneyRequestReport.currency), }); updatedChatReport.lastMessageText = messageText; @@ -2315,7 +2326,7 @@ function editRegularMoneyRequest(transactionID: string, transactionThreadReportI // Update recently used categories if the tag is changed if ('tag' in transactionChanges) { const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport?.policyID, transactionChanges.tag) as OptimisticPolicyRecentlyUsedTags; - if (isNotEmptyObject(optimisticPolicyRecentlyUsedTags)) { + if (!isEmptyObject(optimisticPolicyRecentlyUsedTags)) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${iouReport?.policyID}`, @@ -2389,6 +2400,7 @@ function editRegularMoneyRequest(transactionID: string, transactionThreadReportI { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`, + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style value: chatReport as OnyxTypes.Report, }, { @@ -2453,29 +2465,24 @@ function updateMoneyRequestAmountAndCurrency(transactionID: string, transactionT API.write('UpdateMoneyRequestAmountAndCurrency', params, onyxData); } -/** - * @param {String} transactionID - * @param {Object} reportAction - the money request reportAction we are deleting - * @param {Boolean} isSingleTransactionView - */ -function deleteMoneyRequest(transactionID, reportAction, isSingleTransactionView = false) { +function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) { // STEP 1: Get all collections we're updating - const iouReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${reportAction.originalMessage.IOUReportID}`]; - const chatReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${iouReport.chatReportID}`]; - const reportPreviewAction = ReportActionsUtils.getReportPreviewAction(iouReport.chatReportID, iouReport.reportID); + const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${(reportAction.originalMessage as IOUMessage).IOUReportID}`]; + const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`]; + const reportPreviewAction = ReportActionsUtils.getReportPreviewAction(iouReport?.chatReportID ?? '', iouReport?.reportID ?? ''); const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; const transactionViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`]; const transactionThreadID = reportAction.childReportID; let transactionThread = null; if (transactionThreadID) { - transactionThread = allReports[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`]; + transactionThread = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`]; } // STEP 2: Decide if we need to: // 1. Delete the transactionThread - delete if there are no visible comments in the thread // 2. Update the moneyRequestPreview to show [Deleted request] - update if the transactionThread exists AND it isn't being deleted const shouldDeleteTransactionThread = transactionThreadID ? ReportActionsUtils.getLastVisibleMessage(transactionThreadID).lastMessageText.length === 0 : false; - const shouldShowDeletedRequestMessage = transactionThreadID && !shouldDeleteTransactionThread; + const shouldShowDeletedRequestMessage = !!transactionThreadID && !shouldDeleteTransactionThread; // STEP 3: Update the IOU reportAction and decide if the iouReport should be deleted. We delete the iouReport if there are no visible comments left in the report. const updatedReportAction = { @@ -2494,28 +2501,31 @@ function deleteMoneyRequest(transactionID, reportAction, isSingleTransactionView originalMessage: { IOUTransactionID: null, }, - errors: null, + errors: undefined, }, - }; + } as OnyxTypes.ReportActions; - const lastVisibleAction = ReportActionsUtils.getLastVisibleAction(iouReport.reportID, updatedReportAction); - const iouReportLastMessageText = ReportActionsUtils.getLastVisibleMessage(iouReport.reportID, updatedReportAction).lastMessageText; + const lastVisibleAction = ReportActionsUtils.getLastVisibleAction(iouReport?.reportID ?? '', updatedReportAction); + const iouReportLastMessageText = ReportActionsUtils.getLastVisibleMessage(iouReport?.reportID ?? '', updatedReportAction).lastMessageText; const shouldDeleteIOUReport = iouReportLastMessageText.length === 0 && !ReportActionsUtils.isDeletedParentAction(lastVisibleAction) && (!transactionThreadID || shouldDeleteTransactionThread); // STEP 4: Update the iouReport and reportPreview with new totals and messages if it wasn't deleted let updatedIOUReport = null; - let updatedReportPreviewAction = null; + let updatedReportPreviewAction: OnyxTypes.ReportAction | null = null; if (!shouldDeleteIOUReport) { - if (ReportUtils.isExpenseReport(iouReport)) { + if (iouReport && ReportUtils.isExpenseReport(iouReport)) { updatedIOUReport = {...iouReport}; - // Because of the Expense reports are stored as negative values, we add the total from the amount - updatedIOUReport.total += TransactionUtils.getAmount(transaction, true); + if (updatedIOUReport.total) { + // Because of the Expense reports are stored as negative values, we add the total from the amount + updatedIOUReport.total += TransactionUtils.getAmount(transaction, true); + } } else { updatedIOUReport = IOUUtils.updateIOUOwnerAndTotal( - iouReport, - reportAction.actorAccountID, + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style + iouReport as OnyxTypes.Report, + reportAction.actorAccountID ?? -1, TransactionUtils.getAmount(transaction, false), TransactionUtils.getCurrency(transaction), true, @@ -2525,130 +2535,156 @@ function deleteMoneyRequest(transactionID, reportAction, isSingleTransactionView updatedIOUReport.lastMessageText = iouReportLastMessageText; updatedIOUReport.lastVisibleActionCreated = lodashGet(lastVisibleAction, 'created'); - updatedReportPreviewAction = {...reportPreviewAction}; - const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(iouReport); + updatedReportPreviewAction = reportPreviewAction ? {...reportPreviewAction} : null; + const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(iouReport?.reportID); const messageText = Localize.translateLocal(hasNonReimbursableTransactions ? 'iou.payerSpentAmount' : 'iou.payerOwesAmount', { - payer: ReportUtils.getPersonalDetailsForAccountID(updatedIOUReport.managerID).login || '', + payer: ReportUtils.getPersonalDetailsForAccountID(updatedIOUReport?.managerID ?? -1).login ?? '', amount: CurrencyUtils.convertToDisplayString(updatedIOUReport.total, updatedIOUReport.currency), }); - updatedReportPreviewAction.message[0].text = messageText; - updatedReportPreviewAction.message[0].html = messageText; - if (reportPreviewAction.childMoneyRequestCount > 0) { + + if (updatedReportPreviewAction?.message?.[0]) { + updatedReportPreviewAction.message[0].text = messageText; + updatedReportPreviewAction.message[0].html = messageText; + } + if (updatedReportPreviewAction && reportPreviewAction?.childMoneyRequestCount && reportPreviewAction?.childMoneyRequestCount > 0) { updatedReportPreviewAction.childMoneyRequestCount = reportPreviewAction.childMoneyRequestCount - 1; } } // STEP 5: Build Onyx data - const optimisticData = [ + const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, value: null, }, - ...(Permissions.canUseViolations(betas) - ? [ - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, - value: null, - }, - ] - : []), - ...(shouldDeleteTransactionThread - ? [ - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`, - value: null, - }, - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadID}`, - value: null, - }, - ] - : []), - { - onyxMethod: shouldDeleteIOUReport ? Onyx.METHOD.SET : Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`, - value: shouldDeleteIOUReport ? null : updatedReportAction, - }, - { - onyxMethod: shouldDeleteIOUReport ? Onyx.METHOD.SET : Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, - value: updatedIOUReport, - }, + ]; + + if (Permissions.canUseViolations(betas)) { + optimisticData.push({ + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, + value: null, + }); + } + + if (shouldDeleteTransactionThread) { + optimisticData.push( + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`, + value: null, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadID}`, + value: null, + }, + ); + } + + optimisticData.push( + shouldDeleteIOUReport + ? { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.reportID}`, + value: null, + } + : { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.reportID}`, + value: updatedReportAction, + }, + shouldDeleteIOUReport + ? { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style + value: updatedIOUReport as OnyxTypes.Report, + } + : { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style + value: updatedIOUReport as OnyxTypes.Report, + }, { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`, value: { - [reportPreviewAction.reportActionID]: updatedReportPreviewAction, + [reportPreviewAction?.reportActionID ?? '']: updatedReportPreviewAction, }, }, - ...(!shouldDeleteIOUReport && updatedReportPreviewAction.childMoneyRequestCount === 0 - ? [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, - value: { - hasOutstandingChildRequest: false, - }, - }, - ] - : []), - ...(shouldDeleteIOUReport - ? [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, - value: { - hasOutstandingChildRequest: false, - iouReportID: null, - lastMessageText: ReportActionsUtils.getLastVisibleMessage(iouReport.chatReportID, {[reportPreviewAction.reportActionID]: null}).lastMessageText, - lastVisibleActionCreated: lodashGet(ReportActionsUtils.getLastVisibleAction(iouReport.chatReportID, {[reportPreviewAction.reportActionID]: null}), 'created'), - }, - }, - ] - : []), - ]; + ); - const successData = [ + if (!shouldDeleteIOUReport && updatedReportPreviewAction?.childMoneyRequestCount === 0) { + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`, + value: { + hasOutstandingChildRequest: false, + }, + }); + } + + if (shouldDeleteIOUReport) { + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`, + value: { + hasOutstandingChildRequest: false, + iouReportID: null, + lastMessageText: + iouReport && reportPreviewAction + ? ReportActionsUtils.getLastVisibleMessage(iouReport.chatReportID ?? '', {[reportPreviewAction.reportActionID]: null}).lastMessageText + : '', + lastVisibleActionCreated: + iouReport && reportPreviewAction + ? lodashGet(ReportActionsUtils.getLastVisibleAction(iouReport.chatReportID ?? '', {[reportPreviewAction.reportActionID]: null}), 'created') + : 'created', + }, + }); + } + + const successData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.reportID}`, value: { [reportAction.reportActionID]: {pendingAction: null}, }, }, ]; - const failureData = [ + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, value: transaction, }, - ...(Permissions.canUseViolations(betas) - ? [ - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, - value: transactionViolations, - }, - ] - : []), - ...(shouldDeleteTransactionThread - ? [ - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`, - value: transactionThread, - }, - ] - : []), + ]; + + if (Permissions.canUseViolations(betas)) { + failureData.push({ + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, + value: transactionViolations, + }); + } + + if (shouldDeleteTransactionThread) { + failureData.push({ + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`, + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style + value: transactionThread as OnyxTypes.Report, + }); + } + + failureData.push( { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.reportID}`, value: { [reportAction.reportActionID]: { ...reportAction, @@ -2656,58 +2692,67 @@ function deleteMoneyRequest(transactionID, reportAction, isSingleTransactionView }, }, }, - { - onyxMethod: shouldDeleteIOUReport ? Onyx.METHOD.SET : Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, - value: iouReport, - }, + shouldDeleteIOUReport + ? { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style + value: iouReport as OnyxTypes.Report, + } + : { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style + value: iouReport as OnyxTypes.Report, + }, { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`, value: { - [reportPreviewAction.reportActionID]: reportPreviewAction, + [reportPreviewAction?.reportActionID ?? '']: reportPreviewAction, }, }, - ...(shouldDeleteIOUReport - ? [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, - value: chatReport, - }, - ] - : []), - ...(!shouldDeleteIOUReport && updatedReportPreviewAction.childMoneyRequestCount === 0 - ? [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, - value: { - hasOutstandingChildRequest: true, - }, - }, - ] - : []), - ]; + ); + + if (shouldDeleteIOUReport) { + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`, + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style + value: chatReport as OnyxTypes.Report, + }); + } + if (!shouldDeleteIOUReport && updatedReportPreviewAction?.childMoneyRequestCount === 0) { + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`, + value: { + hasOutstandingChildRequest: true, + }, + }); + } + + type DeleteMoneyRequestParams = { + transactionID: string; + reportActionID: string; + }; + + const parameters: DeleteMoneyRequestParams = { + transactionID, + reportActionID: reportAction.reportActionID, + }; // STEP 6: Make the API request - API.write( - 'DeleteMoneyRequest', - { - transactionID, - reportActionID: reportAction.reportActionID, - }, - {optimisticData, successData, failureData}, - ); + API.write('DeleteMoneyRequest', parameters, {optimisticData, successData, failureData}); // STEP 7: Navigate the user depending on which page they are on and which resources were deleted - if (isSingleTransactionView && shouldDeleteTransactionThread && !shouldDeleteIOUReport) { + if (iouReport && isSingleTransactionView && shouldDeleteTransactionThread && !shouldDeleteIOUReport) { // Pop the deleted report screen before navigating. This prevents navigating to the Concierge chat due to the missing report. Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(iouReport.reportID)); return; } - if (shouldDeleteIOUReport) { + if (iouReport?.chatReportID && shouldDeleteIOUReport) { // Pop the deleted report screen before navigating. This prevents navigating to the Concierge chat due to the missing report. Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(iouReport.chatReportID)); } @@ -2716,7 +2761,6 @@ function deleteMoneyRequest(transactionID, reportAction, isSingleTransactionView /** * @param managerID - Account ID of the person sending the money * @param recipient - The user receiving the money - * @returns {Object} */ function getSendMoneyParams( report: OnyxTypes.Report, @@ -2775,7 +2819,7 @@ function getSendMoneyParams( // 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 - let optimisticChatReportData: OnyxUpdate = isNewChat + const optimisticChatReportData: OnyxUpdate = isNewChat ? { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, @@ -2918,7 +2962,7 @@ function getSendMoneyParams( } const optimisticData: OnyxUpdate[] = [optimisticChatReportData, optimisticIOUReportData, optimisticChatReportActionsData, optimisticIOUReportActionsData, optimisticTransactionData]; - if (isNotEmptyObject(optimisticPersonalDetailListData)) { + if (!isEmptyObject(optimisticPersonalDetailListData)) { optimisticData.push(optimisticPersonalDetailListData); } From 992fdeaa0a9c8597f47257cd8de032e7be356145 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 8 Jan 2024 09:50:40 +0100 Subject: [PATCH 21/68] Migrate getPayMoneyRequestParams and payMoneyRequest functions --- src/libs/actions/IOU.ts | 66 +++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 43b6a06890a5..ef84843f6116 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -97,6 +97,20 @@ type UpdateMoneyRequestData = { onyxData: OnyxData; }; +type PayMoneyRequestParams = { + iouReportID: string; + chatReportID: string; + reportActionID: string; + paymentMethodType: PaymentMethodType; +}; + +type PayMoneyRequestData = { + params: PayMoneyRequestParams; + optimisticData: OnyxUpdate[]; + successData: OnyxUpdate[]; + failureData: OnyxUpdate[]; +}; + type PaymentMethodType = DeepValueOf; type SendMoneyParams = { @@ -2634,14 +2648,8 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor value: { hasOutstandingChildRequest: false, iouReportID: null, - lastMessageText: - iouReport && reportPreviewAction - ? ReportActionsUtils.getLastVisibleMessage(iouReport.chatReportID ?? '', {[reportPreviewAction.reportActionID]: null}).lastMessageText - : '', - lastVisibleActionCreated: - iouReport && reportPreviewAction - ? lodashGet(ReportActionsUtils.getLastVisibleAction(iouReport.chatReportID ?? '', {[reportPreviewAction.reportActionID]: null}), 'created') - : 'created', + lastMessageText: ReportActionsUtils.getLastVisibleMessage(iouReport?.chatReportID ?? '', {[reportPreviewAction?.reportActionID ?? '']: null}).lastMessageText, + lastVisibleActionCreated: lodashGet(ReportActionsUtils.getLastVisibleAction(iouReport?.chatReportID ?? '', {[reportPreviewAction?.reportActionID ?? '']: null}), 'created'), }, }); } @@ -2941,6 +2949,7 @@ function getSendMoneyParams( [recipientAccountID]: { accountID: recipientAccountID, avatar: UserUtils.getDefaultAvatarURL(recipient.accountID), + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing displayName: recipient.displayName || recipient.login, login: recipient.login, }, @@ -2983,18 +2992,11 @@ function getSendMoneyParams( }; } -/** - * @param {Object} chatReport - * @param {Object} iouReport - * @param {Object} recipient - * @param {String} paymentMethodType - * @returns {Object} - */ -function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMethodType) { +function getPayMoneyRequestParams(chatReport: OnyxTypes.Report, iouReport: OnyxTypes.Report, recipient: Participant, paymentMethodType: PaymentMethodType): PayMoneyRequestData { const optimisticIOUReportAction = ReportUtils.buildOptimisticIOUReportAction( CONST.IOU.REPORT_ACTION_TYPE.PAY, - -iouReport.total, - iouReport.currency, + -(iouReport.total ?? 0), + iouReport.currency ?? '', '', [recipient], '', @@ -3013,7 +3015,7 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho const currentNextStep = lodashGet(allNextSteps, `${ONYXKEYS.COLLECTION.NEXT_STEP}${iouReport.reportID}`, null); - const optimisticData = [ + const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, @@ -3023,8 +3025,8 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho lastVisibleActionCreated: optimisticIOUReportAction.created, hasOutstandingChildRequest: false, iouReportID: null, - lastMessageText: optimisticIOUReportAction.message[0].text, - lastMessageHtml: optimisticIOUReportAction.message[0].html, + lastMessageText: optimisticIOUReportAction.message?.[0].text, + lastMessageHtml: optimisticIOUReportAction.message?.[0].html, }, }, { @@ -3032,7 +3034,7 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`, value: { [optimisticIOUReportAction.reportActionID]: { - ...optimisticIOUReportAction, + ...(optimisticIOUReportAction as OnyxTypes.ReportAction), pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }, }, @@ -3042,8 +3044,8 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, value: { ...iouReport, - lastMessageText: optimisticIOUReportAction.message[0].text, - lastMessageHtml: optimisticIOUReportAction.message[0].html, + lastMessageText: optimisticIOUReportAction.message?.[0].text, + lastMessageHtml: optimisticIOUReportAction.message?.[0].html, hasOutstandingChildRequest: false, statusNum: CONST.REPORT.STATUS.REIMBURSED, }, @@ -3051,11 +3053,11 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.NVP_LAST_PAYMENT_METHOD, - value: {[iouReport.policyID]: paymentMethodType}, + value: {[iouReport.policyID ?? '']: paymentMethodType}, }, ]; - const successData = [ + const successData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`, @@ -3067,7 +3069,7 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho }, ]; - const failureData = [ + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`, @@ -3079,7 +3081,7 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho }, ]; - if (!_.isNull(currentNextStep)) { + if (currentNextStep !== null) { optimisticData.push({ onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${iouReport.reportID}`, @@ -3347,13 +3349,7 @@ function submitReport(expenseReport: OnyxTypes.Report) { API.write('SubmitReport', parameters, {optimisticData, successData, failureData}); } -/** - * @param {String} paymentType - * @param {Object} chatReport - * @param {Object} iouReport - * @param {String} reimbursementBankAccountState - */ -function payMoneyRequest(paymentType, chatReport, iouReport) { +function payMoneyRequest(paymentType: PaymentMethodType, chatReport: OnyxTypes.Report, iouReport: OnyxTypes.Report) { const recipient = {accountID: iouReport.ownerAccountID}; const {params, optimisticData, successData, failureData} = getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentType); From 6f658cddf5c177280578a08211e6f50dbe6b10b5 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 8 Jan 2024 10:09:10 +0100 Subject: [PATCH 22/68] Get rid of lodashGet and underscore usage --- src/libs/actions/IOU.ts | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index ef84843f6116..d7e4fb2cde07 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -2,14 +2,12 @@ import type {StackScreenProps} from '@react-navigation/stack'; import {format} from 'date-fns'; import Str from 'expensify-common/lib/str'; -import lodashGet from 'lodash/get'; import lodashHas from 'lodash/has'; import type {ImageSourcePropType} from 'react-native'; import Onyx from 'react-native-onyx'; import type {OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import OnyxUtils from 'react-native-onyx/lib/utils'; import type {ValueOf} from 'type-fest'; -import _ from 'underscore'; import ReceiptGeneric from '@assets/images/receipt-generic.png'; import * as API from '@libs/API'; import * as CurrencyUtils from '@libs/CurrencyUtils'; @@ -259,7 +257,7 @@ function startMoneyRequest_temporaryForRefactor(reportID: string, isFromGlobalCr amount: 0, comment, created, - currency: lodashGet(currentUserPersonalDetails, 'localCurrencyCode', CONST.CURRENCY.USD), + currency: currentUserPersonalDetails?.localCurrencyCode ?? CONST.CURRENCY.USD, iouRequestType, reportID, transactionID: newTransactionID, @@ -1054,7 +1052,7 @@ function getUpdateMoneyRequestParams( iouReport?.policyID, transactionChanges.tag, ) as OptimisticPolicyRecentlyUsedTags; - if (!_.isEmpty(optimisticPolicyRecentlyUsedTags)) { + if (!isEmptyObject(optimisticPolicyRecentlyUsedTags)) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${iouReport?.policyID}`, @@ -1439,9 +1437,9 @@ function createSplitsAndOnyxData( // STEP 2: Get existing IOU/Expense report and update its total OR build a new optimistic one // For Control policy expense chats, if the report is already approved, create a new expense report - let oneOnOneIOUReport = oneOnOneChatReport.iouReportID ? lodashGet(allReports, `${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`, undefined) : undefined; + let oneOnOneIOUReport = oneOnOneChatReport.iouReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`] ?? undefined : undefined; const shouldCreateNewOneOnOneIOUReport = - _.isUndefined(oneOnOneIOUReport) || (isOwnPolicyExpenseChat && ReportUtils.isControlPolicyExpenseReport(oneOnOneIOUReport) && ReportUtils.isReportApproved(oneOnOneIOUReport)); + oneOnOneIOUReport === undefined || (isOwnPolicyExpenseChat && ReportUtils.isControlPolicyExpenseReport(oneOnOneIOUReport) && ReportUtils.isReportApproved(oneOnOneIOUReport)); if (shouldCreateNewOneOnOneIOUReport) { oneOnOneIOUReport = isOwnPolicyExpenseChat @@ -1506,6 +1504,7 @@ function createSplitsAndOnyxData( [accountID]: { accountID, avatar: UserUtils.getDefaultAvatarURL(accountID), + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing displayName: LocalePhoneNumber.formatPhoneNumber(participant.displayName || email), login: participant.login, isOptimisticPersonalDetail: true, @@ -2072,9 +2071,9 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA oneOnOneChatReport = existingChatReport ?? ReportUtils.buildOptimisticChatReport(participant.accountID ? [participant.accountID] : []); } - let oneOnOneIOUReport = oneOnOneChatReport?.iouReportID ? lodashGet(allReports, `${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`, undefined) : undefined; + let oneOnOneIOUReport = oneOnOneChatReport?.iouReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`] ?? undefined : undefined; const shouldCreateNewOneOnOneIOUReport = - _.isUndefined(oneOnOneIOUReport) || (isPolicyExpenseChat && ReportUtils.isControlPolicyExpenseReport(oneOnOneIOUReport) && ReportUtils.isReportApproved(oneOnOneIOUReport)); + oneOnOneIOUReport === undefined || (isPolicyExpenseChat && ReportUtils.isControlPolicyExpenseReport(oneOnOneIOUReport) && ReportUtils.isReportApproved(oneOnOneIOUReport)); if (shouldCreateNewOneOnOneIOUReport) { oneOnOneIOUReport = isPolicyExpenseChat @@ -2547,7 +2546,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor } updatedIOUReport.lastMessageText = iouReportLastMessageText; - updatedIOUReport.lastVisibleActionCreated = lodashGet(lastVisibleAction, 'created'); + updatedIOUReport.lastVisibleActionCreated = lastVisibleAction?.created; updatedReportPreviewAction = reportPreviewAction ? {...reportPreviewAction} : null; const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(iouReport?.reportID); @@ -2648,8 +2647,8 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor value: { hasOutstandingChildRequest: false, iouReportID: null, - lastMessageText: ReportActionsUtils.getLastVisibleMessage(iouReport?.chatReportID ?? '', {[reportPreviewAction?.reportActionID ?? '']: null}).lastMessageText, - lastVisibleActionCreated: lodashGet(ReportActionsUtils.getLastVisibleAction(iouReport?.chatReportID ?? '', {[reportPreviewAction?.reportActionID ?? '']: null}), 'created'), + lastMessageText: ReportActionsUtils.getLastVisibleMessage(iouReport?.chatReportID ?? '', {[reportPreviewAction?.reportActionID ?? '']: null})?.lastMessageText, + lastVisibleActionCreated: ReportActionsUtils.getLastVisibleAction(iouReport?.chatReportID ?? '', {[reportPreviewAction?.reportActionID ?? '']: null})?.created, }, }); } @@ -3013,7 +3012,7 @@ function getPayMoneyRequestParams(chatReport: OnyxTypes.Report, iouReport: OnyxT optimisticReportPreviewAction = ReportUtils.updateReportPreview(iouReport, reportPreviewAction, true); } - const currentNextStep = lodashGet(allNextSteps, `${ONYXKEYS.COLLECTION.NEXT_STEP}${iouReport.reportID}`, null); + const currentNextStep = allNextSteps[`${ONYXKEYS.COLLECTION.NEXT_STEP}${iouReport.reportID}`] ?? null; const optimisticData: OnyxUpdate[] = [ { @@ -3256,8 +3255,8 @@ function submitReport(expenseReport: OnyxTypes.Report) { key: `${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`, value: { ...expenseReport, - lastMessageText: lodashGet(optimisticSubmittedReportAction, 'message.0.text', ''), - lastMessageHtml: lodashGet(optimisticSubmittedReportAction, 'message.0.html', ''), + lastMessageText: optimisticSubmittedReportAction.message?.[0].text ?? '', + lastMessageHtml: optimisticSubmittedReportAction.message?.[0].html ?? '', state: CONST.REPORT.STATE.SUBMITTED, stateNum: CONST.REPORT.STATE_NUM.PROCESSING, statusNum: CONST.REPORT.STATUS.SUBMITTED, From 4c7928b905cae9977b2dcb354cd01fe50d7673d8 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 8 Jan 2024 10:41:49 +0100 Subject: [PATCH 23/68] Fix TS errors --- src/components/OfflineWithFeedback.tsx | 2 +- src/libs/ErrorUtils.ts | 4 ++-- src/libs/Localize/index.ts | 2 +- src/libs/ReceiptUtils.ts | 2 +- src/libs/ReportActionsUtils.ts | 8 +++++--- src/libs/ReportUtils.ts | 4 ++-- src/libs/SidebarUtils.ts | 2 +- src/libs/ValidationUtils.ts | 2 +- 8 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/components/OfflineWithFeedback.tsx b/src/components/OfflineWithFeedback.tsx index fa0ae5162346..0446bd31025f 100644 --- a/src/components/OfflineWithFeedback.tsx +++ b/src/components/OfflineWithFeedback.tsx @@ -25,7 +25,7 @@ type OfflineWithFeedbackProps = ChildrenProps & { shouldHideOnDelete?: boolean; /** The errors to display */ - errors?: OnyxCommon.Errors | null; + errors?: OnyxCommon.SimpleErrors | null; /** Whether we should show the error messages */ shouldShowErrorMessages?: boolean; diff --git a/src/libs/ErrorUtils.ts b/src/libs/ErrorUtils.ts index cd2b04f27782..98b137502755 100644 --- a/src/libs/ErrorUtils.ts +++ b/src/libs/ErrorUtils.ts @@ -8,9 +8,9 @@ import * as Localize from './Localize'; type ErrorObject = Record; -type MicroSecondOnyxError = Record; +type MicroSecondOnyxError = Record; -type MicroSecondOnyxErrorObject = Record; +type MicroSecondOnyxErrorObject = Record; function getAuthenticateErrorMessage(response: Response): keyof TranslationFlatObject { switch (response.jsonCode) { diff --git a/src/libs/Localize/index.ts b/src/libs/Localize/index.ts index bc40f93dd13b..0cdbbc2e6e1f 100644 --- a/src/libs/Localize/index.ts +++ b/src/libs/Localize/index.ts @@ -97,7 +97,7 @@ function translateLocal(phrase: TKey, ...variable return translate(BaseLocaleListener.getPreferredLocale(), phrase, ...variables); } -type MaybePhraseKey = string | [string, Record & {isTranslated?: true}] | []; +type MaybePhraseKey = string | [string, Record & {isTranslated?: true}] | [] | null; /** * Return translated string for given error. diff --git a/src/libs/ReceiptUtils.ts b/src/libs/ReceiptUtils.ts index 734c40271208..091a3a89bc01 100644 --- a/src/libs/ReceiptUtils.ts +++ b/src/libs/ReceiptUtils.ts @@ -30,7 +30,7 @@ type FileNameAndExtension = { */ function getThumbnailAndImageURIs(transaction: Transaction, receiptPath: string | null = null, receiptFileName: string | null = null): ThumbnailAndImageURI { // URI to image, i.e. blob:new.expensify.com/9ef3a018-4067-47c6-b29f-5f1bd35f213d or expensify.com/receipts/w_e616108497ef940b7210ec6beb5a462d01a878f4.jpg - const path = transaction?.receipt?.source ?? receiptPath ?? ''; + const path = (transaction?.receipt?.source as string) ?? receiptPath ?? ''; // filename of uploaded image or last part of remote URI const filename = transaction?.filename ?? receiptFileName ?? ''; const isReceiptImage = Str.isImage(filename); diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index c8b7e673aed4..b6d60bbf726c 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -39,6 +39,8 @@ type MemberChangeMessageRoomReferenceElement = { type MemberChangeMessageElement = MessageTextElement | MemberChangeMessageUserMentionElement | MemberChangeMessageRoomReferenceElement; +type ActionsToMerge = Record; + const allReports: OnyxCollection = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT, @@ -432,9 +434,9 @@ function replaceBaseURL(reportAction: ReportAction): ReportAction { /** */ -function getLastVisibleAction(reportID: string, actionsToMerge: ReportActions = {}): OnyxEntry { +function getLastVisibleAction(reportID: string, actionsToMerge: ActionsToMerge = {}): OnyxEntry { const reportActions = Object.values(OnyxUtils.fastMerge(allReportActions?.[reportID] ?? {}, actionsToMerge)); - const visibleReportActions = Object.values(reportActions ?? {}).filter((action) => shouldReportActionBeVisibleAsLastAction(action)); + const visibleReportActions = Object.values(reportActions ?? {}).filter((action): action is ReportAction => shouldReportActionBeVisibleAsLastAction(action)); const sortedReportActions = getSortedReportActions(visibleReportActions, true); if (sortedReportActions.length === 0) { return null; @@ -442,7 +444,7 @@ function getLastVisibleAction(reportID: string, actionsToMerge: ReportActions = return sortedReportActions[0]; } -function getLastVisibleMessage(reportID: string, actionsToMerge: ReportActions = {}): LastVisibleMessage { +function getLastVisibleMessage(reportID: string, actionsToMerge: ActionsToMerge = {}): LastVisibleMessage { const lastVisibleAction = getLastVisibleAction(reportID, actionsToMerge); const message = lastVisibleAction?.message?.[0]; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index a4dadc25b469..ceae4f6603dc 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -16,7 +16,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Beta, Login, PersonalDetails, PersonalDetailsList, Policy, Report, ReportAction, ReportMetadata, Session, Transaction} from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; -import type {Errors, Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; +import type {Errors, Icon, PendingAction, SimpleErrors} from '@src/types/onyx/OnyxCommon'; import type {IOUMessage, OriginalMessageActionName, OriginalMessageCreated} from '@src/types/onyx/OriginalMessage'; import type {Status} from '@src/types/onyx/PersonalDetails'; import type {NotificationPreference} from '@src/types/onyx/Report'; @@ -289,7 +289,7 @@ type CustomIcon = { type OptionData = { text: string; alternateText?: string | null; - allReportErrors?: Errors | null; + allReportErrors?: SimpleErrors | null; brickRoadIndicator?: typeof CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR | '' | null; tooltipText?: string | null; alternateTextMaxLines?: number; diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index db16cf5cb552..3c49d8dd7aba 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -290,7 +290,7 @@ function getOptionData( result.isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report); result.shouldShowSubscript = ReportUtils.shouldReportShowSubscript(report); result.pendingAction = report.pendingFields ? report.pendingFields.addWorkspaceRoom || report.pendingFields.createChat : undefined; - result.allReportErrors = OptionsListUtils.getAllReportErrors(report, reportActions) as OnyxCommon.Errors; + result.allReportErrors = OptionsListUtils.getAllReportErrors(report, reportActions) as OnyxCommon.SimpleErrors; result.brickRoadIndicator = Object.keys(result.allReportErrors ?? {}).length !== 0 ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''; result.ownerAccountID = report.ownerAccountID; result.managerID = report.managerID; diff --git a/src/libs/ValidationUtils.ts b/src/libs/ValidationUtils.ts index 4b973d95d136..f7e725abb3a0 100644 --- a/src/libs/ValidationUtils.ts +++ b/src/libs/ValidationUtils.ts @@ -73,7 +73,7 @@ function isValidPastDate(date: string | Date): boolean { /** * Used to validate a value that is "required". */ -function isRequiredFulfilled(value: string | Date | unknown[] | Record): boolean { +function isRequiredFulfilled(value: string | Date | unknown[] | Record | null): boolean { if (typeof value === 'string') { return !StringUtils.isEmptyString(value); } From e60ebaad7428186dfc850248a55cc77f0a41f87e Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 8 Jan 2024 11:49:50 +0100 Subject: [PATCH 24/68] TS fixes after merging main --- src/ONYXKEYS.ts | 2 +- src/libs/ViolationsUtils.ts | 7 +-- src/libs/actions/IOU.ts | 87 ++++++++++--------------------------- src/types/onyx/Policy.ts | 6 +++ 4 files changed, 31 insertions(+), 71 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 0eadce1524bd..904e44feff5f 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -460,7 +460,7 @@ type OnyxValues = { [ONYXKEYS.COLLECTION.TRANSACTION]: OnyxTypes.Transaction; [ONYXKEYS.COLLECTION.TRANSACTION_DRAFT]: OnyxTypes.TransactionDraft; [ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT]: OnyxTypes.TransactionDraft; - [ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS]: OnyxTypes.TransactionViolation; + [ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS]: OnyxTypes.TransactionViolation[]; [ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS]: OnyxTypes.RecentlyUsedTags; [ONYXKEYS.COLLECTION.SELECTED_TAB]: string; [ONYXKEYS.COLLECTION.PRIVATE_NOTES_DRAFT]: string; diff --git a/src/libs/ViolationsUtils.ts b/src/libs/ViolationsUtils.ts index 2637686e726b..9b2b2c5f6dda 100644 --- a/src/libs/ViolationsUtils.ts +++ b/src/libs/ViolationsUtils.ts @@ -1,5 +1,6 @@ import reject from 'lodash/reject'; import Onyx from 'react-native-onyx'; +import type {OnyxUpdate} from 'react-native-onyx'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import type {PolicyCategories, PolicyTags, Transaction, TransactionViolation} from '@src/types/onyx'; @@ -17,11 +18,7 @@ const ViolationsUtils = { policyTags: PolicyTags, policyRequiresCategories: boolean, policyCategories: PolicyCategories, - ): { - onyxMethod: string; - key: string; - value: TransactionViolation[]; - } { + ): OnyxUpdate { let newTransactionViolations = [...transactionViolations]; if (policyRequiresCategories) { diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 101adfceed76..46c1f8cae17e 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -27,8 +27,8 @@ import * as ReportUtils from '@libs/ReportUtils'; import type {OptimisticChatReport, OptimisticCreatedReportAction, OptimisticIOUReportAction, TransactionDetails} from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import * as UserUtils from '@libs/UserUtils'; -import type {MoneyRequestNavigatorParamList} from '@navigation/types'; import ViolationsUtils from '@libs/ViolationsUtils'; +import type {MoneyRequestNavigatorParamList} from '@navigation/types'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -174,7 +174,7 @@ Onyx.connect({ }, }); -let allTransactionViolations: Record = {}; +let allTransactionViolations: Record = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, waitForCollectionCallback: true, @@ -352,27 +352,7 @@ function getReceiptError(receipt?: Receipt, filename?: string, isScanRequest = t : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: receipt.source, filename}); } -/** - * Builds the Onyx data for a money request. - * - * @param {Object} chatReport - * @param {Object} iouReport - * @param {Object} transaction - * @param {Object} chatCreatedAction - * @param {Object} iouCreatedAction - * @param {Object} iouAction - * @param {Object} optimisticPersonalDetailListAction - * @param {Object} reportPreviewAction - * @param {Array} optimisticPolicyRecentlyUsedCategories - * @param {Array} optimisticPolicyRecentlyUsedTags - * @param {boolean} isNewChatReport - * @param {boolean} isNewIOUReport - * @param {Object} policy - May be undefined, an empty object, or an object matching the Policy type (src/types/onyx/Policy.ts) - * @param {Array} policyTags - * @param {Array} policyCategories - * @param {Boolean} hasOutstandingChildRequest - * @returns {Array} - An array containing the optimistic data, success data, and failure data. - */ +/** Builds the Onyx data for a money request */ function buildOnyxDataForMoneyRequest( chatReport: OnyxTypes.Report, iouReport: OnyxTypes.Report, @@ -386,9 +366,9 @@ function buildOnyxDataForMoneyRequest( optimisticPolicyRecentlyUsedTags: OptimisticPolicyRecentlyUsedTags, isNewChatReport: boolean, isNewIOUReport: boolean, - policy, - policyTags, - policyCategories, + policy?: OnyxTypes.Policy | EmptyObject | undefined, + policyTags: OnyxTypes.PolicyTags = {}, + policyCategories: OnyxTypes.PolicyCategories = {}, hasOutstandingChildRequest = false, ): OnyxUpdate[][] { const isScanRequest = TransactionUtils.isScanRequest(transaction); @@ -644,18 +624,18 @@ function buildOnyxDataForMoneyRequest( ]; // Policy won't be set for P2P cases for which we don't need to compute violations - if (!policy || !policy.id) { + if (!policy?.id) { return [optimisticData, successData, failureData]; } - const violationsOnyxData = ViolationsUtils.getViolationsOnyxData(transaction, [], policy.requiresTag, policyTags, policy.requiresCategory, policyCategories); + const violationsOnyxData = ViolationsUtils.getViolationsOnyxData(transaction, [], !!policy.requiresTag, policyTags, !!policy.requiresCategory, policyCategories); if (violationsOnyxData) { optimisticData.push(violationsOnyxData); failureData.push({ onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction.transactionID}`, - value: [], + value: null, }); } @@ -681,9 +661,9 @@ function getMoneyRequestInformation( category?: string, tag?: string, billable?: boolean, - policy = undefined, - policyTags = undefined, - policyCategories = undefined, + policy?: OnyxTypes.Policy | EmptyObject, + policyTags?: OnyxTypes.PolicyTags, + policyCategories?: OnyxTypes.PolicyCategories, ): MoneyRequestInformation { const payerEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login ?? ''); const payerAccountID = Number(participant.accountID); @@ -717,10 +697,10 @@ function getMoneyRequestInformation( let needsToBeManuallySubmitted = false; let isFromPaidPolicy = false; if (isPolicyExpenseChat) { - isFromPaidPolicy = PolicyUtils.isPaidGroupPolicy(policy); + isFromPaidPolicy = PolicyUtils.isPaidGroupPolicy(policy ?? null); // If the scheduled submit is turned off on the policy, user needs to manually submit the report which is indicated by GBR in LHN - needsToBeManuallySubmitted = isFromPaidPolicy && !(policy.isHarvestingEnabled || false); + needsToBeManuallySubmitted = isFromPaidPolicy && !(!!policy?.isHarvestingEnabled || false); // If the linked expense report on paid policy is not draft, we need to create a new draft expense report if (iouReport && isFromPaidPolicy && !ReportUtils.isDraftExpenseReport(iouReport)) { @@ -876,24 +856,7 @@ function getMoneyRequestInformation( }; } -/** - * Requests money based on a distance (eg. mileage from a map) - * - * @param {Object} report - * @param {Object} participant - * @param {String} comment - * @param {String} created - * @param {String} [category] - * @param {String} [tag] - * @param {Number} amount - * @param {String} currency - * @param {String} merchant - * @param {Boolean} [billable] - * @param {Object} validWaypoints - * @param {Object} policy - May be undefined, an empty object, or an object matching the Policy type (src/types/onyx/Policy.ts) - * @param {Array} policyTags - * @param {Array} policyCategories - */ +/** Requests money based on a distance (eg. mileage from a map) */ function createDistanceRequest( report: OnyxTypes.Report, participant: Participant, @@ -906,9 +869,9 @@ function createDistanceRequest( merchant: string, billable: boolean | undefined, validWaypoints: WaypointCollection, - policy, - policyTags, - policyCategories + policy: OnyxTypes.Policy | EmptyObject | undefined, + policyTags: OnyxTypes.PolicyTags, + policyCategories: OnyxTypes.PolicyCategories, ) { // 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); @@ -1055,7 +1018,7 @@ function getUpdateMoneyRequestParams( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread?.reportID}`, value: { [updatedReportAction.reportActionID]: { - ...updatedReportAction, + ...(updatedReportAction as OnyxTypes.ReportAction), errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericEditFailureMessage'), }, }, @@ -1187,15 +1150,9 @@ function updateMoneyRequestDate(transactionID: string, transactionThreadReportID API.write('UpdateMoneyRequestDate', params, onyxData); } -/** - * Updates the created date of a money request - * - * @param {String} transactionID - * @param {Number} transactionThreadReportID - * @param {String} tag - */ -function updateMoneyRequestTag(transactionID, transactionThreadReportID, tag) { - const transactionChanges = { +/** Updates the created date of a money request */ +function updateMoneyRequestTag(transactionID: string, transactionThreadReportID: string, tag: string) { + const transactionChanges: TransactionChanges = { tag, }; const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true); diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index ff3a5e1dd23c..b71705a92192 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -82,6 +82,12 @@ type Policy = { /** The employee list of the policy */ employeeList?: []; + + /** Whether or not the policy requires tags */ + requiresTag?: boolean; + + /** Whether or not the policy requires categories */ + requiresCategory?: boolean; }; export default Policy; From 36420a7379571986475cab9510af6b6a1e593d9b Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 8 Jan 2024 11:57:41 +0100 Subject: [PATCH 25/68] Lint fixes --- src/components/TextInput/BaseTextInput/index.native.tsx | 2 ++ src/components/TextInput/BaseTextInput/index.tsx | 2 ++ src/libs/IOUUtils.ts | 1 - src/libs/ReportUtils.ts | 2 +- src/types/onyx/IOU.ts | 6 +++--- src/types/onyx/Transaction.ts | 4 ++-- 6 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/components/TextInput/BaseTextInput/index.native.tsx b/src/components/TextInput/BaseTextInput/index.native.tsx index f4cc1ee9e0ba..7d3c2d087914 100644 --- a/src/components/TextInput/BaseTextInput/index.native.tsx +++ b/src/components/TextInput/BaseTextInput/index.native.tsx @@ -247,6 +247,8 @@ function BaseTextInput( const hasLabel = Boolean(label?.length); const isReadOnly = inputProps.readOnly ?? inputProps.disabled; + // Disabling this line for safeness as nullish coalescing works only if the value is undefined or null + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const inputHelpText = errorText || hint; const placeholderValue = !!prefixCharacter || isFocused || !hasLabel || (hasLabel && forceActiveLabel) ? placeholder : undefined; const maxHeight = StyleSheet.flatten(containerStyles)?.maxHeight; diff --git a/src/components/TextInput/BaseTextInput/index.tsx b/src/components/TextInput/BaseTextInput/index.tsx index 9c3899979aaa..ad19948316ee 100644 --- a/src/components/TextInput/BaseTextInput/index.tsx +++ b/src/components/TextInput/BaseTextInput/index.tsx @@ -243,6 +243,8 @@ function BaseTextInput( const hasLabel = Boolean(label?.length); const isReadOnly = inputProps.readOnly ?? inputProps.disabled; + // Disabling this line for safeness as nullish coalescing works only if the value is undefined or null + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const inputHelpText = errorText || hint; const newPlaceholder = !!prefixCharacter || isFocused || !hasLabel || (hasLabel && forceActiveLabel) ? placeholder : undefined; const maxHeight = StyleSheet.flatten(containerStyles).maxHeight; diff --git a/src/libs/IOUUtils.ts b/src/libs/IOUUtils.ts index 8a6036ca95d8..19a9e558bf46 100644 --- a/src/libs/IOUUtils.ts +++ b/src/libs/IOUUtils.ts @@ -1,4 +1,3 @@ -import type {OnyxEntry} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index e04969f6e375..8e113634ba82 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -16,7 +16,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Beta, Login, PersonalDetails, PersonalDetailsList, Policy, Report, ReportAction, ReportMetadata, Session, Transaction} from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; -import type {Errors, Icon, PendingAction, SimpleErrors} from '@src/types/onyx/OnyxCommon'; +import type {Icon, PendingAction, SimpleErrors} from '@src/types/onyx/OnyxCommon'; import type {IOUMessage, OriginalMessageActionName, OriginalMessageCreated} from '@src/types/onyx/OriginalMessage'; import type {Status} from '@src/types/onyx/PersonalDetails'; import type {NotificationPreference} from '@src/types/onyx/Report'; diff --git a/src/types/onyx/IOU.ts b/src/types/onyx/IOU.ts index 4f9989d347a6..59709de4638e 100644 --- a/src/types/onyx/IOU.ts +++ b/src/types/onyx/IOU.ts @@ -1,6 +1,6 @@ -import {ValueOf} from 'type-fest'; -import CONST from '@src/CONST'; -import {Icon} from './OnyxCommon'; +import type {ValueOf} from 'type-fest'; +import type CONST from '@src/CONST'; +import type {Icon} from './OnyxCommon'; type Participant = { accountID?: number; diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 3875e70aff48..b093234368b5 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -1,7 +1,7 @@ -import {ImageSourcePropType} from 'react-native'; +import type {ImageSourcePropType} from 'react-native'; import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; -import {Participant} from './IOU'; +import type {Participant} from './IOU'; import type * as OnyxCommon from './OnyxCommon'; import type RecentWaypoint from './RecentWaypoint'; From d082cd428da7a711ca63fa64d6dfcbac4621562d Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 8 Jan 2024 15:35:17 +0100 Subject: [PATCH 26/68] Minor code improvements --- src/ONYXKEYS.ts | 2 +- src/libs/Localize/index.ts | 2 +- src/libs/actions/IOU.ts | 67 ++++++++++++-------------- src/types/onyx/TransactionViolation.ts | 4 +- src/types/onyx/index.ts | 3 +- 5 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 904e44feff5f..781f375385f6 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -460,7 +460,7 @@ type OnyxValues = { [ONYXKEYS.COLLECTION.TRANSACTION]: OnyxTypes.Transaction; [ONYXKEYS.COLLECTION.TRANSACTION_DRAFT]: OnyxTypes.TransactionDraft; [ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT]: OnyxTypes.TransactionDraft; - [ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS]: OnyxTypes.TransactionViolation[]; + [ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS]: OnyxTypes.TransactionViolations; [ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS]: OnyxTypes.RecentlyUsedTags; [ONYXKEYS.COLLECTION.SELECTED_TAB]: string; [ONYXKEYS.COLLECTION.PRIVATE_NOTES_DRAFT]: string; diff --git a/src/libs/Localize/index.ts b/src/libs/Localize/index.ts index 0cdbbc2e6e1f..bc40f93dd13b 100644 --- a/src/libs/Localize/index.ts +++ b/src/libs/Localize/index.ts @@ -97,7 +97,7 @@ function translateLocal(phrase: TKey, ...variable return translate(BaseLocaleListener.getPreferredLocale(), phrase, ...variables); } -type MaybePhraseKey = string | [string, Record & {isTranslated?: true}] | [] | null; +type MaybePhraseKey = string | [string, Record & {isTranslated?: true}] | []; /** * Return translated string for given error. diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 46c1f8cae17e..0ed7a47e2aa5 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import type {StackScreenProps} from '@react-navigation/stack'; import {format} from 'date-fns'; import Str from 'expensify-common/lib/str'; @@ -58,6 +57,8 @@ type MoneyRequestRoute = StackScreenProps< type IOURequestType = ValueOf; +type PaymentMethodType = DeepValueOf; + type MoneyRequestInformation = { payerAccountID: number; payerEmail: string; @@ -110,8 +111,6 @@ type PayMoneyRequestData = { failureData: OnyxUpdate[]; }; -type PaymentMethodType = DeepValueOf; - type SendMoneyParams = { iouReportID: string; chatReportID: string; @@ -174,7 +173,7 @@ Onyx.connect({ }, }); -let allTransactionViolations: Record = {}; +let allTransactionViolations: Record = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, waitForCollectionCallback: true, @@ -235,7 +234,7 @@ Onyx.connect({ /** * Initialize money request info * @param reportID to attach the transaction to - * @param [iouRequestType] one of manual/scan/distance + * @param iouRequestType one of manual/scan/distance */ function startMoneyRequest_temporaryForRefactor(reportID: string, isFromGlobalCreate: boolean, iouRequestType: IOURequestType = CONST.IOU.REQUEST_TYPE.MANUAL) { // Generate a brand new transactionID @@ -258,7 +257,7 @@ function startMoneyRequest_temporaryForRefactor(reportID: string, isFromGlobalCr amount: 0, comment, created, - currency: currentUserPersonalDetails?.localCurrencyCode ?? CONST.CURRENCY.USD, + currency: currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD, iouRequestType, reportID, transactionID: newTransactionID, @@ -328,7 +327,7 @@ function resetMoneyRequestInfo(id = '') { Onyx.merge(ONYXKEYS.IOU, { id, amount: 0, - currency: currentUserPersonalDetails?.localCurrencyCode ?? CONST.CURRENCY.USD, + currency: currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD, comment: '', participants: [], merchant: CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT, @@ -360,13 +359,13 @@ function buildOnyxDataForMoneyRequest( chatCreatedAction: OptimisticCreatedReportAction, iouCreatedAction: OptimisticCreatedReportAction, iouAction: OptimisticIOUReportAction, - optimisticPersonalDetailListAction: OnyxTypes.PersonalDetailsList | undefined, + optimisticPersonalDetailListAction: OnyxTypes.PersonalDetailsList, reportPreviewAction: ReportAction, optimisticPolicyRecentlyUsedCategories: OptimisticPolicyRecentlyUsedCategories, optimisticPolicyRecentlyUsedTags: OptimisticPolicyRecentlyUsedTags, isNewChatReport: boolean, isNewIOUReport: boolean, - policy?: OnyxTypes.Policy | EmptyObject | undefined, + policy?: OnyxTypes.Policy | EmptyObject, policyTags: OnyxTypes.PolicyTags = {}, policyCategories: OnyxTypes.PolicyCategories = {}, hasOutstandingChildRequest = false, @@ -711,7 +710,7 @@ function getMoneyRequestInformation( if (iouReport) { if (isPolicyExpenseChat) { iouReport = {...iouReport}; - if (iouReport?.currency === currency && iouReport.total) { + if (iouReport?.currency === currency && typeof iouReport.total === 'number') { // Because of the Expense reports are stored as negative values, we substract the total from the amount iouReport.total -= amount; } @@ -749,8 +748,10 @@ function getMoneyRequestInformation( billable, ); + // TODO: Remove this type once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, category) as OptimisticPolicyRecentlyUsedCategories; + // TODO: Remove this type once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport.policyID, tag) as OptimisticPolicyRecentlyUsedTags; // If there is an existing transaction (which is the case for distance requests), then the data from the existing transaction @@ -812,7 +813,7 @@ function getMoneyRequestInformation( isOptimisticPersonalDetail: true, }, } - : undefined; + : {}; // The policy expense chat should have the GBR only when its a paid policy and the scheduled submit is turned off // so the employee has to submit to their manager manually. @@ -959,14 +960,7 @@ function getUpdateMoneyRequestParams( // Step 1: Set any "pending fields" (ones updated while the user was offline) to have error messages in the failureData const pendingFields = Object.fromEntries(Object.keys(transactionChanges).map((key) => [key, CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE])); 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 errorFields = Object.fromEntries(Object.keys(pendingFields).map((key) => [key, {[DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.genericEditFailureMessage')}])); // Step 2: Get all the collections being updated const transactionThread = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; @@ -1066,7 +1060,8 @@ function getUpdateMoneyRequestParams( // Update recently used categories if the category is changed if ('category' in transactionChanges) { - const optimisticPolicyRecentlyUsedCategories: OptimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories( + // TODO: Remove assertion once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. + const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories( iouReport?.policyID, transactionChanges.category, ) as OptimisticPolicyRecentlyUsedCategories; @@ -1081,10 +1076,8 @@ function getUpdateMoneyRequestParams( // Update recently used categories if the tag is changed if ('tag' in transactionChanges) { - const optimisticPolicyRecentlyUsedTags: OptimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags( - iouReport?.policyID, - transactionChanges.tag, - ) as OptimisticPolicyRecentlyUsedTags; + // TODO: Remove assertion once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. + const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport?.policyID, transactionChanges.tag) as OptimisticPolicyRecentlyUsedTags; if (!isEmptyObject(optimisticPolicyRecentlyUsedTags)) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, @@ -1509,7 +1502,7 @@ function createSplitsAndOnyxData( ? ReportUtils.buildOptimisticExpenseReport(oneOnOneChatReport.reportID, oneOnOneChatReport.policyID ?? '', currentUserAccountID, splitAmount, currency) : ReportUtils.buildOptimisticIOUReport(currentUserAccountID, accountID, splitAmount, oneOnOneChatReport.reportID, currency); } else if (isOwnPolicyExpenseChat) { - if (oneOnOneIOUReport?.total) { + 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; } @@ -1562,7 +1555,7 @@ function createSplitsAndOnyxData( ); // Add optimistic personal details for new participants - const oneOnOnePersonalDetailListAction: OnyxTypes.PersonalDetailsList | undefined = shouldCreateOptimisticPersonalDetails + const oneOnOnePersonalDetailListAction: OnyxTypes.PersonalDetailsList = shouldCreateOptimisticPersonalDetails ? { [accountID]: { accountID, @@ -1573,7 +1566,7 @@ function createSplitsAndOnyxData( isOptimisticPersonalDetail: true, }, } - : undefined; + : {}; let oneOnOneReportPreviewAction = ReportActionsUtils.getReportPreviewAction(oneOnOneChatReport.reportID, oneOnOneIOUReport?.reportID ?? ''); if (oneOnOneReportPreviewAction) { @@ -1585,13 +1578,15 @@ function createSplitsAndOnyxData( } // Add category to optimistic policy recently used categories when a participant is a workspace - const optimisticPolicyRecentlyUsedCategories: OptimisticPolicyRecentlyUsedCategories = isPolicyExpenseChat - ? (Policy.buildOptimisticPolicyRecentlyUsedCategories(participant.policyID, category) as OptimisticPolicyRecentlyUsedCategories) + const optimisticPolicyRecentlyUsedCategories = isPolicyExpenseChat + ? // TODO: Remove assertion once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. + (Policy.buildOptimisticPolicyRecentlyUsedCategories(participant.policyID, category) as OptimisticPolicyRecentlyUsedCategories) : []; // Add tag to optimistic policy recently used tags when a participant is a workspace - const optimisticPolicyRecentlyUsedTags: OptimisticPolicyRecentlyUsedTags = isPolicyExpenseChat - ? (Policy.buildOptimisticPolicyRecentlyUsedTags(participant.policyID, tag) as OptimisticPolicyRecentlyUsedTags) + const optimisticPolicyRecentlyUsedTags = isPolicyExpenseChat + ? // TODO: Remove assertion once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. + (Policy.buildOptimisticPolicyRecentlyUsedTags(participant.policyID, tag) as OptimisticPolicyRecentlyUsedTags) : {}; // STEP 5: Build Onyx Data @@ -2143,7 +2138,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA ? ReportUtils.buildOptimisticExpenseReport(oneOnOneChatReport?.reportID ?? '', participant.policyID ?? '', sessionAccountID, splitAmount, currency ?? '') : ReportUtils.buildOptimisticIOUReport(sessionAccountID, participant.accountID ?? -1, splitAmount, oneOnOneChatReport?.reportID ?? '', currency ?? ''); } else if (isPolicyExpenseChat) { - if (oneOnOneIOUReport?.total) { + 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; } @@ -2291,7 +2286,7 @@ function editRegularMoneyRequest(transactionID: string, transactionThreadReportI const updatedChatReport = {...chatReport}; const diff = TransactionUtils.getAmount(transaction, true) - TransactionUtils.getAmount(updatedTransaction, true); if (updatedTransaction?.currency === iouReport?.currency && updatedTransaction?.modifiedAmount && diff !== 0) { - if (ReportUtils.isExpenseReport(iouReport) && updatedMoneyRequestReport.total) { + if (ReportUtils.isExpenseReport(iouReport) && typeof updatedMoneyRequestReport.total === 'number') { updatedMoneyRequestReport.total += diff; } else { updatedMoneyRequestReport = iouReport @@ -2315,7 +2310,7 @@ function editRegularMoneyRequest(transactionID: string, transactionThreadReportI updatedMoneyRequestReport.lastMessageHtml = lastMessage[0].html; // Update the last message of the chat report - const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(iouReport?.reportID); // There was an error before - wrong value was sent + const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(iouReport?.reportID); const messageText = Localize.translateLocal(hasNonReimbursableTransactions ? 'iou.payerSpentAmount' : 'iou.payerOwesAmount', { payer: ReportUtils.getPersonalDetailsForAccountID(updatedMoneyRequestReport.managerID ?? -1).login ?? '', amount: CurrencyUtils.convertToDisplayString(updatedMoneyRequestReport.total, updatedMoneyRequestReport.currency), @@ -2386,6 +2381,7 @@ function editRegularMoneyRequest(transactionID: string, transactionThreadReportI // Update recently used categories if the category is changed if ('category' in transactionChanges) { + // TODO: Remove assertion once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories( iouReport?.policyID, transactionChanges.category, @@ -2401,6 +2397,7 @@ function editRegularMoneyRequest(transactionID: string, transactionThreadReportI // Update recently used categories if the tag is changed if ('tag' in transactionChanges) { + // TODO: Remove assertion once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport?.policyID, transactionChanges.tag) as OptimisticPolicyRecentlyUsedTags; if (!isEmptyObject(optimisticPolicyRecentlyUsedTags)) { optimisticData.push({ @@ -2593,7 +2590,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor if (iouReport && ReportUtils.isExpenseReport(iouReport)) { updatedIOUReport = {...iouReport}; - if (updatedIOUReport.total) { + if (typeof updatedIOUReport.total === 'number') { // Because of the Expense reports are stored as negative values, we add the total from the amount updatedIOUReport.total += TransactionUtils.getAmount(transaction, true); } diff --git a/src/types/onyx/TransactionViolation.ts b/src/types/onyx/TransactionViolation.ts index dd7a9ef65746..6b5882cfc73d 100644 --- a/src/types/onyx/TransactionViolation.ts +++ b/src/types/onyx/TransactionViolation.ts @@ -31,4 +31,6 @@ type TransactionViolation = { }; }; -export type {TransactionViolation, ViolationName}; +type TransactionViolations = TransactionViolation[]; + +export type {TransactionViolation, TransactionViolations, ViolationName}; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 262312c563f7..b17dd5b7bafc 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -56,7 +56,7 @@ import type Session from './Session'; import type Task from './Task'; import type Transaction from './Transaction'; import type {TransactionDraft} from './Transaction'; -import type {TransactionViolation, ViolationName} from './TransactionViolation'; +import type {TransactionViolation, TransactionViolations, ViolationName} from './TransactionViolation'; import type User from './User'; import type UserLocation from './UserLocation'; import type UserWallet from './UserWallet'; @@ -127,6 +127,7 @@ export type { Transaction, TransactionDraft, TransactionViolation, + TransactionViolations, User, UserLocation, UserWallet, From a8a7d64203bc2bef070f5b9a6d4be5d8b40d6c1b Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 9 Jan 2024 09:16:27 +0100 Subject: [PATCH 27/68] TS updates after merging main --- src/libs/actions/IOU.ts | 42 +++++++++++------------------------------ 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 796fe99635d7..0b4f592ccf80 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/naming-convention */ import type {StackScreenProps} from '@react-navigation/stack'; import {format} from 'date-fns'; import Str from 'expensify-common/lib/str'; @@ -1143,55 +1144,34 @@ function updateMoneyRequestDate(transactionID: string, transactionThreadReportID API.write('UpdateMoneyRequestDate', params, onyxData); } -/** - * Updates the billable field of a money request - * - * @param {String} transactionID - * @param {Number} transactionThreadReportID - * @param {String} val - */ -function updateMoneyRequestBillable(transactionID, transactionThreadReportID, val) { - const transactionChanges = { +/** Updates the billable field of a money request */ +function updateMoneyRequestBillable(transactionID: string, transactionThreadReportID: string, val: boolean) { + const transactionChanges: TransactionChanges = { billable: val, }; const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true); API.write('UpdateMoneyRequestBillable', params, onyxData); } -/** - * Updates the merchant field of a money request - * - * @param {String} transactionID - * @param {Number} transactionThreadReportID - * @param {String} val - */ -function updateMoneyRequestMerchant(transactionID, transactionThreadReportID, val) { - const transactionChanges = { +/** Updates the merchant field of a money request */ +function updateMoneyRequestMerchant(transactionID: string, transactionThreadReportID: string, val: string) { + const transactionChanges: TransactionChanges = { merchant: val, }; const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true); API.write('UpdateMoneyRequestMerchant', params, onyxData); } -/** - * Updates the created date of a money request - * - * @param {String} transactionID - * @param {Number} transactionThreadReportID - * @param {String} tag - */ -function updateMoneyRequestTag(transactionID, transactionThreadReportID, tag) { - const transactionChanges = { +/** Updates the created date of a money request */ +function updateMoneyRequestTag(transactionID: string, transactionThreadReportID: string, tag: string) { + const transactionChanges: TransactionChanges = { tag, }; const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true); API.write('UpdateMoneyRequestTag', params, onyxData); } -/** - * Edits an existing distance request - * - */ +/** Edits an existing distance request */ function updateDistanceRequest(transactionID: string, transactionThreadReportID: string, transactionChanges: TransactionChanges) { const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, false); API.write('UpdateDistanceRequest', params, onyxData); From fb6a0ad03120b61a422cba0748a972b42335bbed Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 9 Jan 2024 10:34:17 +0100 Subject: [PATCH 28/68] Update updateIOUOwnerAndTotal function typing to get rid of assertions --- src/libs/IOUUtils.ts | 5 +++-- src/libs/actions/IOU.ts | 25 +++++++++++++------------ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/libs/IOUUtils.ts b/src/libs/IOUUtils.ts index 19a9e558bf46..095c715dfeae 100644 --- a/src/libs/IOUUtils.ts +++ b/src/libs/IOUUtils.ts @@ -1,3 +1,4 @@ +import type {OnyxEntry} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; @@ -73,13 +74,13 @@ function calculateAmount(numberOfParticipants: number, total: number, currency: * * @param isDeleting - whether the user is deleting the request */ -function updateIOUOwnerAndTotal(iouReport: Report, actorAccountID: number, amount: number, currency: string, isDeleting = false): Report { +function updateIOUOwnerAndTotal>(iouReport: TReport, actorAccountID: number, amount: number, currency: string, isDeleting = false): TReport { if (currency !== iouReport?.currency) { return iouReport; } // Make a copy so we don't mutate the original object - const iouReportUpdate: Report = {...iouReport}; + const iouReportUpdate = {...iouReport}; if (iouReportUpdate.total) { if (actorAccountID === iouReport.ownerAccountID) { diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 0b4f592ccf80..e75c8f000f79 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -60,6 +60,8 @@ type IOURequestType = ValueOf; type PaymentMethodType = DeepValueOf; +type OneOnOneIOUReport = OnyxTypes.Report | undefined | null; + type MoneyRequestInformation = { payerAccountID: number; payerEmail: string; @@ -1509,7 +1511,7 @@ function createSplitsAndOnyxData( // STEP 2: Get existing IOU/Expense report and update its total OR build a new optimistic one // For Control policy expense chats, if the report is already approved, create a new expense report - let oneOnOneIOUReport = oneOnOneChatReport.iouReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`] ?? undefined : undefined; + let oneOnOneIOUReport: OneOnOneIOUReport = oneOnOneChatReport.iouReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`] ?? undefined : undefined; const shouldCreateNewOneOnOneIOUReport = oneOnOneIOUReport === undefined || (isOwnPolicyExpenseChat && ReportUtils.isControlPolicyExpenseReport(oneOnOneIOUReport) && ReportUtils.isReportApproved(oneOnOneIOUReport)); @@ -1523,8 +1525,7 @@ function createSplitsAndOnyxData( oneOnOneIOUReport.total -= splitAmount; } } else { - // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style - oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(oneOnOneIOUReport as OnyxTypes.Report, currentUserAccountID, splitAmount, currency); + oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(oneOnOneIOUReport ?? null, currentUserAccountID, splitAmount, currency); } // STEP 3: Build optimistic transaction @@ -2145,7 +2146,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA oneOnOneChatReport = existingChatReport ?? ReportUtils.buildOptimisticChatReport(participant.accountID ? [participant.accountID] : []); } - let oneOnOneIOUReport = oneOnOneChatReport?.iouReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`] ?? undefined : undefined; + let oneOnOneIOUReport: OneOnOneIOUReport = oneOnOneChatReport?.iouReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`] ?? undefined : undefined; const shouldCreateNewOneOnOneIOUReport = oneOnOneIOUReport === undefined || (isPolicyExpenseChat && ReportUtils.isControlPolicyExpenseReport(oneOnOneIOUReport) && ReportUtils.isReportApproved(oneOnOneIOUReport)); @@ -2159,8 +2160,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA oneOnOneIOUReport.total -= splitAmount; } } else { - // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style - oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(oneOnOneIOUReport as OnyxTypes.Report, sessionAccountID, splitAmount, currency ?? ''); + oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(oneOnOneIOUReport ?? null, sessionAccountID, splitAmount, currency ?? ''); } const oneOnOneTransaction = TransactionUtils.buildOptimisticTransaction( @@ -2556,7 +2556,7 @@ function updateMoneyRequestAmountAndCurrency(transactionID: string, transactionT function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) { // STEP 1: Get all collections we're updating - const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${(reportAction.originalMessage as IOUMessage).IOUReportID}`]; + const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${(reportAction.originalMessage as IOUMessage).IOUReportID}`] ?? null; const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`]; const reportPreviewAction = ReportActionsUtils.getReportPreviewAction(iouReport?.chatReportID ?? '', iouReport?.reportID ?? ''); const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; @@ -2612,8 +2612,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor } } else { updatedIOUReport = IOUUtils.updateIOUOwnerAndTotal( - // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style - iouReport as OnyxTypes.Report, + iouReport, reportAction.actorAccountID ?? -1, TransactionUtils.getAmount(transaction, false), TransactionUtils.getCurrency(transaction), @@ -2621,14 +2620,16 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor ); } - updatedIOUReport.lastMessageText = iouReportLastMessageText; - updatedIOUReport.lastVisibleActionCreated = lastVisibleAction?.created; + if (updatedIOUReport) { + updatedIOUReport.lastMessageText = iouReportLastMessageText; + updatedIOUReport.lastVisibleActionCreated = lastVisibleAction?.created; + } updatedReportPreviewAction = reportPreviewAction ? {...reportPreviewAction} : null; const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(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), + amount: CurrencyUtils.convertToDisplayString(updatedIOUReport?.total, updatedIOUReport?.currency), }); if (updatedReportPreviewAction?.message?.[0]) { From 659f2363458fafcc744cf3b3bcbd471bcc03080b Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 9 Jan 2024 11:49:47 +0100 Subject: [PATCH 29/68] Get rid of nullable assertions in onyx update data --- src/libs/actions/IOU.ts | 74 +++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 43 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index e75c8f000f79..2b275037e7e0 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -35,7 +35,6 @@ import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; -import type {IOUMessage} from '@src/types/onyx/OriginalMessage'; import type ReportAction from '@src/types/onyx/ReportAction'; import type {OnyxData} from '@src/types/onyx/Request'; import type {Comment, Receipt, TaxRate, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; @@ -979,7 +978,7 @@ function getUpdateMoneyRequestParams( } const dataToIncludeInParams: Partial | undefined = onlyIncludeChangedFields - ? (Object.fromEntries(Object.entries(transactionDetails ?? {}).filter(([key]) => Object.keys(transactionChanges).includes(key))) as Partial) + ? Object.fromEntries(Object.entries(transactionDetails ?? {}).filter(([key]) => Object.keys(transactionChanges).includes(key))) : transactionDetails; const params: UpdateMoneyRequestParams = { @@ -1121,13 +1120,14 @@ function getUpdateMoneyRequestParams( }, }); - // Reset the iouReport to it's original state - failureData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, - // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style - value: iouReport as OnyxTypes.Report, - }); + if (iouReport) { + // Reset the iouReport to it's original state + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, + value: iouReport, + }); + } return { params, @@ -1515,7 +1515,7 @@ function createSplitsAndOnyxData( const shouldCreateNewOneOnOneIOUReport = oneOnOneIOUReport === undefined || (isOwnPolicyExpenseChat && ReportUtils.isControlPolicyExpenseReport(oneOnOneIOUReport) && ReportUtils.isReportApproved(oneOnOneIOUReport)); - if (shouldCreateNewOneOnOneIOUReport) { + if (oneOnOneIOUReport === undefined || shouldCreateNewOneOnOneIOUReport) { oneOnOneIOUReport = isOwnPolicyExpenseChat ? ReportUtils.buildOptimisticExpenseReport(oneOnOneChatReport.reportID, oneOnOneChatReport.policyID ?? '', currentUserAccountID, splitAmount, currency) : ReportUtils.buildOptimisticIOUReport(currentUserAccountID, accountID, splitAmount, oneOnOneChatReport.reportID, currency); @@ -1530,8 +1530,7 @@ function createSplitsAndOnyxData( // STEP 3: Build optimistic transaction const oneOnOneTransaction = TransactionUtils.buildOptimisticTransaction( - // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style - ReportUtils.isExpenseReport(oneOnOneIOUReport as OnyxTypes.Report) ? -splitAmount : splitAmount, + ReportUtils.isExpenseReport(oneOnOneIOUReport ?? null) ? -splitAmount : splitAmount, currency, oneOnOneIOUReport?.reportID ?? '', comment, @@ -1587,11 +1586,9 @@ function createSplitsAndOnyxData( let oneOnOneReportPreviewAction = ReportActionsUtils.getReportPreviewAction(oneOnOneChatReport.reportID, oneOnOneIOUReport?.reportID ?? ''); if (oneOnOneReportPreviewAction) { - // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style - oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport as OnyxTypes.Report, oneOnOneReportPreviewAction); + oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction); } else { - // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style - oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport as OnyxTypes.Report); + oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport); } // Add category to optimistic policy recently used categories when a participant is a workspace @@ -1609,8 +1606,7 @@ function createSplitsAndOnyxData( // STEP 5: Build Onyx Data const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest( oneOnOneChatReport, - // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style - oneOnOneIOUReport as OnyxTypes.Report, + oneOnOneIOUReport, oneOnOneTransaction, oneOnOneCreatedActionForChat, oneOnOneCreatedActionForIOU, @@ -2150,7 +2146,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA const shouldCreateNewOneOnOneIOUReport = oneOnOneIOUReport === undefined || (isPolicyExpenseChat && ReportUtils.isControlPolicyExpenseReport(oneOnOneIOUReport) && ReportUtils.isReportApproved(oneOnOneIOUReport)); - if (shouldCreateNewOneOnOneIOUReport) { + if (oneOnOneIOUReport === undefined || shouldCreateNewOneOnOneIOUReport) { oneOnOneIOUReport = isPolicyExpenseChat ? ReportUtils.buildOptimisticExpenseReport(oneOnOneChatReport?.reportID ?? '', participant.policyID ?? '', sessionAccountID, splitAmount, currency ?? '') : ReportUtils.buildOptimisticIOUReport(sessionAccountID, participant.accountID ?? -1, splitAmount, oneOnOneChatReport?.reportID ?? '', currency ?? ''); @@ -2199,8 +2195,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest( // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style oneOnOneChatReport as OnyxTypes.Report, - // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style - oneOnOneIOUReport as OnyxTypes.Report, + oneOnOneIOUReport, oneOnOneTransaction, oneOnOneCreatedActionForChat, oneOnOneCreatedActionForIOU, @@ -2489,8 +2484,7 @@ function editRegularMoneyRequest(transactionID: string, transactionThreadReportI { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`, - // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style - value: chatReport as OnyxTypes.Report, + value: chatReport ?? {}, }, { onyxMethod: Onyx.METHOD.MERGE, @@ -2556,7 +2550,8 @@ function updateMoneyRequestAmountAndCurrency(transactionID: string, transactionT function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) { // STEP 1: Get all collections we're updating - const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${(reportAction.originalMessage as IOUMessage).IOUReportID}`] ?? null; + const iouReportID = reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? reportAction.originalMessage.IOUReportID : ''; + const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReportID}`] ?? null; const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`]; const reportPreviewAction = ReportActionsUtils.getReportPreviewAction(iouReport?.chatReportID ?? '', iouReport?.reportID ?? ''); const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; @@ -2564,7 +2559,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor const transactionThreadID = reportAction.childReportID; let transactionThread = null; if (transactionThreadID) { - transactionThread = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`]; + transactionThread = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`] ?? null; } // STEP 2: Decide if we need to: @@ -2689,14 +2684,12 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor ? { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, - // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style - value: updatedIOUReport as OnyxTypes.Report, + value: updatedIOUReport, } : { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, - // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style - value: updatedIOUReport as OnyxTypes.Report, + value: updatedIOUReport ?? {}, }, { onyxMethod: Onyx.METHOD.MERGE, @@ -2760,8 +2753,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor failureData.push({ onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`, - // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style - value: transactionThread as OnyxTypes.Report, + value: transactionThread, }); } @@ -2780,14 +2772,12 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor ? { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, - // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style - value: iouReport as OnyxTypes.Report, + value: iouReport, } : { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, - // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style - value: iouReport as OnyxTypes.Report, + value: iouReport ?? {}, }, { onyxMethod: Onyx.METHOD.MERGE, @@ -2801,12 +2791,11 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor }, ); - if (shouldDeleteIOUReport) { + if (chatReport && shouldDeleteIOUReport) { failureData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`, - // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style - value: chatReport as OnyxTypes.Report, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, + value: chatReport, }); } if (!shouldDeleteIOUReport && updatedReportPreviewAction?.childMoneyRequestCount === 0) { @@ -3441,9 +3430,8 @@ function payMoneyRequest(paymentType: PaymentMethodType, chatReport: OnyxTypes.R } function detachReceipt(transactionID: string) { - // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style - const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] as OnyxTypes.Transaction; - const newTransaction = {...transaction, filename: '', receipt: {}}; + const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; + const newTransaction = transaction ? {...transaction, filename: '', receipt: {}} : null; const optimisticData: OnyxUpdate[] = [ { @@ -3457,7 +3445,7 @@ function detachReceipt(transactionID: string) { { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, - value: transaction, + value: transaction ?? {}, }, ]; From 5944ec61bb590aa627cfc19c8ccc925fb5756b79 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 9 Jan 2024 12:24:27 +0100 Subject: [PATCH 30/68] Remove assertions, update buildOnyxDataForMoneyRequest typing --- src/ONYXKEYS.ts | 2 +- src/libs/actions/IOU.ts | 45 ++++++++++++++++++++++------------------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 781f375385f6..7b3d56ad7485 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -459,7 +459,7 @@ type OnyxValues = { [ONYXKEYS.COLLECTION.SECURITY_GROUP]: OnyxTypes.SecurityGroup; [ONYXKEYS.COLLECTION.TRANSACTION]: OnyxTypes.Transaction; [ONYXKEYS.COLLECTION.TRANSACTION_DRAFT]: OnyxTypes.TransactionDraft; - [ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT]: OnyxTypes.TransactionDraft; + [ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT]: OnyxTypes.Transaction; [ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS]: OnyxTypes.TransactionViolations; [ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS]: OnyxTypes.RecentlyUsedTags; [ONYXKEYS.COLLECTION.SELECTED_TAB]: string; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 2b275037e7e0..759311568604 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -189,7 +189,7 @@ Onyx.connect({ }, }); -let allDraftSplitTransactions: Record = {}; +let allDraftSplitTransactions: Record = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT, waitForCollectionCallback: true, @@ -355,7 +355,7 @@ function getReceiptError(receipt?: Receipt, filename?: string, isScanRequest = t /** Builds the Onyx data for a money request */ function buildOnyxDataForMoneyRequest( - chatReport: OnyxTypes.Report, + chatReport: OnyxEntry, iouReport: OnyxTypes.Report, transaction: OnyxTypes.Transaction, chatCreatedAction: OptimisticCreatedReportAction, @@ -373,8 +373,10 @@ function buildOnyxDataForMoneyRequest( hasOutstandingChildRequest = false, ): OnyxUpdate[][] { const isScanRequest = TransactionUtils.isScanRequest(transaction); - const optimisticData: OnyxUpdate[] = [ - { + const optimisticData: OnyxUpdate[] = []; + + if (chatReport) { + optimisticData.push({ // Use 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 onyxMethod: isNewChatReport ? Onyx.METHOD.SET : Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, @@ -386,7 +388,10 @@ function buildOnyxDataForMoneyRequest( hasOutstandingChildRequest, ...(isNewChatReport ? {pendingFields: {createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}} : {}), }, - }, + }); + } + + optimisticData.push( { onyxMethod: isNewIOUReport ? Onyx.METHOD.SET : Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, @@ -407,7 +412,7 @@ function buildOnyxDataForMoneyRequest( isNewChatReport ? { onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`, value: { [chatCreatedAction.reportActionID]: chatCreatedAction, [reportPreviewAction.reportActionID]: reportPreviewAction, @@ -415,7 +420,7 @@ function buildOnyxDataForMoneyRequest( } : { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`, value: { [reportPreviewAction.reportActionID]: reportPreviewAction, }, @@ -443,7 +448,7 @@ function buildOnyxDataForMoneyRequest( key: `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`, value: null, }, - ]; + ); if (optimisticPolicyRecentlyUsedCategories.length) { optimisticData.push({ @@ -474,7 +479,7 @@ function buildOnyxDataForMoneyRequest( if (isNewChatReport) { successData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`, value: { pendingFields: null, errorFields: null, @@ -502,7 +507,7 @@ function buildOnyxDataForMoneyRequest( { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`, value: { ...(isNewChatReport ? { @@ -540,10 +545,10 @@ function buildOnyxDataForMoneyRequest( const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`, value: { - iouReportID: chatReport.iouReportID, - lastReadTime: chatReport.lastReadTime, + iouReportID: chatReport?.iouReportID, + lastReadTime: chatReport?.lastReadTime, pendingFields: null, ...(isNewChatReport ? { @@ -583,7 +588,7 @@ function buildOnyxDataForMoneyRequest( { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`, value: { ...(isNewChatReport ? { @@ -2193,8 +2198,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA } const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest( - // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style - oneOnOneChatReport as OnyxTypes.Report, + oneOnOneChatReport, oneOnOneIOUReport, oneOnOneTransaction, oneOnOneCreatedActionForChat, @@ -2272,9 +2276,9 @@ function setDraftSplitTransaction(transactionID: string, transactionChanges: Tra draftSplitTransaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; } - const updatedTransaction = TransactionUtils.getUpdatedTransaction(draftSplitTransaction as OnyxTypes.Transaction, transactionChanges, false, false); + const updatedTransaction = draftSplitTransaction ? TransactionUtils.getUpdatedTransaction(draftSplitTransaction, transactionChanges, false, false) : null; - Onyx.merge(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`, updatedTransaction); + Onyx.merge(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`, updatedTransaction ?? {}); } function editRegularMoneyRequest(transactionID: string, transactionThreadReportID: string, transactionChanges: TransactionChanges) { @@ -2287,8 +2291,7 @@ function editRegularMoneyRequest(transactionID: string, transactionThreadReportI // STEP 2: Build new modified expense report action. const updatedReportAction = ReportUtils.buildOptimisticModifiedExpenseReportAction(transactionThread, transaction, transactionChanges, isFromExpenseReport); - // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style - const updatedTransaction = TransactionUtils.getUpdatedTransaction(transaction as OnyxTypes.Transaction, transactionChanges, isFromExpenseReport); + const updatedTransaction = transaction ? TransactionUtils.getUpdatedTransaction(transaction, transactionChanges, isFromExpenseReport) : null; // STEP 3: Compute the IOU total and update the report preview message so LHN amount owed is correct // Should only update if the transaction matches the currency of the report, else we wait for the update @@ -2345,7 +2348,7 @@ function editRegularMoneyRequest(transactionID: string, transactionThreadReportI { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, - value: updatedTransaction, + value: updatedTransaction ?? {}, }, { onyxMethod: Onyx.METHOD.MERGE, From c51b798f25019ddfb8e8a0bf95a59a2c303202a3 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 9 Jan 2024 14:52:33 +0100 Subject: [PATCH 31/68] Add Split type --- src/libs/actions/IOU.ts | 12 ++++++------ src/types/onyx/IOU.ts | 31 ++++++++++++++----------------- src/types/onyx/Transaction.ts | 4 ++-- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 759311568604..feb27d7987cd 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -34,7 +34,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; -import type {Participant} from '@src/types/onyx/IOU'; +import type {Participant, Split} from '@src/types/onyx/IOU'; import type ReportAction from '@src/types/onyx/ReportAction'; import type {OnyxData} from '@src/types/onyx/Request'; import type {Comment, Receipt, TaxRate, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; @@ -84,7 +84,7 @@ type SplitData = { type SplitsAndOnyxData = { splitData: SplitData; - splits: Participant[]; + splits: Split[]; onyxData: OnyxData; }; @@ -1477,7 +1477,7 @@ function createSplitsAndOnyxData( // Loop through participants creating individual chats, iouReports and reportActionIDs as needed const splitAmount = IOUUtils.calculateAmount(participants.length, amount, currency, false); - const splits: Participant[] = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID, amount: IOUUtils.calculateAmount(participants.length, amount, currency, true)}]; + const splits: Split[] = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID, amount: IOUUtils.calculateAmount(participants.length, amount, currency, true)}]; const hasMultipleParticipants = participants.length > 1; participants.forEach((participant) => { @@ -1950,7 +1950,7 @@ function startSplitBill( ); } - const splits: Participant[] = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID}]; + const splits: Split[] = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID}]; participants.forEach((participant) => { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing @@ -2109,13 +2109,13 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA }, ]; - const splitParticipants = updatedTransaction.comment.splits ?? []; + const splitParticipants: Split[] = updatedTransaction.comment.splits ?? []; const {modifiedAmount: amount, modifiedCurrency: currency} = updatedTransaction; // 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 splits: Participant[] = [{email: currentUserEmailForIOUSplit}]; + const splits: Split[] = [{email: currentUserEmailForIOUSplit}]; splitParticipants.forEach((participant) => { // Skip creating the transaction for the current user if (participant.email === currentUserEmailForIOUSplit) { diff --git a/src/types/onyx/IOU.ts b/src/types/onyx/IOU.ts index 59709de4638e..9aa4a024a3c4 100644 --- a/src/types/onyx/IOU.ts +++ b/src/types/onyx/IOU.ts @@ -1,31 +1,28 @@ import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; -import type {Icon} from './OnyxCommon'; type Participant = { accountID?: number; login?: string; - email?: string; + displayName?: string; isPolicyExpenseChat?: boolean; - chatReportID?: string; - iouReportID?: string; - transactionID?: string; - reportActionID?: string; isOwnPolicyExpenseChat?: boolean; chatType?: ValueOf; - amount?: number; - selected?: boolean; reportID?: string; policyID?: string; - displayName?: string; - alternateText?: string; - firstName?: string; - icons?: Icon[]; - keyForList?: string; - lastName?: string; - phoneNumber?: string; - searchText?: string; + selected?: boolean; text?: string; +}; + +type Split = { + email?: string; + amount?: number; + accountID?: number; + chatReportID?: string; + iouReportID?: string; + reportActionID?: string; + transactionID?: string; + policyID?: string; createdChatReportActionID?: string; createdIOUReportActionID?: string; reportPreviewReportActionID?: string; @@ -50,4 +47,4 @@ type IOU = { }; export default IOU; -export type {Participant}; +export type {Participant, Split}; diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index b093234368b5..3498fa375c67 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -1,7 +1,7 @@ import type {ImageSourcePropType} from 'react-native'; import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; -import type {Participant} from './IOU'; +import type {Participant, Split} from './IOU'; import type * as OnyxCommon from './OnyxCommon'; import type RecentWaypoint from './RecentWaypoint'; @@ -29,7 +29,7 @@ type Comment = { customUnit?: Record; source?: string; originalTransactionID?: string; - splits?: Participant[]; + splits?: Split[]; }; type GeometryType = 'LineString'; From a1eeacd9f9ccf6c45ae871fd102b76d59fb08f65 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 9 Jan 2024 15:17:02 +0100 Subject: [PATCH 32/68] Add type params comments --- src/types/onyx/ReportAction.ts | 1 + src/types/onyx/Transaction.ts | 86 ++++++++++++++++++++++++++++++---- 2 files changed, 77 insertions(+), 10 deletions(-) diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts index 19ab889b1801..47945ffba4bb 100644 --- a/src/types/onyx/ReportAction.ts +++ b/src/types/onyx/ReportAction.ts @@ -140,6 +140,7 @@ type ReportActionBase = { /** Type of child report */ childType?: string; + /** The user's ID */ accountID?: number; childOldestFourEmails?: string; diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 3498fa375c67..7c40118207a0 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -71,61 +71,127 @@ type TaxRate = { }; type Transaction = { + /** The original transaction amount */ amount: number; + + /** Whether the request is billable */ billable: boolean; + + /** The category name */ category: string; + + /** The comment object on the transaction */ comment: Comment; + + /** Date that the request was created */ created: string; + + /** The original currency of the transaction */ currency: string; + + /** Any additional error message to show */ errors?: OnyxCommon.Errors; + + /** Server side errors keyed by microtime */ errorFields?: OnyxCommon.ErrorFields<'route'>; - // The name of the file used for a receipt (formerly receiptFilename) + + /** The name of the file used for a receipt (formerly receiptFilename) */ filename?: string; - // Used during the creation flow before the transaction is saved to the server + + /** Used during the creation flow before the transaction is saved to the server */ iouRequestType?: ValueOf; + + /** The original merchant name */ merchant: string; + + /** The edited transaction amount */ modifiedAmount?: number; + + /** The edited transaction date */ modifiedCreated?: string; + + /** The edited currency of the transaction */ modifiedCurrency?: string; + + /** The edited merchant name */ modifiedMerchant?: string; + + /** The edited waypoints for the distance request */ modifiedWaypoints?: WaypointCollection; - // Used during the creation flow before the transaction is saved to the server and helps dictate where the user is navigated to when pressing the back button on the confirmation step + + /** + * Used during the creation flow before the transaction is saved to the server and helps dictate where + * the user is navigated to when pressing the back button on the confirmation step + */ participantsAutoAssigned?: boolean; + + /** Selected participants */ participants?: Participant[]; + + /** The type of action that's pending */ pendingAction: OnyxCommon.PendingAction; + + /** The receipt object associated with the transaction */ receipt?: Receipt; + + /** The iouReportID associated with the transaction */ reportID: string; + + /** Existing routes */ routes?: Routes; + + /** The transaction id */ transactionID: string; + + /** The transaction tag */ tag: string; + + /** Whether the transaction was created globally */ + isFromGlobalCreate?: boolean; + + /** The transaction tax rate */ + taxRate?: TaxRate; + + /** Tax amount */ + taxAmount?: number; + + /** Pending fields for the transaction */ pendingFields?: Partial<{[K in keyof Transaction | keyof Comment]: ValueOf}>; /** Card Transactions */ + /** The parent transaction id */ parentTransactionID?: string; + + /** Whether the expense is reimbursable or not */ reimbursable?: boolean; + /** The CC for this transaction */ cardID?: number; + /** If the transaction is pending or posted */ status?: ValueOf; + /** If an EReceipt should be generated for this transaction */ hasEReceipt?: boolean; + /** The MCC Group for this transaction */ mccGroup?: ValueOf; + + /** Modified MCC Group */ modifiedMCCGroup?: ValueOf; + /** If the transaction was made in a foreign currency, we send the original amount and currency */ originalAmount?: number; + + /** The original currency of the transaction */ originalCurrency?: string; + + /** Indicates transaction loading */ isLoading?: boolean; }; -type TransactionDraft = Partial & { - isFromGlobalCreate?: boolean; - taxRate?: TaxRate; - - /** Calculated tax amount based on selected tax rate */ - taxAmount?: number; -}; +type TransactionDraft = Partial; type AdditionalTransactionChanges = { comment?: string; From 992e61d8d25492c531fe58ac3b187470661479c1 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 9 Jan 2024 15:50:54 +0100 Subject: [PATCH 33/68] ReportUtils file updates --- src/libs/ReportUtils.ts | 27 +++++++-------------------- src/libs/actions/IOU.ts | 6 +++--- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 7f1cdb3d2893..2a1cbfc21550 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -400,7 +400,7 @@ Onyx.connect({ }, }); -function getChatType(report: OnyxEntry | Participant | EmptyObject): ValueOf | undefined { +function getChatType(report: OnyxEntry | Participant): ValueOf | undefined { return report?.chatType; } @@ -673,7 +673,7 @@ function isUserCreatedPolicyRoom(report: OnyxEntry): boolean { /** * Whether the provided report is a Policy Expense chat. */ -function isPolicyExpenseChat(report: OnyxEntry | Participant | EmptyObject): boolean { +function isPolicyExpenseChat(report: OnyxEntry | Participant): boolean { return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT || (report?.isPolicyExpenseChat ?? false); } @@ -2670,7 +2670,7 @@ function buildOptimisticIOUReportAction( comment: string, participants: Participant[], transactionID: string, - paymentType: DeepValueOf | undefined, + paymentType?: DeepValueOf, iouReportID = '', isSettlingUp = false, isSendMoneyFlow = false, @@ -2858,13 +2858,7 @@ function buildOptimisticSubmittedReportAction(amount: number, currency: string, * @param [comment] - User comment for the IOU. * @param [transaction] - optimistic first transaction of preview */ -function buildOptimisticReportPreview( - chatReport: OnyxEntry, - iouReport: OnyxEntry, - comment = '', - transaction: OnyxEntry = null, - childReportID?: string, -): ReportAction { +function buildOptimisticReportPreview(chatReport: OnyxEntry, iouReport: Report, comment = '', transaction: OnyxEntry = null, childReportID?: string): ReportAction { const hasReceipt = TransactionUtils.hasReceipt(transaction); const isReceiptBeingScanned = hasReceipt && TransactionUtils.isReceiptBeingScanned(transaction); const message = getReportPreviewMessage(iouReport); @@ -2875,7 +2869,7 @@ function buildOptimisticReportPreview( actionName: CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, originalMessage: { - linkedReportID: iouReport?.reportID ?? '', + linkedReportID: iouReport?.reportID, }, message: [ { @@ -2944,13 +2938,7 @@ function buildOptimisticModifiedExpenseReportAction( * @param [transaction] - optimistic newest transaction of a report preview * */ -function updateReportPreview( - iouReport: OnyxEntry, - reportPreviewAction: OnyxEntry, - isPayRequest = false, - comment = '', - transaction: OnyxEntry = null, -): ReportAction { +function updateReportPreview(iouReport: OnyxEntry, reportPreviewAction: ReportAction, isPayRequest = false, comment = '', transaction: OnyxEntry = null): ReportAction { const hasReceipt = TransactionUtils.hasReceipt(transaction); const recentReceiptTransactions = reportPreviewAction?.childRecentReceiptTransactionIDs ?? {}; const transactionsToKeep = TransactionUtils.getRecentTransactions(recentReceiptTransactions); @@ -2967,8 +2955,7 @@ function updateReportPreview( const message = getReportPreviewMessage(iouReport, reportPreviewAction); return { - // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style - ...(reportPreviewAction as ReportAction), + ...reportPreviewAction, created: DateUtils.getDBTime(), message: [ { diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index feb27d7987cd..69a919185296 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -2161,7 +2161,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA oneOnOneIOUReport.total -= splitAmount; } } else { - oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(oneOnOneIOUReport ?? null, sessionAccountID, splitAmount, currency ?? ''); + oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(oneOnOneIOUReport, sessionAccountID, splitAmount, currency ?? ''); } const oneOnOneTransaction = TransactionUtils.buildOptimisticTransaction( @@ -2192,9 +2192,9 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA let oneOnOneReportPreviewAction = ReportActionsUtils.getReportPreviewAction(oneOnOneChatReport?.reportID ?? '', oneOnOneIOUReport?.reportID ?? ''); if (oneOnOneReportPreviewAction) { - oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport ?? null, oneOnOneReportPreviewAction); + oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction); } else { - oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport ?? null, '', oneOnOneTransaction); + oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport, '', oneOnOneTransaction); } const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest( From a488df6475ba7d4deb506138e2d3a3883b0bd297 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 9 Jan 2024 16:36:58 +0100 Subject: [PATCH 34/68] Update receipt source type --- src/libs/ErrorUtils.ts | 3 +-- src/libs/ReceiptUtils.ts | 2 +- src/libs/actions/IOU.ts | 7 +++---- src/types/onyx/Transaction.ts | 3 +-- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/libs/ErrorUtils.ts b/src/libs/ErrorUtils.ts index 98b137502755..d38a05dc5a5c 100644 --- a/src/libs/ErrorUtils.ts +++ b/src/libs/ErrorUtils.ts @@ -1,4 +1,3 @@ -import type {ImageSourcePropType} from 'react-native'; import CONST from '@src/CONST'; import type {TranslationFlatObject, TranslationPaths} from '@src/languages/types'; import type {ErrorFields, SimpleErrors} from '@src/types/onyx/OnyxCommon'; @@ -6,7 +5,7 @@ import type Response from '@src/types/onyx/Response'; import DateUtils from './DateUtils'; import * as Localize from './Localize'; -type ErrorObject = Record; +type ErrorObject = Record; type MicroSecondOnyxError = Record; diff --git a/src/libs/ReceiptUtils.ts b/src/libs/ReceiptUtils.ts index 70e7a72f6b5c..bcba68a3a0bd 100644 --- a/src/libs/ReceiptUtils.ts +++ b/src/libs/ReceiptUtils.ts @@ -30,7 +30,7 @@ type FileNameAndExtension = { */ function getThumbnailAndImageURIs(transaction: Transaction, receiptPath: string | null = null, receiptFileName: string | null = null): ThumbnailAndImageURI { // URI to image, i.e. blob:new.expensify.com/9ef3a018-4067-47c6-b29f-5f1bd35f213d or expensify.com/receipts/w_e616108497ef940b7210ec6beb5a462d01a878f4.jpg - const path = (transaction?.receipt?.source as string) ?? receiptPath ?? ''; + const path = transaction?.receipt?.source ?? receiptPath ?? ''; // filename of uploaded image or last part of remote URI const filename = transaction?.filename ?? receiptFileName ?? ''; const isReceiptImage = Str.isImage(filename); diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 69a919185296..a0e522ea54ed 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -3,7 +3,6 @@ import type {StackScreenProps} from '@react-navigation/stack'; import {format} from 'date-fns'; import Str from 'expensify-common/lib/str'; import lodashHas from 'lodash/has'; -import type {ImageSourcePropType} from 'react-native'; import Onyx from 'react-native-onyx'; import type {OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import OnyxUtils from 'react-native-onyx/lib/utils'; @@ -316,7 +315,7 @@ function setMoneyRequestParticipants_temporaryForRefactor(transactionID: string, Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {participants}); } -function setMoneyRequestReceipt_temporaryForRefactor(transactionID: string, source: ImageSourcePropType, filename: string) { +function setMoneyRequestReceipt_temporaryForRefactor(transactionID: string, source: string, filename: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {receipt: {source}, filename}); } @@ -886,7 +885,7 @@ function createDistanceRequest( const currentChatReport = isMoneyRequestReport ? ReportUtils.getReport(report.chatReportID) : report; const optimisticReceipt: Receipt = { - source: ReceiptGeneric, + source: ReceiptGeneric as string, state: CONST.IOU.RECEIPT_STATE.OPEN, }; const {iouReport, chatReport, transaction, iouAction, createdChatReportActionID, createdIOUReportActionID, reportPreviewAction, onyxData} = getMoneyRequestInformation( @@ -3455,7 +3454,7 @@ function detachReceipt(transactionID: string) { API.write('DetachReceipt', {transactionID}, {optimisticData, failureData}); } -function replaceReceipt(transactionID: string, receipt: Receipt, filePath: ImageSourcePropType) { +function replaceReceipt(transactionID: string, receipt: Receipt, filePath: string) { const transaction = allTransactions.transactionID; const oldReceipt = transaction?.receipt ?? {}; diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 7c40118207a0..6fdd8d309408 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -1,4 +1,3 @@ -import type {ImageSourcePropType} from 'react-native'; import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; import type {Participant, Split} from './IOU'; @@ -43,7 +42,7 @@ type Receipt = { receiptID?: number; path?: string; name?: string; - source?: ImageSourcePropType; + source?: string; filename?: string; state?: ValueOf; }; From bd8005542ce0212cae6cf2eb9079ae49ee74acbc Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 9 Jan 2024 17:24:18 +0100 Subject: [PATCH 35/68] Update errors types --- src/components/OfflineWithFeedback.tsx | 9 ++------- src/libs/ErrorUtils.ts | 21 +++++++-------------- src/libs/ReportUtils.ts | 8 ++++---- src/libs/SidebarUtils.ts | 2 +- src/libs/actions/IOU.ts | 6 +++--- src/types/onyx/OnyxCommon.ts | 9 ++++----- src/types/onyx/ReportAction.ts | 2 +- 7 files changed, 22 insertions(+), 35 deletions(-) diff --git a/src/components/OfflineWithFeedback.tsx b/src/components/OfflineWithFeedback.tsx index 0446bd31025f..5a825e9ce24f 100644 --- a/src/components/OfflineWithFeedback.tsx +++ b/src/components/OfflineWithFeedback.tsx @@ -25,7 +25,7 @@ type OfflineWithFeedbackProps = ChildrenProps & { shouldHideOnDelete?: boolean; /** The errors to display */ - errors?: OnyxCommon.SimpleErrors | null; + errors?: OnyxCommon.Errors | null; /** Whether we should show the error messages */ shouldShowErrorMessages?: boolean; @@ -57,11 +57,6 @@ type OfflineWithFeedbackProps = ChildrenProps & { type StrikethroughProps = Partial & {style: Array}; -function omitBy(obj: Record | undefined | null, predicate: (value: T) => boolean) { - // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-unused-vars - return Object.fromEntries(Object.entries(obj ?? {}).filter(([_, value]) => !predicate(value))); -} - function OfflineWithFeedback({ pendingAction, canDismissError = true, @@ -83,7 +78,7 @@ function OfflineWithFeedback({ const hasErrors = isNotEmptyObject(errors ?? {}); // Some errors have a null message. This is used to apply opacity only and to avoid showing redundant messages. - const errorMessages = omitBy(errors, (e) => e === null); + const errorMessages = Object.fromEntries(Object.entries(errors ?? {}).filter((errorEntry): errorEntry is [string, string] => errorEntry[1] !== null)); const hasErrorMessages = isNotEmptyObject(errorMessages); const isOfflinePendingAction = !!isOffline && !!pendingAction; const isUpdateOrDeleteError = hasErrors && (pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE); diff --git a/src/libs/ErrorUtils.ts b/src/libs/ErrorUtils.ts index d38a05dc5a5c..6c1540ccaa55 100644 --- a/src/libs/ErrorUtils.ts +++ b/src/libs/ErrorUtils.ts @@ -1,16 +1,10 @@ import CONST from '@src/CONST'; import type {TranslationFlatObject, TranslationPaths} from '@src/languages/types'; -import type {ErrorFields, SimpleErrors} from '@src/types/onyx/OnyxCommon'; +import type {ErrorFields, Errors, ErrorsObject} from '@src/types/onyx/OnyxCommon'; import type Response from '@src/types/onyx/Response'; import DateUtils from './DateUtils'; import * as Localize from './Localize'; -type ErrorObject = Record; - -type MicroSecondOnyxError = Record; - -type MicroSecondOnyxErrorObject = Record; - function getAuthenticateErrorMessage(response: Response): keyof TranslationFlatObject { switch (response.jsonCode) { case CONST.JSON_CODE.UNABLE_TO_RETRY: @@ -44,7 +38,7 @@ function getAuthenticateErrorMessage(response: Response): keyof TranslationFlatO * Method used to get an error object with microsecond as the key. * @param error - error key or message to be saved */ -function getMicroSecondOnyxError(error: string | null): MicroSecondOnyxError { +function getMicroSecondOnyxError(error: string | null): Errors { return {[DateUtils.getMicroseconds()]: error}; } @@ -52,15 +46,15 @@ function getMicroSecondOnyxError(error: string | null): MicroSecondOnyxError { * Method used to get an error object with microsecond as the key and an object as the value. * @param error - error key or message to be saved */ -function getMicroSecondOnyxErrorObject(error: ErrorObject): MicroSecondOnyxErrorObject { +function getMicroSecondOnyxErrorObject(error: Errors): ErrorsObject { return {[DateUtils.getMicroseconds()]: error}; } type OnyxDataWithErrors = { - errors?: SimpleErrors; + errors?: Errors; }; -function getLatestErrorMessage(onyxData: TOnyxData): string { +function getLatestErrorMessage(onyxData: TOnyxData): string | null { const errors = onyxData.errors ?? {}; if (Object.keys(errors).length === 0) { @@ -76,7 +70,7 @@ type OnyxDataWithErrorFields = { errorFields?: ErrorFields; }; -function getLatestErrorField(onyxData: TOnyxData, fieldName: string): Record { +function getLatestErrorField(onyxData: TOnyxData, fieldName: string): Errors { const errorsForField = onyxData.errorFields?.[fieldName] ?? {}; if (Object.keys(errorsForField).length === 0) { @@ -88,7 +82,7 @@ function getLatestErrorField(onyxData return {[key]: errorsForField[key]}; } -function getEarliestErrorField(onyxData: TOnyxData, fieldName: string): Record { +function getEarliestErrorField(onyxData: TOnyxData, fieldName: string): Errors { const errorsForField = onyxData.errorFields?.[fieldName] ?? {}; if (Object.keys(errorsForField).length === 0) { @@ -126,4 +120,3 @@ function addErrorMessage(errors: ErrorsList, inpu } export {getAuthenticateErrorMessage, getMicroSecondOnyxError, getMicroSecondOnyxErrorObject, getLatestErrorMessage, getLatestErrorField, getEarliestErrorField, addErrorMessage}; -export type {MicroSecondOnyxErrorObject, MicroSecondOnyxError}; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 2a1cbfc21550..1fb20a558294 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -16,7 +16,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Beta, Login, PersonalDetails, PersonalDetailsList, Policy, Report, ReportAction, ReportMetadata, Session, Transaction} from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; -import type {Icon, PendingAction, SimpleErrors} from '@src/types/onyx/OnyxCommon'; +import type {Errors, Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; import type {IOUMessage, OriginalMessageActionName, OriginalMessageCreated} from '@src/types/onyx/OriginalMessage'; import type {Status} from '@src/types/onyx/PersonalDetails'; import type {NotificationPreference} from '@src/types/onyx/Report'; @@ -133,7 +133,7 @@ type ReportRouteParams = { type ReportOfflinePendingActionAndErrors = { addWorkspaceRoomOrChatPendingAction: PendingAction | undefined; - addWorkspaceRoomOrChatErrors: Record | null | undefined; + addWorkspaceRoomOrChatErrors: Errors | null | undefined; }; type OptimisticApprovedReportAction = Pick< @@ -292,7 +292,7 @@ type CustomIcon = { type OptionData = { text: string; alternateText?: string | null; - allReportErrors?: SimpleErrors | null; + allReportErrors?: Errors | null; brickRoadIndicator?: typeof CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR | '' | null; tooltipText?: string | null; alternateTextMaxLines?: number; @@ -3885,7 +3885,7 @@ function isValidReportIDFromPath(reportIDFromPath: string): boolean { /** * Return the errors we have when creating a chat or a workspace room */ -function getAddWorkspaceRoomOrChatReportErrors(report: OnyxEntry): Record | null | undefined { +function getAddWorkspaceRoomOrChatReportErrors(report: OnyxEntry): Errors | null | undefined { // We are either adding a workspace room, or we're creating a chat, it isn't possible for both of these to have errors for the same report at the same time, so // simply looking up the first truthy value will get the relevant property if it's set. return report?.errorFields?.addWorkspaceRoom ?? report?.errorFields?.createChat; diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index a5d3b40e99fc..6e46ec320066 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -291,7 +291,7 @@ function getOptionData( result.isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report); result.shouldShowSubscript = ReportUtils.shouldReportShowSubscript(report); result.pendingAction = report.pendingFields ? report.pendingFields.addWorkspaceRoom || report.pendingFields.createChat : undefined; - result.allReportErrors = OptionsListUtils.getAllReportErrors(report, reportActions) as OnyxCommon.SimpleErrors; + result.allReportErrors = OptionsListUtils.getAllReportErrors(report, reportActions) as OnyxCommon.Errors; result.brickRoadIndicator = Object.keys(result.allReportErrors ?? {}).length !== 0 ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''; result.ownerAccountID = report.ownerAccountID; result.managerID = report.managerID; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index a0e522ea54ed..16a43be58ccd 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -12,7 +12,6 @@ import * as API from '@libs/API'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import DateUtils from '@libs/DateUtils'; import * as ErrorUtils from '@libs/ErrorUtils'; -import type {MicroSecondOnyxError, MicroSecondOnyxErrorObject} from '@libs/ErrorUtils'; import * as IOUUtils from '@libs/IOUUtils'; import * as LocalePhoneNumber from '@libs/LocalePhoneNumber'; import * as Localize from '@libs/Localize'; @@ -34,6 +33,7 @@ import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; import type {Participant, Split} from '@src/types/onyx/IOU'; +import {Errors, ErrorsObject} from '@src/types/onyx/OnyxCommon'; import type ReportAction from '@src/types/onyx/ReportAction'; import type {OnyxData} from '@src/types/onyx/Request'; import type {Comment, Receipt, TaxRate, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; @@ -346,10 +346,10 @@ function resetMoneyRequestInfo(id = '') { /** * Helper function to get the receipt error for money requests, or the generic error if there's no receipt */ -function getReceiptError(receipt?: Receipt, filename?: string, isScanRequest = true): MicroSecondOnyxError | MicroSecondOnyxErrorObject { +function getReceiptError(receipt?: Receipt, filename?: string, isScanRequest = true): Errors | ErrorsObject { return isEmptyObject(receipt) || !isScanRequest ? ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage') - : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: receipt.source, filename}); + : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: receipt.source ?? '', filename: filename ?? ''}); } /** Builds the Onyx data for a money request */ diff --git a/src/types/onyx/OnyxCommon.ts b/src/types/onyx/OnyxCommon.ts index 60a3fc5b89df..cff72ed94e10 100644 --- a/src/types/onyx/OnyxCommon.ts +++ b/src/types/onyx/OnyxCommon.ts @@ -1,5 +1,4 @@ import type {ValueOf} from 'type-fest'; -import type {MicroSecondOnyxError, MicroSecondOnyxErrorObject} from '@libs/ErrorUtils'; import type {AvatarSource} from '@libs/UserUtils'; import type CONST from '@src/CONST'; @@ -7,11 +6,11 @@ type PendingAction = ValueOf; type PendingFields = Record; -type SimpleErrors = Record; +type ErrorFields = Record; -type ErrorFields = Record; +type Errors = Record; -type Errors = SimpleErrors | MicroSecondOnyxError | MicroSecondOnyxErrorObject; +type ErrorsObject = Record; type AvatarType = typeof CONST.ICON_TYPE_AVATAR | typeof CONST.ICON_TYPE_WORKSPACE; @@ -32,4 +31,4 @@ type Icon = { fallbackIcon?: AvatarSource; }; -export type {Icon, PendingAction, PendingFields, ErrorFields, Errors, AvatarType, SimpleErrors}; +export type {Icon, PendingAction, PendingFields, ErrorFields, Errors, AvatarType, ErrorsObject}; diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts index 47945ffba4bb..f14f93d84372 100644 --- a/src/types/onyx/ReportAction.ts +++ b/src/types/onyx/ReportAction.ts @@ -178,7 +178,7 @@ type ReportActionBase = { delegateAccountID?: string; /** Server side errors keyed by microtime */ - errors?: OnyxCommon.Errors; + errors?: OnyxCommon.Errors | OnyxCommon.ErrorsObject; /** Whether the report action is attachment */ isAttachment?: boolean; From 55d7cf0373fe398c70aceed62ba408f759dbd66e Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 9 Jan 2024 18:11:48 +0100 Subject: [PATCH 36/68] Minor code improvements --- src/libs/actions/IOU.ts | 46 ++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 16a43be58ccd..9429809d6568 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -2,7 +2,6 @@ import type {StackScreenProps} from '@react-navigation/stack'; import {format} from 'date-fns'; import Str from 'expensify-common/lib/str'; -import lodashHas from 'lodash/has'; import Onyx from 'react-native-onyx'; import type {OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import OnyxUtils from 'react-native-onyx/lib/utils'; @@ -33,7 +32,7 @@ import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; import type {Participant, Split} from '@src/types/onyx/IOU'; -import {Errors, ErrorsObject} from '@src/types/onyx/OnyxCommon'; +import type {Errors, ErrorsObject} from '@src/types/onyx/OnyxCommon'; import type ReportAction from '@src/types/onyx/ReportAction'; import type {OnyxData} from '@src/types/onyx/Request'; import type {Comment, Receipt, TaxRate, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; @@ -151,7 +150,7 @@ Onyx.connect({ callback: (val) => (allReports = val), }); -let allTransactions: Record = {}; +let allTransactions: Record> = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.TRANSACTION, waitForCollectionCallback: true, @@ -165,7 +164,7 @@ Onyx.connect({ }, }); -let allTransactionDrafts: Record = {}; +let allTransactionDrafts: Record> = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.TRANSACTION_DRAFT, waitForCollectionCallback: true, @@ -174,7 +173,7 @@ Onyx.connect({ }, }); -let allTransactionViolations: Record = {}; +let allTransactionViolations: Record> = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, waitForCollectionCallback: true, @@ -188,7 +187,7 @@ Onyx.connect({ }, }); -let allDraftSplitTransactions: Record = {}; +let allDraftSplitTransactions: Record> = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT, waitForCollectionCallback: true, @@ -197,7 +196,7 @@ Onyx.connect({ }, }); -let allNextSteps: Record = {}; +let allNextSteps: Record> = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.NEXT_STEP, waitForCollectionCallback: true, @@ -240,7 +239,8 @@ Onyx.connect({ function startMoneyRequest_temporaryForRefactor(reportID: string, isFromGlobalCreate: boolean, iouRequestType: IOURequestType = CONST.IOU.REQUEST_TYPE.MANUAL) { // Generate a brand new transactionID const newTransactionID = CONST.IOU.OPTIMISTIC_TRANSACTION_ID; - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- currentDate can be an empty string + // Disabling this line since currentDate can be an empty string + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const created = currentDate || format(new Date(), 'yyyy-MM-dd'); const comment: Comment = {}; @@ -323,7 +323,8 @@ function setMoneyRequestReceipt_temporaryForRefactor(transactionID: string, sour * Reset money request info from the store with its initial value */ function resetMoneyRequestInfo(id = '') { - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- currentDate can be an empty string + // Disabling this line since currentDate can be an empty string + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const created = currentDate || format(new Date(), CONST.DATE.FNS_FORMAT_STRING); Onyx.merge(ONYXKEYS.IOU, { id, @@ -640,7 +641,7 @@ function buildOnyxDataForMoneyRequest( failureData.push({ onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction.transactionID}`, - value: null, + value: [], }); } @@ -813,6 +814,7 @@ function getMoneyRequestInformation( [payerAccountID]: { accountID: payerAccountID, avatar: UserUtils.getDefaultAvatarURL(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), login: participant.login, @@ -1414,7 +1416,7 @@ function createSplitsAndOnyxData( { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`, - value: {pendingAction: null}, + value: {}, }, ]; @@ -1437,7 +1439,7 @@ function createSplitsAndOnyxData( { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`, - value: {pendingAction: null}, + value: {}, }, ]; @@ -1496,7 +1498,7 @@ function createSplitsAndOnyxData( let oneOnOneChatReport: OptimisticChatReport; let isNewOneOnOneChatReport = false; let shouldCreateOptimisticPersonalDetails = false; - const personalDetailExists = lodashHas(allPersonalDetails, accountID); + const personalDetailExists = accountID in allPersonalDetails; // If this is a split between two people only and the function // wasn't provided with an existing group chat report id @@ -1529,14 +1531,14 @@ function createSplitsAndOnyxData( oneOnOneIOUReport.total -= splitAmount; } } else { - oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(oneOnOneIOUReport ?? null, currentUserAccountID, splitAmount, currency); + oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(oneOnOneIOUReport, currentUserAccountID, splitAmount, currency); } // STEP 3: Build optimistic transaction const oneOnOneTransaction = TransactionUtils.buildOptimisticTransaction( - ReportUtils.isExpenseReport(oneOnOneIOUReport ?? null) ? -splitAmount : splitAmount, + ReportUtils.isExpenseReport(oneOnOneIOUReport) ? -splitAmount : splitAmount, currency, - oneOnOneIOUReport?.reportID ?? '', + oneOnOneIOUReport.reportID, comment, '', CONST.IOU.TYPE.SPLIT, @@ -1566,7 +1568,7 @@ function createSplitsAndOnyxData( [participant], oneOnOneTransaction.transactionID, undefined, - oneOnOneIOUReport?.reportID ?? '', + oneOnOneIOUReport.reportID, undefined, undefined, undefined, @@ -1580,6 +1582,7 @@ function createSplitsAndOnyxData( [accountID]: { accountID, avatar: UserUtils.getDefaultAvatarURL(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), login: participant.login, @@ -1588,7 +1591,7 @@ function createSplitsAndOnyxData( } : {}; - let oneOnOneReportPreviewAction = ReportActionsUtils.getReportPreviewAction(oneOnOneChatReport.reportID, oneOnOneIOUReport?.reportID ?? ''); + let oneOnOneReportPreviewAction = ReportActionsUtils.getReportPreviewAction(oneOnOneChatReport.reportID, oneOnOneIOUReport.reportID); if (oneOnOneReportPreviewAction) { oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction); } else { @@ -1627,7 +1630,7 @@ function createSplitsAndOnyxData( email, accountID, amount: splitAmount, - iouReportID: oneOnOneIOUReport?.reportID, + iouReportID: oneOnOneIOUReport.reportID, chatReportID: oneOnOneChatReport.reportID, transactionID: oneOnOneTransaction.transactionID, reportActionID: oneOnOneIOUAction.reportActionID, @@ -1952,6 +1955,7 @@ function startSplitBill( const splits: Split[] = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID}]; 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 ? '' : OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login || participant.text || '').toLowerCase(); const accountID = participant.isOwnPolicyExpenseChat ? 0 : Number(participant.accountID); @@ -1977,8 +1981,10 @@ function startSplitBill( [accountID]: { accountID, avatar: UserUtils.getDefaultAvatarURL(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), + // 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, isOptimisticPersonalDetail: true, @@ -3019,6 +3025,7 @@ function getSendMoneyParams( [recipientAccountID]: { accountID: recipientAccountID, avatar: UserUtils.getDefaultAvatarURL(recipient.accountID), + // Disabling this line since participant.displayName can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing displayName: recipient.displayName || recipient.login, login: recipient.login, @@ -3634,6 +3641,7 @@ function navigateToNextPage(iou: OnyxEntry, iouType: string, repo * Gets a report id from the first participant of the IOU object stored in Onyx. */ function getIOUReportID(iou?: OnyxTypes.IOU, route?: MoneyRequestRoute): string { + // Disabling this line for safeness as nullish coalescing works only if the value is undefined or null // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing return route?.params.reportID || iou?.participants?.[0]?.reportID || ''; } From c059ca3466198a648f3ead8a6ef83f1590b6d4fa Mon Sep 17 00:00:00 2001 From: VickyStash Date: Wed, 10 Jan 2024 10:44:50 +0100 Subject: [PATCH 37/68] Remove TransactionDraft type, update deleteMoneyRequest typing after merging main --- src/ONYXKEYS.ts | 2 +- src/libs/ViolationsUtils.ts | 4 +- src/libs/actions/IOU.ts | 276 ++++++++++++++++++---------------- src/types/onyx/Transaction.ts | 12 +- src/types/onyx/index.ts | 2 - 5 files changed, 152 insertions(+), 144 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 7b3d56ad7485..3049ed8978b8 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -458,7 +458,7 @@ type OnyxValues = { [ONYXKEYS.COLLECTION.REPORT_USER_IS_LEAVING_ROOM]: boolean; [ONYXKEYS.COLLECTION.SECURITY_GROUP]: OnyxTypes.SecurityGroup; [ONYXKEYS.COLLECTION.TRANSACTION]: OnyxTypes.Transaction; - [ONYXKEYS.COLLECTION.TRANSACTION_DRAFT]: OnyxTypes.TransactionDraft; + [ONYXKEYS.COLLECTION.TRANSACTION_DRAFT]: OnyxTypes.Transaction; [ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT]: OnyxTypes.Transaction; [ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS]: OnyxTypes.TransactionViolations; [ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS]: OnyxTypes.RecentlyUsedTags; diff --git a/src/libs/ViolationsUtils.ts b/src/libs/ViolationsUtils.ts index 9b2b2c5f6dda..d014030c7b3e 100644 --- a/src/libs/ViolationsUtils.ts +++ b/src/libs/ViolationsUtils.ts @@ -24,7 +24,7 @@ const ViolationsUtils = { if (policyRequiresCategories) { const hasCategoryOutOfPolicyViolation = transactionViolations.some((violation) => violation.name === 'categoryOutOfPolicy'); const hasMissingCategoryViolation = transactionViolations.some((violation) => violation.name === 'missingCategory'); - const isCategoryInPolicy = Boolean(policyCategories[transaction.category]?.enabled); + const isCategoryInPolicy = Boolean(policyCategories[transaction.category ?? '']?.enabled); // Add 'categoryOutOfPolicy' violation if category is not in policy if (!hasCategoryOutOfPolicyViolation && transaction.category && !isCategoryInPolicy) { @@ -50,7 +50,7 @@ const ViolationsUtils = { if (policyRequiresTags) { const hasTagOutOfPolicyViolation = transactionViolations.some((violation) => violation.name === 'tagOutOfPolicy'); const hasMissingTagViolation = transactionViolations.some((violation) => violation.name === 'missingTag'); - const isTagInPolicy = Boolean(policyTags[transaction.tag]?.enabled); + const isTagInPolicy = Boolean(policyTags[transaction.tag ?? '']?.enabled); // Add 'tagOutOfPolicy' violation if tag is not in policy if (!hasTagOutOfPolicyViolation && transaction.tag && !isTagInPolicy) { diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 41c3b4d28d8e..0602732e4965 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -164,7 +164,7 @@ Onyx.connect({ }, }); -let allTransactionDrafts: Record> = {}; +let allTransactionDrafts: Record> = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.TRANSACTION_DRAFT, waitForCollectionCallback: true, @@ -768,7 +768,7 @@ function getMoneyRequestInformation( // to remind me to do this. const existingTransaction = allTransactionDrafts[`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`]; if (existingTransaction && existingTransaction.iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE) { - optimisticTransaction = OnyxUtils.fastMerge(existingTransaction, optimisticTransaction) as OnyxTypes.Transaction; + optimisticTransaction = OnyxUtils.fastMerge(existingTransaction, optimisticTransaction); } // STEP 4: Build optimistic reportActions. We need: @@ -2603,117 +2603,125 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor iouReportLastMessageText.length === 0 && !ReportActionsUtils.isDeletedParentAction(lastVisibleAction) && (!transactionThreadID || shouldDeleteTransactionThread); // STEP 4: Update the iouReport and reportPreview with new totals and messages if it wasn't deleted - let updatedIOUReport = {...iouReport}; - const updatedReportPreviewAction = {...reportPreviewAction}; + let updatedIOUReport: OnyxTypes.Report | null; + const updatedReportPreviewAction: OnyxTypes.ReportAction | EmptyObject = {...reportPreviewAction}; updatedReportPreviewAction.pendingAction = shouldDeleteIOUReport ? CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE : CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE; - if (ReportUtils.isExpenseReport(iouReport)) { + if (iouReport && ReportUtils.isExpenseReport(iouReport)) { updatedIOUReport = {...iouReport}; - // Because of the Expense reports are stored as negative values, we add the total from the amount - updatedIOUReport.total += TransactionUtils.getAmount(transaction, true); + if (typeof updatedIOUReport.total === 'number') { + // Because of the Expense reports are stored as negative values, we add the total from the amount + updatedIOUReport.total += TransactionUtils.getAmount(transaction, true); + } } else { updatedIOUReport = IOUUtils.updateIOUOwnerAndTotal( iouReport, - reportAction.actorAccountID, + reportAction.actorAccountID ?? -1, TransactionUtils.getAmount(transaction, false), TransactionUtils.getCurrency(transaction), true, ); } - updatedIOUReport.lastMessageText = iouReportLastMessageText; - updatedIOUReport.lastVisibleActionCreated = lodashGet(lastVisibleAction, 'created'); + if (updatedIOUReport) { + updatedIOUReport.lastMessageText = iouReportLastMessageText; + updatedIOUReport.lastVisibleActionCreated = lastVisibleAction?.created; + } - const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(iouReport); + const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(iouReport?.reportID); const messageText = Localize.translateLocal(hasNonReimbursableTransactions ? 'iou.payerSpentAmount' : 'iou.payerOwesAmount', { - payer: ReportUtils.getPersonalDetailsForAccountID(updatedIOUReport.managerID).login || '', - amount: CurrencyUtils.convertToDisplayString(updatedIOUReport.total, updatedIOUReport.currency), + payer: ReportUtils.getPersonalDetailsForAccountID(updatedIOUReport?.managerID ?? -1).login ?? '', + amount: CurrencyUtils.convertToDisplayString(updatedIOUReport?.total, updatedIOUReport?.currency), }); - updatedReportPreviewAction.message[0].text = messageText; - updatedReportPreviewAction.message[0].html = messageText; - if (reportPreviewAction.childMoneyRequestCount > 0) { + if (updatedReportPreviewAction?.message?.[0]) { + updatedReportPreviewAction.message[0].text = messageText; + updatedReportPreviewAction.message[0].html = messageText; + } + + if (updatedReportPreviewAction && reportPreviewAction?.childMoneyRequestCount && reportPreviewAction?.childMoneyRequestCount > 0) { updatedReportPreviewAction.childMoneyRequestCount = reportPreviewAction.childMoneyRequestCount - 1; } // STEP 5: Build Onyx data - const optimisticData = [ + const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, value: null, }, - ...(Permissions.canUseViolations(betas) - ? [ - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, - value: null, - }, - ] - : []), - ...(shouldDeleteTransactionThread - ? [ - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`, - value: null, - }, - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadID}`, - value: null, - }, - ] - : []), + ]; + + if (Permissions.canUseViolations(betas)) { + optimisticData.push({ + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, + value: null, + }); + } + + if (shouldDeleteTransactionThread) { + optimisticData.push( + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`, + value: null, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadID}`, + value: null, + }, + ); + } + + optimisticData.push( { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.reportID}`, value: updatedReportAction, }, { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, - value: updatedIOUReport, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, + value: updatedIOUReport ?? {}, }, { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`, value: { - [reportPreviewAction.reportActionID]: updatedReportPreviewAction, + [reportPreviewAction?.reportActionID ?? '']: updatedReportPreviewAction, }, }, - ...(!shouldDeleteIOUReport && updatedReportPreviewAction.childMoneyRequestCount === 0 - ? [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, - value: { - hasOutstandingChildRequest: false, - }, - }, - ] - : []), - ...(shouldDeleteIOUReport - ? [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, - value: { - hasOutstandingChildRequest: false, - iouReportID: null, - lastMessageText: ReportActionsUtils.getLastVisibleMessage(iouReport.chatReportID, {[reportPreviewAction.reportActionID]: null}).lastMessageText, - lastVisibleActionCreated: lodashGet(ReportActionsUtils.getLastVisibleAction(iouReport.chatReportID, {[reportPreviewAction.reportActionID]: null}), 'created'), - }, - }, - ] - : []), - ]; + ); - const successData = [ + if (!shouldDeleteIOUReport && updatedReportPreviewAction.childMoneyRequestCount === 0) { + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`, + value: { + hasOutstandingChildRequest: false, + }, + }); + } + + if (shouldDeleteIOUReport) { + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`, + value: { + hasOutstandingChildRequest: false, + iouReportID: null, + lastMessageText: ReportActionsUtils.getLastVisibleMessage(iouReport?.chatReportID ?? '', {[reportPreviewAction?.reportActionID ?? '']: null})?.lastMessageText, + lastVisibleActionCreated: ReportActionsUtils.getLastVisibleAction(iouReport?.chatReportID ?? '', {[reportPreviewAction?.reportActionID ?? '']: null})?.created, + }, + }); + } + + const successData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.reportID}`, value: { [reportAction.reportActionID]: shouldDeleteIOUReport ? null @@ -2724,9 +2732,9 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor }, { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`, value: { - [reportPreviewAction.reportActionID]: shouldDeleteIOUReport + [reportPreviewAction?.reportActionID ?? '']: shouldDeleteIOUReport ? null : { pendingAction: null, @@ -2734,44 +2742,44 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor }, }, }, - ...(shouldDeleteIOUReport - ? [ - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, - value: null, - }, - ] - : []), ]; - const failureData = [ + if (shouldDeleteIOUReport) { + successData.push({ + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, + value: null, + }); + } + + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, value: transaction, }, - ...(Permissions.canUseViolations(betas) - ? [ - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, - value: transactionViolations, - }, - ] - : []), - ...(shouldDeleteTransactionThread - ? [ - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`, - value: transactionThread, - }, - ] - : []), + ]; + + if (Permissions.canUseViolations(betas)) { + failureData.push({ + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, + value: transactionViolations, + }); + } + + if (shouldDeleteTransactionThread) { + failureData.push({ + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`, + value: transactionThread, + }); + } + + failureData.push( { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.reportID}`, value: { [reportAction.reportActionID]: { ...reportAction, @@ -2779,42 +2787,46 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor }, }, }, - { - onyxMethod: shouldDeleteIOUReport ? Onyx.METHOD.SET : Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, - value: iouReport, - }, + shouldDeleteIOUReport + ? { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, + value: iouReport, + } + : { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, + value: iouReport ?? {}, + }, { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`, value: { - [reportPreviewAction.reportActionID]: { + [reportPreviewAction?.reportActionID ?? '']: { ...reportPreviewAction, errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericDeleteFailureMessage'), }, }, }, - ...(shouldDeleteIOUReport - ? [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, - value: chatReport, - }, - ] - : []), - ...(!shouldDeleteIOUReport && updatedReportPreviewAction.childMoneyRequestCount === 0 - ? [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, - value: { - hasOutstandingChildRequest: true, - }, - }, - ] - : []), - ]; + ); + + if (chatReport && shouldDeleteIOUReport) { + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, + value: chatReport, + }); + } + + if (!shouldDeleteIOUReport && updatedReportPreviewAction.childMoneyRequestCount === 0) { + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`, + value: { + hasOutstandingChildRequest: true, + }, + }); + } type DeleteMoneyRequestParams = { transactionID: string; diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 6fdd8d309408..7117158216e4 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -74,10 +74,10 @@ type Transaction = { amount: number; /** Whether the request is billable */ - billable: boolean; + billable?: boolean; /** The category name */ - category: string; + category?: string; /** The comment object on the transaction */ comment: Comment; @@ -128,7 +128,7 @@ type Transaction = { participants?: Participant[]; /** The type of action that's pending */ - pendingAction: OnyxCommon.PendingAction; + pendingAction?: OnyxCommon.PendingAction; /** The receipt object associated with the transaction */ receipt?: Receipt; @@ -143,7 +143,7 @@ type Transaction = { transactionID: string; /** The transaction tag */ - tag: string; + tag?: string; /** Whether the transaction was created globally */ isFromGlobalCreate?: boolean; @@ -190,8 +190,6 @@ type Transaction = { isLoading?: boolean; }; -type TransactionDraft = Partial; - type AdditionalTransactionChanges = { comment?: string; waypoints?: WaypointCollection; @@ -202,4 +200,4 @@ type AdditionalTransactionChanges = { type TransactionChanges = Partial & AdditionalTransactionChanges; export default Transaction; -export type {WaypointCollection, Comment, Receipt, Waypoint, TransactionDraft, TransactionChanges, TaxRate}; +export type {WaypointCollection, Comment, Receipt, Waypoint, TransactionChanges, TaxRate}; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index b17dd5b7bafc..9fd52bd0628e 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -55,7 +55,6 @@ import type SecurityGroup from './SecurityGroup'; import type Session from './Session'; import type Task from './Task'; import type Transaction from './Transaction'; -import type {TransactionDraft} from './Transaction'; import type {TransactionViolation, TransactionViolations, ViolationName} from './TransactionViolation'; import type User from './User'; import type UserLocation from './UserLocation'; @@ -125,7 +124,6 @@ export type { Session, Task, Transaction, - TransactionDraft, TransactionViolation, TransactionViolations, User, From ebfb6b91b3990076bf89c48b1c88513e53c6f585 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Wed, 10 Jan 2024 16:32:50 +0100 Subject: [PATCH 38/68] Update createdChatReportActionID and createdIOUReportActionID type, update TODO comment --- src/libs/actions/IOU.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 0602732e4965..80ca05ffb08a 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -66,8 +66,8 @@ type MoneyRequestInformation = { chatReport: OnyxTypes.Report; transaction: OnyxTypes.Transaction; iouAction: OptimisticIOUReportAction; - createdChatReportActionID: string | number; - createdIOUReportActionID: string | number; + createdChatReportActionID: string; + createdIOUReportActionID: string; reportPreviewAction: OnyxTypes.ReportAction; onyxData: OnyxData; }; @@ -755,10 +755,10 @@ function getMoneyRequestInformation( billable, ); - // TODO: Remove this type once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. + // TODO: Remove assertion once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, category) as OptimisticPolicyRecentlyUsedCategories; - // TODO: Remove this type once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. + // TODO: Remove assertion once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport.policyID, tag) as OptimisticPolicyRecentlyUsedTags; // If there is an existing transaction (which is the case for distance requests), then the data from the existing transaction @@ -854,8 +854,8 @@ function getMoneyRequestInformation( chatReport, transaction: optimisticTransaction, iouAction, - createdChatReportActionID: isNewChatReport ? optimisticCreatedActionForChat.reportActionID : 0, - createdIOUReportActionID: isNewIOUReport ? optimisticCreatedActionForIOU.reportActionID : 0, + createdChatReportActionID: isNewChatReport ? optimisticCreatedActionForChat.reportActionID : '0', + createdIOUReportActionID: isNewIOUReport ? optimisticCreatedActionForIOU.reportActionID : '0', reportPreviewAction, onyxData: { optimisticData, @@ -916,8 +916,8 @@ function createDistanceRequest( chatReportID: string; transactionID: string; reportActionID: string; - createdChatReportActionID: string | number; - createdIOUReportActionID: string | number; + createdChatReportActionID: string; + createdIOUReportActionID: string; reportPreviewReportActionID: string; waypoints: string; created: string; @@ -1247,8 +1247,8 @@ function requestMoney( chatReportID: string; transactionID: string; reportActionID: string; - createdChatReportActionID: string | number; - createdIOUReportActionID: string | number; + createdChatReportActionID: string; + createdIOUReportActionID: string; reportPreviewReportActionID: string; receipt: Receipt; receiptState?: ValueOf; From 185f26b4f678a1533dc774bf4e7a9ac551b901da Mon Sep 17 00:00:00 2001 From: VickyStash Date: Wed, 10 Jan 2024 17:11:14 +0100 Subject: [PATCH 39/68] Minor code improvements --- src/libs/actions/IOU.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 80ca05ffb08a..6a60a27f9b1b 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -368,8 +368,8 @@ function buildOnyxDataForMoneyRequest( isNewChatReport: boolean, isNewIOUReport: boolean, policy?: OnyxTypes.Policy | EmptyObject, - policyTags: OnyxTypes.PolicyTags = {}, - policyCategories: OnyxTypes.PolicyCategories = {}, + policyTags?: OnyxTypes.PolicyTags, + policyCategories?: OnyxTypes.PolicyCategories, hasOutstandingChildRequest = false, ): OnyxUpdate[][] { const isScanRequest = TransactionUtils.isScanRequest(transaction); @@ -634,7 +634,7 @@ function buildOnyxDataForMoneyRequest( return [optimisticData, successData, failureData]; } - const violationsOnyxData = ViolationsUtils.getViolationsOnyxData(transaction, [], !!policy.requiresTag, policyTags, !!policy.requiresCategory, policyCategories); + const violationsOnyxData = ViolationsUtils.getViolationsOnyxData(transaction, [], !!policy.requiresTag, policyTags ?? {}, !!policy.requiresCategory, policyCategories ?? {}); if (violationsOnyxData) { optimisticData.push(violationsOnyxData); @@ -706,7 +706,7 @@ function getMoneyRequestInformation( isFromPaidPolicy = PolicyUtils.isPaidGroupPolicy(policy ?? null); // If the scheduled submit is turned off on the policy, user needs to manually submit the report which is indicated by GBR in LHN - needsToBeManuallySubmitted = isFromPaidPolicy && !(!!policy?.isHarvestingEnabled || false); + needsToBeManuallySubmitted = isFromPaidPolicy && !policy?.isHarvestingEnabled; // If the linked expense report on paid policy is not draft, we need to create a new draft expense report if (iouReport && isFromPaidPolicy && !ReportUtils.isDraftExpenseReport(iouReport)) { @@ -1804,7 +1804,7 @@ function startSplitBill( ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${existingSplitChatReportID || participants[0].reportID}`] : ReportUtils.getChatByParticipants(participantAccountIDs); const splitChatReport = existingSplitChatReport ?? ReportUtils.buildOptimisticChatReport(participantAccountIDs); - const isOwnPolicyExpenseChat = !!splitChatReport.isOwnPolicyExpenseChat || false; + const isOwnPolicyExpenseChat = !!splitChatReport.isOwnPolicyExpenseChat; const {name: filename, source, state = CONST.IOU.RECEIPT_STATE.SCANREADY} = receipt; const receiptObject: Receipt = {state, source}; From 1af5ac6c17f84dc803537a279134b1c94256ba65 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Thu, 11 Jan 2024 10:36:27 +0100 Subject: [PATCH 40/68] Update replaceReceipt typing after merging main --- src/libs/actions/IOU.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index bf02aa4e6528..b7eba7e54085 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -3476,8 +3476,8 @@ function detachReceipt(transactionID: string) { API.write('DetachReceipt', {transactionID}, {optimisticData, failureData}); } -function replaceReceipt(transactionID: string, file: any, source: string) { - const transaction = allTransactions.transactionID ?? {}; +function replaceReceipt(transactionID: string, file: File, source: string) { + const transaction = allTransactions.transactionID; const oldReceipt = transaction?.receipt ?? {}; const optimisticData: OnyxUpdate[] = [ @@ -3507,7 +3507,7 @@ function replaceReceipt(transactionID: string, file: any, source: string) { type ReplaceReceiptParams = { transactionID: string; - receipt: any; + receipt: File; }; const parameters: ReplaceReceiptParams = { From d2d5d460235f08e2c614835d6649512b3f8dfc61 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Fri, 12 Jan 2024 12:08:08 +0100 Subject: [PATCH 41/68] Onyx values type updates, minor code improvements --- src/libs/actions/IOU.ts | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 74dbffe030d8..3595f65e329c 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import type {StackScreenProps} from '@react-navigation/stack'; import {format} from 'date-fns'; import Str from 'expensify-common/lib/str'; @@ -150,7 +149,7 @@ Onyx.connect({ callback: (val) => (allReports = val), }); -let allTransactions: Record> = {}; +let allTransactions: NonNullable> = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.TRANSACTION, waitForCollectionCallback: true, @@ -164,7 +163,7 @@ Onyx.connect({ }, }); -let allTransactionDrafts: Record> = {}; +let allTransactionDrafts: NonNullable> = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.TRANSACTION_DRAFT, waitForCollectionCallback: true, @@ -173,7 +172,7 @@ Onyx.connect({ }, }); -let allTransactionViolations: Record> = {}; +let allTransactionViolations: NonNullable> = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, waitForCollectionCallback: true, @@ -187,7 +186,7 @@ Onyx.connect({ }, }); -let allDraftSplitTransactions: Record> = {}; +let allDraftSplitTransactions: NonNullable> = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT, waitForCollectionCallback: true, @@ -196,7 +195,7 @@ Onyx.connect({ }, }); -let allNextSteps: Record> = {}; +let allNextSteps: NonNullable> = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.NEXT_STEP, waitForCollectionCallback: true, @@ -236,6 +235,7 @@ Onyx.connect({ * @param reportID to attach the transaction to * @param iouRequestType one of manual/scan/distance */ +// eslint-disable-next-line @typescript-eslint/naming-convention function startMoneyRequest_temporaryForRefactor(reportID: string, isFromGlobalCreate: boolean, iouRequestType: IOURequestType = CONST.IOU.REQUEST_TYPE.MANUAL) { // Generate a brand new transactionID const newTransactionID = CONST.IOU.OPTIMISTIC_TRANSACTION_ID; @@ -271,46 +271,57 @@ function clearMoneyRequest(transactionID: string) { Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, null); } +// eslint-disable-next-line @typescript-eslint/naming-convention function setMoneyRequestAmount_temporaryForRefactor(transactionID: string, amount: number, currency: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {amount, currency}); } +// eslint-disable-next-line @typescript-eslint/naming-convention function setMoneyRequestCreated_temporaryForRefactor(transactionID: string, created: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {created}); } +// eslint-disable-next-line @typescript-eslint/naming-convention function setMoneyRequestCurrency_temporaryForRefactor(transactionID: string, currency: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {currency}); } +// eslint-disable-next-line @typescript-eslint/naming-convention function setMoneyRequestDescription_temporaryForRefactor(transactionID: string, comment: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {comment: {comment: comment.trim()}}); } +// eslint-disable-next-line @typescript-eslint/naming-convention function setMoneyRequestMerchant_temporaryForRefactor(transactionID: string, merchant: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {merchant: merchant.trim()}); } +// eslint-disable-next-line @typescript-eslint/naming-convention function setMoneyRequestCategory_temporaryForRefactor(transactionID: string, category: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {category}); } +// eslint-disable-next-line @typescript-eslint/naming-convention function resetMoneyRequestCategory_temporaryForRefactor(transactionID: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {category: null}); } +// eslint-disable-next-line @typescript-eslint/naming-convention function setMoneyRequestTag_temporaryForRefactor(transactionID: string, tag: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {tag}); } +// eslint-disable-next-line @typescript-eslint/naming-convention function resetMoneyRequestTag_temporaryForRefactor(transactionID: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {tag: null}); } +// eslint-disable-next-line @typescript-eslint/naming-convention function setMoneyRequestBillable_temporaryForRefactor(transactionID: string, billable: boolean) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {billable}); } +// eslint-disable-next-line @typescript-eslint/naming-convention function setMoneyRequestParticipants_temporaryForRefactor(transactionID: string, participants: Participant[]) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {participants}); } @@ -374,7 +385,7 @@ function buildOnyxDataForMoneyRequest( policyTags?: OnyxTypes.PolicyTags, policyCategories?: OnyxTypes.PolicyCategories, hasOutstandingChildRequest = false, -): OnyxUpdate[][] { +): [OnyxUpdate[], OnyxUpdate[], OnyxUpdate[]] { const isScanRequest = TransactionUtils.isScanRequest(transaction); const optimisticData: OnyxUpdate[] = []; @@ -596,7 +607,9 @@ function buildOnyxDataForMoneyRequest( ...(isNewChatReport ? { [chatCreatedAction.reportActionID]: { - errors: getReceiptError(transaction?.receipt, transaction.filename ?? transaction.receipt?.filename, isScanRequest), + // Disabling this line since transaction.filename can be an empty string + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + errors: getReceiptError(transaction?.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest), }, [reportPreviewAction.reportActionID]: { errors: ErrorUtils.getMicroSecondOnyxError(null), @@ -605,7 +618,9 @@ function buildOnyxDataForMoneyRequest( : { [reportPreviewAction.reportActionID]: { created: reportPreviewAction.created, - errors: getReceiptError(transaction?.receipt, transaction.filename ?? transaction.receipt?.filename, isScanRequest), + // Disabling this line since transaction.filename can be an empty string + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + errors: getReceiptError(transaction?.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest), }, }), }, @@ -617,7 +632,9 @@ function buildOnyxDataForMoneyRequest( ...(isNewIOUReport ? { [iouCreatedAction.reportActionID]: { - errors: getReceiptError(transaction.receipt, transaction.filename ?? transaction.receipt?.filename, isScanRequest), + // Disabling this line since transaction.filename can be an empty string + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest), }, [iouAction.reportActionID]: { errors: ErrorUtils.getMicroSecondOnyxError(null), @@ -625,7 +642,9 @@ function buildOnyxDataForMoneyRequest( } : { [iouAction.reportActionID]: { - errors: getReceiptError(transaction.receipt, transaction.filename ?? transaction.receipt?.filename, isScanRequest), + // Disabling this line since transaction.filename can be an empty string + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest), }, }), }, From 038f64638c2736a03eeda62ce46a16651086bf38 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Fri, 12 Jan 2024 14:06:04 +0100 Subject: [PATCH 42/68] Get rid of undefined checks --- src/libs/actions/IOU.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 3595f65e329c..cac07dc1c501 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1539,11 +1539,11 @@ function createSplitsAndOnyxData( // STEP 2: Get existing IOU/Expense report and update its total OR build a new optimistic one // For Control policy expense chats, if the report is already approved, create a new expense report - let oneOnOneIOUReport: OneOnOneIOUReport = oneOnOneChatReport.iouReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`] ?? undefined : undefined; + let oneOnOneIOUReport: OneOnOneIOUReport = oneOnOneChatReport.iouReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`] : null; const shouldCreateNewOneOnOneIOUReport = - oneOnOneIOUReport === undefined || (isOwnPolicyExpenseChat && ReportUtils.isControlPolicyExpenseReport(oneOnOneIOUReport) && ReportUtils.isReportApproved(oneOnOneIOUReport)); + !oneOnOneIOUReport || (isOwnPolicyExpenseChat && ReportUtils.isControlPolicyExpenseReport(oneOnOneIOUReport) && ReportUtils.isReportApproved(oneOnOneIOUReport)); - if (oneOnOneIOUReport === undefined || shouldCreateNewOneOnOneIOUReport) { + if (!oneOnOneIOUReport || shouldCreateNewOneOnOneIOUReport) { oneOnOneIOUReport = isOwnPolicyExpenseChat ? ReportUtils.buildOptimisticExpenseReport(oneOnOneChatReport.reportID, oneOnOneChatReport.policyID ?? '', currentUserAccountID, splitAmount, currency) : ReportUtils.buildOptimisticIOUReport(currentUserAccountID, accountID, splitAmount, oneOnOneChatReport.reportID, currency); @@ -2174,11 +2174,11 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA oneOnOneChatReport = existingChatReport ?? ReportUtils.buildOptimisticChatReport(participant.accountID ? [participant.accountID] : []); } - let oneOnOneIOUReport: OneOnOneIOUReport = oneOnOneChatReport?.iouReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`] ?? undefined : undefined; + let oneOnOneIOUReport: OneOnOneIOUReport = oneOnOneChatReport?.iouReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`] : null; const shouldCreateNewOneOnOneIOUReport = - oneOnOneIOUReport === undefined || (isPolicyExpenseChat && ReportUtils.isControlPolicyExpenseReport(oneOnOneIOUReport) && ReportUtils.isReportApproved(oneOnOneIOUReport)); + !oneOnOneIOUReport || (isPolicyExpenseChat && ReportUtils.isControlPolicyExpenseReport(oneOnOneIOUReport) && ReportUtils.isReportApproved(oneOnOneIOUReport)); - if (oneOnOneIOUReport === undefined || shouldCreateNewOneOnOneIOUReport) { + if (!oneOnOneIOUReport || shouldCreateNewOneOnOneIOUReport) { oneOnOneIOUReport = isPolicyExpenseChat ? ReportUtils.buildOptimisticExpenseReport(oneOnOneChatReport?.reportID ?? '', participant.policyID ?? '', sessionAccountID, splitAmount, currency ?? '') : ReportUtils.buildOptimisticIOUReport(sessionAccountID, participant.accountID ?? -1, splitAmount, oneOnOneChatReport?.reportID ?? '', currency ?? ''); From 679ce09bc7dfe755e3bc1cca2b3e1cb393d991a6 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 15 Jan 2024 16:30:12 +0100 Subject: [PATCH 43/68] Migrate new cancelPayment function --- src/libs/ReportUtils.ts | 2 +- src/libs/actions/IOU.ts | 99 ++++++++++++++++++++-------------------- src/types/onyx/Report.ts | 3 ++ 3 files changed, 53 insertions(+), 51 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index bba9a3e7cb2f..098a583e2750 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -452,7 +452,7 @@ function getRootParentReport(report: OnyxEntry | undefined | EmptyObject return getRootParentReport(isNotEmptyObject(parentReport) ? parentReport : null); } -function getPolicy(policyID: string): Policy | EmptyObject { +function getPolicy(policyID: string | undefined): Policy | EmptyObject { if (!allPolicies || !policyID) { return {}; } diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index f883b4a16841..ae6c13163fad 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -3469,21 +3469,17 @@ function submitReport(expenseReport: OnyxTypes.Report) { API.write('SubmitReport', parameters, {optimisticData, successData, failureData}); } -/** - * @param {Object} expenseReport - * @param {Object} chatReport - */ -function cancelPayment(expenseReport, chatReport) { +function cancelPayment(expenseReport: OnyxTypes.Report, chatReport: OnyxEntry) { const optimisticReportAction = ReportUtils.buildOptimisticCancelPaymentReportAction(expenseReport.reportID); - const policy = ReportUtils.getPolicy(chatReport.policyID); + const policy = ReportUtils.getPolicy(chatReport?.policyID); const isFree = policy && policy.type === CONST.POLICY.TYPE.FREE; - const optimisticData = [ + const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`, value: { [optimisticReportAction.reportActionID]: { - ...optimisticReportAction, + ...(optimisticReportAction as OnyxTypes.ReportAction), pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }, }, @@ -3493,29 +3489,28 @@ function cancelPayment(expenseReport, chatReport) { key: `${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`, value: { ...expenseReport, - lastMessageText: lodashGet(optimisticReportAction, 'message.0.text', ''), - lastMessageHtml: lodashGet(optimisticReportAction, 'message.0.html', ''), + lastMessageText: optimisticReportAction.message?.[0]?.text ?? '', + lastMessageHtml: optimisticReportAction.message?.[0]?.html ?? '', stateNum: isFree ? CONST.REPORT.STATE_NUM.SUBMITTED : CONST.REPORT.STATE_NUM.OPEN, statusNum: isFree ? CONST.REPORT.STATUS_NUM.SUBMITTED : CONST.REPORT.STATUS_NUM.OPEN, }, }, - ...(chatReport.reportID - ? [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, - value: { - ...chatReport, - hasOutstandingIOU: true, - hasOutstandingChildRequest: true, - iouReportID: expenseReport.reportID, - }, - }, - ] - : []), ]; - const successData = [ + if (chatReport?.reportID) { + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, + value: { + ...chatReport, + hasOutstandingIOU: true, + hasOutstandingChildRequest: true, + iouReportID: expenseReport.reportID, + }, + }); + } + + const successData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`, @@ -3527,12 +3522,12 @@ function cancelPayment(expenseReport, chatReport) { }, ]; - const failureData = [ + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`, value: { - [expenseReport.reportActionID]: { + [expenseReport.reportActionID ?? '']: { errors: ErrorUtils.getMicroSecondOnyxError('iou.error.other'), }, }, @@ -3544,31 +3539,35 @@ function cancelPayment(expenseReport, chatReport) { statusNum: CONST.REPORT.STATUS_NUM.REIMBURSED, }, }, - ...(chatReport.reportID - ? [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, - value: { - hasOutstandingIOU: false, - hasOutstandingChildRequest: false, - iouReportID: 0, - }, - }, - ] - : []), ]; - API.write( - 'CancelPayment', - { - iouReportID: expenseReport.reportID, - chatReportID: chatReport.reportID, - managerAccountID: expenseReport.managerID, - reportActionID: optimisticReportAction.reportActionID, - }, - {optimisticData, successData, failureData}, - ); + if (chatReport?.reportID) { + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, + value: { + hasOutstandingIOU: false, + hasOutstandingChildRequest: false, + iouReportID: '0', + }, + }); + } + + type CancelPaymentParams = { + iouReportID: string; + chatReportID?: string; + managerAccountID?: number; + reportActionID: string; + }; + + const parameters: CancelPaymentParams = { + iouReportID: expenseReport.reportID, + chatReportID: chatReport?.reportID, + managerAccountID: expenseReport.managerID, + reportActionID: optimisticReportAction.reportActionID, + }; + + API.write('CancelPayment', parameters, {optimisticData, successData, failureData}); } function payMoneyRequest(paymentType: PaymentMethodType, chatReport: OnyxTypes.Report, iouReport: OnyxTypes.Report) { diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts index 57a36be1d99a..cd0f339382ce 100644 --- a/src/types/onyx/Report.ts +++ b/src/types/onyx/Report.ts @@ -104,6 +104,9 @@ type Report = { /** The report visibility */ visibility?: ValueOf; + /** Whether the report has outstanding IOU */ + hasOutstandingIOU?: boolean; + /** Report cached total */ cachedTotal?: string; From b85408fd62052a8aa6e260acae57e1aecb6204d7 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 15 Jan 2024 16:50:47 +0100 Subject: [PATCH 44/68] Code improvement --- src/components/OfflineWithFeedback.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/OfflineWithFeedback.tsx b/src/components/OfflineWithFeedback.tsx index 361113488801..54657661cc65 100644 --- a/src/components/OfflineWithFeedback.tsx +++ b/src/components/OfflineWithFeedback.tsx @@ -78,8 +78,12 @@ function OfflineWithFeedback({ const {isOffline} = useNetwork(); const hasErrors = isNotEmptyObject(errors ?? {}); + // Some errors have a null message. This is used to apply opacity only and to avoid showing redundant messages. - const errorMessages = Object.fromEntries(Object.entries(errors ?? {}).filter((errorEntry): errorEntry is [string, string] => errorEntry[1] !== null)); + const errorEntries = Object.entries(errors ?? {}); + const filteredErrorEntries = errorEntries.filter((errorEntry): errorEntry is [string, string] => errorEntry[1] !== null); + const errorMessages = Object.fromEntries(filteredErrorEntries); + const hasErrorMessages = isNotEmptyObject(errorMessages); const isOfflinePendingAction = !!isOffline && !!pendingAction; const isUpdateOrDeleteError = hasErrors && (pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE); From b8aedfc659d66a827c01cfc585954eb157a96ae6 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 16 Jan 2024 11:13:17 +0100 Subject: [PATCH 45/68] Update getMoneyRequestInformation params order --- src/libs/actions/IOU.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index ae6c13163fad..49ee8f612feb 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -682,16 +682,16 @@ function getMoneyRequestInformation( currency: string, created: string, merchant: string, + receipt: Receipt | undefined, + existingTransactionID: string | undefined, + category: string | undefined, + tag: string | undefined, + billable: boolean | undefined, + policy: OnyxTypes.Policy | EmptyObject | undefined, + policyTags: OnyxTypes.PolicyTags | undefined, + policyCategories: OnyxTypes.PolicyCategories | undefined, payeeAccountID = userAccountID, payeeEmail = currentUserEmail, - receipt?: Receipt, - existingTransactionID?: string, - category?: string, - tag?: string, - billable?: boolean, - policy?: OnyxTypes.Policy | EmptyObject, - policyTags?: OnyxTypes.PolicyTags, - policyCategories?: OnyxTypes.PolicyCategories, ): MoneyRequestInformation { const payerEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login ?? ''); const payerAccountID = Number(participant.accountID); @@ -920,8 +920,6 @@ function createDistanceRequest( currency, created, merchant, - userAccountID, - currentUserEmail, optimisticReceipt, undefined, category, @@ -930,6 +928,8 @@ function createDistanceRequest( policy, policyTags, policyCategories, + userAccountID, + currentUserEmail, ); type CreateDistanceRequestParams = { @@ -1244,8 +1244,6 @@ function requestMoney( currency, created, merchant, - payeeAccountID, - payeeEmail, receipt, undefined, category, @@ -1254,6 +1252,8 @@ function requestMoney( policy, policyTags, policyCategories, + payeeAccountID, + payeeEmail, ); const activeReportID = isMoneyRequestReport ? report.reportID : chatReport.reportID; From 7e7d69752bf13a4a2eebf46a9ecfbcb7fd75816b Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 16 Jan 2024 11:26:03 +0100 Subject: [PATCH 46/68] Migrate to TS new parts of the code --- src/libs/actions/IOU.ts | 44 +++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 14e2b2ecff19..9bf65b5c8891 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1089,28 +1089,26 @@ function getUpdateMoneyRequestParams( }, }); - if (isScanning && (_.has(transactionChanges, 'amount') || _.has(transactionChanges, 'currency'))) { + if (isScanning && ('amount' in transactionChanges || 'currency' in transactionChanges)) { optimisticData.push( - ...[ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`, - value: { - [transactionThread.parentReportActionID]: { - whisperedToAccountIDs: [], - }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.reportID}`, + value: { + [transactionThread?.parentReportActionID ?? '']: { + whisperedToAccountIDs: [], }, }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.parentReportID}`, - value: { - [iouReport.parentReportActionID]: { - whisperedToAccountIDs: [], - }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.parentReportID}`, + value: { + [iouReport?.parentReportActionID ?? '']: { + whisperedToAccountIDs: [], }, }, - ], + }, ); } @@ -1227,15 +1225,9 @@ function updateMoneyRequestTag(transactionID: string, transactionThreadReportID: API.write('UpdateMoneyRequestTag', params, onyxData); } -/** - * Updates the description of a money request - * - * @param {String} transactionID - * @param {Number} transactionThreadReportID - * @param {String} comment - */ -function updateMoneyRequestDescription(transactionID, transactionThreadReportID, comment) { - const transactionChanges = { +/** Updates the description of a money request */ +function updateMoneyRequestDescription(transactionID: string, transactionThreadReportID: string, comment: string) { + const transactionChanges: TransactionChanges = { comment, }; const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true); From ff6fc296d10ae2a8c800de76fd93464f7f5ece61 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 16 Jan 2024 15:59:41 +0100 Subject: [PATCH 47/68] Minor code improvements --- src/libs/actions/IOU.ts | 58 ++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 9bf65b5c8891..40a51de1ba7d 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -131,14 +131,14 @@ type SendMoneyParamsData = { let betas: OnyxTypes.Beta[] = []; Onyx.connect({ key: ONYXKEYS.BETAS, - callback: (val) => (betas = val ?? []), + callback: (value) => (betas = value ?? []), }); let allPersonalDetails: OnyxTypes.PersonalDetailsList = {}; Onyx.connect({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, - callback: (val) => { - allPersonalDetails = val ?? {}; + callback: (value) => { + allPersonalDetails = value ?? {}; }, }); @@ -146,20 +146,20 @@ let allReports: OnyxCollection = null; Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT, waitForCollectionCallback: true, - callback: (val) => (allReports = val), + callback: (value) => (allReports = value), }); let allTransactions: NonNullable> = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.TRANSACTION, waitForCollectionCallback: true, - callback: (val) => { - if (!val) { + callback: (value) => { + if (!value) { allTransactions = {}; return; } - allTransactions = val; + allTransactions = value; }, }); @@ -167,8 +167,8 @@ let allTransactionDrafts: NonNullable> = { Onyx.connect({ key: ONYXKEYS.COLLECTION.TRANSACTION_DRAFT, waitForCollectionCallback: true, - callback: (val) => { - allTransactionDrafts = val ?? {}; + callback: (value) => { + allTransactionDrafts = value ?? {}; }, }); @@ -176,13 +176,13 @@ let allTransactionViolations: NonNullable { - if (!val) { + callback: (value) => { + if (!value) { allTransactionViolations = {}; return; } - allTransactionViolations = val; + allTransactionViolations = value; }, }); @@ -190,8 +190,8 @@ let allDraftSplitTransactions: NonNullable Onyx.connect({ key: ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT, waitForCollectionCallback: true, - callback: (val) => { - allDraftSplitTransactions = val ?? {}; + callback: (value) => { + allDraftSplitTransactions = value ?? {}; }, }); @@ -199,8 +199,8 @@ let allNextSteps: NonNullable> = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.NEXT_STEP, waitForCollectionCallback: true, - callback: (val) => { - allNextSteps = val ?? {}; + callback: (value) => { + allNextSteps = value ?? {}; }, }); @@ -208,25 +208,25 @@ let userAccountID = -1; let currentUserEmail = ''; Onyx.connect({ key: ONYXKEYS.SESSION, - callback: (val) => { - currentUserEmail = val?.email ?? ''; - userAccountID = val?.accountID ?? -1; + callback: (value) => { + currentUserEmail = value?.email ?? ''; + userAccountID = value?.accountID ?? -1; }, }); let currentUserPersonalDetails: OnyxTypes.PersonalDetails | EmptyObject = {}; Onyx.connect({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, - callback: (val) => { - currentUserPersonalDetails = val?.[userAccountID] ?? {}; + callback: (value) => { + currentUserPersonalDetails = value?.[userAccountID] ?? {}; }, }); let currentDate: OnyxEntry = ''; Onyx.connect({ key: ONYXKEYS.CURRENT_DATE, - callback: (val) => { - currentDate = val; + callback: (value) => { + currentDate = value; }, }); @@ -1190,27 +1190,27 @@ function getUpdateMoneyRequestParams( /** * Updates the created date of a money request */ -function updateMoneyRequestDate(transactionID: string, transactionThreadReportID: string, val: string) { +function updateMoneyRequestDate(transactionID: string, transactionThreadReportID: string, value: string) { const transactionChanges: TransactionChanges = { - created: val, + created: value, }; const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true); API.write('UpdateMoneyRequestDate', params, onyxData); } /** Updates the billable field of a money request */ -function updateMoneyRequestBillable(transactionID: string, transactionThreadReportID: string, val: boolean) { +function updateMoneyRequestBillable(transactionID: string, transactionThreadReportID: string, value: boolean) { const transactionChanges: TransactionChanges = { - billable: val, + billable: value, }; const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true); API.write('UpdateMoneyRequestBillable', params, onyxData); } /** Updates the merchant field of a money request */ -function updateMoneyRequestMerchant(transactionID: string, transactionThreadReportID: string, val: string) { +function updateMoneyRequestMerchant(transactionID: string, transactionThreadReportID: string, value: string) { const transactionChanges: TransactionChanges = { - merchant: val, + merchant: value, }; const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true); API.write('UpdateMoneyRequestMerchant', params, onyxData); From 12970726137467b155756e1aa942e7ef112d0c92 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Wed, 17 Jan 2024 08:29:22 +0100 Subject: [PATCH 48/68] TS fixes after merging main --- .../home/report/ContextMenu/PopoverReportActionContextMenu.tsx | 2 +- src/types/onyx/Report.ts | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx index 46b783bca3f9..728baca6f425 100644 --- a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx @@ -237,7 +237,7 @@ function PopoverReportActionContextMenu(_props: never, ref: ForwardedRef (onComfirmDeleteModal.current = runAndResetCallback(onComfirmDeleteModal.current)); const reportAction = reportActionRef.current; if (ReportActionsUtils.isMoneyRequestAction(reportAction) && reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) { - IOU.deleteMoneyRequest(reportAction?.originalMessage?.IOUTransactionID, reportAction); + IOU.deleteMoneyRequest(reportAction?.originalMessage?.IOUTransactionID ?? '', reportAction); } else if (reportAction) { Report.deleteReportComment(reportIDRef.current, reportAction); } diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts index cd0f339382ce..57a36be1d99a 100644 --- a/src/types/onyx/Report.ts +++ b/src/types/onyx/Report.ts @@ -104,9 +104,6 @@ type Report = { /** The report visibility */ visibility?: ValueOf; - /** Whether the report has outstanding IOU */ - hasOutstandingIOU?: boolean; - /** Report cached total */ cachedTotal?: string; From 1621e4bf61dad08d35629265fdea5ac92c9ea3dd Mon Sep 17 00:00:00 2001 From: VickyStash Date: Wed, 17 Jan 2024 16:10:46 +0100 Subject: [PATCH 49/68] Reuse existing types instead of creating new one --- src/libs/ErrorUtils.ts | 4 ++-- src/libs/ReportActionsUtils.ts | 8 +++----- src/libs/actions/IOU.ts | 4 ++-- src/types/onyx/OnyxCommon.ts | 4 +--- src/types/onyx/ReportAction.ts | 2 +- 5 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/libs/ErrorUtils.ts b/src/libs/ErrorUtils.ts index 6c1540ccaa55..e985ab5fab64 100644 --- a/src/libs/ErrorUtils.ts +++ b/src/libs/ErrorUtils.ts @@ -1,6 +1,6 @@ import CONST from '@src/CONST'; import type {TranslationFlatObject, TranslationPaths} from '@src/languages/types'; -import type {ErrorFields, Errors, ErrorsObject} from '@src/types/onyx/OnyxCommon'; +import type {ErrorFields, Errors} from '@src/types/onyx/OnyxCommon'; import type Response from '@src/types/onyx/Response'; import DateUtils from './DateUtils'; import * as Localize from './Localize'; @@ -46,7 +46,7 @@ function getMicroSecondOnyxError(error: string | null): Errors { * Method used to get an error object with microsecond as the key and an object as the value. * @param error - error key or message to be saved */ -function getMicroSecondOnyxErrorObject(error: Errors): ErrorsObject { +function getMicroSecondOnyxErrorObject(error: Errors): ErrorFields { return {[DateUtils.getMicroseconds()]: error}; } diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 4d7424843d41..6668e3ac628e 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -39,8 +39,6 @@ type MemberChangeMessageRoomReferenceElement = { type MemberChangeMessageElement = MessageTextElement | MemberChangeMessageUserMentionElement | MemberChangeMessageRoomReferenceElement; -type ActionsToMerge = Record; - const allReports: OnyxCollection = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT, @@ -444,8 +442,8 @@ function replaceBaseURL(reportAction: ReportAction): ReportAction { /** */ -function getLastVisibleAction(reportID: string, actionsToMerge: ActionsToMerge = {}): OnyxEntry { - const reportActions = Object.values(OnyxUtils.fastMerge(allReportActions?.[reportID] ?? {}, actionsToMerge)); +function getLastVisibleAction(reportID: string, actionsToMerge: OnyxCollection = {}): OnyxEntry { + const reportActions = Object.values(OnyxUtils.fastMerge(allReportActions?.[reportID] ?? {}, actionsToMerge ?? {})); const visibleReportActions = Object.values(reportActions ?? {}).filter((action): action is ReportAction => shouldReportActionBeVisibleAsLastAction(action)); const sortedReportActions = getSortedReportActions(visibleReportActions, true); if (sortedReportActions.length === 0) { @@ -454,7 +452,7 @@ function getLastVisibleAction(reportID: string, actionsToMerge: ActionsToMerge = return sortedReportActions[0]; } -function getLastVisibleMessage(reportID: string, actionsToMerge: ActionsToMerge = {}): LastVisibleMessage { +function getLastVisibleMessage(reportID: string, actionsToMerge: OnyxCollection = {}): LastVisibleMessage { const lastVisibleAction = getLastVisibleAction(reportID, actionsToMerge); const message = lastVisibleAction?.message?.[0]; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index f0c54ec7ea9b..5dee77d31b47 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -31,7 +31,7 @@ import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; import type {Participant, Split} from '@src/types/onyx/IOU'; -import type {Errors, ErrorsObject} from '@src/types/onyx/OnyxCommon'; +import type {ErrorFields, Errors} from '@src/types/onyx/OnyxCommon'; import type ReportAction from '@src/types/onyx/ReportAction'; import type {OnyxData} from '@src/types/onyx/Request'; import type {Comment, Receipt, TaxRate, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; @@ -361,7 +361,7 @@ function resetMoneyRequestInfo(id = '') { /** * Helper function to get the receipt error for money requests, or the generic error if there's no receipt */ -function getReceiptError(receipt?: Receipt, filename?: string, isScanRequest = true): Errors | ErrorsObject { +function getReceiptError(receipt?: Receipt, filename?: string, isScanRequest = true): Errors | ErrorFields { return isEmptyObject(receipt) || !isScanRequest ? ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage') : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: receipt.source ?? '', filename: filename ?? ''}); diff --git a/src/types/onyx/OnyxCommon.ts b/src/types/onyx/OnyxCommon.ts index cff72ed94e10..27c90cca2753 100644 --- a/src/types/onyx/OnyxCommon.ts +++ b/src/types/onyx/OnyxCommon.ts @@ -10,8 +10,6 @@ type ErrorFields = Record; -type ErrorsObject = Record; - type AvatarType = typeof CONST.ICON_TYPE_AVATAR | typeof CONST.ICON_TYPE_WORKSPACE; type Icon = { @@ -31,4 +29,4 @@ type Icon = { fallbackIcon?: AvatarSource; }; -export type {Icon, PendingAction, PendingFields, ErrorFields, Errors, AvatarType, ErrorsObject}; +export type {Icon, PendingAction, PendingFields, ErrorFields, Errors, AvatarType}; diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts index cfa85b6b174c..c6f19c0bf93f 100644 --- a/src/types/onyx/ReportAction.ts +++ b/src/types/onyx/ReportAction.ts @@ -187,7 +187,7 @@ type ReportActionBase = { delegateAccountID?: string; /** Server side errors keyed by microtime */ - errors?: OnyxCommon.Errors | OnyxCommon.ErrorsObject; + errors?: OnyxCommon.Errors | OnyxCommon.ErrorFields; /** Whether the report action is attachment */ isAttachment?: boolean; From 5e48ce9169df7d03e903e9bc65ff3d2d067a4778 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Wed, 17 Jan 2024 16:34:54 +0100 Subject: [PATCH 50/68] Code improvements --- src/libs/ViolationsUtils.ts | 6 +++--- src/libs/actions/IOU.ts | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libs/ViolationsUtils.ts b/src/libs/ViolationsUtils.ts index d014030c7b3e..ef277549dfaf 100644 --- a/src/libs/ViolationsUtils.ts +++ b/src/libs/ViolationsUtils.ts @@ -24,7 +24,7 @@ const ViolationsUtils = { if (policyRequiresCategories) { const hasCategoryOutOfPolicyViolation = transactionViolations.some((violation) => violation.name === 'categoryOutOfPolicy'); const hasMissingCategoryViolation = transactionViolations.some((violation) => violation.name === 'missingCategory'); - const isCategoryInPolicy = Boolean(policyCategories[transaction.category ?? '']?.enabled); + const isCategoryInPolicy = !!policyCategories[transaction.category ?? '']?.enabled; // Add 'categoryOutOfPolicy' violation if category is not in policy if (!hasCategoryOutOfPolicyViolation && transaction.category && !isCategoryInPolicy) { @@ -50,7 +50,7 @@ const ViolationsUtils = { if (policyRequiresTags) { const hasTagOutOfPolicyViolation = transactionViolations.some((violation) => violation.name === 'tagOutOfPolicy'); const hasMissingTagViolation = transactionViolations.some((violation) => violation.name === 'missingTag'); - const isTagInPolicy = Boolean(policyTags[transaction.tag ?? '']?.enabled); + const isTagInPolicy = !!policyTags[transaction.tag ?? '']?.enabled; // Add 'tagOutOfPolicy' violation if tag is not in policy if (!hasTagOutOfPolicyViolation && transaction.tag && !isTagInPolicy) { @@ -152,7 +152,7 @@ const ViolationsUtils = { brokenBankConnection: violation.data?.brokenBankConnection ?? false, isAdmin: violation.data?.isAdmin ?? false, email: violation.data?.email, - isTransactionOlderThan7Days: Boolean(violation.data?.isTransactionOlderThan7Days), + isTransactionOlderThan7Days: !!violation.data?.isTransactionOlderThan7Days, member: violation.data?.member, }); case 'smartscanFailed': diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 5dee77d31b47..f0f9c3f39651 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -472,7 +472,7 @@ function buildOnyxDataForMoneyRequest( }); } - if (Object.keys(optimisticPolicyRecentlyUsedTags).length) { + if (!isEmptyObject(optimisticPolicyRecentlyUsedTags)) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${iouReport.policyID}`, @@ -480,7 +480,7 @@ function buildOnyxDataForMoneyRequest( }); } - if (optimisticPersonalDetailListAction && Object.keys(optimisticPersonalDetailListAction).length) { + if (!isEmptyObject(optimisticPersonalDetailListAction)) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, @@ -1377,7 +1377,7 @@ function createSplitsAndOnyxData( ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${existingSplitChatReportID || participants[0].reportID}`] : ReportUtils.getChatByParticipants(participantAccountIDs); const splitChatReport = existingSplitChatReport ?? ReportUtils.buildOptimisticChatReport(participantAccountIDs); - const isOwnPolicyExpenseChat = splitChatReport.isOwnPolicyExpenseChat; + const isOwnPolicyExpenseChat = !!splitChatReport.isOwnPolicyExpenseChat; const splitTransaction = TransactionUtils.buildOptimisticTransaction( amount, @@ -1542,8 +1542,8 @@ 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 ? '' : OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login ?? '').toLowerCase(); - const accountID = !!isOwnPolicyExpenseChat || isPolicyExpenseChat ? 0 : Number(participant.accountID); + const email = isOwnPolicyExpenseChat || isPolicyExpenseChat ? '' : OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login ?? '').toLowerCase(); + const accountID = isOwnPolicyExpenseChat || isPolicyExpenseChat ? 0 : Number(participant.accountID); if (email === currentUserEmailForIOUSplit) { return; } @@ -1678,7 +1678,7 @@ function createSplitsAndOnyxData( optimisticPolicyRecentlyUsedCategories, optimisticPolicyRecentlyUsedTags, isNewOneOnOneChatReport, - !!shouldCreateNewOneOnOneIOUReport, + shouldCreateNewOneOnOneIOUReport, ); const individualSplit = { From c218af52030a491f4563f239053e99a4eb076dca Mon Sep 17 00:00:00 2001 From: VickyStash Date: Wed, 17 Jan 2024 16:44:54 +0100 Subject: [PATCH 51/68] Update comments to go in one line --- src/libs/actions/IOU.ts | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index f0f9c3f39651..e06a4423ffb2 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -333,9 +333,7 @@ function setMoneyRequestReceipt(transactionID: string, source: string, filename: }); } -/** - * Reset money request info from the store with its initial value - */ +/** Reset money request info from the store with its initial value */ function resetMoneyRequestInfo(id = '') { // Disabling this line since currentDate can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing @@ -358,9 +356,7 @@ function resetMoneyRequestInfo(id = '') { }); } -/** - * Helper function to get the receipt error for money requests, or the generic error if there's no receipt - */ +/** Helper function to get the receipt error for money requests, or the generic error if there's no receipt */ function getReceiptError(receipt?: Receipt, filename?: string, isScanRequest = true): Errors | ErrorFields { return isEmptyObject(receipt) || !isScanRequest ? ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage') @@ -1187,9 +1183,7 @@ function getUpdateMoneyRequestParams( }; } -/** - * Updates the created date of a money request - */ +/** Updates the created date of a money request */ function updateMoneyRequestDate(transactionID: string, transactionThreadReportID: string, value: string) { const transactionChanges: TransactionChanges = { created: value, @@ -1242,7 +1236,6 @@ function updateDistanceRequest(transactionID: string, transactionThreadReportID: /** * Request money from another user - * * @param amount - always in the smallest unit of the currency */ function requestMoney( @@ -2599,9 +2592,7 @@ function editMoneyRequest(transaction: OnyxTypes.Transaction, transactionThreadR } } -/** - * Updates the amount and currency fields of a money request - */ +/** Updates the amount and currency fields of a money request */ function updateMoneyRequestAmountAndCurrency(transactionID: string, transactionThreadReportID: string, currency: string, amount: number) { const transactionChanges = { amount, @@ -3695,9 +3686,7 @@ function setMoneyRequestParticipantsFromReport(transactionID: string, report: On Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {participants, participantsAutoAssigned: true}); } -/** - * Initialize money request info and navigate to the MoneyRequest page - */ +/** Initialize money request info and navigate to the MoneyRequest page */ function startMoneyRequest(iouType: string, reportID = '') { resetMoneyRequestInfo(`${iouType}${reportID}`); Navigation.navigate(ROUTES.MONEY_REQUEST.getRoute(iouType, reportID)); @@ -3768,9 +3757,7 @@ function setUpDistanceTransaction() { Onyx.merge(ONYXKEYS.IOU, {transactionID}); } -/** - * Navigates to the next IOU page based on where the IOU request was started - */ +/** Navigates to the next IOU page based on where the IOU request was started */ function navigateToNextPage(iou: OnyxEntry, iouType: string, report?: OnyxTypes.Report, path = '') { const moneyRequestID = `${iouType}${report?.reportID ?? ''}`; const shouldReset = iou?.id !== moneyRequestID && !!report?.reportID; From 7043ef4d5de0fc4238417b38d591541e5dc7e95d Mon Sep 17 00:00:00 2001 From: VickyStash Date: Wed, 17 Jan 2024 17:00:35 +0100 Subject: [PATCH 52/68] Remove not necessary anymore TODO --- src/components/MoneyReportHeader.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index a712438bb07c..2795267a9f02 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -69,7 +69,6 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, nextSt const [isConfirmModalVisible, setIsConfirmModalVisible] = useState(false); const cancelPayment = useCallback(() => { - // @ts-expect-error TODO: Remove this once IOU (https://github.com/Expensify/App/issues/24926) is migrated to TypeScript. IOU.cancelPayment(moneyRequestReport, chatReport); setIsConfirmModalVisible(false); }, [moneyRequestReport, chatReport]); From c8afe1949168742dd43aef6399dcd10d301a9216 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Wed, 17 Jan 2024 18:05:34 +0100 Subject: [PATCH 53/68] Update Receipt source type, turn MERGE into SET --- src/libs/ErrorUtils.ts | 2 +- src/libs/ReceiptUtils.ts | 2 +- src/libs/ValidationUtils.ts | 2 +- src/libs/actions/IOU.ts | 12 ++++++------ src/types/onyx/OnyxCommon.ts | 2 +- src/types/onyx/Transaction.ts | 6 ++++-- 6 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/libs/ErrorUtils.ts b/src/libs/ErrorUtils.ts index e985ab5fab64..fe7d65d72c6c 100644 --- a/src/libs/ErrorUtils.ts +++ b/src/libs/ErrorUtils.ts @@ -54,7 +54,7 @@ type OnyxDataWithErrors = { errors?: Errors; }; -function getLatestErrorMessage(onyxData: TOnyxData): string | null { +function getLatestErrorMessage(onyxData: TOnyxData): string | number | null { const errors = onyxData.errors ?? {}; if (Object.keys(errors).length === 0) { diff --git a/src/libs/ReceiptUtils.ts b/src/libs/ReceiptUtils.ts index bcba68a3a0bd..a44fe39f5b31 100644 --- a/src/libs/ReceiptUtils.ts +++ b/src/libs/ReceiptUtils.ts @@ -43,7 +43,7 @@ function getThumbnailAndImageURIs(transaction: Transaction, receiptPath: string } // For local files, we won't have a thumbnail yet - if (isReceiptImage && (path.startsWith('blob:') || path.startsWith('file:'))) { + if (isReceiptImage && typeof path === 'string' && (path.startsWith('blob:') || path.startsWith('file:'))) { return {thumbnail: null, image: path, isLocalFile: true}; } diff --git a/src/libs/ValidationUtils.ts b/src/libs/ValidationUtils.ts index 444c2618ee1b..fa04176f93f8 100644 --- a/src/libs/ValidationUtils.ts +++ b/src/libs/ValidationUtils.ts @@ -73,7 +73,7 @@ function isValidPastDate(date: string | Date): boolean { /** * Used to validate a value that is "required". */ -function isRequiredFulfilled(value: string | Date | unknown[] | Record | null): boolean { +function isRequiredFulfilled(value: string | number | Date | unknown[] | Record | null): boolean { if (typeof value === 'string') { return !StringUtils.isEmptyString(value); } diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index e06a4423ffb2..31ed4ecb90fb 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -34,7 +34,7 @@ import type {Participant, Split} from '@src/types/onyx/IOU'; import type {ErrorFields, Errors} from '@src/types/onyx/OnyxCommon'; import type ReportAction from '@src/types/onyx/ReportAction'; import type {OnyxData} from '@src/types/onyx/Request'; -import type {Comment, Receipt, TaxRate, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; +import type {Comment, Receipt, ReceiptSource, TaxRate, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; import type DeepValueOf from '@src/types/utils/DeepValueOf'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -905,7 +905,7 @@ function createDistanceRequest( const currentChatReport = isMoneyRequestReport ? ReportUtils.getReport(report.chatReportID) : report; const optimisticReceipt: Receipt = { - source: ReceiptGeneric as string, + source: ReceiptGeneric as ReceiptSource, state: CONST.IOU.RECEIPT_STATE.OPEN, }; const {iouReport, chatReport, transaction, iouAction, createdChatReportActionID, createdIOUReportActionID, reportPreviewAction, onyxData} = getMoneyRequestInformation( @@ -1462,9 +1462,9 @@ function createSplitsAndOnyxData( value: {pendingAction: null}, }, { - onyxMethod: Onyx.METHOD.MERGE, + onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`, - value: {}, + value: null, }, ]; @@ -1485,9 +1485,9 @@ function createSplitsAndOnyxData( }, }, { - onyxMethod: Onyx.METHOD.MERGE, + onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`, - value: {}, + value: null, }, ]; diff --git a/src/types/onyx/OnyxCommon.ts b/src/types/onyx/OnyxCommon.ts index 27c90cca2753..15e40173e185 100644 --- a/src/types/onyx/OnyxCommon.ts +++ b/src/types/onyx/OnyxCommon.ts @@ -8,7 +8,7 @@ type PendingFields = Record = Record; -type Errors = Record; +type Errors = Record; type AvatarType = typeof CONST.ICON_TYPE_AVATAR | typeof CONST.ICON_TYPE_WORKSPACE; diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 7117158216e4..56dfdc2e5c26 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -38,11 +38,13 @@ type Geometry = { type?: GeometryType; }; +type ReceiptSource = string | number; + type Receipt = { receiptID?: number; path?: string; name?: string; - source?: string; + source?: ReceiptSource; filename?: string; state?: ValueOf; }; @@ -200,4 +202,4 @@ type AdditionalTransactionChanges = { type TransactionChanges = Partial & AdditionalTransactionChanges; export default Transaction; -export type {WaypointCollection, Comment, Receipt, Waypoint, TransactionChanges, TaxRate}; +export type {WaypointCollection, Comment, Receipt, Waypoint, TransactionChanges, TaxRate, ReceiptSource}; From 9ba4d4060f2fde956e4bc1662c534c6be70d969b Mon Sep 17 00:00:00 2001 From: VickyStash Date: Thu, 18 Jan 2024 09:20:53 +0100 Subject: [PATCH 54/68] Remove unnecessary TODOs from IOU file --- src/libs/actions/IOU.ts | 44 +++++++++----------------------------- src/libs/actions/Policy.ts | 4 ++-- 2 files changed, 12 insertions(+), 36 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index b94400d9de92..ad86a6cc9e52 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -41,12 +41,6 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; import * as Report from './Report'; -// TODO: Remove this once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. -type OptimisticPolicyRecentlyUsedCategories = string[]; - -// TODO: Remove this once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. -type OptimisticPolicyRecentlyUsedTags = Record; - type MoneyRequestRoute = StackScreenProps< MoneyRequestNavigatorParamList, typeof SCREENS.MONEY_REQUEST.CATEGORY | typeof SCREENS.MONEY_REQUEST.TAG | typeof SCREENS.MONEY_REQUEST.CONFIRMATION @@ -373,8 +367,8 @@ function buildOnyxDataForMoneyRequest( iouAction: OptimisticIOUReportAction, optimisticPersonalDetailListAction: OnyxTypes.PersonalDetailsList, reportPreviewAction: ReportAction, - optimisticPolicyRecentlyUsedCategories: OptimisticPolicyRecentlyUsedCategories, - optimisticPolicyRecentlyUsedTags: OptimisticPolicyRecentlyUsedTags, + optimisticPolicyRecentlyUsedCategories: string[], + optimisticPolicyRecentlyUsedTags: OnyxTypes.RecentlyUsedTags, isNewChatReport: boolean, isNewIOUReport: boolean, policy?: OnyxTypes.Policy | EmptyObject, @@ -773,11 +767,9 @@ function getMoneyRequestInformation( billable, ); - // TODO: Remove assertion once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. - const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, category) as OptimisticPolicyRecentlyUsedCategories; + const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, category); - // TODO: Remove assertion once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. - const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport.policyID, tag) as OptimisticPolicyRecentlyUsedTags; + const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport.policyID, tag); // 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 @@ -1110,11 +1102,7 @@ function getUpdateMoneyRequestParams( // Update recently used categories if the category is changed if ('category' in transactionChanges) { - // TODO: Remove assertion once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. - const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories( - iouReport?.policyID, - transactionChanges.category, - ) as OptimisticPolicyRecentlyUsedCategories; + const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport?.policyID, transactionChanges.category); if (optimisticPolicyRecentlyUsedCategories.length) { optimisticData.push({ onyxMethod: Onyx.METHOD.SET, @@ -1126,8 +1114,7 @@ function getUpdateMoneyRequestParams( // Update recently used categories if the tag is changed if ('tag' in transactionChanges) { - // TODO: Remove assertion once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. - const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport?.policyID, transactionChanges.tag) as OptimisticPolicyRecentlyUsedTags; + const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport?.policyID, transactionChanges.tag); if (!isEmptyObject(optimisticPolicyRecentlyUsedTags)) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, @@ -1647,16 +1634,10 @@ function createSplitsAndOnyxData( } // Add category to optimistic policy recently used categories when a participant is a workspace - const optimisticPolicyRecentlyUsedCategories = isPolicyExpenseChat - ? // TODO: Remove assertion once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. - (Policy.buildOptimisticPolicyRecentlyUsedCategories(participant.policyID, category) as OptimisticPolicyRecentlyUsedCategories) - : []; + const optimisticPolicyRecentlyUsedCategories = isPolicyExpenseChat ? Policy.buildOptimisticPolicyRecentlyUsedCategories(participant.policyID, category) : []; // Add tag to optimistic policy recently used tags when a participant is a workspace - const optimisticPolicyRecentlyUsedTags = isPolicyExpenseChat - ? // TODO: Remove assertion once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. - (Policy.buildOptimisticPolicyRecentlyUsedTags(participant.policyID, tag) as OptimisticPolicyRecentlyUsedTags) - : {}; + const optimisticPolicyRecentlyUsedTags = isPolicyExpenseChat ? Policy.buildOptimisticPolicyRecentlyUsedTags(participant.policyID, tag) : {}; // STEP 5: Build Onyx Data const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest( @@ -2448,11 +2429,7 @@ function editRegularMoneyRequest(transactionID: string, transactionThreadReportI // Update recently used categories if the category is changed if ('category' in transactionChanges) { - // TODO: Remove assertion once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. - const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories( - iouReport?.policyID, - transactionChanges.category, - ) as OptimisticPolicyRecentlyUsedCategories; + const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport?.policyID, transactionChanges.category); if (optimisticPolicyRecentlyUsedCategories.length) { optimisticData.push({ onyxMethod: Onyx.METHOD.SET, @@ -2464,8 +2441,7 @@ function editRegularMoneyRequest(transactionID: string, transactionThreadReportI // Update recently used categories if the tag is changed if ('tag' in transactionChanges) { - // TODO: Remove assertion once Policy.js (https://github.com/Expensify/App/issues/24918) is migrated to TypeScript. - const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport?.policyID, transactionChanges.tag) as OptimisticPolicyRecentlyUsedTags; + const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport?.policyID, transactionChanges.tag); if (!isEmptyObject(optimisticPolicyRecentlyUsedTags)) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 263d5fb68529..6357476126c1 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -1556,7 +1556,7 @@ function dismissAddedWithPrimaryLoginMessages(policyID: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {primaryLoginsInvited: null}); } -function buildOptimisticPolicyRecentlyUsedCategories(policyID: string, category: string) { +function buildOptimisticPolicyRecentlyUsedCategories(policyID?: string, category?: string) { if (!policyID || !category) { return []; } @@ -1566,7 +1566,7 @@ function buildOptimisticPolicyRecentlyUsedCategories(policyID: string, category: return lodashUnion([category], policyRecentlyUsedCategories); } -function buildOptimisticPolicyRecentlyUsedTags(policyID: string, tag: string): RecentlyUsedTags { +function buildOptimisticPolicyRecentlyUsedTags(policyID?: string, tag?: string): RecentlyUsedTags { if (!policyID || !tag) { return {}; } From 0b5eccdaf9c92fcbba6734c2da34893049e239aa Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 22 Jan 2024 11:12:43 +0100 Subject: [PATCH 55/68] Minor code improvements --- src/ONYXKEYS.ts | 1 - src/libs/actions/IOU.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 7fd7af0393d8..e1f356bd383f 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -460,7 +460,6 @@ type OnyxValues = { [ONYXKEYS.COLLECTION.TRANSACTION]: OnyxTypes.Transaction; [ONYXKEYS.COLLECTION.TRANSACTION_DRAFT]: OnyxTypes.Transaction; [ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT]: OnyxTypes.Transaction; - [ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS]: OnyxTypes.TransactionViolations; [ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS]: OnyxTypes.RecentlyUsedTags; [ONYXKEYS.COLLECTION.SELECTED_TAB]: string; [ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS]: OnyxTypes.TransactionViolations; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 6c5b64cbcc14..9eb1b628fa21 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -3203,7 +3203,7 @@ function getPayMoneyRequestParams(chatReport: OnyxTypes.Report, iouReport: OnyxT }, ]; - if (currentNextStep !== null) { + if (currentNextStep) { optimisticData.push({ onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${iouReport.reportID}`, From 74eb19989385ead4d84568062c89b54134e643a1 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 23 Jan 2024 11:35:38 +0100 Subject: [PATCH 56/68] Fix TS issues in the new part of code --- src/libs/actions/IOU.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 00bcc44c1ef0..2f283609fa96 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -2037,7 +2037,7 @@ function startSplitBill( }); }); - _.each(participants, (participant) => { + participants.forEach((participant) => { const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(participant); if (!isPolicyExpenseChat) { return; @@ -2046,7 +2046,7 @@ function startSplitBill( const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(participant.policyID, category); const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(participant.policyID, tag); - if (!_.isEmpty(optimisticPolicyRecentlyUsedCategories)) { + if (optimisticPolicyRecentlyUsedCategories.length > 0) { optimisticData.push({ onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${participant.policyID}`, @@ -2054,7 +2054,7 @@ function startSplitBill( }); } - if (!_.isEmpty(optimisticPolicyRecentlyUsedTags)) { + if (!isEmptyObject(optimisticPolicyRecentlyUsedTags)) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${participant.policyID}`, @@ -3499,7 +3499,7 @@ function submitReport(expenseReport: OnyxTypes.Report) { const parameters: SubmitReportParams = { reportID: expenseReport.reportID, - managerAccountID: policy.submitsTo || expenseReport.managerID, + managerAccountID: policy.submitsTo ?? expenseReport.managerID, reportActionID: optimisticSubmittedReportAction.reportActionID, }; From 4be927fb1d0811d50e98ce4ae5c8510d79b16037 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 29 Jan 2024 12:10:14 +0100 Subject: [PATCH 57/68] Migrate new functions to TS, move api typing to api folder --- .../parameters/ApproveMoneyRequestParams.ts | 6 + .../API/parameters/CompleteSplitBillParams.ts | 13 + .../parameters/CreateDistanceRequestParams.ts | 17 ++ .../parameters/DeleteMoneyRequestParams.ts | 6 + .../API/parameters/DetachReceiptParams.ts | 5 + .../API/parameters/EditMoneyRequestParams.ts | 14 + .../API/parameters/PayMoneyRequestParams.ts | 11 + .../API/parameters/ReplaceReceiptParams.ts | 6 + src/libs/API/parameters/RequestMoneyParams.ts | 29 ++ src/libs/API/parameters/SendMoneyParams.ts | 15 + src/libs/API/parameters/SplitBillParams.ts | 16 ++ .../API/parameters/StartSplitBillParams.ts | 16 ++ src/libs/API/parameters/SubmitReportParams.ts | 7 + .../parameters/UpdateMoneyRequestParams.ts | 9 + src/libs/API/parameters/index.ts | 14 + src/libs/API/types.ts | 50 ++++ src/libs/PolicyUtils.ts | 2 +- src/libs/ReportUtils.ts | 4 +- src/libs/actions/IOU.ts | 265 +++++------------- 19 files changed, 301 insertions(+), 204 deletions(-) create mode 100644 src/libs/API/parameters/ApproveMoneyRequestParams.ts create mode 100644 src/libs/API/parameters/CompleteSplitBillParams.ts create mode 100644 src/libs/API/parameters/CreateDistanceRequestParams.ts create mode 100644 src/libs/API/parameters/DeleteMoneyRequestParams.ts create mode 100644 src/libs/API/parameters/DetachReceiptParams.ts create mode 100644 src/libs/API/parameters/EditMoneyRequestParams.ts create mode 100644 src/libs/API/parameters/PayMoneyRequestParams.ts create mode 100644 src/libs/API/parameters/ReplaceReceiptParams.ts create mode 100644 src/libs/API/parameters/RequestMoneyParams.ts create mode 100644 src/libs/API/parameters/SendMoneyParams.ts create mode 100644 src/libs/API/parameters/SplitBillParams.ts create mode 100644 src/libs/API/parameters/StartSplitBillParams.ts create mode 100644 src/libs/API/parameters/SubmitReportParams.ts create mode 100644 src/libs/API/parameters/UpdateMoneyRequestParams.ts diff --git a/src/libs/API/parameters/ApproveMoneyRequestParams.ts b/src/libs/API/parameters/ApproveMoneyRequestParams.ts new file mode 100644 index 000000000000..f35ff31702d6 --- /dev/null +++ b/src/libs/API/parameters/ApproveMoneyRequestParams.ts @@ -0,0 +1,6 @@ +type ApproveMoneyRequestParams = { + reportID: string; + approvedReportActionID: string; +}; + +export default ApproveMoneyRequestParams; diff --git a/src/libs/API/parameters/CompleteSplitBillParams.ts b/src/libs/API/parameters/CompleteSplitBillParams.ts new file mode 100644 index 000000000000..50054ba6fd10 --- /dev/null +++ b/src/libs/API/parameters/CompleteSplitBillParams.ts @@ -0,0 +1,13 @@ +type CompleteSplitBillParams = { + transactionID: string; + amount?: number; + currency?: string; + created?: string; + merchant?: string; + comment?: string; + category?: string; + tag?: string; + splits: string; +}; + +export default CompleteSplitBillParams; diff --git a/src/libs/API/parameters/CreateDistanceRequestParams.ts b/src/libs/API/parameters/CreateDistanceRequestParams.ts new file mode 100644 index 000000000000..c1eb1003a698 --- /dev/null +++ b/src/libs/API/parameters/CreateDistanceRequestParams.ts @@ -0,0 +1,17 @@ +type CreateDistanceRequestParams = { + comment: string; + iouReportID: string; + chatReportID: string; + transactionID: string; + reportActionID: string; + createdChatReportActionID: string; + createdIOUReportActionID: string; + reportPreviewReportActionID: string; + waypoints: string; + created: string; + category?: string; + tag?: string; + billable?: boolean; +}; + +export default CreateDistanceRequestParams; diff --git a/src/libs/API/parameters/DeleteMoneyRequestParams.ts b/src/libs/API/parameters/DeleteMoneyRequestParams.ts new file mode 100644 index 000000000000..6e7fe30811c4 --- /dev/null +++ b/src/libs/API/parameters/DeleteMoneyRequestParams.ts @@ -0,0 +1,6 @@ +type DeleteMoneyRequestParams = { + transactionID: string; + reportActionID: string; +}; + +export default DeleteMoneyRequestParams; diff --git a/src/libs/API/parameters/DetachReceiptParams.ts b/src/libs/API/parameters/DetachReceiptParams.ts new file mode 100644 index 000000000000..a19b525a0ef0 --- /dev/null +++ b/src/libs/API/parameters/DetachReceiptParams.ts @@ -0,0 +1,5 @@ +type DetachReceiptParams = { + transactionID: string; +}; + +export default DetachReceiptParams; diff --git a/src/libs/API/parameters/EditMoneyRequestParams.ts b/src/libs/API/parameters/EditMoneyRequestParams.ts new file mode 100644 index 000000000000..6d320510e267 --- /dev/null +++ b/src/libs/API/parameters/EditMoneyRequestParams.ts @@ -0,0 +1,14 @@ +type EditMoneyRequestParams = { + transactionID: string; + reportActionID: string; + created?: string; + amount?: number; + currency?: string; + comment?: string; + merchant?: string; + category?: string; + billable?: boolean; + tag?: string; +}; + +export default EditMoneyRequestParams; diff --git a/src/libs/API/parameters/PayMoneyRequestParams.ts b/src/libs/API/parameters/PayMoneyRequestParams.ts new file mode 100644 index 000000000000..94f62bcca065 --- /dev/null +++ b/src/libs/API/parameters/PayMoneyRequestParams.ts @@ -0,0 +1,11 @@ +import type CONST from '@src/CONST'; +import type DeepValueOf from '@src/types/utils/DeepValueOf'; + +type PayMoneyRequestParams = { + iouReportID: string; + chatReportID: string; + reportActionID: string; + paymentMethodType: DeepValueOf; +}; + +export default PayMoneyRequestParams; diff --git a/src/libs/API/parameters/ReplaceReceiptParams.ts b/src/libs/API/parameters/ReplaceReceiptParams.ts new file mode 100644 index 000000000000..1046c46bc930 --- /dev/null +++ b/src/libs/API/parameters/ReplaceReceiptParams.ts @@ -0,0 +1,6 @@ +type ReplaceReceiptParams = { + transactionID: string; + receipt: File; +}; + +export default ReplaceReceiptParams; diff --git a/src/libs/API/parameters/RequestMoneyParams.ts b/src/libs/API/parameters/RequestMoneyParams.ts new file mode 100644 index 000000000000..ccafdd692137 --- /dev/null +++ b/src/libs/API/parameters/RequestMoneyParams.ts @@ -0,0 +1,29 @@ +import type {ValueOf} from 'type-fest'; +import type CONST from '@src/CONST'; +import type {Receipt} from '@src/types/onyx/Transaction'; + +type RequestMoneyParams = { + debtorEmail: string; + debtorAccountID: number; + amount: number; + currency: string; + comment: string; + created: string; + merchant: string; + iouReportID: string; + chatReportID: string; + transactionID: string; + reportActionID: string; + createdChatReportActionID: string; + createdIOUReportActionID: string; + reportPreviewReportActionID: string; + receipt: Receipt; + receiptState?: ValueOf; + category?: string; + tag?: string; + taxCode: string; + taxAmount: number; + billable?: boolean; +}; + +export default RequestMoneyParams; diff --git a/src/libs/API/parameters/SendMoneyParams.ts b/src/libs/API/parameters/SendMoneyParams.ts new file mode 100644 index 000000000000..c32287d5b4ec --- /dev/null +++ b/src/libs/API/parameters/SendMoneyParams.ts @@ -0,0 +1,15 @@ +import type CONST from '@src/CONST'; +import type DeepValueOf from '@src/types/utils/DeepValueOf'; + +type SendMoneyParams = { + iouReportID: string; + chatReportID: string; + reportActionID: string; + paymentMethodType: DeepValueOf; + transactionID: string; + newIOUReportDetails: string; + createdReportActionID: string; + reportPreviewReportActionID: string; +}; + +export default SendMoneyParams; diff --git a/src/libs/API/parameters/SplitBillParams.ts b/src/libs/API/parameters/SplitBillParams.ts new file mode 100644 index 000000000000..f8b81d9d6734 --- /dev/null +++ b/src/libs/API/parameters/SplitBillParams.ts @@ -0,0 +1,16 @@ +type SplitBillParams = { + reportID: string; + amount: number; + splits: string; + comment: string; + currency: string; + merchant: string; + category: string; + tag: string; + transactionID: string; + reportActionID: string; + createdReportActionID?: string; + policyID?: string; +}; + +export default SplitBillParams; diff --git a/src/libs/API/parameters/StartSplitBillParams.ts b/src/libs/API/parameters/StartSplitBillParams.ts new file mode 100644 index 000000000000..8824f0f9c0e2 --- /dev/null +++ b/src/libs/API/parameters/StartSplitBillParams.ts @@ -0,0 +1,16 @@ +import type {Receipt} from '@src/types/onyx/Transaction'; + +type StartSplitBillParams = { + chatReportID: string; + reportActionID: string; + transactionID: string; + splits: string; + receipt: Receipt; + comment: string; + category: string; + tag: string; + isFromGroupDM: boolean; + createdReportActionID?: string; +}; + +export default StartSplitBillParams; diff --git a/src/libs/API/parameters/SubmitReportParams.ts b/src/libs/API/parameters/SubmitReportParams.ts new file mode 100644 index 000000000000..0132344aab6c --- /dev/null +++ b/src/libs/API/parameters/SubmitReportParams.ts @@ -0,0 +1,7 @@ +type SubmitReportParams = { + reportID: string; + managerAccountID?: number; + reportActionID: string; +}; + +export default SubmitReportParams; diff --git a/src/libs/API/parameters/UpdateMoneyRequestParams.ts b/src/libs/API/parameters/UpdateMoneyRequestParams.ts new file mode 100644 index 000000000000..549d02260beb --- /dev/null +++ b/src/libs/API/parameters/UpdateMoneyRequestParams.ts @@ -0,0 +1,9 @@ +import type {TransactionDetails} from '@libs/ReportUtils'; + +type UpdateMoneyRequestParams = Partial & { + reportID?: string; + transactionID: string; + reportActionID?: string; +}; + +export default UpdateMoneyRequestParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 039398c0fbf6..ae30a315ad7f 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -122,3 +122,17 @@ export type {default as ReopenTaskParams} from './ReopenTaskParams'; export type {default as CompleteTaskParams} from './CompleteTaskParams'; export type {default as CompleteEngagementModalParams} from './CompleteEngagementModalParams'; export type {default as SetNameValuePairParams} from './SetNameValuePairParams'; +export type {default as CompleteSplitBillParams} from './CompleteSplitBillParams'; +export type {default as UpdateMoneyRequestParams} from './UpdateMoneyRequestParams'; +export type {default as RequestMoneyParams} from './RequestMoneyParams'; +export type {default as SplitBillParams} from './SplitBillParams'; +export type {default as DeleteMoneyRequestParams} from './DeleteMoneyRequestParams'; +export type {default as CreateDistanceRequestParams} from './CreateDistanceRequestParams'; +export type {default as StartSplitBillParams} from './StartSplitBillParams'; +export type {default as SendMoneyParams} from './SendMoneyParams'; +export type {default as ApproveMoneyRequestParams} from './ApproveMoneyRequestParams'; +export type {default as EditMoneyRequestParams} from './EditMoneyRequestParams'; +export type {default as ReplaceReceiptParams} from './ReplaceReceiptParams'; +export type {default as SubmitReportParams} from './SubmitReportParams'; +export type {default as DetachReceiptParams} from './DetachReceiptParams'; +export type {default as PayMoneyRequestParams} from './PayMoneyRequestParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index f58ebc30b4a2..2a8a688ed2dc 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -113,6 +113,31 @@ const WRITE_COMMANDS = { COMPLETE_TASK: 'CompleteTask', COMPLETE_ENGAGEMENT_MODAL: 'CompleteEngagementModal', SET_NAME_VALUE_PAIR: 'SetNameValuePair', + COMPLETE_SPLIT_BILL: 'CompleteSplitBill', + UPDATE_MONEY_REQUEST_DATE: 'UpdateMoneyRequestDate', + UPDATE_MONEY_REQUEST_BILLABLE: 'UpdateMoneyRequestBillable', + UPDATE_MONEY_REQUEST_MERCHANT: 'UpdateMoneyRequestMerchant', + UPDATE_MONEY_REQUEST_TAG: 'UpdateMoneyRequestTag', + UPDATE_MONEY_REQUEST_DISTANCE: 'UpdateMoneyRequestDistance', + UPDATE_MONEY_REQUEST_CATEGORY: 'UpdateMoneyRequestCategory', + UPDATE_MONEY_REQUEST_DESCRIPTION: 'UpdateMoneyRequestDescription', + UPDATE_MONEY_REQUEST_AMOUNT_AND_CURRENCY: 'UpdateMoneyRequestAmountAndCurrency', + UPDATE_DISTANCE_REQUEST: 'UpdateDistanceRequest', + REQUEST_MONEY: 'RequestMoney', + SPLIT_BILL: 'SplitBill', + SPLIT_BILL_AND_OPEN_REPORT: 'SplitBillAndOpenReport', + DELETE_MONEY_REQUEST: 'DeleteMoneyRequest', + CREATE_DISTANCE_REQUEST: 'CreateDistanceRequest', + START_SPLIT_BILL: 'StartSplitBill', + SEND_MONEY_ELSEWHERE: 'SendMoneyElsewhere', + SEND_MONEY_WITH_WALLET: 'SendMoneyWithWallet', + APPROVE_MONEY_REQUEST: 'ApproveMoneyRequest', + EDIT_MONEY_REQUEST: 'EditMoneyRequest', + REPLACE_RECEIPT: 'ReplaceReceipt', + SUBMIT_REPORT: 'SubmitReport', + DETACH_RECEIPT: 'DetachReceipt', + PAY_MONEY_REQUEST_WITH_WALLET: 'PayMoneyRequestWithWallet', + PAY_MONEY_REQUEST: 'PayMoneyRequest', } as const; type WriteCommand = ValueOf; @@ -223,6 +248,31 @@ type WriteCommandParameters = { [WRITE_COMMANDS.COMPLETE_TASK]: Parameters.CompleteTaskParams; [WRITE_COMMANDS.COMPLETE_ENGAGEMENT_MODAL]: Parameters.CompleteEngagementModalParams; [WRITE_COMMANDS.SET_NAME_VALUE_PAIR]: Parameters.SetNameValuePairParams; + [WRITE_COMMANDS.COMPLETE_SPLIT_BILL]: Parameters.CompleteSplitBillParams; + [WRITE_COMMANDS.UPDATE_MONEY_REQUEST_DATE]: Parameters.UpdateMoneyRequestParams; + [WRITE_COMMANDS.UPDATE_MONEY_REQUEST_MERCHANT]: Parameters.UpdateMoneyRequestParams; + [WRITE_COMMANDS.UPDATE_MONEY_REQUEST_BILLABLE]: Parameters.UpdateMoneyRequestParams; + [WRITE_COMMANDS.UPDATE_MONEY_REQUEST_TAG]: Parameters.UpdateMoneyRequestParams; + [WRITE_COMMANDS.UPDATE_MONEY_REQUEST_DISTANCE]: Parameters.UpdateMoneyRequestParams; + [WRITE_COMMANDS.UPDATE_MONEY_REQUEST_CATEGORY]: Parameters.UpdateMoneyRequestParams; + [WRITE_COMMANDS.UPDATE_MONEY_REQUEST_DESCRIPTION]: Parameters.UpdateMoneyRequestParams; + [WRITE_COMMANDS.UPDATE_DISTANCE_REQUEST]: Parameters.UpdateMoneyRequestParams; + [WRITE_COMMANDS.UPDATE_MONEY_REQUEST_AMOUNT_AND_CURRENCY]: Parameters.UpdateMoneyRequestParams; + [WRITE_COMMANDS.REQUEST_MONEY]: Parameters.RequestMoneyParams; + [WRITE_COMMANDS.SPLIT_BILL]: Parameters.SplitBillParams; + [WRITE_COMMANDS.SPLIT_BILL_AND_OPEN_REPORT]: Parameters.SplitBillParams; + [WRITE_COMMANDS.DELETE_MONEY_REQUEST]: Parameters.DeleteMoneyRequestParams; + [WRITE_COMMANDS.CREATE_DISTANCE_REQUEST]: Parameters.CreateDistanceRequestParams; + [WRITE_COMMANDS.START_SPLIT_BILL]: Parameters.StartSplitBillParams; + [WRITE_COMMANDS.SEND_MONEY_ELSEWHERE]: Parameters.SendMoneyParams; + [WRITE_COMMANDS.SEND_MONEY_WITH_WALLET]: Parameters.SendMoneyParams; + [WRITE_COMMANDS.APPROVE_MONEY_REQUEST]: Parameters.ApproveMoneyRequestParams; + [WRITE_COMMANDS.EDIT_MONEY_REQUEST]: Parameters.EditMoneyRequestParams; + [WRITE_COMMANDS.REPLACE_RECEIPT]: Parameters.ReplaceReceiptParams; + [WRITE_COMMANDS.SUBMIT_REPORT]: Parameters.SubmitReportParams; + [WRITE_COMMANDS.DETACH_RECEIPT]: Parameters.DetachReceiptParams; + [WRITE_COMMANDS.PAY_MONEY_REQUEST_WITH_WALLET]: Parameters.PayMoneyRequestParams; + [WRITE_COMMANDS.PAY_MONEY_REQUEST]: Parameters.PayMoneyRequestParams; }; const READ_COMMANDS = { diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 654671b6514d..f822f255b8ba 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -110,7 +110,7 @@ function isExpensifyGuideTeam(email: string): boolean { /** * Checks if the current user is an admin of the policy. */ -const isPolicyAdmin = (policy: OnyxEntry): boolean => policy?.role === CONST.POLICY.ROLE.ADMIN; +const isPolicyAdmin = (policy: OnyxEntry | EmptyObject): boolean => policy?.role === CONST.POLICY.ROLE.ADMIN; const isPolicyMember = (policyID: string, policies: Record): boolean => Object.values(policies).some((policy) => policy?.id === policyID); diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 5e302a9481cd..21b03fd67187 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -465,7 +465,7 @@ Onyx.connect({ }, }); -function getChatType(report: OnyxEntry | Participant): ValueOf | undefined { +function getChatType(report: OnyxEntry | Participant | EmptyObject): ValueOf | undefined { return report?.chatType; } @@ -745,7 +745,7 @@ function isUserCreatedPolicyRoom(report: OnyxEntry): boolean { /** * Whether the provided report is a Policy Expense chat. */ -function isPolicyExpenseChat(report: OnyxEntry | Participant): boolean { +function isPolicyExpenseChat(report: OnyxEntry | Participant | EmptyObject): boolean { return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT || (report?.isPolicyExpenseChat ?? false); } diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index b179a4ffc63f..897133b81c7a 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -7,6 +7,23 @@ import OnyxUtils from 'react-native-onyx/lib/utils'; import type {ValueOf} from 'type-fest'; import ReceiptGeneric from '@assets/images/receipt-generic.png'; import * as API from '@libs/API'; +import type { + ApproveMoneyRequestParams, + CompleteSplitBillParams, + CreateDistanceRequestParams, + DeleteMoneyRequestParams, + DetachReceiptParams, + EditMoneyRequestParams, + PayMoneyRequestParams, + ReplaceReceiptParams, + RequestMoneyParams, + SendMoneyParams, + SplitBillParams, + StartSplitBillParams, + SubmitReportParams, + UpdateMoneyRequestParams, +} from '@libs/API/parameters'; +import {WRITE_COMMANDS} from '@libs/API/types'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import DateUtils from '@libs/DateUtils'; import * as ErrorUtils from '@libs/ErrorUtils'; @@ -42,10 +59,7 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; import * as Report from './Report'; -type MoneyRequestRoute = StackScreenProps< - MoneyRequestNavigatorParamList, - typeof SCREENS.MONEY_REQUEST.CATEGORY | typeof SCREENS.MONEY_REQUEST.TAG | typeof SCREENS.MONEY_REQUEST.CONFIRMATION ->['route']; +type MoneyRequestRoute = StackScreenProps['route']; type IOURequestType = ValueOf; @@ -80,24 +94,11 @@ type SplitsAndOnyxData = { onyxData: OnyxData; }; -type UpdateMoneyRequestParams = Partial & { - reportID?: string; - transactionID: string; - reportActionID?: string; -}; - type UpdateMoneyRequestData = { params: UpdateMoneyRequestParams; onyxData: OnyxData; }; -type PayMoneyRequestParams = { - iouReportID: string; - chatReportID: string; - reportActionID: string; - paymentMethodType: PaymentMethodType; -}; - type PayMoneyRequestData = { params: PayMoneyRequestParams; optimisticData: OnyxUpdate[]; @@ -105,17 +106,6 @@ type PayMoneyRequestData = { failureData: OnyxUpdate[]; }; -type SendMoneyParams = { - iouReportID: string; - chatReportID: string; - reportActionID: string; - paymentMethodType: PaymentMethodType; - transactionID: string; - newIOUReportDetails: string; - createdReportActionID: string; - reportPreviewReportActionID: string; -}; - type SendMoneyParamsData = { params: SendMoneyParams; optimisticData: OnyxUpdate[]; @@ -123,6 +113,10 @@ type SendMoneyParamsData = { failureData: OnyxUpdate[]; }; +type OutstandingChildRequest = { + hasOutstandingChildRequest?: boolean; +}; + let betas: OnyxTypes.Beta[] = []; Onyx.connect({ key: ONYXKEYS.BETAS, @@ -358,13 +352,8 @@ function getReceiptError(receipt?: Receipt, filename?: string, isScanRequest = t : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: receipt.source ?? '', filename: filename ?? ''}); } -/** - * Return the object to update hasOutstandingChildRequest - * @param {Object} [policy] - * @param {Boolean} needsToBeManuallySubmitted - * @returns {Object} - */ -function getOutstandingChildRequest(policy, needsToBeManuallySubmitted) { +/** Return the object to update hasOutstandingChildRequest */ +function getOutstandingChildRequest(needsToBeManuallySubmitted: boolean, policy: OnyxEntry | EmptyObject = null): OutstandingChildRequest { if (!needsToBeManuallySubmitted) { return { hasOutstandingChildRequest: false, @@ -579,7 +568,7 @@ function buildOnyxDataForMoneyRequest( iouReportID: chatReport?.iouReportID, lastReadTime: chatReport?.lastReadTime, pendingFields: null, - hasOutstandingChildRequest: chatReport.hasOutstandingChildRequest, + hasOutstandingChildRequest: chatReport?.hasOutstandingChildRequest, ...(isNewChatReport ? { errorFields: { @@ -942,22 +931,6 @@ function createDistanceRequest( currentUserEmail, ); - type CreateDistanceRequestParams = { - comment: string; - iouReportID: string; - chatReportID: string; - transactionID: string; - reportActionID: string; - createdChatReportActionID: string; - createdIOUReportActionID: string; - reportPreviewReportActionID: string; - waypoints: string; - created: string; - category?: string; - tag?: string; - billable?: boolean; - }; - const parameters: CreateDistanceRequestParams = { comment, iouReportID: iouReport.reportID, @@ -974,7 +947,7 @@ function createDistanceRequest( billable, }; - API.write('CreateDistanceRequest', parameters, onyxData); + API.write(WRITE_COMMANDS.CREATE_DISTANCE_REQUEST, parameters, onyxData); Navigation.dismissModal(isMoneyRequestReport ? report.reportID : chatReport.reportID); Report.notifyNewAction(chatReport.reportID, userAccountID); } @@ -1198,7 +1171,7 @@ function updateMoneyRequestDate(transactionID: string, transactionThreadReportID created: value, }; const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true); - API.write('UpdateMoneyRequestDate', params, onyxData); + API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_DATE, params, onyxData); } /** Updates the billable field of a money request */ @@ -1207,7 +1180,7 @@ function updateMoneyRequestBillable(transactionID: string, transactionThreadRepo billable: value, }; const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true); - API.write('UpdateMoneyRequestBillable', params, onyxData); + API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_BILLABLE, params, onyxData); } /** Updates the merchant field of a money request */ @@ -1216,7 +1189,7 @@ function updateMoneyRequestMerchant(transactionID: string, transactionThreadRepo merchant: value, }; const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true); - API.write('UpdateMoneyRequestMerchant', params, onyxData); + API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_MERCHANT, params, onyxData); } /** Updates the tag of a money request */ @@ -1225,16 +1198,16 @@ function updateMoneyRequestTag(transactionID: string, transactionThreadReportID: tag, }; const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true); - API.write('UpdateMoneyRequestTag', params, onyxData); + API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_TAG, params, onyxData); } /** Updates the waypoints of a distance money request */ -function updateMoneyRequestDistance(transactionID: string, transactionThreadReportID: string, waypoints) { +function updateMoneyRequestDistance(transactionID: string, transactionThreadReportID: string, waypoints: WaypointCollection) { const transactionChanges: TransactionChanges = { waypoints, }; const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true); - API.write('UpdateMoneyRequestDistance', params, onyxData); + API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_DISTANCE, params, onyxData); } /** Updates the category of a money request */ @@ -1243,7 +1216,7 @@ function updateMoneyRequestCategory(transactionID: string, transactionThreadRepo category, }; const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true); - API.write('UpdateMoneyRequestCategory', params, onyxData); + API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_CATEGORY, params, onyxData); } /** Updates the description of a money request */ @@ -1252,13 +1225,13 @@ function updateMoneyRequestDescription(transactionID: string, transactionThreadR comment, }; const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true); - API.write('UpdateMoneyRequestDescription', params, onyxData); + API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_DESCRIPTION, params, onyxData); } /** Edits an existing distance request */ function updateDistanceRequest(transactionID: string, transactionThreadReportID: string, transactionChanges: TransactionChanges) { const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, false); - API.write('UpdateDistanceRequest', params, onyxData); + API.write(WRITE_COMMANDS.UPDATE_DISTANCE_REQUEST, params, onyxData); } /** @@ -1310,30 +1283,6 @@ function requestMoney( ); const activeReportID = isMoneyRequestReport ? report.reportID : chatReport.reportID; - type RequestMoneyParams = { - debtorEmail: string; - debtorAccountID: number; - amount: number; - currency: string; - comment: string; - created: string; - merchant: string; - iouReportID: string; - chatReportID: string; - transactionID: string; - reportActionID: string; - createdChatReportActionID: string; - createdIOUReportActionID: string; - reportPreviewReportActionID: string; - receipt: Receipt; - receiptState?: ValueOf; - category?: string; - tag?: string; - taxCode: string; - taxAmount: number; - billable?: boolean; - }; - const parameters: RequestMoneyParams = { debtorEmail: payerEmail, debtorAccountID: payerAccountID, @@ -1358,7 +1307,7 @@ function requestMoney( billable, }; - API.write('RequestMoney', parameters, onyxData); + API.write(WRITE_COMMANDS.REQUEST_MONEY, parameters, onyxData); resetMoneyRequestInfo(); Navigation.dismissModal(activeReportID); Report.notifyNewAction(activeReportID, payeeAccountID); @@ -1761,21 +1710,6 @@ function splitBill( existingSplitChatReportID, ); - type SplitBillParams = { - reportID: string; - amount: number; - splits: string; - comment: string; - currency: string; - merchant: string; - category: string; - tag: string; - transactionID: string; - reportActionID: string; - createdReportActionID?: string; - policyID?: string; - }; - const parameters: SplitBillParams = { reportID: splitData.chatReportID, amount, @@ -1791,7 +1725,7 @@ function splitBill( policyID: splitData.policyID, }; - API.write('SplitBill', parameters, onyxData); + API.write(WRITE_COMMANDS.SPLIT_BILL, parameters, onyxData); resetMoneyRequestInfo(); Navigation.dismissModal(); @@ -1814,22 +1748,7 @@ function splitBillAndOpenReport( ) { const {splitData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, merchant, category, tag); - type SplitBillAndOpenReport = { - reportID: string; - amount: number; - splits: string; - currency: string; - merchant: string; - comment: string; - category: string; - tag: string; - transactionID: string; - reportActionID: string; - createdReportActionID?: string; - policyID?: string; - }; - - const parameters: SplitBillAndOpenReport = { + const parameters: SplitBillParams = { reportID: splitData.chatReportID, amount, splits: JSON.stringify(splits), @@ -1844,7 +1763,7 @@ function splitBillAndOpenReport( policyID: splitData.policyID, }; - API.write('SplitBillAndOpenReport', parameters, onyxData); + API.write(WRITE_COMMANDS.SPLIT_BILL_AND_OPEN_REPORT, parameters, onyxData); resetMoneyRequestInfo(); Navigation.dismissModal(splitData.chatReportID); @@ -2108,19 +2027,6 @@ function startSplitBill( }, }); - type StartSplitBillParams = { - chatReportID: string; - reportActionID: string; - transactionID: string; - splits: string; - receipt: Receipt; - comment: string; - category: string; - tag: string; - isFromGroupDM: boolean; - createdReportActionID?: string; - }; - const parameters: StartSplitBillParams = { chatReportID: splitChatReport.reportID, reportActionID: splitIOUReportAction.reportActionID, @@ -2134,7 +2040,7 @@ function startSplitBill( ...(existingSplitChatReport ? {} : {createdReportActionID: splitChatCreatedReportAction.reportActionID}), }; - API.write('StartSplitBill', parameters, {optimisticData, successData, failureData}); + API.write(WRITE_COMMANDS.START_SPLIT_BILL, parameters, {optimisticData, successData, failureData}); resetMoneyRequestInfo(); Navigation.dismissModal(splitChatReport.reportID); @@ -2343,18 +2249,6 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA tag: transactionTag, } = ReportUtils.getTransactionDetails(updatedTransaction) ?? {}; - type CompleteSplitBillParams = { - transactionID: string; - amount?: number; - currency?: string; - created?: string; - merchant?: string; - comment?: string; - category?: string; - tag?: string; - splits: string; - }; - const parameters: CompleteSplitBillParams = { transactionID, amount: transactionAmount, @@ -2367,7 +2261,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA splits: JSON.stringify(splits), }; - API.write('CompleteSplitBill', parameters, {optimisticData, successData, failureData}); + API.write(WRITE_COMMANDS.COMPLETE_SPLIT_BILL, parameters, {optimisticData, successData, failureData}); Navigation.dismissModal(chatReportID); Report.notifyNewAction(chatReportID, sessionAccountID); } @@ -2600,19 +2494,6 @@ function editRegularMoneyRequest(transactionID: string, transactionThreadReportI // STEP 6: Call the API endpoint const {created, amount, currency, comment, merchant, category, billable, tag} = ReportUtils.getTransactionDetails(updatedTransaction) ?? {}; - type EditMoneyRequestParams = { - transactionID: string; - reportActionID: string; - created?: string; - amount?: number; - currency?: string; - comment?: string; - merchant?: string; - category?: string; - billable?: boolean; - tag?: string; - }; - const parameters: EditMoneyRequestParams = { transactionID, reportActionID: updatedReportAction.reportActionID, @@ -2626,7 +2507,7 @@ function editRegularMoneyRequest(transactionID: string, transactionThreadReportI tag, }; - API.write('EditMoneyRequest', parameters, {optimisticData, successData, failureData}); + API.write(WRITE_COMMANDS.EDIT_MONEY_REQUEST, parameters, {optimisticData, successData, failureData}); } function editMoneyRequest(transaction: OnyxTypes.Transaction, transactionThreadReportID: string, transactionChanges: TransactionChanges) { @@ -2644,7 +2525,7 @@ function updateMoneyRequestAmountAndCurrency(transactionID: string, transactionT currency, }; const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true); - API.write('UpdateMoneyRequestAmountAndCurrency', params, onyxData); + API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_AMOUNT_AND_CURRENCY, params, onyxData); } function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) { @@ -2920,18 +2801,13 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor }); } - type DeleteMoneyRequestParams = { - transactionID: string; - reportActionID: string; - }; - const parameters: DeleteMoneyRequestParams = { transactionID, reportActionID: reportAction.reportActionID, }; // STEP 6: Make the API request - API.write('DeleteMoneyRequest', parameters, {optimisticData, successData, failureData}); + API.write(WRITE_COMMANDS.DELETE_MONEY_REQUEST, parameters, {optimisticData, successData, failureData}); // STEP 7: Navigate the user depending on which page they are on and which resources were deleted if (iouReport && isSingleTransactionView && shouldDeleteTransactionThread && !shouldDeleteIOUReport) { @@ -3325,7 +3201,7 @@ function getPayMoneyRequestParams(chatReport: OnyxTypes.Report, iouReport: OnyxT function sendMoneyElsewhere(report: OnyxTypes.Report, amount: number, currency: string, comment: string, managerID: number, recipient: Participant) { const {params, optimisticData, successData, failureData} = getSendMoneyParams(report, amount, currency, comment, CONST.IOU.PAYMENT_TYPE.ELSEWHERE, managerID, recipient); - API.write('SendMoneyElsewhere', params, {optimisticData, successData, failureData}); + API.write(WRITE_COMMANDS.SEND_MONEY_ELSEWHERE, params, {optimisticData, successData, failureData}); resetMoneyRequestInfo(); Navigation.dismissModal(params.chatReportID); @@ -3339,7 +3215,7 @@ function sendMoneyElsewhere(report: OnyxTypes.Report, amount: number, currency: function sendMoneyWithWallet(report: OnyxTypes.Report, amount: number, currency: string, comment: string, managerID: number, recipient: Participant) { const {params, optimisticData, successData, failureData} = getSendMoneyParams(report, amount, currency, comment, CONST.IOU.PAYMENT_TYPE.EXPENSIFY, managerID, recipient); - API.write('SendMoneyWithWallet', params, {optimisticData, successData, failureData}); + API.write(WRITE_COMMANDS.SEND_MONEY_WITH_WALLET, params, {optimisticData, successData, failureData}); resetMoneyRequestInfo(); Navigation.dismissModal(params.chatReportID); @@ -3411,17 +3287,12 @@ function approveMoneyRequest(expenseReport: OnyxTypes.Report) { }); } - type ApproveMoneyRequestParams = { - reportID: string; - approvedReportActionID: string; - }; - const parameters: ApproveMoneyRequestParams = { reportID: expenseReport.reportID, approvedReportActionID: optimisticApprovedReportAction.reportActionID, }; - API.write('ApproveMoneyRequest', parameters, {optimisticData, successData, failureData}); + API.write(WRITE_COMMANDS.APPROVE_MONEY_REQUEST, parameters, {optimisticData, successData, failureData}); } function submitReport(expenseReport: OnyxTypes.Report) { @@ -3525,19 +3396,13 @@ function submitReport(expenseReport: OnyxTypes.Report) { }); } - type SubmitReportParams = { - reportID: string; - managerAccountID?: number; - reportActionID: string; - }; - const parameters: SubmitReportParams = { reportID: expenseReport.reportID, managerAccountID: policy.submitsTo ?? expenseReport.managerID, reportActionID: optimisticSubmittedReportAction.reportActionID, }; - API.write('SubmitReport', parameters, {optimisticData, successData, failureData}); + API.write(WRITE_COMMANDS.SUBMIT_REPORT, parameters, {optimisticData, successData, failureData}); } function payMoneyRequest(paymentType: PaymentMethodType, chatReport: OnyxTypes.Report, iouReport: OnyxTypes.Report) { @@ -3546,7 +3411,7 @@ function payMoneyRequest(paymentType: PaymentMethodType, chatReport: OnyxTypes.R // For now we need to call the PayMoneyRequestWithWallet API since PayMoneyRequest was not updated to work with // Expensify Wallets. - const apiCommand = paymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY ? 'PayMoneyRequestWithWallet' : 'PayMoneyRequest'; + const apiCommand = paymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY ? WRITE_COMMANDS.PAY_MONEY_REQUEST_WITH_WALLET : WRITE_COMMANDS.PAY_MONEY_REQUEST; API.write(apiCommand, params, {optimisticData, successData, failureData}); Navigation.dismissModal(chatReport.reportID); @@ -3572,7 +3437,9 @@ function detachReceipt(transactionID: string) { }, ]; - API.write('DetachReceipt', {transactionID}, {optimisticData, failureData}); + const parameters: DetachReceiptParams = {transactionID}; + + API.write(WRITE_COMMANDS.DETACH_RECEIPT, parameters, {optimisticData, failureData}); } function replaceReceipt(transactionID: string, file: File, source: string) { @@ -3604,17 +3471,12 @@ function replaceReceipt(transactionID: string, file: File, source: string) { }, ]; - type ReplaceReceiptParams = { - transactionID: string; - receipt: File; - }; - const parameters: ReplaceReceiptParams = { transactionID, receipt: file, }; - API.write('ReplaceReceipt', parameters, {optimisticData, failureData}); + API.write(WRITE_COMMANDS.REPLACE_RECEIPT, parameters, {optimisticData, failureData}); } /** @@ -3717,6 +3579,7 @@ function navigateToNextPage(iou: OnyxEntry, iouType: string, repo // If we're adding a receipt, that means the user came from the confirmation page and we need to navigate back to it. if (path.slice(1) === ROUTES.MONEY_REQUEST_RECEIPT.getRoute(iouType, report?.reportID)) { + // @ts-expect-error TODO: Remove this once NewRequestAmountPage (https://github.com/Expensify/App/issues/34614) and NewDistanceRequestPage (https://github.com/Expensify/App/issues/34610) are removed. Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report?.reportID)); return; } @@ -3735,6 +3598,7 @@ function navigateToNextPage(iou: OnyxEntry, iouType: string, repo resetMoneyRequestCategory(); resetMoneyRequestTag(); } + // @ts-expect-error TODO: Remove this once NewRequestAmountPage (https://github.com/Expensify/App/issues/34614) and NewDistanceRequestPage (https://github.com/Expensify/App/issues/34610) are removed. Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report.reportID)); return; } @@ -3752,17 +3616,16 @@ function getIOUReportID(iou?: OnyxTypes.IOU, route?: MoneyRequestRoute): string return route?.params.reportID || iou?.participants?.[0]?.reportID || ''; } -/** - * @param {String} receiptFilename - * @param {String} receiptPath - * @param {Function} onSuccess - * @param {String} requestType - * @param {String} iouType - * @param {String} transactionID - * @param {String} reportID - */ // eslint-disable-next-line rulesdir/no-negated-variables -function navigateToStartStepIfScanFileCannotBeRead(receiptFilename, receiptPath, onSuccess, requestType, iouType, transactionID, reportID) { +function navigateToStartStepIfScanFileCannotBeRead( + receiptFilename: string, + receiptPath: string, + onSuccess: (file: File) => void, + requestType: ValueOf, + iouType: ValueOf, + transactionID: string, + reportID: string, +) { if (!receiptFilename || !receiptPath) { return; } From 1d18bea64f7969ed177b2fac886abc22b2274402 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 29 Jan 2024 12:28:08 +0100 Subject: [PATCH 58/68] Fix TS issues --- src/types/onyx/IOU.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/types/onyx/IOU.ts b/src/types/onyx/IOU.ts index 6df3d9e46c52..b04011978d73 100644 --- a/src/types/onyx/IOU.ts +++ b/src/types/onyx/IOU.ts @@ -3,8 +3,8 @@ import type CONST from '@src/CONST'; import type {Icon} from './OnyxCommon'; type Participant = { - accountID: number; - login: string; + accountID?: number; + login?: string; displayName?: string; isPolicyExpenseChat?: boolean; isOwnPolicyExpenseChat?: boolean; @@ -13,13 +13,13 @@ type Participant = { policyID?: string; selected?: boolean; searchText?: string; - alternateText: string; - firstName: string; - icons: Icon[]; - keyForList: string; - lastName: string; - phoneNumber: string; - text: string; + alternateText?: string; + firstName?: string; + icons?: Icon[]; + keyForList?: string; + lastName?: string; + phoneNumber?: string; + text?: string; isSelected?: boolean; }; From f6cef2487aa05f580d1cdea79888c9e06f6ae11c Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 29 Jan 2024 14:06:09 +0100 Subject: [PATCH 59/68] Update typing to fix ts errors --- src/components/FormAlertWithSubmitButton.tsx | 2 +- src/components/FormAlertWrapper.tsx | 2 +- src/libs/ErrorUtils.ts | 2 +- src/libs/Localize/index.ts | 2 +- src/libs/actions/IOU.ts | 2 +- src/pages/TeachersUnite/IntroSchoolPrincipalPage.tsx | 2 +- src/types/onyx/OnyxCommon.ts | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/FormAlertWithSubmitButton.tsx b/src/components/FormAlertWithSubmitButton.tsx index ae96aa6c5359..789f1cd2466d 100644 --- a/src/components/FormAlertWithSubmitButton.tsx +++ b/src/components/FormAlertWithSubmitButton.tsx @@ -7,7 +7,7 @@ import FormAlertWrapper from './FormAlertWrapper'; type FormAlertWithSubmitButtonProps = { /** Error message to display above button */ - message?: string; + message?: string | null; /** Whether the button is disabled */ isDisabled?: boolean; diff --git a/src/components/FormAlertWrapper.tsx b/src/components/FormAlertWrapper.tsx index 65fa2311620d..bdd5622f7aeb 100644 --- a/src/components/FormAlertWrapper.tsx +++ b/src/components/FormAlertWrapper.tsx @@ -28,7 +28,7 @@ type FormAlertWrapperProps = { isMessageHtml?: boolean; /** Error message to display above button */ - message?: string; + message?: string | null; /** Props to detect online status */ network: Network; diff --git a/src/libs/ErrorUtils.ts b/src/libs/ErrorUtils.ts index 98de6f1c5ff1..dfddf645bceb 100644 --- a/src/libs/ErrorUtils.ts +++ b/src/libs/ErrorUtils.ts @@ -54,7 +54,7 @@ type OnyxDataWithErrors = { errors?: Errors | null; }; -function getLatestErrorMessage(onyxData: TOnyxData): string | number | null { +function getLatestErrorMessage(onyxData: TOnyxData): string | null { const errors = onyxData.errors ?? {}; if (Object.keys(errors).length === 0) { diff --git a/src/libs/Localize/index.ts b/src/libs/Localize/index.ts index bc40f93dd13b..43db1a1d84ba 100644 --- a/src/libs/Localize/index.ts +++ b/src/libs/Localize/index.ts @@ -97,7 +97,7 @@ function translateLocal(phrase: TKey, ...variable return translate(BaseLocaleListener.getPreferredLocale(), phrase, ...variables); } -type MaybePhraseKey = string | [string, Record & {isTranslated?: true}] | []; +type MaybePhraseKey = string | null | [string, Record & {isTranslated?: true}] | []; /** * Return translated string for given error. diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 897133b81c7a..7cc566a8d098 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -349,7 +349,7 @@ function resetMoneyRequestInfo(id = '') { function getReceiptError(receipt?: Receipt, filename?: string, isScanRequest = true): Errors | ErrorFields { return isEmptyObject(receipt) || !isScanRequest ? ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage') - : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: receipt.source ?? '', filename: filename ?? ''}); + : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: receipt.source?.toString() ?? '', filename: filename ?? ''}); } /** Return the object to update hasOutstandingChildRequest */ diff --git a/src/pages/TeachersUnite/IntroSchoolPrincipalPage.tsx b/src/pages/TeachersUnite/IntroSchoolPrincipalPage.tsx index ba1e3c1de6fb..f9c5d6a1fa5d 100644 --- a/src/pages/TeachersUnite/IntroSchoolPrincipalPage.tsx +++ b/src/pages/TeachersUnite/IntroSchoolPrincipalPage.tsx @@ -48,7 +48,7 @@ function IntroSchoolPrincipalPage(props: IntroSchoolPrincipalPageProps) { */ const validate = useCallback( (values: OnyxFormValuesFields) => { - const errors: Errors = {}; + const errors: Partial, string>> = {}; if (!values.firstName || !ValidationUtils.isValidPersonName(values.firstName)) { ErrorUtils.addErrorMessage(errors, 'firstName', 'bankAccount.error.firstName'); diff --git a/src/types/onyx/OnyxCommon.ts b/src/types/onyx/OnyxCommon.ts index 15e40173e185..27c90cca2753 100644 --- a/src/types/onyx/OnyxCommon.ts +++ b/src/types/onyx/OnyxCommon.ts @@ -8,7 +8,7 @@ type PendingFields = Record = Record; -type Errors = Record; +type Errors = Record; type AvatarType = typeof CONST.ICON_TYPE_AVATAR | typeof CONST.ICON_TYPE_WORKSPACE; From 93dd12ac1376f002abc1a7a1f88507f62079e763 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 30 Jan 2024 14:58:17 +0100 Subject: [PATCH 60/68] TS fixes after merging main --- src/libs/ReportActionsUtils.ts | 6 ++-- src/libs/actions/IOU.ts | 32 ++++++++++--------- .../IntroSchoolPrincipalPage.tsx | 1 - 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 79de9f7785af..94a929ec8b94 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -438,9 +438,9 @@ function replaceBaseURL(reportAction: ReportAction): ReportAction { /** */ -function getLastVisibleAction(reportID: string, actionsToMerge: ReportActions = {}): OnyxEntry { - const reportActions = Object.values(fastMerge(allReportActions?.[reportID] ?? {}, actionsToMerge, true)); - const visibleReportActions = Object.values(reportActions ?? {}).filter((action) => shouldReportActionBeVisibleAsLastAction(action)); +function getLastVisibleAction(reportID: string, actionsToMerge: OnyxCollection = {}): OnyxEntry { + const reportActions = Object.values(fastMerge(allReportActions?.[reportID] ?? {}, actionsToMerge ?? {}, true)); + const visibleReportActions = Object.values(reportActions ?? {}).filter((action): action is ReportAction => shouldReportActionBeVisibleAsLastAction(action)); const sortedReportActions = getSortedReportActions(visibleReportActions, true); if (sortedReportActions.length === 0) { return null; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 0963a6d2c027..f1e147db2af9 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -4,7 +4,6 @@ import fastMerge from 'expensify-common/lib/fastMerge'; import Str from 'expensify-common/lib/str'; import Onyx from 'react-native-onyx'; import type {OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx'; -import OnyxUtils from 'react-native-onyx/lib/utils'; import type {ValueOf} from 'type-fest'; import ReceiptGeneric from '@assets/images/receipt-generic.png'; import * as API from '@libs/API'; @@ -60,7 +59,10 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; import * as Report from './Report'; -type MoneyRequestRoute = StackScreenProps['route']; +type MoneyRequestRoute = StackScreenProps< + MoneyRequestNavigatorParamList, + typeof SCREENS.MONEY_REQUEST.CATEGORY | typeof SCREENS.MONEY_REQUEST.TAG | typeof SCREENS.MONEY_REQUEST.CONFIRMATION +>['route']; type IOURequestType = ValueOf; @@ -794,7 +796,7 @@ function getMoneyRequestInformation( // to remind me to do this. const existingTransaction = allTransactionDrafts[`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`]; if (existingTransaction && existingTransaction.iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE) { - optimisticTransaction = fastMerge(existingTransaction, optimisticTransaction); + optimisticTransaction = fastMerge(existingTransaction, optimisticTransaction, false); } // STEP 4: Build optimistic reportActions. We need: @@ -1441,7 +1443,7 @@ function createSplitsAndOnyxData( value: {pendingAction: null}, }, { - onyxMethod: Onyx.METHOD.SET, + onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`, value: null, }, @@ -1464,7 +1466,7 @@ function createSplitsAndOnyxData( }, }, { - onyxMethod: Onyx.METHOD.SET, + onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`, value: null, }, @@ -2278,7 +2280,7 @@ function setDraftSplitTransaction(transactionID: string, transactionChanges: Tra const updatedTransaction = draftSplitTransaction ? TransactionUtils.getUpdatedTransaction(draftSplitTransaction, transactionChanges, false, false) : null; - Onyx.merge(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`, updatedTransaction ?? {}); + Onyx.merge(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`, updatedTransaction); } function editRegularMoneyRequest(transactionID: string, transactionThreadReportID: string, transactionChanges: TransactionChanges) { @@ -2348,7 +2350,7 @@ function editRegularMoneyRequest(transactionID: string, transactionThreadReportI { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, - value: updatedTransaction ?? {}, + value: updatedTransaction, }, { onyxMethod: Onyx.METHOD.MERGE, @@ -2482,7 +2484,7 @@ function editRegularMoneyRequest(transactionID: string, transactionThreadReportI { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`, - value: chatReport ?? {}, + value: chatReport, }, { onyxMethod: Onyx.METHOD.MERGE, @@ -2659,7 +2661,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, - value: updatedIOUReport ?? {}, + value: updatedIOUReport, }, { onyxMethod: Onyx.METHOD.MERGE, @@ -2772,7 +2774,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor : { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, - value: iouReport ?? {}, + value: iouReport, }, { onyxMethod: Onyx.METHOD.MERGE, @@ -3016,8 +3018,10 @@ function getSendMoneyParams( }, }; - // Add an optimistic created action to the optimistic chat reportActions data - optimisticChatReportActionsData.value[optimisticCreatedAction.reportActionID] = optimisticCreatedAction; + if (optimisticChatReportActionsData.value) { + // Add an optimistic created action to the optimistic chat reportActions data + optimisticChatReportActionsData.value[optimisticCreatedAction.reportActionID] = optimisticCreatedAction; + } } else { failureData.push({ onyxMethod: Onyx.METHOD.MERGE, @@ -3436,7 +3440,7 @@ function detachReceipt(transactionID: string) { { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, - value: transaction ?? {}, + value: transaction, }, ]; @@ -3582,7 +3586,6 @@ function navigateToNextPage(iou: OnyxEntry, iouType: string, repo // If we're adding a receipt, that means the user came from the confirmation page and we need to navigate back to it. if (path.slice(1) === ROUTES.MONEY_REQUEST_RECEIPT.getRoute(iouType, report?.reportID)) { - // @ts-expect-error TODO: Remove this once NewRequestAmountPage (https://github.com/Expensify/App/issues/34614) and NewDistanceRequestPage (https://github.com/Expensify/App/issues/34610) are removed. Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report?.reportID)); return; } @@ -3601,7 +3604,6 @@ function navigateToNextPage(iou: OnyxEntry, iouType: string, repo resetMoneyRequestCategory(); resetMoneyRequestTag(); } - // @ts-expect-error TODO: Remove this once NewRequestAmountPage (https://github.com/Expensify/App/issues/34614) and NewDistanceRequestPage (https://github.com/Expensify/App/issues/34610) are removed. Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report.reportID)); return; } diff --git a/src/pages/TeachersUnite/IntroSchoolPrincipalPage.tsx b/src/pages/TeachersUnite/IntroSchoolPrincipalPage.tsx index 5f5ca39c638a..d5900330e4ba 100644 --- a/src/pages/TeachersUnite/IntroSchoolPrincipalPage.tsx +++ b/src/pages/TeachersUnite/IntroSchoolPrincipalPage.tsx @@ -22,7 +22,6 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {LoginList} from '@src/types/onyx'; -import type {Errors} from '@src/types/onyx/OnyxCommon'; type IntroSchoolPrincipalPageOnyxProps = { loginList: OnyxEntry; From f78414e9139d7250fa4a691e1d0c95e2b1523007 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 30 Jan 2024 15:56:22 +0100 Subject: [PATCH 61/68] Minor code improvement --- src/libs/ValidationUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ValidationUtils.ts b/src/libs/ValidationUtils.ts index 41054f47a27c..b8bc5046b57d 100644 --- a/src/libs/ValidationUtils.ts +++ b/src/libs/ValidationUtils.ts @@ -73,7 +73,7 @@ function isValidPastDate(date: string | Date): boolean { /** * Used to validate a value that is "required". */ -function isRequiredFulfilled(value: string | number | Date | unknown[] | Record | null): boolean { +function isRequiredFulfilled(value: string | Date | unknown[] | Record | null): boolean { if (typeof value === 'string') { return !StringUtils.isEmptyString(value); } From b33dae63c9c4233b24f9f76f6431a775d7546b8c Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 30 Jan 2024 22:32:12 +0100 Subject: [PATCH 62/68] Fix TS issues after merging main --- src/components/AttachmentModal.tsx | 2 +- src/libs/actions/IOU.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/AttachmentModal.tsx b/src/components/AttachmentModal.tsx index f3e8ed316c52..88427afcb73e 100755 --- a/src/components/AttachmentModal.tsx +++ b/src/components/AttachmentModal.tsx @@ -279,7 +279,7 @@ function AttachmentModal({ * Detach the receipt and close the modal. */ const deleteAndCloseModal = useCallback(() => { - IOU.detachReceipt(transaction?.transactionID); + IOU.detachReceipt(transaction?.transactionID ?? ''); setIsDeleteReceiptConfirmModalVisible(false); Navigation.dismissModal(report?.reportID); }, [transaction, report]); diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 10cf7b852b80..238db9eaa509 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -3450,14 +3450,14 @@ function detachReceipt(transactionID: string) { } function replaceReceipt(transactionID: string, file: File, source: string) { - const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? {}; + const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; const oldReceipt = transaction?.receipt ?? {}; const receiptOptimistic = { source, state: CONST.IOU.RECEIPT_STATE.OPEN, }; - const optimisticData = [ + const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, From fe8ca0afd5db6ac7dd7a85fa27da4ebc5529f198 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Thu, 1 Feb 2024 09:19:55 +0100 Subject: [PATCH 63/68] Apply TS fixes to the new code updates --- src/libs/API/parameters/SplitBillParams.ts | 1 + .../API/parameters/StartSplitBillParams.ts | 1 + src/libs/ReportUtils.ts | 1 + src/libs/actions/IOU.ts | 18 +++++++----------- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/libs/API/parameters/SplitBillParams.ts b/src/libs/API/parameters/SplitBillParams.ts index f8b81d9d6734..23d4ff3d6d78 100644 --- a/src/libs/API/parameters/SplitBillParams.ts +++ b/src/libs/API/parameters/SplitBillParams.ts @@ -7,6 +7,7 @@ type SplitBillParams = { merchant: string; category: string; tag: string; + billable: boolean; transactionID: string; reportActionID: string; createdReportActionID?: string; diff --git a/src/libs/API/parameters/StartSplitBillParams.ts b/src/libs/API/parameters/StartSplitBillParams.ts index 8824f0f9c0e2..30d21697ac67 100644 --- a/src/libs/API/parameters/StartSplitBillParams.ts +++ b/src/libs/API/parameters/StartSplitBillParams.ts @@ -11,6 +11,7 @@ type StartSplitBillParams = { tag: string; isFromGroupDM: boolean; createdReportActionID?: string; + billable: boolean; }; export default StartSplitBillParams; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index a6dfda1c4221..ef6fb4371cfc 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -312,6 +312,7 @@ type OptimisticIOUReport = Pick< | 'chatReportID' | 'currency' | 'managerID' + | 'policyID' | 'ownerAccountID' | 'participantAccountIDs' | 'visibleChatMemberAccountIDs' diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 86c96ef981ca..2ce6a98acbfd 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -708,7 +708,7 @@ function getMoneyRequestInformation( // STEP 1: Get existing chat report OR build a new optimistic one let isNewChatReport = false; - let chatReport = parentChatReport?.reportID ? parentChatReport : null; + let chatReport = !isEmptyObject(parentChatReport) && parentChatReport?.reportID ? parentChatReport : null; // 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 @@ -728,12 +728,12 @@ function getMoneyRequestInformation( // STEP 2: Get the money request report. If the moneyRequestReportID has been provided, we want to add the transaction to this specific report. // If no such reportID has been provided, let's use the chatReport.iouReportID property. In case that is not present, build a new optimistic money request report. - let iouReport = null; + let iouReport: OnyxEntry = null; const shouldCreateNewMoneyRequestReport = !moneyRequestReportID && (!chatReport.iouReportID || ReportUtils.hasIOUWaitingOnCurrentUserBankAccount(chatReport)); if (moneyRequestReportID > 0) { - iouReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${moneyRequestReportID}`]; + iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${moneyRequestReportID}`] ?? null; } else if (!shouldCreateNewMoneyRequestReport) { - iouReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${chatReport.iouReportID}`]; + iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReport.iouReportID}`] ?? null; } // Check if the Scheduled Submit is enabled in case of expense report @@ -743,7 +743,7 @@ function getMoneyRequestInformation( isFromPaidPolicy = PolicyUtils.isPaidGroupPolicy(policy ?? null); // If the scheduled submit is turned off on the policy, user needs to manually submit the report which is indicated by GBR in LHN - needsToBeManuallySubmitted = isFromPaidPolicy && !(lodashGet(policy, 'harvesting.enabled', policy.isHarvestingEnabled) || false); + needsToBeManuallySubmitted = isFromPaidPolicy && !(policy?.harvesting?.enabled ?? policy?.isHarvestingEnabled); // If the linked expense report on paid policy is not draft, we need to create a new draft expense report if (iouReport && isFromPaidPolicy && !ReportUtils.isDraftExpenseReport(iouReport)) { @@ -3670,12 +3670,8 @@ function navigateToStartStepIfScanFileCannotBeRead( FileUtils.readFileAsync(receiptPath, receiptFilename, onSuccess, onFailure); } -/** - * Save the preferred payment method for a policy - * @param {String} policyID - * @param {String} paymentMethod - */ -function savePreferredPaymentMethod(policyID, paymentMethod) { +/** Save the preferred payment method for a policy */ +function savePreferredPaymentMethod(policyID: string, paymentMethod: PaymentMethodType) { Onyx.merge(`${ONYXKEYS.NVP_LAST_PAYMENT_METHOD}`, {[policyID]: paymentMethod}); } From f533ee1dd09bb6073a6bc9ff367863a8e922a2a4 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Fri, 2 Feb 2024 13:30:27 +0100 Subject: [PATCH 64/68] Update moneyRequestReportID default value --- src/libs/actions/IOU.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 2ce6a98acbfd..59a31e6d29c4 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -700,7 +700,7 @@ function getMoneyRequestInformation( policyCategories: OnyxTypes.PolicyCategories | undefined, payeeAccountID = userAccountID, payeeEmail = currentUserEmail, - moneyRequestReportID = 0, + moneyRequestReportID = '', ): MoneyRequestInformation { const payerEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login ?? ''); const payerAccountID = Number(participant.accountID); @@ -730,7 +730,7 @@ function getMoneyRequestInformation( // If no such reportID has been provided, let's use the chatReport.iouReportID property. In case that is not present, build a new optimistic money request report. let iouReport: OnyxEntry = null; const shouldCreateNewMoneyRequestReport = !moneyRequestReportID && (!chatReport.iouReportID || ReportUtils.hasIOUWaitingOnCurrentUserBankAccount(chatReport)); - if (moneyRequestReportID > 0) { + if (moneyRequestReportID) { iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${moneyRequestReportID}`] ?? null; } else if (!shouldCreateNewMoneyRequestReport) { iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReport.iouReportID}`] ?? null; @@ -916,7 +916,7 @@ function createDistanceRequest( // 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.getReport(report.chatReportID) : report; - const moneyRequestReportID = isMoneyRequestReport ? report.reportID : 0; + const moneyRequestReportID = isMoneyRequestReport ? report.reportID : ''; const currentCreated = DateUtils.enrichMoneyRequestTimestamp(created); const optimisticReceipt: Receipt = { @@ -1274,7 +1274,7 @@ function requestMoney( // 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 currentChatReport = isMoneyRequestReport ? ReportUtils.getReport(report.chatReportID) : report; - const moneyRequestReportID = isMoneyRequestReport ? report.reportID : 0; + const moneyRequestReportID = isMoneyRequestReport ? report.reportID : ''; const currentCreated = DateUtils.enrichMoneyRequestTimestamp(created); const {payerAccountID, payerEmail, iouReport, chatReport, transaction, iouAction, createdChatReportActionID, createdIOUReportActionID, reportPreviewAction, onyxData} = getMoneyRequestInformation( From c2b9fc7b48d3e705cf3c522e59bc2642754cbaeb Mon Sep 17 00:00:00 2001 From: VickyStash Date: Fri, 2 Feb 2024 13:44:02 +0100 Subject: [PATCH 65/68] Minor TS fix --- src/libs/ErrorUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ErrorUtils.ts b/src/libs/ErrorUtils.ts index 72aa4ef42137..f3a526c0785c 100644 --- a/src/libs/ErrorUtils.ts +++ b/src/libs/ErrorUtils.ts @@ -66,7 +66,7 @@ function getLatestErrorMessage(onyxData: T return errors[key]; } -function getLatestErrorMessageField(onyxData: TOnyxData): Record { +function getLatestErrorMessageField(onyxData: TOnyxData): Errors { const errors = onyxData.errors ?? {}; if (Object.keys(errors).length === 0) { From c445c5e0b94d3bb8d3f8de0508f6f24a7619ae10 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Sat, 3 Feb 2024 12:10:35 +0100 Subject: [PATCH 66/68] Lint fix --- src/ONYXKEYS.ts | 1 - src/types/onyx/Transaction.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index d94eefffacff..20553723462b 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -483,7 +483,6 @@ type OnyxValues = { [ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT]: OnyxTypes.Transaction; [ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS]: OnyxTypes.RecentlyUsedTags; [ONYXKEYS.COLLECTION.SELECTED_TAB]: string; - [ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS]: OnyxTypes.TransactionViolation[]; [ONYXKEYS.COLLECTION.PRIVATE_NOTES_DRAFT]: string; [ONYXKEYS.COLLECTION.NEXT_STEP]: OnyxTypes.ReportNextStep; diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 27bb359ab773..b559346a48de 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -208,4 +208,4 @@ type AdditionalTransactionChanges = { type TransactionChanges = Partial & AdditionalTransactionChanges; export default Transaction; -export type {WaypointCollection, Comment, Receipt, Waypoint, ReceiptError, ReceiptErrors, TransactionPendingFieldsKey, TransactionChanges, TaxRate, ReceiptSource}; +export type {WaypointCollection, Comment, Receipt, Waypoint, ReceiptError, ReceiptErrors, TransactionPendingFieldsKey, TransactionChanges, TaxRate, ReceiptSource}; From de69ae8ba702e9dc3162da578892a490ff56d90f Mon Sep 17 00:00:00 2001 From: VickyStash Date: Sat, 3 Feb 2024 12:17:58 +0100 Subject: [PATCH 67/68] Update comments --- src/components/TextInput/BaseTextInput/index.native.tsx | 2 +- src/components/TextInput/BaseTextInput/index.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/TextInput/BaseTextInput/index.native.tsx b/src/components/TextInput/BaseTextInput/index.native.tsx index 997b0cabe916..6f00f06c4c5e 100644 --- a/src/components/TextInput/BaseTextInput/index.native.tsx +++ b/src/components/TextInput/BaseTextInput/index.native.tsx @@ -249,7 +249,7 @@ function BaseTextInput( const hasLabel = Boolean(label?.length); const isReadOnly = inputProps.readOnly ?? inputProps.disabled; - // Disabling this line for safeness as nullish coalescing works only if the value is undefined or null + // Disabling this line for safeness as nullish coalescing works only if the value is undefined or null, and errorText can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const inputHelpText = errorText || hint; const placeholderValue = !!prefixCharacter || isFocused || !hasLabel || (hasLabel && forceActiveLabel) ? placeholder : undefined; diff --git a/src/components/TextInput/BaseTextInput/index.tsx b/src/components/TextInput/BaseTextInput/index.tsx index e49b8ad2e9c5..800eff15d242 100644 --- a/src/components/TextInput/BaseTextInput/index.tsx +++ b/src/components/TextInput/BaseTextInput/index.tsx @@ -244,7 +244,7 @@ function BaseTextInput( const hasLabel = Boolean(label?.length); const isReadOnly = inputProps.readOnly ?? inputProps.disabled; - // Disabling this line for safeness as nullish coalescing works only if the value is undefined or null + // Disabling this line for safeness as nullish coalescing works only if the value is undefined or null, and errorText can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const inputHelpText = errorText || hint; const newPlaceholder = !!prefixCharacter || isFocused || !hasLabel || (hasLabel && forceActiveLabel) ? placeholder : undefined; From 88d805d052323beb3fdf9bf2f12eb5bc34d9aba9 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 5 Feb 2024 14:37:34 +0100 Subject: [PATCH 68/68] Get rid of removed screen type --- src/libs/actions/IOU.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index d31daf3f62df..1376b6791997 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -59,10 +59,7 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; import * as Report from './Report'; -type MoneyRequestRoute = StackScreenProps< - MoneyRequestNavigatorParamList, - typeof SCREENS.MONEY_REQUEST.CATEGORY | typeof SCREENS.MONEY_REQUEST.TAG | typeof SCREENS.MONEY_REQUEST.CONFIRMATION ->['route']; +type MoneyRequestRoute = StackScreenProps['route']; type IOURequestType = ValueOf;