From 996ee26a0463376fc95539227a607b2cd5d18850 Mon Sep 17 00:00:00 2001 From: Viktoryia Kliushun Date: Thu, 28 Dec 2023 12:16:50 +0100 Subject: [PATCH 001/249] 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 002/249] 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 003/249] 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 004/249] 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 005/249] 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 006/249] 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 007/249] 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 008/249] 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 009/249] 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 010/249] 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 011/249] 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 012/249] 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 013/249] 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 10cb535cedbe180f6ef73c90bd6f8a9a501d6573 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Wed, 3 Jan 2024 12:02:34 +0300 Subject: [PATCH 014/249] Migrate SettlementButton.js component to TypeScript --- src/components/KYCWall/kycWallPropTypes.js | 5 + ...ttlementButton.js => SettlementButton.tsx} | 189 +++++++----------- 2 files changed, 79 insertions(+), 115 deletions(-) rename src/components/{SettlementButton.js => SettlementButton.tsx} (65%) diff --git a/src/components/KYCWall/kycWallPropTypes.js b/src/components/KYCWall/kycWallPropTypes.js index 2f14f1e12e11..aeda8544dd0d 100644 --- a/src/components/KYCWall/kycWallPropTypes.js +++ b/src/components/KYCWall/kycWallPropTypes.js @@ -65,6 +65,11 @@ const propTypes = { /** Whether the personal bank account option should be shown */ shouldShowPersonalBankAccountOption: PropTypes.bool, + + /** Callback to execute when KYC is successful */ + onSuccessfulKYC: PropTypes.func.isRequired, + + children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]).isRequired, }; const defaultProps = { diff --git a/src/components/SettlementButton.js b/src/components/SettlementButton.tsx similarity index 65% rename from src/components/SettlementButton.js rename to src/components/SettlementButton.tsx index 0c8e193af4cc..2786cd852434 100644 --- a/src/components/SettlementButton.js +++ b/src/components/SettlementButton.tsx @@ -1,143 +1,106 @@ -import PropTypes from 'prop-types'; -import React, {useEffect, useMemo} from 'react'; -import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; +import _ from 'lodash'; +import React, {MutableRefObject, useEffect, useMemo} from 'react'; +import {StyleProp, ViewStyle} from 'react-native'; +import {OnyxEntry, withOnyx} from 'react-native-onyx'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; -import compose from '@libs/compose'; import * as ReportUtils from '@libs/ReportUtils'; -import iouReportPropTypes from '@pages/iouReportPropTypes'; import * as BankAccounts from '@userActions/BankAccounts'; import * as IOU from '@userActions/IOU'; import * as PaymentMethods from '@userActions/PaymentMethods'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import {ButtonSizeValue} from '@src/styles/utils/types'; +import type {Report} from '@src/types/onyx'; +import {EmptyObject} from '@src/types/utils/EmptyObject'; import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; import * as Expensicons from './Icon/Expensicons'; import KYCWall from './KYCWall'; -import withNavigation from './withNavigation'; -const propTypes = { - /** Callback to execute when this button is pressed. Receives a single payment type argument. */ - onPress: PropTypes.func.isRequired, +type AnchorAlignment = { + horizontal: 'left' | 'right' | 'center'; + vertical: 'top' | 'center' | 'bottom'; +}; - /** Call the onPress function on main button when Enter key is pressed */ - pressOnEnter: PropTypes.bool, +type TriggerKYCFlow = (event: Event, iouPaymentType: string) => void; - /** Settlement currency type */ - currency: PropTypes.string, +type SettlementButtonOnyxProps = { + /** The last payment method used per policy */ + nvpLastPaymentMethod?: Record; +}; +type SettlementButtonProps = SettlementButtonOnyxProps & { + /** Callback to execute when this button is pressed. Receives a single payment type argument. */ + onPress: (paymentType: string) => void; + /** The route to redirect if user does not have a payment method setup */ + enablePaymentsRoute: string; + /** Call the onPress function on main button when Enter key is pressed */ + pressOnEnter?: boolean; + /** Settlement currency type */ + currency?: string; /** When the button is opened via an IOU, ID for the chatReport that the IOU is linked to */ - chatReportID: PropTypes.string, - + chatReportID?: string; /** The IOU/Expense report we are paying */ - iouReport: iouReportPropTypes, - - /** The route to redirect if user does not have a payment method setup */ - enablePaymentsRoute: PropTypes.string.isRequired, - - /** Should we show the approve button? */ - shouldHidePaymentOptions: PropTypes.bool, - + iouReport?: OnyxEntry | EmptyObject; /** Should we show the payment options? */ - shouldShowApproveButton: PropTypes.bool, - - /** The last payment method used per policy */ - nvp_lastPaymentMethod: PropTypes.objectOf(PropTypes.string), - + shouldHidePaymentOptions?: boolean; + /** Should we show the payment options? */ + shouldShowApproveButton?: boolean; /** The policyID of the report we are paying */ - policyID: PropTypes.string, - + policyID?: string; /** Additional styles to add to the component */ - style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]), - + style?: StyleProp; /** Total money amount in form */ - formattedAmount: PropTypes.string, - + formattedAmount?: string; /** The size of button size */ - buttonSize: PropTypes.oneOf(_.values(CONST.DROPDOWN_BUTTON_SIZE)), - + buttonSize?: ButtonSizeValue; // Replace with the actual sizes /** Route for the Add Bank Account screen for a given navigation stack */ - addBankAccountRoute: PropTypes.string, - + addBankAccountRoute?: string; /** Route for the Add Debit Card screen for a given navigation stack */ - addDebitCardRoute: PropTypes.string, - + addDebitCardRoute?: string; /** Whether the button should be disabled */ - isDisabled: PropTypes.bool, - + isDisabled?: boolean; /** Whether we should show a loading state for the main button */ - isLoading: PropTypes.bool, - + isLoading?: boolean; /** The anchor alignment of the popover menu for payment method dropdown */ - paymentMethodDropdownAnchorAlignment: PropTypes.shape({ - horizontal: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL)), - vertical: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_VERTICAL)), - }), - + paymentMethodDropdownAnchorAlignment?: AnchorAlignment; /** The anchor alignment of the popover menu for KYC wall popover */ - kycWallAnchorAlignment: PropTypes.shape({ - horizontal: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL)), - vertical: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_VERTICAL)), - }), - + kycWallAnchorAlignment?: AnchorAlignment; /** Whether the personal bank account option should be shown */ - shouldShowPersonalBankAccountOption: PropTypes.bool, + shouldShowPersonalBankAccountOption?: boolean; }; -const defaultProps = { - isLoading: false, - isDisabled: false, - pressOnEnter: false, - addBankAccountRoute: '', - addDebitCardRoute: '', - currency: CONST.CURRENCY.USD, - chatReportID: '', - - // The "iouReport" and "nvp_lastPaymentMethod" objects needs to be stable to prevent the "useMemo" - // hook from being recreated unnecessarily, hence the use of CONST.EMPTY_ARRAY and CONST.EMPTY_OBJECT - iouReport: CONST.EMPTY_OBJECT, - nvp_lastPaymentMethod: CONST.EMPTY_OBJECT, - shouldHidePaymentOptions: false, - shouldShowApproveButton: false, - style: [], - policyID: '', - formattedAmount: '', - buttonSize: CONST.DROPDOWN_BUTTON_SIZE.MEDIUM, - kycWallAnchorAlignment: { +function SettlementButton({ + addDebitCardRoute = '', + addBankAccountRoute = '', + kycWallAnchorAlignment = { horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT, // button is at left, so horizontal anchor is at LEFT vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP, // we assume that popover menu opens below the button, anchor is at TOP }, - paymentMethodDropdownAnchorAlignment: { + paymentMethodDropdownAnchorAlignment = { horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT, // caret for dropdown is at right, so horizontal anchor is at RIGHT vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP, // we assume that popover menu opens below the button, anchor is at TOP }, - shouldShowPersonalBankAccountOption: false, -}; - -function SettlementButton({ - addDebitCardRoute, - addBankAccountRoute, - kycWallAnchorAlignment, - paymentMethodDropdownAnchorAlignment, - buttonSize, - chatReportID, - currency, + buttonSize = CONST.DROPDOWN_BUTTON_SIZE.MEDIUM, + chatReportID = '', + currency = CONST.CURRENCY.USD, enablePaymentsRoute, - iouReport, - isDisabled, - isLoading, - formattedAmount, - nvp_lastPaymentMethod, + // The "iouReport" and "nvpLastPaymentMethod" objects needs to be stable to prevent the "useMemo" + // hook from being recreated unnecessarily, hence the use of CONST.EMPTY_ARRAY and CONST.EMPTY_OBJECT + iouReport = CONST.EMPTY_OBJECT, + nvpLastPaymentMethod = CONST.EMPTY_OBJECT, + isDisabled = false, + isLoading = false, + formattedAmount = '', onPress, - pressOnEnter, - policyID, - shouldHidePaymentOptions, - shouldShowApproveButton, - style, - shouldShowPersonalBankAccountOption, -}) { + pressOnEnter = false, + policyID = '', + shouldHidePaymentOptions = false, + shouldShowApproveButton = false, + style = [], + shouldShowPersonalBankAccountOption = false, +}: SettlementButtonProps) { const {translate} = useLocalize(); const {isOffline} = useNetwork(); @@ -179,7 +142,7 @@ function SettlementButton({ // To achieve the one tap pay experience we need to choose the correct payment type as default, // if user already paid for some request or expense, let's use the last payment method or use default. - const paymentMethod = nvp_lastPaymentMethod[policyID] || ''; + const paymentMethod = nvpLastPaymentMethod[policyID] || ''; if (canUseWallet) { buttonOptions.push(paymentMethods[CONST.IOU.PAYMENT_TYPE.EXPENSIFY]); } @@ -197,9 +160,9 @@ function SettlementButton({ return _.sortBy(buttonOptions, (method) => (method.value === paymentMethod ? 0 : 1)); } return buttonOptions; - }, [currency, formattedAmount, iouReport, nvp_lastPaymentMethod, policyID, translate, shouldHidePaymentOptions, shouldShowApproveButton]); + }, [currency, formattedAmount, iouReport, nvpLastPaymentMethod, policyID, translate, shouldHidePaymentOptions, shouldShowApproveButton]); - const selectPaymentType = (event, iouPaymentType, triggerKYCFlow) => { + const selectPaymentType = (event: Event, iouPaymentType: string, triggerKYCFlow: TriggerKYCFlow) => { if (iouPaymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY || iouPaymentType === CONST.IOU.PAYMENT_TYPE.VBBA) { triggerKYCFlow(event, iouPaymentType); BankAccounts.setPersonalBankAccountContinueKYCOnSuccess(ROUTES.ENABLE_PAYMENTS); @@ -227,7 +190,7 @@ function SettlementButton({ anchorAlignment={kycWallAnchorAlignment} shouldShowPersonalBankAccountOption={shouldShowPersonalBankAccountOption} > - {(triggerKYCFlow, buttonRef) => ( + {(triggerKYCFlow: TriggerKYCFlow, buttonRef: MutableRefObject) => ( selectPaymentType(event, iouPaymentType, triggerKYCFlow)} pressOnEnter={pressOnEnter} options={paymentButtonOptions} - style={style} + style={[style]} buttonSize={buttonSize} anchorAlignment={paymentMethodDropdownAnchorAlignment} /> @@ -244,15 +207,11 @@ function SettlementButton({ ); } -SettlementButton.propTypes = propTypes; -SettlementButton.defaultProps = defaultProps; SettlementButton.displayName = 'SettlementButton'; -export default compose( - withNavigation, - withOnyx({ - nvp_lastPaymentMethod: { - key: ONYXKEYS.NVP_LAST_PAYMENT_METHOD, - }, - }), -)(SettlementButton); +export default withOnyx({ + nvpLastPaymentMethod: { + key: ONYXKEYS.NVP_LAST_PAYMENT_METHOD, + selector: (paymentMethod) => paymentMethod ?? {}, + }, +})(SettlementButton); From 53e4b00429ebc9663d55599f3487d90280faea69 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Wed, 3 Jan 2024 13:06:18 +0300 Subject: [PATCH 015/249] Update types --- src/components/SettlementButton.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index 2786cd852434..3eb4ac844fb2 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -195,10 +195,10 @@ function SettlementButton({ buttonRef={buttonRef} isDisabled={isDisabled} isLoading={isLoading} - onPress={(event, iouPaymentType) => selectPaymentType(event, iouPaymentType, triggerKYCFlow)} + onPress={(event: Event, iouPaymentType: string) => selectPaymentType(event, iouPaymentType, triggerKYCFlow)} pressOnEnter={pressOnEnter} options={paymentButtonOptions} - style={[style]} + style={style as Record} buttonSize={buttonSize} anchorAlignment={paymentMethodDropdownAnchorAlignment} /> From 4711e1cd99dfae34ccb59c3de37a10b4f8f6a44c Mon Sep 17 00:00:00 2001 From: VickyStash Date: Thu, 4 Jan 2024 12:41:09 +0100 Subject: [PATCH 016/249] 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 017/249] 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 018/249] 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 019/249] 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 020/249] 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 021/249] 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 dcdf95b12e86c34f0efb4f366c0b01ee02fabf0b Mon Sep 17 00:00:00 2001 From: Yauheni Date: Fri, 5 Jan 2024 13:30:24 +0300 Subject: [PATCH 022/249] Update types --- src/components/Popover/types.ts | 13 ++-------- src/components/PopoverMenu.tsx | 2 +- src/components/SettlementButton.tsx | 37 ++++++++++++++++------------- src/types/onyx/AnchorAlignment.ts | 12 ++++++++++ 4 files changed, 35 insertions(+), 29 deletions(-) create mode 100644 src/types/onyx/AnchorAlignment.ts diff --git a/src/components/Popover/types.ts b/src/components/Popover/types.ts index 3d1f95822e6a..4875676a3caa 100644 --- a/src/components/Popover/types.ts +++ b/src/components/Popover/types.ts @@ -1,16 +1,7 @@ -import type {ValueOf} from 'type-fest'; import type {PopoverAnchorPosition} from '@components/Modal/types'; import type BaseModalProps from '@components/Modal/types'; import type {WindowDimensionsProps} from '@components/withWindowDimensions/types'; -import type CONST from '@src/CONST'; - -type AnchorAlignment = { - /** The horizontal anchor alignment of the popover */ - horizontal: ValueOf; - - /** The vertical anchor alignment of the popover */ - vertical: ValueOf; -}; +import type AnchorAlignment from '@src/types/onyx/AnchorAlignment'; type PopoverDimensions = { width: number; @@ -48,4 +39,4 @@ type PopoverProps = BaseModalProps & { type PopoverWithWindowDimensionsProps = PopoverProps & WindowDimensionsProps; -export type {PopoverProps, PopoverWithWindowDimensionsProps, AnchorAlignment}; +export type {PopoverProps, PopoverWithWindowDimensionsProps}; diff --git a/src/components/PopoverMenu.tsx b/src/components/PopoverMenu.tsx index 502bdbf83b53..9b59b87056e0 100644 --- a/src/components/PopoverMenu.tsx +++ b/src/components/PopoverMenu.tsx @@ -10,8 +10,8 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import CONST from '@src/CONST'; import type {AnchorPosition} from '@src/styles'; +import type AnchorAlignment from '@src/types/onyx/AnchorAlignment'; import MenuItem from './MenuItem'; -import type {AnchorAlignment} from './Popover/types'; import PopoverWithMeasuredContent from './PopoverWithMeasuredContent'; import Text from './Text'; diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index 3eb4ac844fb2..f09a31701536 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -1,7 +1,9 @@ import _ from 'lodash'; -import React, {MutableRefObject, useEffect, useMemo} from 'react'; -import {StyleProp, ViewStyle} from 'react-native'; -import {OnyxEntry, withOnyx} from 'react-native-onyx'; +import type {MutableRefObject} from 'react'; +import React, {useEffect, useMemo} from 'react'; +import type {StyleProp, ViewStyle} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; +import {withOnyx} from 'react-native-onyx'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import * as ReportUtils from '@libs/ReportUtils'; @@ -11,30 +13,29 @@ import * as PaymentMethods from '@userActions/PaymentMethods'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import {ButtonSizeValue} from '@src/styles/utils/types'; +import type {ButtonSizeValue} from '@src/styles/utils/types'; import type {Report} from '@src/types/onyx'; -import {EmptyObject} from '@src/types/utils/EmptyObject'; +import type AnchorAlignment from '@src/types/onyx/AnchorAlignment'; +import type DeepValueOf from '@src/types/utils/DeepValueOf'; +import type {EmptyObject} from '@src/types/utils/EmptyObject'; import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; import * as Expensicons from './Icon/Expensicons'; import KYCWall from './KYCWall'; -type AnchorAlignment = { - horizontal: 'left' | 'right' | 'center'; - vertical: 'top' | 'center' | 'bottom'; -}; - type TriggerKYCFlow = (event: Event, iouPaymentType: string) => void; +type PaymentType = DeepValueOf; + type SettlementButtonOnyxProps = { /** The last payment method used per policy */ - nvpLastPaymentMethod?: Record; + nvpLastPaymentMethod?: OnyxEntry>; }; type SettlementButtonProps = SettlementButtonOnyxProps & { /** Callback to execute when this button is pressed. Receives a single payment type argument. */ - onPress: (paymentType: string) => void; + onPress: (paymentType: PaymentType) => void; /** The route to redirect if user does not have a payment method setup */ - enablePaymentsRoute: string; + enablePaymentsRoute: typeof ROUTES.ENABLE_PAYMENTS | typeof ROUTES.IOU_SEND_ENABLE_PAYMENTS | typeof ROUTES.SETTINGS_ENABLE_PAYMENTS; /** Call the onPress function on main button when Enter key is pressed */ pressOnEnter?: boolean; /** Settlement currency type */ @@ -98,7 +99,7 @@ function SettlementButton({ policyID = '', shouldHidePaymentOptions = false, shouldShowApproveButton = false, - style = [], + style, shouldShowPersonalBankAccountOption = false, }: SettlementButtonProps) { const {translate} = useLocalize(); @@ -142,7 +143,7 @@ function SettlementButton({ // To achieve the one tap pay experience we need to choose the correct payment type as default, // if user already paid for some request or expense, let's use the last payment method or use default. - const paymentMethod = nvpLastPaymentMethod[policyID] || ''; + const paymentMethod = nvpLastPaymentMethod?.[policyID] ?? ''; if (canUseWallet) { buttonOptions.push(paymentMethods[CONST.IOU.PAYMENT_TYPE.EXPENSIFY]); } @@ -162,7 +163,7 @@ function SettlementButton({ return buttonOptions; }, [currency, formattedAmount, iouReport, nvpLastPaymentMethod, policyID, translate, shouldHidePaymentOptions, shouldShowApproveButton]); - const selectPaymentType = (event: Event, iouPaymentType: string, triggerKYCFlow: TriggerKYCFlow) => { + const selectPaymentType = (event: Event, iouPaymentType: PaymentType, triggerKYCFlow: TriggerKYCFlow) => { if (iouPaymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY || iouPaymentType === CONST.IOU.PAYMENT_TYPE.VBBA) { triggerKYCFlow(event, iouPaymentType); BankAccounts.setPersonalBankAccountContinueKYCOnSuccess(ROUTES.ENABLE_PAYMENTS); @@ -195,7 +196,9 @@ function SettlementButton({ buttonRef={buttonRef} isDisabled={isDisabled} isLoading={isLoading} - onPress={(event: Event, iouPaymentType: string) => selectPaymentType(event, iouPaymentType, triggerKYCFlow)} + onPress={(event: Event, iouPaymentType: PaymentType) => + selectPaymentType(event, iouPaymentType, triggerKYCFlow) + } pressOnEnter={pressOnEnter} options={paymentButtonOptions} style={style as Record} diff --git a/src/types/onyx/AnchorAlignment.ts b/src/types/onyx/AnchorAlignment.ts new file mode 100644 index 000000000000..899e3d9e277b --- /dev/null +++ b/src/types/onyx/AnchorAlignment.ts @@ -0,0 +1,12 @@ +import type {ValueOf} from 'type-fest'; +import type CONST from '@src/CONST'; + +type AnchorAlignment = { + /** The horizontal anchor alignment of the popover */ + horizontal: ValueOf; + + /** The vertical anchor alignment of the popover */ + vertical: ValueOf; +}; + +export default AnchorAlignment; From f3004da4052942de46f8134f1faa9a9434794593 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Fri, 5 Jan 2024 15:01:21 +0300 Subject: [PATCH 023/249] Update types x2 --- src/components/SettlementButton.tsx | 39 +++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index f09a31701536..a11481c99cb1 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -1,7 +1,6 @@ -import _ from 'lodash'; import type {MutableRefObject} from 'react'; import React, {useEffect, useMemo} from 'react'; -import type {StyleProp, ViewStyle} from 'react-native'; +import type {GestureResponderEvent, StyleProp, View, ViewStyle} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import useLocalize from '@hooks/useLocalize'; @@ -11,6 +10,7 @@ import * as BankAccounts from '@userActions/BankAccounts'; import * as IOU from '@userActions/IOU'; import * as PaymentMethods from '@userActions/PaymentMethods'; import CONST from '@src/CONST'; +import type {OnyxValues} from '@src/ONYXKEYS'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {ButtonSizeValue} from '@src/styles/utils/types'; @@ -22,52 +22,72 @@ import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; import * as Expensicons from './Icon/Expensicons'; import KYCWall from './KYCWall'; +type Event = GestureResponderEvent | KeyboardEvent; + type TriggerKYCFlow = (event: Event, iouPaymentType: string) => void; type PaymentType = DeepValueOf; type SettlementButtonOnyxProps = { /** The last payment method used per policy */ - nvpLastPaymentMethod?: OnyxEntry>; + nvpLastPaymentMethod?: OnyxEntry; }; type SettlementButtonProps = SettlementButtonOnyxProps & { /** Callback to execute when this button is pressed. Receives a single payment type argument. */ onPress: (paymentType: PaymentType) => void; + /** The route to redirect if user does not have a payment method setup */ enablePaymentsRoute: typeof ROUTES.ENABLE_PAYMENTS | typeof ROUTES.IOU_SEND_ENABLE_PAYMENTS | typeof ROUTES.SETTINGS_ENABLE_PAYMENTS; + /** Call the onPress function on main button when Enter key is pressed */ pressOnEnter?: boolean; + /** Settlement currency type */ currency?: string; + /** When the button is opened via an IOU, ID for the chatReport that the IOU is linked to */ chatReportID?: string; + /** The IOU/Expense report we are paying */ iouReport?: OnyxEntry | EmptyObject; + /** Should we show the payment options? */ shouldHidePaymentOptions?: boolean; + /** Should we show the payment options? */ shouldShowApproveButton?: boolean; + /** The policyID of the report we are paying */ policyID?: string; + /** Additional styles to add to the component */ style?: StyleProp; + /** Total money amount in form */ formattedAmount?: string; + /** The size of button size */ - buttonSize?: ButtonSizeValue; // Replace with the actual sizes + buttonSize?: ButtonSizeValue; + /** Route for the Add Bank Account screen for a given navigation stack */ addBankAccountRoute?: string; + /** Route for the Add Debit Card screen for a given navigation stack */ addDebitCardRoute?: string; + /** Whether the button should be disabled */ isDisabled?: boolean; + /** Whether we should show a loading state for the main button */ isLoading?: boolean; + /** The anchor alignment of the popover menu for payment method dropdown */ paymentMethodDropdownAnchorAlignment?: AnchorAlignment; + /** The anchor alignment of the popover menu for KYC wall popover */ kycWallAnchorAlignment?: AnchorAlignment; + /** Whether the personal bank account option should be shown */ shouldShowPersonalBankAccountOption?: boolean; }; @@ -158,7 +178,7 @@ function SettlementButton({ // Put the preferred payment method to the front of the array so its shown as default if (paymentMethod) { - return _.sortBy(buttonOptions, (method) => (method.value === paymentMethod ? 0 : 1)); + return buttonOptions.sort((method) => (method.value === paymentMethod ? 0 : 1)); } return buttonOptions; }, [currency, formattedAmount, iouReport, nvpLastPaymentMethod, policyID, translate, shouldHidePaymentOptions, shouldShowApproveButton]); @@ -191,17 +211,16 @@ function SettlementButton({ anchorAlignment={kycWallAnchorAlignment} shouldShowPersonalBankAccountOption={shouldShowPersonalBankAccountOption} > - {(triggerKYCFlow: TriggerKYCFlow, buttonRef: MutableRefObject) => ( + {(triggerKYCFlow: TriggerKYCFlow, buttonRef: MutableRefObject) => ( - selectPaymentType(event, iouPaymentType, triggerKYCFlow) - } + onPress={(event: Event, iouPaymentType: PaymentType) => selectPaymentType(event, iouPaymentType, triggerKYCFlow)} pressOnEnter={pressOnEnter} options={paymentButtonOptions} - style={style as Record} + // @ts-expect-error TODO: Remove this once OptionsListUtils (https://github.com/Expensify/App/issues/25065) is migrated to TypeScript. + style={style} buttonSize={buttonSize} anchorAlignment={paymentMethodDropdownAnchorAlignment} /> From e92901687bd21152499eca4cde4167d0f68e58da Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sat, 6 Jan 2024 19:01:19 +0530 Subject: [PATCH 024/249] fixed currency selection on confirm step --- src/libs/actions/IOU.js | 9 +++++++++ .../iou/request/step/IOURequestStepAmount.js | 19 ++++++++++++++++--- .../request/step/IOURequestStepCurrency.js | 4 +--- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index fb4e9f02f1b6..37e72b2133e3 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -198,6 +198,14 @@ function setMoneyRequestCurrency_temporaryForRefactor(transactionID, currency) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {currency}); } +/** + * @param {String} transactionID + * @param {String} originalCurrency + */ +function setMoneyRequestOriginalCurrency_temporaryForRefactor(transactionID, originalCurrency) { + Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {originalCurrency}); +} + /** * @param {String} transactionID * @param {String} comment @@ -3566,6 +3574,7 @@ export { setMoneyRequestCategory_temporaryForRefactor, setMoneyRequestCreated_temporaryForRefactor, setMoneyRequestCurrency_temporaryForRefactor, + setMoneyRequestOriginalCurrency_temporaryForRefactor, setMoneyRequestDescription_temporaryForRefactor, setMoneyRequestMerchant_temporaryForRefactor, setMoneyRequestParticipants_temporaryForRefactor, diff --git a/src/pages/iou/request/step/IOURequestStepAmount.js b/src/pages/iou/request/step/IOURequestStepAmount.js index 84e0ac8533c5..55826244434f 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.js +++ b/src/pages/iou/request/step/IOURequestStepAmount.js @@ -1,6 +1,6 @@ import {useFocusEffect} from '@react-navigation/native'; import PropTypes from 'prop-types'; -import React, {useCallback, useRef} from 'react'; +import React, {useCallback, useEffect, useRef} from 'react'; import {withOnyx} from 'react-native-onyx'; import taxPropTypes from '@components/taxPropTypes'; import transactionPropTypes from '@components/transactionPropTypes'; @@ -62,15 +62,16 @@ function IOURequestStepAmount({ params: {iouType, reportID, transactionID, backTo, currency: selectedCurrency}, }, transaction, - transaction: {currency: originalCurrency}, + transaction: {currency: currentCurrency}, policyTaxRates, policy, }) { const {translate} = useLocalize(); const textInput = useRef(null); const focusTimeoutRef = useRef(null); + const isSaveButtonPressed = useRef(false); const iouRequestType = getRequestType(transaction); - const currency = selectedCurrency || originalCurrency; + const currency = selectedCurrency || currentCurrency; const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(report)); const isTaxTrackingEnabled = isPolicyExpenseChat && policy.isTaxTrackingEnabled; @@ -87,6 +88,17 @@ function IOURequestStepAmount({ }, []), ); + useEffect(() => { + IOU.setMoneyRequestOriginalCurrency_temporaryForRefactor(transactionID, currentCurrency); + return () => { + if (isSaveButtonPressed.current) { + return; + } + IOU.setMoneyRequestCurrency_temporaryForRefactor(transactionID, transaction.originalCurrency); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + const navigateBack = () => { Navigation.goBack(backTo || ROUTES.HOME); }; @@ -99,6 +111,7 @@ function IOURequestStepAmount({ * @param {Number} amount */ const navigateToNextPage = ({amount}) => { + isSaveButtonPressed.current = true; const amountInSmallestCurrencyUnits = CurrencyUtils.convertToBackendAmount(Number.parseFloat(amount)); if ((iouRequestType === CONST.IOU.REQUEST_TYPE.MANUAL || backTo) && isTaxTrackingEnabled) { diff --git a/src/pages/iou/request/step/IOURequestStepCurrency.js b/src/pages/iou/request/step/IOURequestStepCurrency.js index b4281de4d16e..ea6173408371 100644 --- a/src/pages/iou/request/step/IOURequestStepCurrency.js +++ b/src/pages/iou/request/step/IOURequestStepCurrency.js @@ -82,9 +82,7 @@ function IOURequestStepCurrency({ */ const confirmCurrencySelection = (option) => { Keyboard.dismiss(); - if (pageIndex !== 'confirm') { - IOU.setMoneyRequestCurrency_temporaryForRefactor(transactionID, option.currencyCode); - } + IOU.setMoneyRequestCurrency_temporaryForRefactor(transactionID, option.currencyCode); navigateBack(option.currencyCode); }; From ef3810cf358833bd609a8f75db282118d69d6bdc Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sat, 6 Jan 2024 21:14:02 +0530 Subject: [PATCH 025/249] fixed minor bugs regarding currency change --- src/libs/actions/IOU.js | 14 ++++++++++++-- src/pages/iou/request/step/IOURequestStepAmount.js | 6 ++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 37e72b2133e3..098685206c2c 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -177,8 +177,13 @@ function clearMoneyRequest(transactionID) { * @param {String} transactionID * @param {Number} amount * @param {String} currency + * @param {Boolean} [removeOriginalCurrency] */ -function setMoneyRequestAmount_temporaryForRefactor(transactionID, amount, currency) { +function setMoneyRequestAmount_temporaryForRefactor(transactionID, amount, currency, removeOriginalCurrency = false) { + if (removeOriginalCurrency) { + Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {amount, currency, originalCurrency: null}); + return; + } Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {amount, currency}); } @@ -193,8 +198,13 @@ function setMoneyRequestCreated_temporaryForRefactor(transactionID, created) { /** * @param {String} transactionID * @param {String} currency + * @param {Boolean} [removeOriginalCurrency] */ -function setMoneyRequestCurrency_temporaryForRefactor(transactionID, currency) { +function setMoneyRequestCurrency_temporaryForRefactor(transactionID, currency, removeOriginalCurrency = false) { + if (removeOriginalCurrency) { + Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {currency, originalCurrency: null}); + return; + } Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {currency}); } diff --git a/src/pages/iou/request/step/IOURequestStepAmount.js b/src/pages/iou/request/step/IOURequestStepAmount.js index 55826244434f..99dd9ba25ae8 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.js +++ b/src/pages/iou/request/step/IOURequestStepAmount.js @@ -70,6 +70,7 @@ function IOURequestStepAmount({ const textInput = useRef(null); const focusTimeoutRef = useRef(null); const isSaveButtonPressed = useRef(false); + const originalCurrency = useRef(null); const iouRequestType = getRequestType(transaction); const currency = selectedCurrency || currentCurrency; @@ -89,12 +90,13 @@ function IOURequestStepAmount({ ); useEffect(() => { + originalCurrency.current = currentCurrency; IOU.setMoneyRequestOriginalCurrency_temporaryForRefactor(transactionID, currentCurrency); return () => { if (isSaveButtonPressed.current) { return; } - IOU.setMoneyRequestCurrency_temporaryForRefactor(transactionID, transaction.originalCurrency); + IOU.setMoneyRequestCurrency_temporaryForRefactor(transactionID, originalCurrency.current, true); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -120,7 +122,7 @@ function IOURequestStepAmount({ IOU.setMoneyRequestTaxAmount(transaction.transactionID, taxAmountInSmallestCurrencyUnits); } - IOU.setMoneyRequestAmount_temporaryForRefactor(transactionID, amountInSmallestCurrencyUnits, currency || CONST.CURRENCY.USD); + IOU.setMoneyRequestAmount_temporaryForRefactor(transactionID, amountInSmallestCurrencyUnits, currency || CONST.CURRENCY.USD, true); if (backTo) { Navigation.goBack(backTo); From ca2763dd1ffa2bbbeeebb0123b6b5f98f48de9a8 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sat, 6 Jan 2024 21:17:06 +0530 Subject: [PATCH 026/249] fixed deep linking bugs --- src/pages/iou/request/step/IOURequestStepAmount.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepAmount.js b/src/pages/iou/request/step/IOURequestStepAmount.js index 99dd9ba25ae8..8e16af248dc4 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.js +++ b/src/pages/iou/request/step/IOURequestStepAmount.js @@ -90,8 +90,12 @@ function IOURequestStepAmount({ ); useEffect(() => { - originalCurrency.current = currentCurrency; - IOU.setMoneyRequestOriginalCurrency_temporaryForRefactor(transactionID, currentCurrency); + if (transaction.originalCurrency) { + originalCurrency.current = transaction.originalCurrency; + } else { + originalCurrency.current = currentCurrency; + IOU.setMoneyRequestOriginalCurrency_temporaryForRefactor(transactionID, currentCurrency); + } return () => { if (isSaveButtonPressed.current) { return; From 939684581574a4e63218d80805d231ee3a18b3fa Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sat, 6 Jan 2024 21:20:10 +0530 Subject: [PATCH 027/249] mirroring changes in tax step --- .../step/IOURequestStepTaxAmountPage.js | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js b/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js index 8ee3abb56d00..70b2ccd7e270 100644 --- a/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js +++ b/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js @@ -1,5 +1,5 @@ import {useFocusEffect} from '@react-navigation/native'; -import React, {useCallback, useRef} from 'react'; +import React, {useCallback, useRef, useEffect} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; @@ -56,7 +56,7 @@ function IOURequestStepTaxAmountPage({ params: {iouType, reportID, transactionID, backTo, currency: selectedCurrency}, }, transaction, - transaction: {currency: originalCurrency}, + transaction: {currency: currentCurrency}, report, policyTaxRates, }) { @@ -65,10 +65,29 @@ function IOURequestStepTaxAmountPage({ const textInput = useRef(null); const isEditing = Navigation.getActiveRoute().includes('taxAmount'); - const currency = selectedCurrency || originalCurrency; + const currency = selectedCurrency || currentCurrency; const focusTimeoutRef = useRef(null); + const isSaveButtonPressed = useRef(false); + const originalCurrency = useRef(null); + + useEffect(() => { + if (transaction.originalCurrency) { + originalCurrency.current = transaction.originalCurrency; + } else { + originalCurrency.current = currentCurrency; + IOU.setMoneyRequestOriginalCurrency_temporaryForRefactor(transactionID, currentCurrency); + } + return () => { + if (isSaveButtonPressed.current) { + return; + } + IOU.setMoneyRequestCurrency_temporaryForRefactor(transactionID, originalCurrency.current, true); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + useFocusEffect( useCallback(() => { focusTimeoutRef.current = setTimeout(() => textInput.current && textInput.current.focus(), CONST.ANIMATED_TRANSITION); @@ -93,10 +112,11 @@ function IOURequestStepTaxAmountPage({ }; const updateTaxAmount = (currentAmount) => { + isSaveButtonPressed.current = true; const amountInSmallestCurrencyUnits = CurrencyUtils.convertToBackendAmount(Number.parseFloat(currentAmount.amount)); IOU.setMoneyRequestTaxAmount(transactionID, amountInSmallestCurrencyUnits); - IOU.setMoneyRequestCurrency_temporaryForRefactor(transactionID, currency || CONST.CURRENCY.USD); + IOU.setMoneyRequestCurrency_temporaryForRefactor(transactionID, currency || CONST.CURRENCY.USD, true); if (backTo) { Navigation.goBack(backTo); From db92b88156a975a959177cd93eade70856a20339 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sat, 6 Jan 2024 21:22:59 +0530 Subject: [PATCH 028/249] fix lint --- src/pages/iou/request/step/IOURequestStepTaxAmountPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js b/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js index 70b2ccd7e270..9cfd8f7ddf26 100644 --- a/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js +++ b/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js @@ -1,5 +1,5 @@ import {useFocusEffect} from '@react-navigation/native'; -import React, {useCallback, useRef, useEffect} from 'react'; +import React, {useCallback, useEffect, useRef} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; From f27c0371bd62b2f08811aecadb07e803b1888f50 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sat, 6 Jan 2024 21:32:26 +0530 Subject: [PATCH 029/249] removed unecessary param --- src/pages/iou/request/step/IOURequestStepAmount.js | 9 ++++----- src/pages/iou/request/step/IOURequestStepCurrency.js | 10 +++------- .../iou/request/step/IOURequestStepTaxAmountPage.js | 10 ++++------ 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepAmount.js b/src/pages/iou/request/step/IOURequestStepAmount.js index 8e16af248dc4..f91e7cea533b 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.js +++ b/src/pages/iou/request/step/IOURequestStepAmount.js @@ -59,10 +59,10 @@ const getTaxAmount = (transaction, defaultTaxValue, amount) => { function IOURequestStepAmount({ report, route: { - params: {iouType, reportID, transactionID, backTo, currency: selectedCurrency}, + params: {iouType, reportID, transactionID, backTo}, }, transaction, - transaction: {currency: currentCurrency}, + transaction: {currency}, policyTaxRates, policy, }) { @@ -72,7 +72,6 @@ function IOURequestStepAmount({ const isSaveButtonPressed = useRef(false); const originalCurrency = useRef(null); const iouRequestType = getRequestType(transaction); - const currency = selectedCurrency || currentCurrency; const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(report)); const isTaxTrackingEnabled = isPolicyExpenseChat && policy.isTaxTrackingEnabled; @@ -93,8 +92,8 @@ function IOURequestStepAmount({ if (transaction.originalCurrency) { originalCurrency.current = transaction.originalCurrency; } else { - originalCurrency.current = currentCurrency; - IOU.setMoneyRequestOriginalCurrency_temporaryForRefactor(transactionID, currentCurrency); + originalCurrency.current = currency; + IOU.setMoneyRequestOriginalCurrency_temporaryForRefactor(transactionID, currency); } return () => { if (isSaveButtonPressed.current) { diff --git a/src/pages/iou/request/step/IOURequestStepCurrency.js b/src/pages/iou/request/step/IOURequestStepCurrency.js index ea6173408371..06af0ecf3ca4 100644 --- a/src/pages/iou/request/step/IOURequestStepCurrency.js +++ b/src/pages/iou/request/step/IOURequestStepCurrency.js @@ -59,18 +59,14 @@ function IOURequestStepCurrency({ const [searchValue, setSearchValue] = useState(''); const optionsSelectorRef = useRef(); - const navigateBack = (selectedCurrency = undefined) => { + const navigateBack = () => { // If the currency selection was done from the confirmation step (eg. + > request money > manual > confirm > amount > currency) // then the user needs taken back to the confirmation page instead of the initial amount page. This is because the route params // are only able to handle one backTo param at a time and the user needs to go back to the amount page before going back // to the confirmation page if (pageIndex === 'confirm') { const routeToAmountPageWithConfirmationAsBackTo = getUrlWithBackToParam(backTo, `/${ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, transactionID, reportID)}`); - if (selectedCurrency) { - Navigation.navigate(`${routeToAmountPageWithConfirmationAsBackTo}¤cy=${selectedCurrency}`); - } else { - Navigation.goBack(routeToAmountPageWithConfirmationAsBackTo); - } + Navigation.goBack(routeToAmountPageWithConfirmationAsBackTo); return; } Navigation.goBack(backTo || ROUTES.HOME); @@ -83,7 +79,7 @@ function IOURequestStepCurrency({ const confirmCurrencySelection = (option) => { Keyboard.dismiss(); IOU.setMoneyRequestCurrency_temporaryForRefactor(transactionID, option.currencyCode); - navigateBack(option.currencyCode); + navigateBack(); }; const {sections, headerMessage, initiallyFocusedOptionKey} = useMemo(() => { diff --git a/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js b/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js index 9cfd8f7ddf26..5c968b8415a4 100644 --- a/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js +++ b/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js @@ -53,10 +53,10 @@ const getTaxAmount = (transaction, defaultTaxValue) => { function IOURequestStepTaxAmountPage({ route: { - params: {iouType, reportID, transactionID, backTo, currency: selectedCurrency}, + params: {iouType, reportID, transactionID, backTo}, }, transaction, - transaction: {currency: currentCurrency}, + transaction: {currency}, report, policyTaxRates, }) { @@ -65,8 +65,6 @@ function IOURequestStepTaxAmountPage({ const textInput = useRef(null); const isEditing = Navigation.getActiveRoute().includes('taxAmount'); - const currency = selectedCurrency || currentCurrency; - const focusTimeoutRef = useRef(null); const isSaveButtonPressed = useRef(false); @@ -76,8 +74,8 @@ function IOURequestStepTaxAmountPage({ if (transaction.originalCurrency) { originalCurrency.current = transaction.originalCurrency; } else { - originalCurrency.current = currentCurrency; - IOU.setMoneyRequestOriginalCurrency_temporaryForRefactor(transactionID, currentCurrency); + originalCurrency.current = currency; + IOU.setMoneyRequestOriginalCurrency_temporaryForRefactor(transactionID, currency); } return () => { if (isSaveButtonPressed.current) { From c92cde7964361533e28ef4b04f8ce1880faba90a Mon Sep 17 00:00:00 2001 From: Yauheni Date: Mon, 8 Jan 2024 10:59:51 +0300 Subject: [PATCH 030/249] Fix ts issue --- src/components/ProcessMoneyRequestHoldMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ProcessMoneyRequestHoldMenu.tsx b/src/components/ProcessMoneyRequestHoldMenu.tsx index 1b711633ed3b..a6b53da467b5 100644 --- a/src/components/ProcessMoneyRequestHoldMenu.tsx +++ b/src/components/ProcessMoneyRequestHoldMenu.tsx @@ -2,11 +2,11 @@ import React from 'react'; import {View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; +import type AnchorAlignment from '@src/types/onyx/AnchorAlignment'; import Button from './Button'; import HoldMenuSectionList from './HoldMenuSectionList'; import type {PopoverAnchorPosition} from './Modal/types'; import Popover from './Popover'; -import type {AnchorAlignment} from './Popover/types'; import Text from './Text'; import TextPill from './TextPill'; From 63576708f951cd44fa6750572fac4b7e2d12eed7 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 8 Jan 2024 09:34:52 +0100 Subject: [PATCH 031/249] 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 032/249] 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 033/249] 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 034/249] 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 035/249] 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 036/249] 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 037/249] 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 038/249] 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 039/249] 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 040/249] 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 041/249] 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 042/249] 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 043/249] 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 044/249] 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 cf01991b76d89dcf4c700e47df981cc0f6e3ed84 Mon Sep 17 00:00:00 2001 From: someone-here Date: Tue, 9 Jan 2024 20:27:16 +0530 Subject: [PATCH 045/249] Migrate welcome message to room description for report --- src/CONST.ts | 1 - src/ONYXKEYS.ts | 8 +-- src/ROUTES.ts | 6 +-- src/SCREENS.ts | 4 +- src/components/ReportWelcomeText.tsx | 27 ++++++---- src/languages/en.ts | 8 +-- src/languages/es.ts | 8 +-- .../AppNavigator/ModalStackNavigators.tsx | 8 +-- .../Navigators/RightModalNavigator.tsx | 4 +- src/libs/Navigation/linkingConfig.ts | 4 +- src/libs/Navigation/types.ts | 8 +-- src/libs/Permissions.ts | 2 +- src/libs/ReportUtils.ts | 22 +++++--- src/libs/actions/Report.ts | 26 +++++----- ...essagePage.js => ReportDescriptionPage.js} | 52 +++++++++---------- src/pages/ReportDetailsPage.js | 8 +++ src/pages/home/HeaderView.js | 49 +++++++++++++---- .../settings/Report/ReportSettingsPage.js | 11 ---- src/pages/workspace/WorkspaceNewRoomPage.js | 10 ++-- src/types/onyx/Report.ts | 1 - 20 files changed, 155 insertions(+), 112 deletions(-) rename src/pages/{ReportWelcomeMessagePage.js => ReportDescriptionPage.js} (71%) diff --git a/src/CONST.ts b/src/CONST.ts index c6849db630f2..8fcb888d65da 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1534,7 +1534,6 @@ const CONST = { INVITE: 'invite', SETTINGS: 'settings', LEAVE_ROOM: 'leaveRoom', - WELCOME_MESSAGE: 'welcomeMessage', PRIVATE_NOTES: 'privateNotes', }, EDIT_REQUEST_FIELD: { diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 89ddbdc06883..0ef82873e929 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -302,8 +302,8 @@ const ONYXKEYS = { DISPLAY_NAME_FORM_DRAFT: 'displayNameFormDraft', ROOM_NAME_FORM: 'roomNameForm', ROOM_NAME_FORM_DRAFT: 'roomNameFormDraft', - WELCOME_MESSAGE_FORM: 'welcomeMessageForm', - WELCOME_MESSAGE_FORM_DRAFT: 'welcomeMessageFormDraft', + REPORT_DESCRIPTION_FORM: 'reportDescriptionForm', + REPORT_DESCRIPTION_FORM_DRAFT: 'reportDescriptionFormDraft', LEGAL_NAME_FORM: 'legalNameForm', LEGAL_NAME_FORM_DRAFT: 'legalNameFormDraft', WORKSPACE_INVITE_MESSAGE_FORM: 'workspaceInviteMessageForm', @@ -478,8 +478,8 @@ type OnyxValues = { [ONYXKEYS.FORMS.DISPLAY_NAME_FORM_DRAFT]: OnyxTypes.Form; [ONYXKEYS.FORMS.ROOM_NAME_FORM]: OnyxTypes.Form; [ONYXKEYS.FORMS.ROOM_NAME_FORM_DRAFT]: OnyxTypes.Form; - [ONYXKEYS.FORMS.WELCOME_MESSAGE_FORM]: OnyxTypes.Form; - [ONYXKEYS.FORMS.WELCOME_MESSAGE_FORM_DRAFT]: OnyxTypes.Form; + [ONYXKEYS.FORMS.REPORT_DESCRIPTION_FORM]: OnyxTypes.Form; + [ONYXKEYS.FORMS.REPORT_DESCRIPTION_FORM_DRAFT]: OnyxTypes.Form; [ONYXKEYS.FORMS.LEGAL_NAME_FORM]: OnyxTypes.Form; [ONYXKEYS.FORMS.LEGAL_NAME_FORM_DRAFT]: OnyxTypes.Form; [ONYXKEYS.FORMS.WORKSPACE_INVITE_MESSAGE_FORM]: OnyxTypes.Form; diff --git a/src/ROUTES.ts b/src/ROUTES.ts index e8a860582bb1..1dfe3a2dcf84 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -195,9 +195,9 @@ const ROUTES = { route: 'r/:reportID/settings/who-can-post', getRoute: (reportID: string) => `r/${reportID}/settings/who-can-post` as const, }, - REPORT_WELCOME_MESSAGE: { - route: 'r/:reportID/welcomeMessage', - getRoute: (reportID: string) => `r/${reportID}/welcomeMessage` as const, + REPORT_DESCRIPTION: { + route: 'r/:reportID/roomDescription', + getRoute: (reportID: string) => `r/${reportID}/roomDescription` as const, }, SPLIT_BILL_DETAILS: { route: 'r/:reportID/split/:reportActionID', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 703cb309d641..b053782d43be 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -91,7 +91,7 @@ const SCREENS = { PROFILE: 'Profile', REPORT_DETAILS: 'Report_Details', REPORT_SETTINGS: 'Report_Settings', - REPORT_WELCOME_MESSAGE: 'Report_WelcomeMessage', + REPORT_DESCRIPTION: 'Report_Description', PARTICIPANTS: 'Participants', MONEY_REQUEST: 'MoneyRequest', NEW_TASK: 'NewTask', @@ -233,7 +233,7 @@ const SCREENS = { DETAILS_ROOT: 'Details_Root', PROFILE_ROOT: 'Profile_Root', PROCESS_MONEY_REQUEST_HOLD_ROOT: 'ProcessMoneyRequestHold_Root', - REPORT_WELCOME_MESSAGE_ROOT: 'Report_WelcomeMessage_Root', + REPORT_DESCRIPTION_ROOT: 'Report_Description_Root', REPORT_PARTICIPANTS_ROOT: 'ReportParticipants_Root', ROOM_MEMBERS_ROOT: 'RoomMembers_Root', ROOM_INVITE_ROOT: 'RoomInvite_Root', diff --git a/src/components/ReportWelcomeText.tsx b/src/components/ReportWelcomeText.tsx index b337c3581213..2c544720a22d 100644 --- a/src/components/ReportWelcomeText.tsx +++ b/src/components/ReportWelcomeText.tsx @@ -12,6 +12,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {PersonalDetailsList, Policy, Report} from '@src/types/onyx'; +import RenderHTML from './RenderHTML'; import Text from './Text'; import UserDetailsTooltip from './UserDetailsTooltip'; @@ -73,17 +74,23 @@ function ReportWelcomeText({report, policy, personalDetails}: ReportWelcomeTextP )} {isChatRoom && ( <> - {roomWelcomeMessage.phrase1} - {roomWelcomeMessage.showReportName && ( - - {ReportUtils.getReportName(report)} - + {report?.description ? ( + + ) : ( + <> + {roomWelcomeMessage.phrase1} + {roomWelcomeMessage.showReportName && ( + + {ReportUtils.getReportName(report)} + + )} + {roomWelcomeMessage.phrase2 !== undefined && {roomWelcomeMessage.phrase2}} + )} - {roomWelcomeMessage.phrase2 !== undefined && {roomWelcomeMessage.phrase2}} )} {isDefault && ( diff --git a/src/languages/en.ts b/src/languages/en.ts index c57b1ce310b5..e90060b3f740 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1033,10 +1033,10 @@ export default { }, }, }, - welcomeMessagePage: { - welcomeMessage: 'Welcome message', - welcomeMessageOptional: 'Welcome message (optional)', - explainerText: 'Set a custom welcome message that will be sent to users when they join this room.', + reportDescriptionPage: { + roomDescription: 'Room description', + roomDescriptionOptional: 'Room description (optional)', + explainerText: 'Set a custom decription for the room.', }, languagePage: { language: 'Language', diff --git a/src/languages/es.ts b/src/languages/es.ts index b83385b602c8..29688d4a19ae 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1032,10 +1032,10 @@ export default { }, }, }, - welcomeMessagePage: { - welcomeMessage: 'Mensaje de bienvenida', - welcomeMessageOptional: 'Mensaje de bienvenida (opcional)', - explainerText: 'Configura un mensaje de bienvenida privado y personalizado que se enviará cuando los usuarios se unan a esta sala de chat.', + reportDescriptionPage: { + roomDescription: 'Descripción de la habitación', + roomDescriptionOptional: 'Descripción de la habitación (opcional)', + explainerText: 'Establece una descripción personalizada para la habitación.', }, languagePage: { language: 'Idioma', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index 4be1c988561b..e033de853275 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -17,9 +17,9 @@ import type { ProfileNavigatorParamList, ReferralDetailsNavigatorParamList, ReimbursementAccountNavigatorParamList, + ReportDescriptionNavigatorParamList, ReportDetailsNavigatorParamList, ReportSettingsNavigatorParamList, - ReportWelcomeMessageNavigatorParamList, RoomInviteNavigatorParamList, RoomMembersNavigatorParamList, SearchNavigatorParamList, @@ -141,8 +141,8 @@ const TaskModalStackNavigator = createModalStackNavigator require('../../../pages/tasks/TaskAssigneeSelectorModal').default as React.ComponentType, }); -const ReportWelcomeMessageModalStackNavigator = createModalStackNavigator({ - [SCREENS.REPORT_WELCOME_MESSAGE_ROOT]: () => require('../../../pages/ReportWelcomeMessagePage').default as React.ComponentType, +const ReportDescriptionModalStackNavigator = createModalStackNavigator({ + [SCREENS.REPORT_DESCRIPTION_ROOT]: () => require('../../../pages/ReportDescriptionPage').default as React.ComponentType, }); const ReportParticipantsModalStackNavigator = createModalStackNavigator({ @@ -295,7 +295,7 @@ export { ReportDetailsModalStackNavigator, TaskModalStackNavigator, ReportSettingsModalStackNavigator, - ReportWelcomeMessageModalStackNavigator, + ReportDescriptionModalStackNavigator, ReportParticipantsModalStackNavigator, SearchModalStackNavigator, NewChatModalStackNavigator, diff --git a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx index 7721a64adea9..93d2f8fba989 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx @@ -62,8 +62,8 @@ function RightModalNavigator({navigation}: RightModalNavigatorProps) { component={ModalStackNavigators.ReportSettingsModalStackNavigator} /> = { }, }, }, - [SCREENS.RIGHT_MODAL.REPORT_WELCOME_MESSAGE]: { + [SCREENS.RIGHT_MODAL.REPORT_DESCRIPTION]: { screens: { - [SCREENS.REPORT_WELCOME_MESSAGE_ROOT]: ROUTES.REPORT_WELCOME_MESSAGE.route, + [SCREENS.REPORT_DESCRIPTION_ROOT]: ROUTES.REPORT_DESCRIPTION.route, }, }, [SCREENS.RIGHT_MODAL.NEW_CHAT]: { diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 90f5361f11f4..fd6942f8c9c6 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -161,8 +161,8 @@ type ReportSettingsNavigatorParamList = { [SCREENS.REPORT_SETTINGS.WRITE_CAPABILITY]: undefined; }; -type ReportWelcomeMessageNavigatorParamList = { - [SCREENS.REPORT_WELCOME_MESSAGE_ROOT]: {reportID: string}; +type ReportDescriptionNavigatorParamList = { + [SCREENS.REPORT_DESCRIPTION_ROOT]: {reportID: string}; }; type ParticipantsNavigatorParamList = { @@ -361,7 +361,7 @@ type RightModalNavigatorParamList = { [SCREENS.RIGHT_MODAL.PROFILE]: NavigatorScreenParams; [SCREENS.RIGHT_MODAL.REPORT_DETAILS]: NavigatorScreenParams; [SCREENS.RIGHT_MODAL.REPORT_SETTINGS]: NavigatorScreenParams; - [SCREENS.RIGHT_MODAL.REPORT_WELCOME_MESSAGE]: NavigatorScreenParams; + [SCREENS.RIGHT_MODAL.REPORT_DESCRIPTION]: NavigatorScreenParams; [SCREENS.RIGHT_MODAL.PARTICIPANTS]: NavigatorScreenParams; [SCREENS.RIGHT_MODAL.ROOM_MEMBERS]: NavigatorScreenParams; [SCREENS.RIGHT_MODAL.ROOM_INVITE]: NavigatorScreenParams; @@ -447,7 +447,7 @@ export type { ReportDetailsNavigatorParamList, ReportSettingsNavigatorParamList, TaskDetailsNavigatorParamList, - ReportWelcomeMessageNavigatorParamList, + ReportDescriptionNavigatorParamList, ParticipantsNavigatorParamList, RoomMembersNavigatorParamList, RoomInviteNavigatorParamList, diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts index ce5e0e674c59..582115b0a914 100644 --- a/src/libs/Permissions.ts +++ b/src/libs/Permissions.ts @@ -3,7 +3,7 @@ import CONST from '@src/CONST'; import type Beta from '@src/types/onyx/Beta'; function canUseAllBetas(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.ALL); + return !!betas?.includes(CONST.BETAS.ALL) || true; } function canUseChronos(betas: OnyxEntry): boolean { diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 0d7658adf180..26a69cc51818 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -218,7 +218,7 @@ type OptimisticChatReport = Pick< | 'stateNum' | 'statusNum' | 'visibility' - | 'welcomeMessage' + | 'description' | 'writeCapability' >; @@ -2388,6 +2388,15 @@ function getParsedComment(text: string): string { return text.length <= CONST.MAX_MARKUP_LENGTH ? parser.replace(text) : lodashEscape(text); } +function getReportDescriptionText(report: Report): string { + if (!report.description) { + return ''; + } + + const parser = new ExpensiMark(); + return parser.htmlToText(report.description); +} + function buildOptimisticAddCommentReportAction(text?: string, file?: File): OptimisticReportAction { const parser = new ExpensiMark(); const commentText = getParsedComment(text ?? ''); @@ -3075,7 +3084,7 @@ function buildOptimisticChatReport( notificationPreference: NotificationPreference = CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, parentReportActionID = '', parentReportID = '', - welcomeMessage = '', + description = '', ): OptimisticChatReport { const currentTime = DateUtils.getDBTime(); const isNewlyCreatedWorkspaceChat = chatType === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT && isOwnPolicyExpenseChat; @@ -3104,7 +3113,7 @@ function buildOptimisticChatReport( stateNum: 0, statusNum: 0, visibility, - welcomeMessage, + description, writeCapability, }; } @@ -3585,7 +3594,7 @@ function canFlagReportAction(reportAction: OnyxEntry, reportID: st reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.CHRONOSOOOLIST; if (ReportActionsUtils.isWhisperAction(reportAction)) { // Allow flagging welcome message whispers as they can be set by any room creator - if (report?.welcomeMessage && !isCurrentUserAction && isOriginalMessageHaveHtml && reportAction?.originalMessage?.html === report.welcomeMessage) { + if (report?.description && !isCurrentUserAction && isOriginalMessageHaveHtml && reportAction?.originalMessage?.html === report.description) { return true; } @@ -4270,7 +4279,7 @@ function getRoom(type: ValueOf, policyID: string) /** * We only want policy owners and admins to be able to modify the welcome message, but not in thread chat. */ -function shouldDisableWelcomeMessage(report: OnyxEntry, policy: OnyxEntry): boolean { +function shouldDisableReportDescription(report: OnyxEntry, policy: OnyxEntry): boolean { return isMoneyRequestReport(report) || isArchivedRoom(report) || !isChatRoom(report) || isChatThread(report) || !PolicyUtils.isPolicyAdmin(policy); } /** @@ -4525,13 +4534,14 @@ export { getReimbursementDeQueuedActionMessage, getPersonalDetailsForAccountID, getRoom, - shouldDisableWelcomeMessage, + shouldDisableReportDescription, navigateToPrivateNotes, canEditWriteCapability, hasSmartscanError, shouldAutoFocusOnKeyPress, shouldDisplayThreadReplies, shouldDisableThread, + getReportDescriptionText, }; export type {ExpenseOriginalMessage, OptionData, OptimisticChatReport}; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 55e91834a803..9cffcb45f9cf 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -1481,39 +1481,39 @@ function toggleSubscribeToChildReport(childReportID = '0', parentReportAction: P } } -function updateWelcomeMessage(reportID: string, previousValue: string, newValue: string) { +function updateDescription(reportID: string, previousValue: string, newValue: string) { // No change needed, navigate back if (previousValue === newValue) { - Navigation.goBack(ROUTES.REPORT_SETTINGS.getRoute(reportID)); + Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(reportID)); return; } - const parsedWelcomeMessage = ReportUtils.getParsedComment(newValue); + const parsedDescription = ReportUtils.getParsedComment(newValue); const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, - value: {welcomeMessage: parsedWelcomeMessage}, + value: {description: parsedDescription}, }, ]; const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, - value: {welcomeMessage: previousValue}, + value: {description: previousValue}, }, ]; - type UpdateWelcomeMessageParameters = { + type UpdateReportDescriptionParameters = { reportID: string; - welcomeMessage: string; + description: string; }; - const parameters: UpdateWelcomeMessageParameters = {reportID, welcomeMessage: parsedWelcomeMessage}; + const parameters: UpdateReportDescriptionParameters = {reportID, description: parsedDescription}; - API.write('UpdateWelcomeMessage', parameters, {optimisticData, failureData}); - Navigation.goBack(ROUTES.REPORT_SETTINGS.getRoute(reportID)); + API.write('UpdateRoomDescription', parameters, {optimisticData, failureData}); + Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(reportID)); } function updateWriteCapabilityAndNavigate(report: Report, newValue: WriteCapability) { @@ -1649,7 +1649,7 @@ function addPolicyReport(policyReport: ReportUtils.OptimisticChatReport) { reportName?: string; visibility?: ValueOf; writeCapability?: WriteCapability; - welcomeMessage?: string; + description?: string; }; const parameters: AddWorkspaceRoomParameters = { @@ -1659,7 +1659,7 @@ function addPolicyReport(policyReport: ReportUtils.OptimisticChatReport) { reportID: policyReport.reportID, createdReportActionID: createdReportAction.reportActionID, writeCapability: policyReport.writeCapability, - welcomeMessage: policyReport.welcomeMessage, + description: policyReport.description, }; API.write('AddWorkspaceRoom', parameters, {optimisticData, successData, failureData}); @@ -2590,7 +2590,7 @@ export { addComment, addAttachment, reconnect, - updateWelcomeMessage, + updateDescription, updateWriteCapabilityAndNavigate, updateNotificationPreference, subscribeToReportTypingEvents, diff --git a/src/pages/ReportWelcomeMessagePage.js b/src/pages/ReportDescriptionPage.js similarity index 71% rename from src/pages/ReportWelcomeMessagePage.js rename to src/pages/ReportDescriptionPage.js index ae8a4635a98e..cba19d25c1d3 100644 --- a/src/pages/ReportWelcomeMessagePage.js +++ b/src/pages/ReportDescriptionPage.js @@ -35,7 +35,7 @@ const propTypes = { /** Route params */ route: PropTypes.shape({ params: PropTypes.shape({ - /** Report ID passed via route r/:reportID/welcomeMessage */ + /** Report ID passed via route r/:reportID/roomDescription */ reportID: PropTypes.string, }), }).isRequired, @@ -45,26 +45,26 @@ const defaultProps = { ...policyDefaultProps, }; -function ReportWelcomeMessagePage(props) { +function ReportDescriptionPage(props) { const styles = useThemeStyles(); const parser = new ExpensiMark(); - const [welcomeMessage, setWelcomeMessage] = useState(() => parser.htmlToMarkdown(props.report.welcomeMessage)); - const welcomeMessageInputRef = useRef(null); + const [description, setdescription] = useState(() => parser.htmlToMarkdown(props.report.description)); + const reportDescriptionInputRef = useRef(null); const focusTimeoutRef = useRef(null); - const handleWelcomeMessageChange = useCallback((value) => { - setWelcomeMessage(value); + const handleReportDescriptionChange = useCallback((value) => { + setdescription(value); }, []); const submitForm = useCallback(() => { - Report.updateWelcomeMessage(props.report.reportID, props.report.welcomeMessage, welcomeMessage.trim()); - }, [props.report.reportID, props.report.welcomeMessage, welcomeMessage]); + Report.updateDescription(props.report.reportID, props.report.description, description.trim()); + }, [props.report.reportID, props.report.description, description]); useFocusEffect( useCallback(() => { focusTimeoutRef.current = setTimeout(() => { - if (welcomeMessageInputRef.current) { - welcomeMessageInputRef.current.focus(); + if (reportDescriptionInputRef.current) { + reportDescriptionInputRef.current.focus(); } return () => { if (!focusTimeoutRef.current) { @@ -80,27 +80,27 @@ function ReportWelcomeMessagePage(props) { - + Navigation.goBack(ROUTES.REPORT_SETTINGS.getRoute(props.report.reportID))} /> - {props.translate('welcomeMessagePage.explainerText')} + {props.translate('reportDescriptionPage.explainerText')} @@ -123,9 +123,9 @@ function ReportWelcomeMessagePage(props) { ); } -ReportWelcomeMessagePage.displayName = 'ReportWelcomeMessagePage'; -ReportWelcomeMessagePage.propTypes = propTypes; -ReportWelcomeMessagePage.defaultProps = defaultProps; +ReportDescriptionPage.displayName = 'ReportDescriptionPage'; +ReportDescriptionPage.propTypes = propTypes; +ReportDescriptionPage.defaultProps = defaultProps; export default compose( withLocalize, @@ -135,4 +135,4 @@ export default compose( key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, }, }), -)(ReportWelcomeMessagePage); +)(ReportDescriptionPage); diff --git a/src/pages/ReportDetailsPage.js b/src/pages/ReportDetailsPage.js index ff9ed62c6a65..57b940374d8a 100644 --- a/src/pages/ReportDetailsPage.js +++ b/src/pages/ReportDetailsPage.js @@ -8,6 +8,7 @@ import DisplayNames from '@components/DisplayNames'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; +import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import MultipleAvatars from '@components/MultipleAvatars'; import {withNetwork} from '@components/OnyxProvider'; import ParentNavigationSubtitle from '@components/ParentNavigationSubtitle'; @@ -235,6 +236,13 @@ function ReportDetailsPage(props) { )} + Navigation.navigate(ROUTES.REPORT_DESCRIPTION.getRoute(props.report.reportID))} + /> {_.map(menuItems, (item) => { const brickRoadIndicator = ReportUtils.hasReportNameError(props.report) && item.key === CONST.REPORT_DETAILS_MENU_ITEM.SETTINGS ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''; diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index edf6b65b2f4a..d2a4e8442b6f 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -116,6 +116,10 @@ function HeaderView(props) { const isPolicyMember = useMemo(() => !_.isEmpty(props.policy), [props.policy]); const canLeaveRoom = ReportUtils.canLeaveRoom(props.report, isPolicyMember); const isArchivedRoom = ReportUtils.isArchivedRoom(props.report); + const reportDescription = ReportUtils.getReportDescriptionText(props.report); + const policyName = ReportUtils.getPolicyName(props.report); + // const policyDescription = ReportUtils.getPolicyDescription(props.report.policyID); + const description = reportDescription; // We hide the button when we are chatting with an automated Expensify account since it's not possible to contact // these users via alternative means. It is possible to request a call with Concierge so we leave the option for them. @@ -271,14 +275,33 @@ function HeaderView(props) { /> )} - + + + {!_.isEmpty(policyName) && + !_.isEmpty(reportDescription) && ( // code for the policyName display + <> + + {translate('threads.in')} + + + {policyName} + + + )} + {!_.isEmpty(parentNavigationSubtitleData) && ( )} - {!_.isEmpty(subtitle) && ( + {!_.isEmpty(subtitle) && _.isEmpty(description) && ( )} + {!_.isEmpty(description) && ( + + {description} + + )} {brickRoadIndicator === CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR && ( diff --git a/src/pages/settings/Report/ReportSettingsPage.js b/src/pages/settings/Report/ReportSettingsPage.js index c7cfd9c7850d..fe3953dd0248 100644 --- a/src/pages/settings/Report/ReportSettingsPage.js +++ b/src/pages/settings/Report/ReportSettingsPage.js @@ -63,9 +63,6 @@ function ReportSettingsPage(props) { const shouldDisableRename = useMemo(() => ReportUtils.shouldDisableRename(report, linkedWorkspace), [report, linkedWorkspace]); const isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report); - // We only want policy owners and admins to be able to modify the welcome message, but not in thread chat - const shouldDisableWelcomeMessage = ReportUtils.shouldDisableWelcomeMessage(report, linkedWorkspace); - const shouldDisableSettings = _.isEmpty(report) || ReportUtils.isArchivedRoom(report); const shouldShowRoomName = !ReportUtils.isPolicyExpenseChat(report) && !ReportUtils.isChatThread(report); const notificationPreference = @@ -192,14 +189,6 @@ function ReportSettingsPage(props) { )} - {!shouldDisableWelcomeMessage && ( - Navigation.navigate(ROUTES.REPORT_WELCOME_MESSAGE.getRoute(report.reportID))} - shouldShowRightIcon - /> - )} diff --git a/src/pages/workspace/WorkspaceNewRoomPage.js b/src/pages/workspace/WorkspaceNewRoomPage.js index 21c93b87806a..aa5b24af9958 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.js +++ b/src/pages/workspace/WorkspaceNewRoomPage.js @@ -114,7 +114,7 @@ function WorkspaceNewRoomPage(props) { */ const submit = (values) => { const participants = [props.session.accountID]; - const parsedWelcomeMessage = ReportUtils.getParsedComment(values.welcomeMessage); + const parsedDescription = ReportUtils.getParsedComment(values.reportDescription); const policyReport = ReportUtils.buildOptimisticChatReport( participants, values.roomName, @@ -128,7 +128,7 @@ function WorkspaceNewRoomPage(props) { CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, '', '', - parsedWelcomeMessage, + parsedDescription, ); setNewRoomReportID(policyReport.reportID); Report.addPolicyReport(policyReport); @@ -280,9 +280,9 @@ function WorkspaceNewRoomPage(props) { Date: Tue, 9 Jan 2024 20:49:40 +0530 Subject: [PATCH 046/249] =?UTF-8?q?Fix=20style=20=F0=9F=92=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libs/E2E/apiMocks/openReport.ts | 1 - src/pages/home/HeaderView.js | 8 +++----- src/pages/settings/Report/ReportSettingsPage.js | 2 -- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/libs/E2E/apiMocks/openReport.ts b/src/libs/E2E/apiMocks/openReport.ts index 49d44605592d..4165db650a5c 100644 --- a/src/libs/E2E/apiMocks/openReport.ts +++ b/src/libs/E2E/apiMocks/openReport.ts @@ -24,7 +24,6 @@ export default (): Response => ({ lastMessageText: 'terry+hightraffic@margelo.io owes \u20ac12.00', lastActorAccountID: 14567013, notificationPreference: 'always', - welcomeMessage: '', stateNum: 0, statusNum: 0, oldPolicyName: '', diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index d2a4e8442b6f..0832d789ae35 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -118,8 +118,6 @@ function HeaderView(props) { const isArchivedRoom = ReportUtils.isArchivedRoom(props.report); const reportDescription = ReportUtils.getReportDescriptionText(props.report); const policyName = ReportUtils.getPolicyName(props.report); - // const policyDescription = ReportUtils.getPolicyDescription(props.report.policyID); - const description = reportDescription; // We hide the button when we are chatting with an automated Expensify account since it's not possible to contact // these users via alternative means. It is possible to request a call with Concierge so we leave the option for them. @@ -309,7 +307,7 @@ function HeaderView(props) { pressableStyles={[styles.alignSelfStart, styles.mw100]} /> )} - {!_.isEmpty(subtitle) && _.isEmpty(description) && ( + {!_.isEmpty(subtitle) && _.isEmpty(reportDescription) && ( )} - {!_.isEmpty(description) && ( + {!_.isEmpty(reportDescription) && ( - {description} + {reportDescription} )} diff --git a/src/pages/settings/Report/ReportSettingsPage.js b/src/pages/settings/Report/ReportSettingsPage.js index fe3953dd0248..4c0e3b477a02 100644 --- a/src/pages/settings/Report/ReportSettingsPage.js +++ b/src/pages/settings/Report/ReportSettingsPage.js @@ -7,8 +7,6 @@ import _ from 'underscore'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import DisplayNames from '@components/DisplayNames'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import * as Expensicons from '@components/Icon/Expensicons'; -import MenuItem from '@components/MenuItem'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import ScreenWrapper from '@components/ScreenWrapper'; From a488df6475ba7d4deb506138e2d3a3883b0bd297 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 9 Jan 2024 16:36:58 +0100 Subject: [PATCH 047/249] 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 5be28c79dba6f03e364c8f506e452edf54bd36de Mon Sep 17 00:00:00 2001 From: someone-here Date: Tue, 9 Jan 2024 21:48:40 +0530 Subject: [PATCH 048/249] Fix Permissions --- src/libs/Permissions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts index 582115b0a914..ce5e0e674c59 100644 --- a/src/libs/Permissions.ts +++ b/src/libs/Permissions.ts @@ -3,7 +3,7 @@ import CONST from '@src/CONST'; import type Beta from '@src/types/onyx/Beta'; function canUseAllBetas(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.ALL) || true; + return !!betas?.includes(CONST.BETAS.ALL); } function canUseChronos(betas: OnyxEntry): boolean { From bd8005542ce0212cae6cf2eb9079ae49ee74acbc Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 9 Jan 2024 17:24:18 +0100 Subject: [PATCH 049/249] 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 050/249] 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 3fec0575686d919ac3e1b341e39dfb281fae9b43 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Tue, 9 Jan 2024 18:39:13 +0100 Subject: [PATCH 051/249] Fix comments --- src/components/SettlementButton.tsx | 15 +++++++-------- src/types/onyx/LastPaymentMethod.ts | 3 +++ src/types/onyx/index.ts | 2 ++ 3 files changed, 12 insertions(+), 8 deletions(-) create mode 100644 src/types/onyx/LastPaymentMethod.ts diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index a11481c99cb1..1ad4cb496008 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -10,11 +10,10 @@ import * as BankAccounts from '@userActions/BankAccounts'; import * as IOU from '@userActions/IOU'; import * as PaymentMethods from '@userActions/PaymentMethods'; import CONST from '@src/CONST'; -import type {OnyxValues} from '@src/ONYXKEYS'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {ButtonSizeValue} from '@src/styles/utils/types'; -import type {Report} from '@src/types/onyx'; +import type {LastPaymentMethod, Report} from '@src/types/onyx'; import type AnchorAlignment from '@src/types/onyx/AnchorAlignment'; import type DeepValueOf from '@src/types/utils/DeepValueOf'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; @@ -22,15 +21,15 @@ import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; import * as Expensicons from './Icon/Expensicons'; import KYCWall from './KYCWall'; -type Event = GestureResponderEvent | KeyboardEvent; +type KYCFlowEvent = GestureResponderEvent | KeyboardEvent; -type TriggerKYCFlow = (event: Event, iouPaymentType: string) => void; +type TriggerKYCFlow = (event: KYCFlowEvent, iouPaymentType: string) => void; type PaymentType = DeepValueOf; type SettlementButtonOnyxProps = { /** The last payment method used per policy */ - nvpLastPaymentMethod?: OnyxEntry; + nvpLastPaymentMethod?: OnyxEntry; }; type SettlementButtonProps = SettlementButtonOnyxProps & { @@ -183,7 +182,7 @@ function SettlementButton({ return buttonOptions; }, [currency, formattedAmount, iouReport, nvpLastPaymentMethod, policyID, translate, shouldHidePaymentOptions, shouldShowApproveButton]); - const selectPaymentType = (event: Event, iouPaymentType: PaymentType, triggerKYCFlow: TriggerKYCFlow) => { + const selectPaymentType = (event: KYCFlowEvent, iouPaymentType: PaymentType, triggerKYCFlow: TriggerKYCFlow) => { if (iouPaymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY || iouPaymentType === CONST.IOU.PAYMENT_TYPE.VBBA) { triggerKYCFlow(event, iouPaymentType); BankAccounts.setPersonalBankAccountContinueKYCOnSuccess(ROUTES.ENABLE_PAYMENTS); @@ -211,12 +210,12 @@ function SettlementButton({ anchorAlignment={kycWallAnchorAlignment} shouldShowPersonalBankAccountOption={shouldShowPersonalBankAccountOption} > - {(triggerKYCFlow: TriggerKYCFlow, buttonRef: MutableRefObject) => ( + {(triggerKYCFlow: TriggerKYCFlow, buttonRef: MutableRefObject) => ( selectPaymentType(event, iouPaymentType, triggerKYCFlow)} + onPress={(event: KYCFlowEvent, iouPaymentType: PaymentType) => selectPaymentType(event, iouPaymentType, triggerKYCFlow)} pressOnEnter={pressOnEnter} options={paymentButtonOptions} // @ts-expect-error TODO: Remove this once OptionsListUtils (https://github.com/Expensify/App/issues/25065) is migrated to TypeScript. diff --git a/src/types/onyx/LastPaymentMethod.ts b/src/types/onyx/LastPaymentMethod.ts new file mode 100644 index 000000000000..677a23fa9586 --- /dev/null +++ b/src/types/onyx/LastPaymentMethod.ts @@ -0,0 +1,3 @@ +type LastPaymentMethod = Record; + +export default LastPaymentMethod; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 7bd9c321be5e..824275ace170 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -15,6 +15,7 @@ import type FrequentlyUsedEmoji from './FrequentlyUsedEmoji'; import type {FundList} from './Fund'; import type Fund from './Fund'; import type IOU from './IOU'; +import type LastPaymentMethod from './LastPaymentMethod'; import type Locale from './Locale'; import type {LoginList} from './Login'; import type Login from './Login'; @@ -137,4 +138,5 @@ export type { ReportUserIsTyping, PolicyReportField, RecentlyUsedReportFields, + LastPaymentMethod, }; From c059ca3466198a648f3ead8a6ef83f1590b6d4fa Mon Sep 17 00:00:00 2001 From: VickyStash Date: Wed, 10 Jan 2024 10:44:50 +0100 Subject: [PATCH 052/249] 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 5754adc74b3158b0c0d63a74999974f6cf709dc7 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Wed, 10 Jan 2024 11:34:14 +0100 Subject: [PATCH 053/249] Update type imports --- src/components/Popover/types.ts | 2 +- src/components/PopoverMenu.tsx | 2 +- src/components/ProcessMoneyRequestHoldMenu.tsx | 2 +- src/components/SettlementButton.tsx | 3 +-- src/types/onyx/index.ts | 2 ++ 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/components/Popover/types.ts b/src/components/Popover/types.ts index 4875676a3caa..298c95eeca76 100644 --- a/src/components/Popover/types.ts +++ b/src/components/Popover/types.ts @@ -1,7 +1,7 @@ import type {PopoverAnchorPosition} from '@components/Modal/types'; import type BaseModalProps from '@components/Modal/types'; import type {WindowDimensionsProps} from '@components/withWindowDimensions/types'; -import type AnchorAlignment from '@src/types/onyx/AnchorAlignment'; +import type {AnchorAlignment} from '@src/types/onyx'; type PopoverDimensions = { width: number; diff --git a/src/components/PopoverMenu.tsx b/src/components/PopoverMenu.tsx index 9b59b87056e0..0a1fdf38a172 100644 --- a/src/components/PopoverMenu.tsx +++ b/src/components/PopoverMenu.tsx @@ -10,7 +10,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import CONST from '@src/CONST'; import type {AnchorPosition} from '@src/styles'; -import type AnchorAlignment from '@src/types/onyx/AnchorAlignment'; +import type {AnchorAlignment} from '@src/types/onyx'; import MenuItem from './MenuItem'; import PopoverWithMeasuredContent from './PopoverWithMeasuredContent'; import Text from './Text'; diff --git a/src/components/ProcessMoneyRequestHoldMenu.tsx b/src/components/ProcessMoneyRequestHoldMenu.tsx index a6b53da467b5..1fd37b82afc8 100644 --- a/src/components/ProcessMoneyRequestHoldMenu.tsx +++ b/src/components/ProcessMoneyRequestHoldMenu.tsx @@ -2,7 +2,7 @@ import React from 'react'; import {View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import type AnchorAlignment from '@src/types/onyx/AnchorAlignment'; +import type {AnchorAlignment} from '@src/types/onyx'; import Button from './Button'; import HoldMenuSectionList from './HoldMenuSectionList'; import type {PopoverAnchorPosition} from './Modal/types'; diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index 1ad4cb496008..2fe45e6f7b90 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -13,8 +13,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {ButtonSizeValue} from '@src/styles/utils/types'; -import type {LastPaymentMethod, Report} from '@src/types/onyx'; -import type AnchorAlignment from '@src/types/onyx/AnchorAlignment'; +import type {AnchorAlignment, LastPaymentMethod, Report} from '@src/types/onyx'; import type DeepValueOf from '@src/types/utils/DeepValueOf'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 824275ace170..ecc3603e8f8d 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -1,5 +1,6 @@ import type Account from './Account'; import type AccountData from './AccountData'; +import type AnchorAlignment from './AnchorAlignment'; import type {BankAccountList} from './BankAccount'; import type BankAccount from './BankAccount'; import type Beta from './Beta'; @@ -139,4 +140,5 @@ export type { PolicyReportField, RecentlyUsedReportFields, LastPaymentMethod, + AnchorAlignment, }; From ef7487ab74bc146b82e40dcbe69dd6875cb617dc Mon Sep 17 00:00:00 2001 From: Yauheni Date: Wed, 10 Jan 2024 14:24:13 +0100 Subject: [PATCH 054/249] Fix comments --- src/ONYXKEYS.ts | 4 +++- src/components/SettlementButton.tsx | 7 +++++-- src/types/onyx/LastPaymentMethod.ts | 3 --- src/types/onyx/index.ts | 2 -- 4 files changed, 8 insertions(+), 8 deletions(-) delete mode 100644 src/types/onyx/LastPaymentMethod.ts diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 89ddbdc06883..d3c7756b0dee 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -530,5 +530,7 @@ type OnyxValues = { type OnyxKeyValue = OnyxEntry; +type LastPaymentMethod = Record; + export default ONYXKEYS; -export type {OnyxKey, OnyxCollectionKey, OnyxValues, OnyxKeyValue, OnyxFormKey, OnyxKeysMap}; +export type {OnyxKey, OnyxCollectionKey, OnyxValues, OnyxKeyValue, OnyxFormKey, OnyxKeysMap,LastPaymentMethod}; diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index 2fe45e6f7b90..1fae611018c1 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -10,10 +10,11 @@ import * as BankAccounts from '@userActions/BankAccounts'; import * as IOU from '@userActions/IOU'; import * as PaymentMethods from '@userActions/PaymentMethods'; import CONST from '@src/CONST'; +import type {LastPaymentMethod} from '@src/ONYXKEYS'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {ButtonSizeValue} from '@src/styles/utils/types'; -import type {AnchorAlignment, LastPaymentMethod, Report} from '@src/types/onyx'; +import type {AnchorAlignment, Report} from '@src/types/onyx'; import type DeepValueOf from '@src/types/utils/DeepValueOf'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; @@ -26,6 +27,8 @@ type TriggerKYCFlow = (event: KYCFlowEvent, iouPaymentType: string) => void; type PaymentType = DeepValueOf; +type EnablePaymentsRoute = typeof ROUTES.ENABLE_PAYMENTS | typeof ROUTES.IOU_SEND_ENABLE_PAYMENTS | typeof ROUTES.SETTINGS_ENABLE_PAYMENTS; + type SettlementButtonOnyxProps = { /** The last payment method used per policy */ nvpLastPaymentMethod?: OnyxEntry; @@ -36,7 +39,7 @@ type SettlementButtonProps = SettlementButtonOnyxProps & { onPress: (paymentType: PaymentType) => void; /** The route to redirect if user does not have a payment method setup */ - enablePaymentsRoute: typeof ROUTES.ENABLE_PAYMENTS | typeof ROUTES.IOU_SEND_ENABLE_PAYMENTS | typeof ROUTES.SETTINGS_ENABLE_PAYMENTS; + enablePaymentsRoute: EnablePaymentsRoute; /** Call the onPress function on main button when Enter key is pressed */ pressOnEnter?: boolean; diff --git a/src/types/onyx/LastPaymentMethod.ts b/src/types/onyx/LastPaymentMethod.ts deleted file mode 100644 index 677a23fa9586..000000000000 --- a/src/types/onyx/LastPaymentMethod.ts +++ /dev/null @@ -1,3 +0,0 @@ -type LastPaymentMethod = Record; - -export default LastPaymentMethod; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index ecc3603e8f8d..4e199e88ce88 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -16,7 +16,6 @@ import type FrequentlyUsedEmoji from './FrequentlyUsedEmoji'; import type {FundList} from './Fund'; import type Fund from './Fund'; import type IOU from './IOU'; -import type LastPaymentMethod from './LastPaymentMethod'; import type Locale from './Locale'; import type {LoginList} from './Login'; import type Login from './Login'; @@ -139,6 +138,5 @@ export type { ReportUserIsTyping, PolicyReportField, RecentlyUsedReportFields, - LastPaymentMethod, AnchorAlignment, }; From ebfb6b91b3990076bf89c48b1c88513e53c6f585 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Wed, 10 Jan 2024 16:32:50 +0100 Subject: [PATCH 055/249] 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 056/249] 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 c2d9c887fcc609d90324b556d1716640f6547018 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Wed, 10 Jan 2024 20:05:55 +0100 Subject: [PATCH 057/249] Fix comments x2 --- src/ONYXKEYS.ts | 6 ++---- src/components/SettlementButton.tsx | 3 +-- src/types/onyx/LastPaymentMethod.ts | 3 +++ src/types/onyx/index.ts | 2 ++ 4 files changed, 8 insertions(+), 6 deletions(-) create mode 100644 src/types/onyx/LastPaymentMethod.ts diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index d3c7756b0dee..63eecbea3984 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -391,7 +391,7 @@ type OnyxValues = { [ONYXKEYS.NVP_PRIVATE_PUSH_NOTIFICATION_ID]: string; [ONYXKEYS.NVP_TRY_FOCUS_MODE]: boolean; [ONYXKEYS.FOCUS_MODE_NOTIFICATION]: boolean; - [ONYXKEYS.NVP_LAST_PAYMENT_METHOD]: Record; + [ONYXKEYS.NVP_LAST_PAYMENT_METHOD]: OnyxTypes.LastPaymentMethod; [ONYXKEYS.NVP_RECENT_WAYPOINTS]: OnyxTypes.RecentWaypoint[]; [ONYXKEYS.PUSH_NOTIFICATIONS_ENABLED]: boolean; [ONYXKEYS.PLAID_DATA]: OnyxTypes.PlaidData; @@ -530,7 +530,5 @@ type OnyxValues = { type OnyxKeyValue = OnyxEntry; -type LastPaymentMethod = Record; - export default ONYXKEYS; -export type {OnyxKey, OnyxCollectionKey, OnyxValues, OnyxKeyValue, OnyxFormKey, OnyxKeysMap,LastPaymentMethod}; +export type {OnyxKey, OnyxCollectionKey, OnyxValues, OnyxKeyValue, OnyxFormKey, OnyxKeysMap}; diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index 1fae611018c1..4a4abea14c70 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -10,11 +10,10 @@ import * as BankAccounts from '@userActions/BankAccounts'; import * as IOU from '@userActions/IOU'; import * as PaymentMethods from '@userActions/PaymentMethods'; import CONST from '@src/CONST'; -import type {LastPaymentMethod} from '@src/ONYXKEYS'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {ButtonSizeValue} from '@src/styles/utils/types'; -import type {AnchorAlignment, Report} from '@src/types/onyx'; +import type {AnchorAlignment, LastPaymentMethod, Report} from '@src/types/onyx'; import type DeepValueOf from '@src/types/utils/DeepValueOf'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; diff --git a/src/types/onyx/LastPaymentMethod.ts b/src/types/onyx/LastPaymentMethod.ts new file mode 100644 index 000000000000..677a23fa9586 --- /dev/null +++ b/src/types/onyx/LastPaymentMethod.ts @@ -0,0 +1,3 @@ +type LastPaymentMethod = Record; + +export default LastPaymentMethod; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 4e199e88ce88..ecc3603e8f8d 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -16,6 +16,7 @@ import type FrequentlyUsedEmoji from './FrequentlyUsedEmoji'; import type {FundList} from './Fund'; import type Fund from './Fund'; import type IOU from './IOU'; +import type LastPaymentMethod from './LastPaymentMethod'; import type Locale from './Locale'; import type {LoginList} from './Login'; import type Login from './Login'; @@ -138,5 +139,6 @@ export type { ReportUserIsTyping, PolicyReportField, RecentlyUsedReportFields, + LastPaymentMethod, AnchorAlignment, }; From 1af5ac6c17f84dc803537a279134b1c94256ba65 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Thu, 11 Jan 2024 10:36:27 +0100 Subject: [PATCH 058/249] 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 059/249] 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 060/249] 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 b91bc05bd24e8514f1a75493705f0561d20fe72b Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Fri, 12 Jan 2024 22:41:58 +0700 Subject: [PATCH 061/249] Add highlight to active emoji in EmojiDropDown --- src/CONST.ts | 2 ++ src/components/EmojiPicker/EmojiPicker.js | 5 ++++- .../EmojiPicker/EmojiPickerButtonDropdown.js | 19 +++++++++++++------ .../EmojiPicker/EmojiPickerMenu/index.js | 7 +++++-- src/libs/EmojiUtils.ts | 10 ++++++++++ src/libs/actions/EmojiPickerAction.ts | 4 +++- 6 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index b1a6b6895de7..2734a607615e 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1387,6 +1387,8 @@ const CONST = { EMOJI: /[\p{Extended_Pictographic}\u200d\u{1f1e6}-\u{1f1ff}\u{1f3fb}-\u{1f3ff}\u{e0020}-\u{e007f}\u20E3\uFE0F]|[#*0-9]\uFE0F?\u20E3/gu, // eslint-disable-next-line max-len, no-misleading-character-class EMOJIS: /[\p{Extended_Pictographic}](\u200D[\p{Extended_Pictographic}]|[\u{1F3FB}-\u{1F3FF}]|[\u{E0020}-\u{E007F}]|\uFE0F|\u20E3)*|[\u{1F1E6}-\u{1F1FF}]{2}|[#*0-9]\uFE0F?\u20E3/gu, + // eslint-disable-next-line max-len, no-misleading-character-class + EMOJI_SKIN_TONES: /[\u{1f3fb}-\u{1f3ff}]/gu, TAX_ID: /^\d{9}$/, NON_NUMERIC: /\D/g, diff --git a/src/components/EmojiPicker/EmojiPicker.js b/src/components/EmojiPicker/EmojiPicker.js index 532eb61a99a9..563a2696fab4 100644 --- a/src/components/EmojiPicker/EmojiPicker.js +++ b/src/components/EmojiPicker/EmojiPicker.js @@ -33,6 +33,7 @@ const EmojiPicker = forwardRef((props, ref) => { const emojiPopoverAnchorRef = useRef(null); const onModalHide = useRef(() => {}); const onEmojiSelected = useRef(() => {}); + const activeEmoji = useRef(); const emojiSearchInput = useRef(); const {isSmallScreenWidth, windowHeight} = useWindowDimensions(); @@ -56,9 +57,10 @@ const EmojiPicker = forwardRef((props, ref) => { * @param {Function} [onWillShow=() => {}] - Run a callback when Popover will show * @param {String} id - Unique id for EmojiPicker */ - const showEmojiPicker = (onModalHideValue, onEmojiSelectedValue, emojiPopoverAnchorValue, anchorOrigin, onWillShow = () => {}, id) => { + const showEmojiPicker = (onModalHideValue, onEmojiSelectedValue, emojiPopoverAnchorValue, anchorOrigin, onWillShow = () => {}, id, activeEmojiValue) => { onModalHide.current = onModalHideValue; onEmojiSelected.current = onEmojiSelectedValue; + activeEmoji.current = activeEmojiValue; emojiPopoverAnchorRef.current = emojiPopoverAnchorValue; const emojiPopoverAnchor = getEmojiPopoverAnchor(); if (emojiPopoverAnchor.current && emojiPopoverAnchor.current.blur) { @@ -184,6 +186,7 @@ const EmojiPicker = forwardRef((props, ref) => { > (emojiSearchInput.current = el)} /> diff --git a/src/components/EmojiPicker/EmojiPickerButtonDropdown.js b/src/components/EmojiPicker/EmojiPickerButtonDropdown.js index bfcb66aeefbb..4d4eae49bf86 100644 --- a/src/components/EmojiPicker/EmojiPickerButtonDropdown.js +++ b/src/components/EmojiPicker/EmojiPickerButtonDropdown.js @@ -29,18 +29,25 @@ function EmojiPickerButtonDropdown(props) { const StyleUtils = useStyleUtils(); const emojiPopoverAnchor = useRef(null); useEffect(() => EmojiPickerAction.resetEmojiPopoverAnchor, []); - const onPress = () => { if (EmojiPickerAction.isEmojiPickerVisible()) { EmojiPickerAction.hideEmojiPicker(); return; } - EmojiPickerAction.showEmojiPicker(props.onModalHide, (emoji) => props.onInputChange(emoji), emojiPopoverAnchor, { - horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT, - vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP, - shiftVertical: 4, - }); + EmojiPickerAction.showEmojiPicker( + props.onModalHide, + (emoji) => props.onInputChange(emoji), + emojiPopoverAnchor, + { + horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT, + vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP, + shiftVertical: 4, + }, + () => {}, + undefined, + props.value, + ); }; return ( diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js index a723eed446a4..0be9eafdd4a7 100755 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js @@ -14,6 +14,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import * as Browser from '@libs/Browser'; import canFocusInputOnScreenFocus from '@libs/canFocusInputOnScreenFocus'; +import * as EmojiUtils from '@libs/EmojiUtils'; import isEnterWhileComposition from '@libs/KeyboardShortcut/isEnterWhileComposition'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; @@ -33,7 +34,7 @@ const defaultProps = { const throttleTime = Browser.isMobile() ? 200 : 50; -function EmojiPickerMenu({forwardedRef, onEmojiSelected}) { +function EmojiPickerMenu({forwardedRef, onEmojiSelected, activeEmoji}) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {isSmallScreenWidth, windowWidth} = useWindowDimensions(); @@ -344,7 +345,8 @@ function EmojiPickerMenu({forwardedRef, onEmojiSelected}) { const emojiCode = types && types[preferredSkinTone] ? types[preferredSkinTone] : code; const isEmojiFocused = index === highlightedIndex && isUsingKeyboardMovement; - const shouldEmojiBeHighlighted = index === highlightedIndex && highlightFirstEmoji; + const shouldEmojiBeHighlighted = + (index === highlightedIndex && highlightFirstEmoji) || (activeEmoji && EmojiUtils.getRemovedSkinToneEmoji(emojiCode) === EmojiUtils.getRemovedSkinToneEmoji(activeEmoji)); return ( (prevState === index ? -1 : prevState)) } isFocused={isEmojiFocused} + //isHighlighted={true} isHighlighted={shouldEmojiBeHighlighted} /> ); diff --git a/src/libs/EmojiUtils.ts b/src/libs/EmojiUtils.ts index e34fa0b90fc6..b42049cc627d 100644 --- a/src/libs/EmojiUtils.ts +++ b/src/libs/EmojiUtils.ts @@ -548,6 +548,15 @@ const getEmojiReactionDetails = (emojiName: string, reaction: ReportActionReacti }; }; +/** + * Get base emoji without skintone + * @param emoji emoji string + * @returns emoji without skin tone + */ +const getRemovedSkinToneEmoji = (emoji: string) => { + return emoji.replace(CONST.REGEX.EMOJI_SKIN_TONES, ''); +}; + export { findEmojiByName, findEmojiByCode, @@ -570,4 +579,5 @@ export { getAddedEmojis, isFirstLetterEmoji, hasAccountIDEmojiReacted, + getRemovedSkinToneEmoji, }; diff --git a/src/libs/actions/EmojiPickerAction.ts b/src/libs/actions/EmojiPickerAction.ts index 56a5f34c0b8e..0fc21713c608 100644 --- a/src/libs/actions/EmojiPickerAction.ts +++ b/src/libs/actions/EmojiPickerAction.ts @@ -26,6 +26,7 @@ type EmojiPickerRef = { anchorOrigin?: AnchorOrigin, onWillShow?: OnWillShowPicker, id?: string, + activeEmoji?: string, ) => void; isActive: (id: string) => boolean; clearActive: () => void; @@ -55,12 +56,13 @@ function showEmojiPicker( anchorOrigin?: AnchorOrigin, onWillShow: OnWillShowPicker = () => {}, id?: string, + activeEmoji?: string, ) { if (!emojiPickerRef.current) { return; } - emojiPickerRef.current.showEmojiPicker(onModalHide, onEmojiSelected, emojiPopoverAnchor, anchorOrigin, onWillShow, id); + emojiPickerRef.current.showEmojiPicker(onModalHide, onEmojiSelected, emojiPopoverAnchor, anchorOrigin, onWillShow, id, activeEmoji); } /** From 9698dbf988b7abfa751e514fe7d4de0211fe3735 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Sat, 13 Jan 2024 10:57:16 +0700 Subject: [PATCH 062/249] resolve lint --- src/components/EmojiPicker/EmojiPicker.js | 1 + src/components/EmojiPicker/EmojiPickerMenu/index.js | 3 +-- src/libs/EmojiUtils.ts | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPicker.js b/src/components/EmojiPicker/EmojiPicker.js index 563a2696fab4..68b74a7aeb15 100644 --- a/src/components/EmojiPicker/EmojiPicker.js +++ b/src/components/EmojiPicker/EmojiPicker.js @@ -56,6 +56,7 @@ const EmojiPicker = forwardRef((props, ref) => { * @param {Object} [anchorOrigin=DEFAULT_ANCHOR_ORIGIN] - Anchor origin for Popover * @param {Function} [onWillShow=() => {}] - Run a callback when Popover will show * @param {String} id - Unique id for EmojiPicker + * @param {String} activeEmojiValue - Selected emoji to be highlighted */ const showEmojiPicker = (onModalHideValue, onEmojiSelectedValue, emojiPopoverAnchorValue, anchorOrigin, onWillShow = () => {}, id, activeEmojiValue) => { onModalHide.current = onModalHideValue; diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js index 0be9eafdd4a7..c8ca9c6ac6d1 100755 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js @@ -366,12 +366,11 @@ function EmojiPickerMenu({forwardedRef, onEmojiSelected, activeEmoji}) { setHighlightedIndex((prevState) => (prevState === index ? -1 : prevState)) } isFocused={isEmojiFocused} - //isHighlighted={true} isHighlighted={shouldEmojiBeHighlighted} /> ); }, - [preferredSkinTone, highlightedIndex, isUsingKeyboardMovement, highlightFirstEmoji, singleExecution, translate, onEmojiSelected, isSmallScreenWidth, windowWidth, styles], + [preferredSkinTone, highlightedIndex, isUsingKeyboardMovement, highlightFirstEmoji, singleExecution, translate, onEmojiSelected, isSmallScreenWidth, windowWidth, styles, activeEmoji], ); return ( diff --git a/src/libs/EmojiUtils.ts b/src/libs/EmojiUtils.ts index b42049cc627d..9a1998b35462 100644 --- a/src/libs/EmojiUtils.ts +++ b/src/libs/EmojiUtils.ts @@ -553,9 +553,7 @@ const getEmojiReactionDetails = (emojiName: string, reaction: ReportActionReacti * @param emoji emoji string * @returns emoji without skin tone */ -const getRemovedSkinToneEmoji = (emoji: string) => { - return emoji.replace(CONST.REGEX.EMOJI_SKIN_TONES, ''); -}; +const getRemovedSkinToneEmoji = (emoji: string) => emoji.replace(CONST.REGEX.EMOJI_SKIN_TONES, ''); export { findEmojiByName, From 6e7fc2761fac092106366d45e54e92a9fc10fb63 Mon Sep 17 00:00:00 2001 From: someone-here Date: Sun, 14 Jan 2024 22:16:36 +0530 Subject: [PATCH 063/249] Requested changes --- src/libs/ReportUtils.ts | 8 ++++---- src/pages/ReportDescriptionPage.js | 4 ++-- src/pages/ReportDetailsPage.js | 6 ++++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 26a69cc51818..4f6d2032c8cf 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4277,10 +4277,10 @@ function getRoom(type: ValueOf, policyID: string) } /** - * We only want policy owners and admins to be able to modify the welcome message, but not in thread chat. + * We only want policy owners and admins to be able to modify the report description, but not in thread chat. */ -function shouldDisableReportDescription(report: OnyxEntry, policy: OnyxEntry): boolean { - return isMoneyRequestReport(report) || isArchivedRoom(report) || !isChatRoom(report) || isChatThread(report) || !PolicyUtils.isPolicyAdmin(policy); +function canEditReportDescription(report: OnyxEntry, policy: OnyxEntry): boolean { + return !isMoneyRequestReport(report) && !isArchivedRoom(report) && isChatRoom(report) && !isChatThread(report) && PolicyUtils.isPolicyAdmin(policy); } /** * Checks if report action has error when smart scanning @@ -4534,7 +4534,7 @@ export { getReimbursementDeQueuedActionMessage, getPersonalDetailsForAccountID, getRoom, - shouldDisableReportDescription, + canEditReportDescription, navigateToPrivateNotes, canEditWriteCapability, hasSmartscanError, diff --git a/src/pages/ReportDescriptionPage.js b/src/pages/ReportDescriptionPage.js index cba19d25c1d3..9093d165b876 100644 --- a/src/pages/ReportDescriptionPage.js +++ b/src/pages/ReportDescriptionPage.js @@ -82,14 +82,14 @@ function ReportDescriptionPage(props) { includeSafeAreaPaddingBottom={false} testID={ReportDescriptionPage.displayName} > - + Navigation.goBack(ROUTES.REPORT_SETTINGS.getRoute(props.report.reportID))} /> ReportUtils.isUserCreatedPolicyRoom(props.report), [props.report]); const isArchivedRoom = useMemo(() => ReportUtils.isArchivedRoom(props.report), [props.report]); const isMoneyRequestReport = useMemo(() => ReportUtils.isMoneyRequestReport(props.report), [props.report]); + const canEditReportDescription = useMemo(() => ReportUtils.canEditReportDescription(props.report, policy), [props.report, policy]); // eslint-disable-next-line react-hooks/exhaustive-deps -- policy is a dependency because `getChatRoomSubtitle` calls `getPolicyName` which in turn retrieves the value from the `policy` value stored in Onyx const chatRoomSubtitle = useMemo(() => ReportUtils.getChatRoomSubtitle(props.report), [props.report, policy]); @@ -237,10 +238,11 @@ function ReportDetailsPage(props) { Navigation.navigate(ROUTES.REPORT_DESCRIPTION.getRoute(props.report.reportID))} /> {_.map(menuItems, (item) => { From e28f6cddaf021ce341d75b4a631b1a5a5ffaa3a4 Mon Sep 17 00:00:00 2001 From: someone-here Date: Sun, 14 Jan 2024 22:36:23 +0530 Subject: [PATCH 064/249] Hide Description conditionally --- src/pages/ReportDetailsPage.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/pages/ReportDetailsPage.js b/src/pages/ReportDetailsPage.js index 6be27454a928..f1636d85182f 100644 --- a/src/pages/ReportDetailsPage.js +++ b/src/pages/ReportDetailsPage.js @@ -71,6 +71,7 @@ function ReportDetailsPage(props) { const isArchivedRoom = useMemo(() => ReportUtils.isArchivedRoom(props.report), [props.report]); const isMoneyRequestReport = useMemo(() => ReportUtils.isMoneyRequestReport(props.report), [props.report]); const canEditReportDescription = useMemo(() => ReportUtils.canEditReportDescription(props.report, policy), [props.report, policy]); + const shouldShowReportDescription = canEditReportDescription || !_.isEmpty(props.report.description); // eslint-disable-next-line react-hooks/exhaustive-deps -- policy is a dependency because `getChatRoomSubtitle` calls `getPolicyName` which in turn retrieves the value from the `policy` value stored in Onyx const chatRoomSubtitle = useMemo(() => ReportUtils.getChatRoomSubtitle(props.report), [props.report, policy]); @@ -237,14 +238,16 @@ function ReportDetailsPage(props) { )} - Navigation.navigate(ROUTES.REPORT_DESCRIPTION.getRoute(props.report.reportID))} - /> + {shouldShowReportDescription && ( + Navigation.navigate(ROUTES.REPORT_DESCRIPTION.getRoute(props.report.reportID))} + /> + )} {_.map(menuItems, (item) => { const brickRoadIndicator = ReportUtils.hasReportNameError(props.report) && item.key === CONST.REPORT_DETAILS_MENU_ITEM.SETTINGS ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''; From 679ce09bc7dfe755e3bc1cca2b3e1cb393d991a6 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 15 Jan 2024 16:30:12 +0100 Subject: [PATCH 065/249] 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 066/249] 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 067/249] 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 068/249] 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 3bec4a39b8b9e0a50f1d4877bf0855f7815e1d96 Mon Sep 17 00:00:00 2001 From: Filip Solecki Date: Tue, 16 Jan 2024 15:23:52 +0100 Subject: [PATCH 069/249] Migrate ShareCodePage to functional component and to TS --- src/libs/UserUtils.ts | 4 +- src/pages/ShareCodePage.js | 137 ------------------ src/pages/ShareCodePage.tsx | 121 ++++++++++++++++ .../home/report/ReportDetailsShareCodePage.js | 31 ---- .../report/ReportDetailsShareCodePage.tsx | 17 +++ 5 files changed, 140 insertions(+), 170 deletions(-) delete mode 100644 src/pages/ShareCodePage.js create mode 100644 src/pages/ShareCodePage.tsx delete mode 100644 src/pages/home/report/ReportDetailsShareCodePage.js create mode 100644 src/pages/home/report/ReportDetailsShareCodePage.tsx diff --git a/src/libs/UserUtils.ts b/src/libs/UserUtils.ts index 6ec386679a32..f5973e854fd4 100644 --- a/src/libs/UserUtils.ts +++ b/src/libs/UserUtils.ts @@ -176,8 +176,8 @@ function getAvatar(avatarSource?: AvatarSource, accountID?: number): AvatarSourc * @param avatarURL - the avatar source from user's personalDetails * @param accountID - the accountID of the user */ -function getAvatarUrl(avatarURL: string, accountID: number): string { - return isDefaultAvatar(avatarURL) ? getDefaultAvatarURL(accountID) : avatarURL; +function getAvatarUrl(avatarSource: AvatarSource, accountID: number): AvatarSource { + return isDefaultAvatar(avatarSource) ? getDefaultAvatarURL(accountID) : avatarSource; } /** diff --git a/src/pages/ShareCodePage.js b/src/pages/ShareCodePage.js deleted file mode 100644 index 344e7f4bc886..000000000000 --- a/src/pages/ShareCodePage.js +++ /dev/null @@ -1,137 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import {ScrollView, View} from 'react-native'; -import _ from 'underscore'; -import expensifyLogo from '@assets/images/expensify-logo-round-transparent.png'; -import ContextMenuItem from '@components/ContextMenuItem'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import * as Expensicons from '@components/Icon/Expensicons'; -import MenuItem from '@components/MenuItem'; -import QRShareWithDownload from '@components/QRShare/QRShareWithDownload'; -import ScreenWrapper from '@components/ScreenWrapper'; -import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails'; -import withEnvironment from '@components/withEnvironment'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; -import withThemeStyles, {withThemeStylesPropTypes} from '@components/withThemeStyles'; -import Clipboard from '@libs/Clipboard'; -import compose from '@libs/compose'; -import getPlatform from '@libs/getPlatform'; -import Navigation from '@libs/Navigation/Navigation'; -import * as ReportUtils from '@libs/ReportUtils'; -import * as Url from '@libs/Url'; -import * as UserUtils from '@libs/UserUtils'; -import CONST from '@src/CONST'; -import ROUTES from '@src/ROUTES'; -import reportPropTypes from './reportPropTypes'; - -const propTypes = { - /** The report currently being looked at */ - report: reportPropTypes, - - /** The string value representing the URL of the current environment */ - environmentURL: PropTypes.string.isRequired, - - ...withLocalizePropTypes, - ...withCurrentUserPersonalDetailsPropTypes, - ...withThemeStylesPropTypes, -}; - -const defaultProps = { - report: undefined, - ...withCurrentUserPersonalDetailsDefaultProps, -}; - -// eslint-disable-next-line react/prefer-stateless-function -class ShareCodePage extends React.Component { - qrCodeRef = React.createRef(); - - /** - * @param {Boolean} isReport - * @return {String|string|*} - */ - getSubtitle(isReport) { - if (ReportUtils.isExpenseReport(this.props.report)) { - return ReportUtils.getPolicyName(this.props.report); - } - if (ReportUtils.isMoneyRequestReport(this.props.report)) { - // generate subtitle from participants - return _.map(ReportUtils.getVisibleMemberIDs(this.props.report), (accountID) => ReportUtils.getDisplayNameForParticipant(accountID)).join(' & '); - } - - if (isReport) { - return ReportUtils.getParentNavigationSubtitle(this.props.report).workspaceName || ReportUtils.getChatRoomSubtitle(this.props.report); - } - - return this.props.formatPhoneNumber(this.props.session.email); - } - - render() { - const isReport = this.props.report != null && this.props.report.reportID != null; - const title = isReport ? ReportUtils.getReportName(this.props.report) : this.props.currentUserPersonalDetails.displayName; - const subtitle = this.getSubtitle(isReport); - const urlWithTrailingSlash = Url.addTrailingForwardSlash(this.props.environmentURL); - const url = isReport - ? `${urlWithTrailingSlash}${ROUTES.REPORT_WITH_ID.getRoute(this.props.report.reportID)}` - : `${urlWithTrailingSlash}${ROUTES.PROFILE.getRoute(this.props.session.accountID)}`; - - const platform = getPlatform(); - const isNative = platform === CONST.PLATFORM.IOS || platform === CONST.PLATFORM.ANDROID; - - return ( - - Navigation.goBack(isReport ? ROUTES.REPORT_WITH_ID_DETAILS.getRoute(this.props.report.reportID) : ROUTES.SETTINGS)} - /> - - - - - - - - Clipboard.setString(url)} - /> - - {isNative && ( - this.qrCodeRef.current?.download()} - /> - )} - - Navigation.navigate(ROUTES.REFERRAL_DETAILS_MODAL.getRoute(CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SHARE_CODE))} - /> - - - - ); - } -} - -ShareCodePage.propTypes = propTypes; -ShareCodePage.defaultProps = defaultProps; -ShareCodePage.displayName = 'ShareCodePage'; - -export default compose(withEnvironment, withLocalize, withCurrentUserPersonalDetails, withThemeStyles)(ShareCodePage); diff --git a/src/pages/ShareCodePage.tsx b/src/pages/ShareCodePage.tsx new file mode 100644 index 000000000000..9adeffedefac --- /dev/null +++ b/src/pages/ShareCodePage.tsx @@ -0,0 +1,121 @@ +import React, {useRef} from 'react'; +import {ScrollView, View} from 'react-native'; +import type {ImageSourcePropType} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; +import expensifyLogo from '@assets/images/expensify-logo-round-transparent.png'; +import ContextMenuItem from '@components/ContextMenuItem'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import * as Expensicons from '@components/Icon/Expensicons'; +import MenuItem from '@components/MenuItem'; +import QRShareWithDownload from '@components/QRShare/QRShareWithDownload'; +import type QRShareWithDownloadHandle from '@components/QRShare/QRShareWithDownload/types'; +import ScreenWrapper from '@components/ScreenWrapper'; +import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; +import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; +import useEnvironment from '@hooks/useEnvironment'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Clipboard from '@libs/Clipboard'; +import getPlatform from '@libs/getPlatform'; +import Navigation from '@libs/Navigation/Navigation'; +import * as ReportUtils from '@libs/ReportUtils'; +import * as Url from '@libs/Url'; +import * as UserUtils from '@libs/UserUtils'; +import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; +import type {Report, Session} from '@src/types/onyx'; + +type ShareCodePageOnyxProps = WithCurrentUserPersonalDetailsProps & { + session: OnyxEntry; +}; + +type ShareCodePageProps = ShareCodePageOnyxProps & { + /** The report currently being looked at */ + report?: Report; +}; + +function ShareCodePage({report, session, currentUserPersonalDetails}: ShareCodePageProps) { + const themeStyles = useThemeStyles(); + const {translate} = useLocalize(); + const {environmentURL} = useEnvironment(); + const qrCodeRef = useRef(null); + + const getSubtitle = () => { + if (report) { + if (ReportUtils.isExpenseReport(report)) { + return ReportUtils.getPolicyName(report); + } + if (ReportUtils.isMoneyRequestReport(report)) { + // generate subtitle from participants + return ReportUtils.getVisibleMemberIDs(report) + .map((accountID) => ReportUtils.getDisplayNameForParticipant(accountID)) + .join(' & '); + } + + return ReportUtils.getParentNavigationSubtitle(report).workspaceName ?? ReportUtils.getChatRoomSubtitle(report); + } + + return session?.email; + }; + + const isReport = !!report?.reportID; + const title = isReport ? ReportUtils.getReportName(report) : currentUserPersonalDetails.displayName ?? ''; + const subtitle = getSubtitle(); + const urlWithTrailingSlash = Url.addTrailingForwardSlash(environmentURL); + const url = isReport ? `${urlWithTrailingSlash}${ROUTES.REPORT_WITH_ID.getRoute(report.reportID)}` : `${urlWithTrailingSlash}${ROUTES.PROFILE.getRoute(session?.accountID ?? '')}`; + const platform = getPlatform(); + const isNative = platform === CONST.PLATFORM.IOS || platform === CONST.PLATFORM.ANDROID; + + return ( + + Navigation.goBack(isReport ? ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID) : ROUTES.SETTINGS)} + /> + + + + + + + + Clipboard.setString(url)} + /> + + {isNative && ( + + )} + + Navigation.navigate(ROUTES.REFERRAL_DETAILS_MODAL.getRoute(CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SHARE_CODE))} + /> + + + + ); +} + +ShareCodePage.displayName = 'ShareCodePage'; + +export default withCurrentUserPersonalDetails(ShareCodePage); diff --git a/src/pages/home/report/ReportDetailsShareCodePage.js b/src/pages/home/report/ReportDetailsShareCodePage.js deleted file mode 100644 index 0ef2d46029ea..000000000000 --- a/src/pages/home/report/ReportDetailsShareCodePage.js +++ /dev/null @@ -1,31 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import reportPropTypes from '@pages/reportPropTypes'; -import ShareCodePage from '@pages/ShareCodePage'; -import withReportOrNotFound from './withReportOrNotFound'; - -const propTypes = { - /** Navigation route context info provided by react navigation */ - route: PropTypes.shape({ - /** Route specific parameters used on this screen */ - params: PropTypes.shape({ - reportID: PropTypes.string, - }).isRequired, - }).isRequired, - - /** The report currently being looked at */ - report: reportPropTypes, -}; - -const defaultProps = { - report: undefined, -}; - -function ReportDetailsShareCodePage(props) { - return ; -} - -ReportDetailsShareCodePage.propTypes = propTypes; -ReportDetailsShareCodePage.defaultProps = defaultProps; - -export default withReportOrNotFound()(ReportDetailsShareCodePage); diff --git a/src/pages/home/report/ReportDetailsShareCodePage.tsx b/src/pages/home/report/ReportDetailsShareCodePage.tsx new file mode 100644 index 000000000000..f11895ede5a2 --- /dev/null +++ b/src/pages/home/report/ReportDetailsShareCodePage.tsx @@ -0,0 +1,17 @@ +import type {StackScreenProps} from '@react-navigation/stack'; +import React from 'react'; +import type {ReportDetailsNavigatorParamList} from '@libs/Navigation/types'; +import ShareCodePage from '@pages/ShareCodePage'; +import type SCREENS from '@src/SCREENS'; +import type {Report} from '@src/types/onyx'; +import withReportOrNotFound from './withReportOrNotFound'; + +type ReportDetailsShareCodePageProps = StackScreenProps & { + report: Report; +}; + +function ReportDetailsShareCodePage({report}: ReportDetailsShareCodePageProps) { + return ; +} + +export default withReportOrNotFound()(ReportDetailsShareCodePage); From 10ef66b7bee3d3b6ad0932bdf2f3c0a046dc7744 Mon Sep 17 00:00:00 2001 From: someone-here Date: Tue, 16 Jan 2024 20:19:01 +0530 Subject: [PATCH 070/249] Update spanish translations --- src/languages/es.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/languages/es.ts b/src/languages/es.ts index 29688d4a19ae..fb872528d916 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1033,9 +1033,9 @@ export default { }, }, reportDescriptionPage: { - roomDescription: 'Descripción de la habitación', - roomDescriptionOptional: 'Descripción de la habitación (opcional)', - explainerText: 'Establece una descripción personalizada para la habitación.', + roomDescription: 'Descripción de la sala de chat', + roomDescriptionOptional: 'Descripción de la sala de chat (opcional)', + explainerText: 'Establece una descripción personalizada para la sala de chat.', }, languagePage: { language: 'Idioma', From ff6fc296d10ae2a8c800de76fd93464f7f5ece61 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 16 Jan 2024 15:59:41 +0100 Subject: [PATCH 071/249] 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 03567bd9ddcc1bf61fd11b89927f1c7422857893 Mon Sep 17 00:00:00 2001 From: someone-here Date: Tue, 16 Jan 2024 22:25:27 +0530 Subject: [PATCH 072/249] Fix header for tasks --- src/pages/home/HeaderView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index 72013c3f046d..f18a52ed2bb4 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -313,7 +313,7 @@ function HeaderView(props) { {subtitle} )} - {!_.isEmpty(reportDescription) && ( + {!_.isEmpty(reportDescription) && _.isEmpty(parentNavigationSubtitleData) && ( Date: Tue, 16 Jan 2024 18:35:30 +0100 Subject: [PATCH 073/249] Refactor types --- src/components/ButtonWithDropdownMenu.tsx | 9 ++++++--- src/components/Popover/types.ts | 2 +- src/components/PopoverMenu.tsx | 2 +- src/components/ProcessMoneyRequestHoldMenu.tsx | 2 +- src/components/SettlementButton.tsx | 10 +++++----- src/types/onyx/index.ts | 2 -- src/types/{onyx => utils}/AnchorAlignment.ts | 0 7 files changed, 14 insertions(+), 13 deletions(-) rename src/types/{onyx => utils}/AnchorAlignment.ts (100%) diff --git a/src/components/ButtonWithDropdownMenu.tsx b/src/components/ButtonWithDropdownMenu.tsx index 466c68229a32..011089af8ab9 100644 --- a/src/components/ButtonWithDropdownMenu.tsx +++ b/src/components/ButtonWithDropdownMenu.tsx @@ -9,15 +9,18 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import type {AnchorPosition} from '@styles/index'; import CONST from '@src/CONST'; +import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; +import type DeepValueOf from '@src/types/utils/DeepValueOf'; import type IconAsset from '@src/types/utils/IconAsset'; import Button from './Button'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; -import type {AnchorAlignment} from './Popover/types'; import PopoverMenu from './PopoverMenu'; +type PaymentType = DeepValueOf; + type DropdownOption = { - value: string; + value: PaymentType; text: string; icon: IconAsset; iconWidth?: number; @@ -30,7 +33,7 @@ type ButtonWithDropdownMenuProps = { menuHeaderText?: string; /** Callback to execute when the main button is pressed */ - onPress: (event: GestureResponderEvent | KeyboardEvent | undefined, value: string) => void; + onPress: (event: GestureResponderEvent | KeyboardEvent | undefined, value: PaymentType) => void; /** Call the onPress function on main button when Enter key is pressed */ pressOnEnter?: boolean; diff --git a/src/components/Popover/types.ts b/src/components/Popover/types.ts index 298c95eeca76..4409e8a7e296 100644 --- a/src/components/Popover/types.ts +++ b/src/components/Popover/types.ts @@ -1,7 +1,7 @@ import type {PopoverAnchorPosition} from '@components/Modal/types'; import type BaseModalProps from '@components/Modal/types'; import type {WindowDimensionsProps} from '@components/withWindowDimensions/types'; -import type {AnchorAlignment} from '@src/types/onyx'; +import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; type PopoverDimensions = { width: number; diff --git a/src/components/PopoverMenu.tsx b/src/components/PopoverMenu.tsx index 10599330945f..6990a453a931 100644 --- a/src/components/PopoverMenu.tsx +++ b/src/components/PopoverMenu.tsx @@ -9,7 +9,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import CONST from '@src/CONST'; import type {AnchorPosition} from '@src/styles'; -import type {AnchorAlignment} from '@src/types/onyx'; +import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; import type IconAsset from '@src/types/utils/IconAsset'; import MenuItem from './MenuItem'; import PopoverWithMeasuredContent from './PopoverWithMeasuredContent'; diff --git a/src/components/ProcessMoneyRequestHoldMenu.tsx b/src/components/ProcessMoneyRequestHoldMenu.tsx index 1fd37b82afc8..a069bcfa1a07 100644 --- a/src/components/ProcessMoneyRequestHoldMenu.tsx +++ b/src/components/ProcessMoneyRequestHoldMenu.tsx @@ -2,7 +2,7 @@ import React from 'react'; import {View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import type {AnchorAlignment} from '@src/types/onyx'; +import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; import Button from './Button'; import HoldMenuSectionList from './HoldMenuSectionList'; import type {PopoverAnchorPosition} from './Modal/types'; diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index 4a4abea14c70..82da026d4014 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -1,4 +1,4 @@ -import type {MutableRefObject} from 'react'; +import type {RefObject} from 'react'; import React, {useEffect, useMemo} from 'react'; import type {GestureResponderEvent, StyleProp, View, ViewStyle} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; @@ -13,14 +13,15 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {ButtonSizeValue} from '@src/styles/utils/types'; -import type {AnchorAlignment, LastPaymentMethod, Report} from '@src/types/onyx'; +import type {LastPaymentMethod, Report} from '@src/types/onyx'; +import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; import type DeepValueOf from '@src/types/utils/DeepValueOf'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; import * as Expensicons from './Icon/Expensicons'; import KYCWall from './KYCWall'; -type KYCFlowEvent = GestureResponderEvent | KeyboardEvent; +type KYCFlowEvent = GestureResponderEvent | KeyboardEvent | undefined; type TriggerKYCFlow = (event: KYCFlowEvent, iouPaymentType: string) => void; @@ -211,7 +212,7 @@ function SettlementButton({ anchorAlignment={kycWallAnchorAlignment} shouldShowPersonalBankAccountOption={shouldShowPersonalBankAccountOption} > - {(triggerKYCFlow: TriggerKYCFlow, buttonRef: MutableRefObject) => ( + {(triggerKYCFlow: TriggerKYCFlow, buttonRef: RefObject) => ( selectPaymentType(event, iouPaymentType, triggerKYCFlow)} pressOnEnter={pressOnEnter} options={paymentButtonOptions} - // @ts-expect-error TODO: Remove this once OptionsListUtils (https://github.com/Expensify/App/issues/25065) is migrated to TypeScript. style={style} buttonSize={buttonSize} anchorAlignment={paymentMethodDropdownAnchorAlignment} diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 8b2586db597a..3dd083d47865 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -1,6 +1,5 @@ import type Account from './Account'; import type AccountData from './AccountData'; -import type AnchorAlignment from './AnchorAlignment'; import type {BankAccountList} from './BankAccount'; import type BankAccount from './BankAccount'; import type Beta from './Beta'; @@ -142,5 +141,4 @@ export type { PolicyReportField, RecentlyUsedReportFields, LastPaymentMethod, - AnchorAlignment, }; diff --git a/src/types/onyx/AnchorAlignment.ts b/src/types/utils/AnchorAlignment.ts similarity index 100% rename from src/types/onyx/AnchorAlignment.ts rename to src/types/utils/AnchorAlignment.ts From 2ecaf16e8b9ba9024845c583715b290d7c949953 Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Tue, 16 Jan 2024 22:49:22 +0300 Subject: [PATCH 074/249] fix error message display bug on google signin --- src/pages/signin/LoginForm/BaseLoginForm.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/pages/signin/LoginForm/BaseLoginForm.js b/src/pages/signin/LoginForm/BaseLoginForm.js index 8fcea461eacd..5a6c8aed5050 100644 --- a/src/pages/signin/LoginForm/BaseLoginForm.js +++ b/src/pages/signin/LoginForm/BaseLoginForm.js @@ -276,13 +276,15 @@ function LoginForm(props) { textContentType="username" id="username" name="username" - onBlur={() => { - if (firstBlurred.current || !Visibility.isVisible() || !Visibility.hasFocus()) { - return; - } - firstBlurred.current = true; - validate(login); - }} + onBlur={() => + setTimeout(() => { + if (firstBlurred.current || !Visibility.isVisible() || !Visibility.hasFocus()) { + return; + } + firstBlurred.current = true; + validate(login); + }, 500) + } onChangeText={onTextInput} onSubmitEditing={validateAndSubmitForm} autoCapitalize="none" @@ -332,10 +334,10 @@ function LoginForm(props) { - e.preventDefault()}> + - e.preventDefault()}> + From d615392f8e14448a6a38f7b0607753dbb46210ff Mon Sep 17 00:00:00 2001 From: Filip Solecki Date: Tue, 16 Jan 2024 21:25:54 +0100 Subject: [PATCH 075/249] Fix types --- src/pages/ShareCodePage.tsx | 7 ++++--- .../home/report/ReportDetailsShareCodePage.tsx | 9 ++------- src/pages/home/report/withReportOrNotFound.tsx | 17 +++++++++++------ 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/pages/ShareCodePage.tsx b/src/pages/ShareCodePage.tsx index 9adeffedefac..670d6bed6cef 100644 --- a/src/pages/ShareCodePage.tsx +++ b/src/pages/ShareCodePage.tsx @@ -26,14 +26,15 @@ import ROUTES from '@src/ROUTES'; import type {Report, Session} from '@src/types/onyx'; type ShareCodePageOnyxProps = WithCurrentUserPersonalDetailsProps & { + /** Session info for the currently logged in user. */ session: OnyxEntry; -}; -type ShareCodePageProps = ShareCodePageOnyxProps & { /** The report currently being looked at */ - report?: Report; + report?: OnyxEntry; }; +type ShareCodePageProps = ShareCodePageOnyxProps; + function ShareCodePage({report, session, currentUserPersonalDetails}: ShareCodePageProps) { const themeStyles = useThemeStyles(); const {translate} = useLocalize(); diff --git a/src/pages/home/report/ReportDetailsShareCodePage.tsx b/src/pages/home/report/ReportDetailsShareCodePage.tsx index f11895ede5a2..28b1d5cd71d7 100644 --- a/src/pages/home/report/ReportDetailsShareCodePage.tsx +++ b/src/pages/home/report/ReportDetailsShareCodePage.tsx @@ -1,14 +1,9 @@ -import type {StackScreenProps} from '@react-navigation/stack'; import React from 'react'; -import type {ReportDetailsNavigatorParamList} from '@libs/Navigation/types'; import ShareCodePage from '@pages/ShareCodePage'; -import type SCREENS from '@src/SCREENS'; -import type {Report} from '@src/types/onyx'; +import type {WithReportOrNotFoundProps} from './withReportOrNotFound'; import withReportOrNotFound from './withReportOrNotFound'; -type ReportDetailsShareCodePageProps = StackScreenProps & { - report: Report; -}; +type ReportDetailsShareCodePageProps = WithReportOrNotFoundProps; function ReportDetailsShareCodePage({report}: ReportDetailsShareCodePageProps) { return ; diff --git a/src/pages/home/report/withReportOrNotFound.tsx b/src/pages/home/report/withReportOrNotFound.tsx index 7613bafeacdc..6a523a0e13ed 100644 --- a/src/pages/home/report/withReportOrNotFound.tsx +++ b/src/pages/home/report/withReportOrNotFound.tsx @@ -11,27 +11,30 @@ import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; import ONYXKEYS from '@src/ONYXKEYS'; import type * as OnyxTypes from '@src/types/onyx'; -type OnyxProps = { +type WithReportOrNotFoundOnyxProps = { /** The report currently being looked at */ report: OnyxEntry; + /** The policies which the user has access to */ policies: OnyxCollection; + /** Beta features list */ betas: OnyxEntry; + /** Indicated whether the report data is loading */ isLoadingReportData: OnyxEntry; }; -type ComponentProps = OnyxProps & { +type WithReportOrNotFoundProps = WithReportOrNotFoundOnyxProps & { route: RouteProp<{params: {reportID: string}}>; }; export default function ( shouldRequireReportID = true, -): ( +): ( WrappedComponent: React.ComponentType>, -) => React.ComponentType, keyof OnyxProps>> { - return function (WrappedComponent: ComponentType>) { +) => React.ComponentType, keyof WithReportOrNotFoundOnyxProps>> { + return function (WrappedComponent: ComponentType>) { function WithReportOrNotFound(props: TProps, ref: ForwardedRef) { const contentShown = React.useRef(false); @@ -73,7 +76,7 @@ export default function ( WithReportOrNotFound.displayName = `withReportOrNotFound(${getComponentDisplayName(WrappedComponent)})`; - return withOnyx, OnyxProps>({ + return withOnyx, WithReportOrNotFoundOnyxProps>({ report: { key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`, }, @@ -89,3 +92,5 @@ export default function ( })(React.forwardRef(WithReportOrNotFound)); }; } + +export type {WithReportOrNotFoundProps}; From 99fac30a5392b79446d95510727e618de489c03e Mon Sep 17 00:00:00 2001 From: Filip Solecki Date: Wed, 17 Jan 2024 07:32:21 +0100 Subject: [PATCH 076/249] Reuse existing logic --- src/pages/ShareCodePage.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pages/ShareCodePage.tsx b/src/pages/ShareCodePage.tsx index 670d6bed6cef..7b374810a4b3 100644 --- a/src/pages/ShareCodePage.tsx +++ b/src/pages/ShareCodePage.tsx @@ -41,8 +41,10 @@ function ShareCodePage({report, session, currentUserPersonalDetails}: ShareCodeP const {environmentURL} = useEnvironment(); const qrCodeRef = useRef(null); + const isReport = !!report?.reportID; + const getSubtitle = () => { - if (report) { + if (isReport) { if (ReportUtils.isExpenseReport(report)) { return ReportUtils.getPolicyName(report); } @@ -59,7 +61,6 @@ function ShareCodePage({report, session, currentUserPersonalDetails}: ShareCodeP return session?.email; }; - const isReport = !!report?.reportID; const title = isReport ? ReportUtils.getReportName(report) : currentUserPersonalDetails.displayName ?? ''; const subtitle = getSubtitle(); const urlWithTrailingSlash = Url.addTrailingForwardSlash(environmentURL); From 12970726137467b155756e1aa942e7ef112d0c92 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Wed, 17 Jan 2024 08:29:22 +0100 Subject: [PATCH 077/249] 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 772370cf1c5e5c11f82f282b99fdc16256e69e39 Mon Sep 17 00:00:00 2001 From: Filip Solecki Date: Wed, 17 Jan 2024 09:41:24 +0100 Subject: [PATCH 078/249] Fix download code button --- src/components/MenuItem.tsx | 2 +- src/pages/ShareCodePage.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx index 334fa9895205..5162a8227277 100644 --- a/src/components/MenuItem.tsx +++ b/src/components/MenuItem.tsx @@ -57,7 +57,7 @@ type NoIcon = { type MenuItemProps = (IconProps | AvatarProps | NoIcon) & { /** Function to fire when component is pressed */ - onPress?: (event: GestureResponderEvent | KeyboardEvent) => void; + onPress?: (event: GestureResponderEvent | KeyboardEvent) => void | Promise; /** Whether the menu item should be interactive at all */ interactive?: boolean; diff --git a/src/pages/ShareCodePage.tsx b/src/pages/ShareCodePage.tsx index 7b374810a4b3..62368b2520e6 100644 --- a/src/pages/ShareCodePage.tsx +++ b/src/pages/ShareCodePage.tsx @@ -103,7 +103,7 @@ function ShareCodePage({report, session, currentUserPersonalDetails}: ShareCodeP isAnonymousAction title={translate('common.download')} icon={Expensicons.Download} - onPress={qrCodeRef.current?.download} + onPress={() => qrCodeRef.current?.download()} /> )} From 1621e4bf61dad08d35629265fdea5ac92c9ea3dd Mon Sep 17 00:00:00 2001 From: VickyStash Date: Wed, 17 Jan 2024 16:10:46 +0100 Subject: [PATCH 079/249] 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 080/249] 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 081/249] 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 082/249] 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 fad567c1071c523ca2b432477b56731a146f0aed Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Wed, 17 Jan 2024 16:00:38 +0000 Subject: [PATCH 083/249] refactor: move methods to personalDetailsUtils, remove unused one --- src/libs/PersonalDetailsUtils.ts | 69 +++++++++++++++++ src/libs/actions/PersonalDetails.ts | 74 +------------------ src/libs/actions/User.ts | 4 +- .../EnablePayments/AdditionalDetailsStep.js | 6 +- 4 files changed, 75 insertions(+), 78 deletions(-) diff --git a/src/libs/PersonalDetailsUtils.ts b/src/libs/PersonalDetailsUtils.ts index 3346094adeec..10b966a1a688 100644 --- a/src/libs/PersonalDetailsUtils.ts +++ b/src/libs/PersonalDetailsUtils.ts @@ -1,5 +1,6 @@ import type {OnyxEntry} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; +import Str from 'expensify-common/lib/str'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalDetails, PersonalDetailsList, PrivatePersonalDetails} from '@src/types/onyx'; @@ -7,6 +8,12 @@ import * as LocalePhoneNumber from './LocalePhoneNumber'; import * as Localize from './Localize'; import * as UserUtils from './UserUtils'; + +type FirstAndLastName = { + firstName: string; + lastName: string; +}; + let personalDetails: Array = []; let allPersonalDetails: OnyxEntry = {}; Onyx.connect({ @@ -198,6 +205,66 @@ function getEffectiveDisplayName(personalDetail?: PersonalDetails): string | und return undefined; } +/** + * Creates a new displayName for a user based on passed personal details or login. + * + * @param login - user's login + * @param passedPersonalDetails - details object with firstName and lastName + * @returns - The effective display name + */ +function createDisplayName(login: string, passedPersonalDetails: Pick | OnyxEntry): string { + // If we have a number like +15857527441@expensify.sms then let's remove @expensify.sms and format it + // so that the option looks cleaner in our UI. + const userLogin = LocalePhoneNumber.formatPhoneNumber(login); + + if (!passedPersonalDetails) { + return userLogin; + } + + const firstName = passedPersonalDetails.firstName ?? ''; + const lastName = passedPersonalDetails.lastName ?? ''; + const fullName = `${firstName} ${lastName}`.trim(); + + // It's possible for fullName to be empty string, so we must use "||" to fallback to userLogin. + return fullName || userLogin; +} + +/** + * Gets the first and last name from the user's personal details. + * If the login is the same as the displayName, then they don't exist, + * so we return empty strings instead. + * + * @param login - user's login + * @param displayName - user display name + * @param firstName + * @param lastName + */ +function extractFirstAndLastNameFromAvailableDetails({login, displayName, firstName, lastName}: PersonalDetails): FirstAndLastName { + // It's possible for firstName to be empty string, so we must use "||" to consider lastName instead. + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + if (firstName || lastName) { + return {firstName: firstName ?? '', lastName: lastName ?? ''}; + } + if (login && Str.removeSMSDomain(login) === displayName) { + return {firstName: '', lastName: ''}; + } + + if (displayName) { + const firstSpaceIndex = displayName.indexOf(' '); + const lastSpaceIndex = displayName.lastIndexOf(' '); + if (firstSpaceIndex === -1) { + return {firstName: displayName, lastName: ''}; + } + + return { + firstName: displayName.substring(0, firstSpaceIndex).trim(), + lastName: displayName.substring(lastSpaceIndex).trim(), + }; + } + + return {firstName: '', lastName: ''}; +} + export { getDisplayNameOrDefault, getPersonalDetailsByIDs, @@ -208,4 +275,6 @@ export { getFormattedStreet, getStreetLines, getEffectiveDisplayName, + createDisplayName, + extractFirstAndLastNameFromAvailableDetails }; diff --git a/src/libs/actions/PersonalDetails.ts b/src/libs/actions/PersonalDetails.ts index 508cca34fb88..b09b664ff745 100644 --- a/src/libs/actions/PersonalDetails.ts +++ b/src/libs/actions/PersonalDetails.ts @@ -1,10 +1,8 @@ -import Str from 'expensify-common/lib/str'; import type {OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import * as API from '@libs/API'; import type {CustomRNImageManipulatorResult} from '@libs/cropOrRotateImage/types'; import DateUtils from '@libs/DateUtils'; -import * as LocalePhoneNumber from '@libs/LocalePhoneNumber'; import Navigation from '@libs/Navigation/Navigation'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as UserUtils from '@libs/UserUtils'; @@ -15,11 +13,6 @@ import type {DateOfBirthForm, PersonalDetails, PersonalDetailsList, PrivatePerso import type {SelectedTimezone, Timezone} from '@src/types/onyx/PersonalDetails'; import * as Session from './Session'; -type FirstAndLastName = { - firstName: string; - lastName: string; -}; - let currentUserEmail = ''; let currentUserAccountID = -1; Onyx.connect({ @@ -42,68 +35,6 @@ Onyx.connect({ callback: (val) => (privatePersonalDetails = val), }); -/** - * Creates a new displayName for a user based on passed personal details or login. - */ -function createDisplayName(login: string, personalDetails: Pick | OnyxEntry): string { - // If we have a number like +15857527441@expensify.sms then let's remove @expensify.sms and format it - // so that the option looks cleaner in our UI. - const userLogin = LocalePhoneNumber.formatPhoneNumber(login); - - if (!personalDetails) { - return userLogin; - } - - const firstName = personalDetails.firstName ?? ''; - const lastName = personalDetails.lastName ?? ''; - const fullName = `${firstName} ${lastName}`.trim(); - - // It's possible for fullName to be empty string, so we must use "||" to fallback to userLogin. - return fullName || userLogin; -} - -/** - * Gets the first and last name from the user's personal details. - * If the login is the same as the displayName, then they don't exist, - * so we return empty strings instead. - */ -function extractFirstAndLastNameFromAvailableDetails({login, displayName, firstName, lastName}: PersonalDetails): FirstAndLastName { - // It's possible for firstName to be empty string, so we must use "||" to consider lastName instead. - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - if (firstName || lastName) { - return {firstName: firstName ?? '', lastName: lastName ?? ''}; - } - if (login && Str.removeSMSDomain(login) === displayName) { - return {firstName: '', lastName: ''}; - } - - if (displayName) { - const firstSpaceIndex = displayName.indexOf(' '); - const lastSpaceIndex = displayName.lastIndexOf(' '); - if (firstSpaceIndex === -1) { - return {firstName: displayName, lastName: ''}; - } - - return { - firstName: displayName.substring(0, firstSpaceIndex).trim(), - lastName: displayName.substring(lastSpaceIndex).trim(), - }; - } - - return {firstName: '', lastName: ''}; -} - -/** - * Convert country names obtained from the backend to their respective ISO codes - * This is for backward compatibility of stored data before E/App#15507 - */ -function getCountryISO(countryName: string): string { - if (!countryName || countryName.length === 2) { - return countryName; - } - - return Object.entries(CONST.ALL_COUNTRIES).find(([, value]) => value === countryName)?.[0] ?? ''; -} function updatePronouns(pronouns: string) { if (currentUserAccountID) { @@ -149,7 +80,7 @@ function updateDisplayName(firstName: string, lastName: string) { [currentUserAccountID]: { firstName, lastName, - displayName: createDisplayName(currentUserEmail ?? '', { + displayName: PersonalDetailsUtils.createDisplayName(currentUserEmail ?? '', { firstName, lastName, }), @@ -563,9 +494,6 @@ function getPrivatePersonalDetails(): OnyxEntry { export { clearAvatarErrors, deleteAvatar, - extractFirstAndLastNameFromAvailableDetails, - getCountryISO, - createDisplayName, getPrivatePersonalDetails, openPersonalDetailsPage, openPublicProfilePage, diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts index df5709ac68e2..1766b1a29677 100644 --- a/src/libs/actions/User.ts +++ b/src/libs/actions/User.ts @@ -10,6 +10,7 @@ import * as SequentialQueue from '@libs/Network/SequentialQueue'; import * as Pusher from '@libs/Pusher/pusher'; import PusherUtils from '@libs/PusherUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; +import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -23,7 +24,6 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import * as Link from './Link'; import * as OnyxUpdates from './OnyxUpdates'; -import * as PersonalDetails from './PersonalDetails'; import * as Report from './Report'; import * as Session from './Session'; @@ -716,7 +716,7 @@ function setContactMethodAsDefault(newDefaultContactMethod: string) { value: { [currentUserAccountID]: { login: newDefaultContactMethod, - displayName: PersonalDetails.createDisplayName(newDefaultContactMethod, myPersonalDetails), + displayName: PersonalDetailsUtils.createDisplayName(newDefaultContactMethod, myPersonalDetails), }, }, }, diff --git a/src/pages/EnablePayments/AdditionalDetailsStep.js b/src/pages/EnablePayments/AdditionalDetailsStep.js index 5ca51e208b49..0371a70ede4b 100644 --- a/src/pages/EnablePayments/AdditionalDetailsStep.js +++ b/src/pages/EnablePayments/AdditionalDetailsStep.js @@ -18,8 +18,8 @@ import useThemeStyles from '@hooks/useThemeStyles'; import compose from '@libs/compose'; import {parsePhoneNumber} from '@libs/PhoneNumber'; import * as ValidationUtils from '@libs/ValidationUtils'; +import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import AddressForm from '@pages/ReimbursementAccount/AddressForm'; -import * as PersonalDetails from '@userActions/PersonalDetails'; import * as Wallet from '@userActions/Wallet'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -194,7 +194,7 @@ function AdditionalDetailsStep({walletAdditionalDetails, translate, currentUserP label={translate(fieldNameTranslationKeys.legalFirstName)} accessibilityLabel={translate(fieldNameTranslationKeys.legalFirstName)} role={CONST.ROLE.PRESENTATION} - defaultValue={PersonalDetails.extractFirstAndLastNameFromAvailableDetails(currentUserPersonalDetails).firstName} + defaultValue={PersonalDetailsUtils.extractFirstAndLastNameFromAvailableDetails(currentUserPersonalDetails).firstName} shouldSaveDraft /> Date: Wed, 17 Jan 2024 18:05:34 +0100 Subject: [PATCH 084/249] 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 085/249] 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 dc7694036da1a085e0bfb1ed391b34ede581cef7 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Fri, 19 Jan 2024 10:04:55 +0000 Subject: [PATCH 086/249] fix: run prettier --- src/libs/PersonalDetailsUtils.ts | 5 ++--- src/libs/actions/PersonalDetails.ts | 1 - src/libs/actions/User.ts | 2 +- src/pages/EnablePayments/AdditionalDetailsStep.js | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/libs/PersonalDetailsUtils.ts b/src/libs/PersonalDetailsUtils.ts index 85c439c11736..945c0b581b16 100644 --- a/src/libs/PersonalDetailsUtils.ts +++ b/src/libs/PersonalDetailsUtils.ts @@ -1,6 +1,6 @@ +import Str from 'expensify-common/lib/str'; import type {OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; -import Str from 'expensify-common/lib/str'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalDetails, PersonalDetailsList, PrivatePersonalDetails} from '@src/types/onyx'; @@ -9,7 +9,6 @@ import * as LocalePhoneNumber from './LocalePhoneNumber'; import * as Localize from './Localize'; import * as UserUtils from './UserUtils'; - type FirstAndLastName = { firstName: string; lastName: string; @@ -273,5 +272,5 @@ export { getStreetLines, getEffectiveDisplayName, createDisplayName, - extractFirstAndLastNameFromAvailableDetails + extractFirstAndLastNameFromAvailableDetails, }; diff --git a/src/libs/actions/PersonalDetails.ts b/src/libs/actions/PersonalDetails.ts index b09b664ff745..afd0dc6037e8 100644 --- a/src/libs/actions/PersonalDetails.ts +++ b/src/libs/actions/PersonalDetails.ts @@ -35,7 +35,6 @@ Onyx.connect({ callback: (val) => (privatePersonalDetails = val), }); - function updatePronouns(pronouns: string) { if (currentUserAccountID) { type UpdatePronounsParams = { diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts index 1766b1a29677..b304be62b407 100644 --- a/src/libs/actions/User.ts +++ b/src/libs/actions/User.ts @@ -7,10 +7,10 @@ import * as API from '@libs/API'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as SequentialQueue from '@libs/Network/SequentialQueue'; +import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as Pusher from '@libs/Pusher/pusher'; import PusherUtils from '@libs/PusherUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; -import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; diff --git a/src/pages/EnablePayments/AdditionalDetailsStep.js b/src/pages/EnablePayments/AdditionalDetailsStep.js index 0371a70ede4b..cf769bf58fd3 100644 --- a/src/pages/EnablePayments/AdditionalDetailsStep.js +++ b/src/pages/EnablePayments/AdditionalDetailsStep.js @@ -16,9 +16,9 @@ import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultPro import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import compose from '@libs/compose'; +import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import {parsePhoneNumber} from '@libs/PhoneNumber'; import * as ValidationUtils from '@libs/ValidationUtils'; -import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import AddressForm from '@pages/ReimbursementAccount/AddressForm'; import * as Wallet from '@userActions/Wallet'; import CONST from '@src/CONST'; From 6685a9a4615bd356a2a95813cfd3d98b6f4dae8a Mon Sep 17 00:00:00 2001 From: someone-here Date: Fri, 19 Jan 2024 22:29:24 +0530 Subject: [PATCH 087/249] Reconcile description route and permission --- src/ROUTES.ts | 6 +- src/SCREENS.ts | 1 - src/components/ReportActionItem/TaskView.js | 2 +- src/libs/Navigation/linkingConfig.ts | 2 - src/libs/ReportUtils.ts | 2 +- src/pages/ReportDescriptionPage.js | 123 ++--------------- src/pages/RoomDescriptionPage.js | 138 ++++++++++++++++++++ 7 files changed, 152 insertions(+), 122 deletions(-) create mode 100644 src/pages/RoomDescriptionPage.js diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 6e07666c052e..4690637a4098 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -195,10 +195,6 @@ const ROUTES = { route: 'r/:reportID/settings/who-can-post', getRoute: (reportID: string) => `r/${reportID}/settings/who-can-post` as const, }, - REPORT_DESCRIPTION: { - route: 'r/:reportID/roomDescription', - getRoute: (reportID: string) => `r/${reportID}/roomDescription` as const, - }, SPLIT_BILL_DETAILS: { route: 'r/:reportID/split/:reportActionID', getRoute: (reportID: string, reportActionID: string) => `r/${reportID}/split/${reportActionID}` as const, @@ -216,7 +212,7 @@ const ROUTES = { route: 'r/:reportID/title', getRoute: (reportID: string) => `r/${reportID}/title` as const, }, - TASK_DESCRIPTION: { + REPORT_DESCRIPTION: { route: 'r/:reportID/description', getRoute: (reportID: string) => `r/${reportID}/description` as const, }, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index b053782d43be..ca33c8b9da15 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -175,7 +175,6 @@ const SCREENS = { TASK: { TITLE: 'Task_Title', - DESCRIPTION: 'Task_Description', ASSIGNEE: 'Task_Assignee', }, diff --git a/src/components/ReportActionItem/TaskView.js b/src/components/ReportActionItem/TaskView.js index 7f7b177136ed..03b631313750 100644 --- a/src/components/ReportActionItem/TaskView.js +++ b/src/components/ReportActionItem/TaskView.js @@ -150,7 +150,7 @@ function TaskView(props) { shouldParseTitle description={props.translate('task.description')} title={props.report.description || ''} - onPress={() => Navigation.navigate(ROUTES.TASK_DESCRIPTION.getRoute(props.report.reportID))} + onPress={() => Navigation.navigate(ROUTES.REPORT_DESCRIPTION.getRoute(props.report.reportID))} shouldShowRightIcon={isOpen} disabled={disableState} wrapperStyle={[styles.pv2, styles.taskDescriptionMenuItem]} diff --git a/src/libs/Navigation/linkingConfig.ts b/src/libs/Navigation/linkingConfig.ts index de1ef75fcefd..7a4e49be9372 100644 --- a/src/libs/Navigation/linkingConfig.ts +++ b/src/libs/Navigation/linkingConfig.ts @@ -335,7 +335,6 @@ const linkingConfig: LinkingOptions = { [SCREENS.NEW_TASK.TASK_SHARE_DESTINATION_SELECTOR]: ROUTES.NEW_TASK_SHARE_DESTINATION, [SCREENS.NEW_TASK.DETAILS]: ROUTES.NEW_TASK_DETAILS, [SCREENS.NEW_TASK.TITLE]: ROUTES.NEW_TASK_TITLE, - [SCREENS.NEW_TASK.DESCRIPTION]: ROUTES.NEW_TASK_DESCRIPTION, }, }, [SCREENS.RIGHT_MODAL.TEACHERS_UNITE]: { @@ -450,7 +449,6 @@ const linkingConfig: LinkingOptions = { [SCREENS.RIGHT_MODAL.TASK_DETAILS]: { screens: { [SCREENS.TASK.TITLE]: ROUTES.TASK_TITLE.route, - [SCREENS.TASK.DESCRIPTION]: ROUTES.TASK_DESCRIPTION.route, [SCREENS.TASK.ASSIGNEE]: ROUTES.TASK_ASSIGNEE.route, }, }, diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index b2da8426e256..7fb640f55168 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4339,7 +4339,7 @@ function getRoom(type: ValueOf, policyID: string) * We only want policy owners and admins to be able to modify the report description, but not in thread chat. */ function canEditReportDescription(report: OnyxEntry, policy: OnyxEntry): boolean { - return !isMoneyRequestReport(report) && !isArchivedRoom(report) && isChatRoom(report) && !isChatThread(report) && PolicyUtils.isPolicyAdmin(policy); + return !isMoneyRequestReport(report) && !isArchivedRoom(report) && isChatRoom(report) && !isChatThread(report) && isEmpty(policy); } /** * Checks if report action has error when smart scanning diff --git a/src/pages/ReportDescriptionPage.js b/src/pages/ReportDescriptionPage.js index 9093d165b876..9b9680e1e81d 100644 --- a/src/pages/ReportDescriptionPage.js +++ b/src/pages/ReportDescriptionPage.js @@ -1,34 +1,12 @@ -import {useFocusEffect} from '@react-navigation/native'; -import ExpensiMark from 'expensify-common/lib/ExpensiMark'; import PropTypes from 'prop-types'; -import React, {useCallback, useRef, useState} from 'react'; -import {View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; -import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; -import FormProvider from '@components/Form/FormProvider'; -import InputWrapper from '@components/Form/InputWrapper'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import ScreenWrapper from '@components/ScreenWrapper'; -import Text from '@components/Text'; -import TextInput from '@components/TextInput'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; -import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; -import Navigation from '@libs/Navigation/Navigation'; +import React from 'react'; import * as ReportUtils from '@libs/ReportUtils'; -import updateMultilineInputRange from '@libs/updateMultilineInputRange'; -import * as Report from '@userActions/Report'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; import withReportOrNotFound from './home/report/withReportOrNotFound'; import reportPropTypes from './reportPropTypes'; -import {policyDefaultProps, policyPropTypes} from './workspace/withPolicy'; +import RoomDescriptionPage from './RoomDescriptionPage'; +import TaskDescriptionPage from './tasks/TaskDescriptionPage'; const propTypes = { - ...withLocalizePropTypes, - ...policyPropTypes, - /** The report currently being looked at */ report: reportPropTypes.isRequired, @@ -41,98 +19,19 @@ const propTypes = { }).isRequired, }; -const defaultProps = { - ...policyDefaultProps, -}; - function ReportDescriptionPage(props) { - const styles = useThemeStyles(); - const parser = new ExpensiMark(); - const [description, setdescription] = useState(() => parser.htmlToMarkdown(props.report.description)); - const reportDescriptionInputRef = useRef(null); - const focusTimeoutRef = useRef(null); - - const handleReportDescriptionChange = useCallback((value) => { - setdescription(value); - }, []); - - const submitForm = useCallback(() => { - Report.updateDescription(props.report.reportID, props.report.description, description.trim()); - }, [props.report.reportID, props.report.description, description]); + const isTask = ReportUtils.isTaskReport(props.report); - useFocusEffect( - useCallback(() => { - focusTimeoutRef.current = setTimeout(() => { - if (reportDescriptionInputRef.current) { - reportDescriptionInputRef.current.focus(); - } - return () => { - if (!focusTimeoutRef.current) { - return; - } - clearTimeout(focusTimeoutRef.current); - }; - }, CONST.ANIMATED_TRANSITION); - }, []), - ); + if (isTask) { + // eslint-disable-next-line react/jsx-props-no-spreading + return ; + } - return ( - - - Navigation.goBack(ROUTES.REPORT_SETTINGS.getRoute(props.report.reportID))} - /> - - {props.translate('reportDescriptionPage.explainerText')} - - { - if (!el) { - return; - } - reportDescriptionInputRef.current = el; - updateMultilineInputRange(reportDescriptionInputRef.current); - }} - value={description} - onChangeText={handleReportDescriptionChange} - autoCapitalize="none" - containerStyles={[styles.autoGrowHeightMultilineInput]} - /> - - - - - ); + // eslint-disable-next-line react/jsx-props-no-spreading + return ; } ReportDescriptionPage.displayName = 'ReportDescriptionPage'; ReportDescriptionPage.propTypes = propTypes; -ReportDescriptionPage.defaultProps = defaultProps; -export default compose( - withLocalize, - withReportOrNotFound(), - withOnyx({ - policy: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, - }, - }), -)(ReportDescriptionPage); +export default withReportOrNotFound()(ReportDescriptionPage); diff --git a/src/pages/RoomDescriptionPage.js b/src/pages/RoomDescriptionPage.js new file mode 100644 index 000000000000..f7c6e621454b --- /dev/null +++ b/src/pages/RoomDescriptionPage.js @@ -0,0 +1,138 @@ +import {useFocusEffect} from '@react-navigation/native'; +import ExpensiMark from 'expensify-common/lib/ExpensiMark'; +import PropTypes from 'prop-types'; +import React, {useCallback, useRef, useState} from 'react'; +import {View} from 'react-native'; +import {withOnyx} from 'react-native-onyx'; +import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; +import FormProvider from '@components/Form/FormProvider'; +import InputWrapper from '@components/Form/InputWrapper'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import Text from '@components/Text'; +import TextInput from '@components/TextInput'; +import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import compose from '@libs/compose'; +import Navigation from '@libs/Navigation/Navigation'; +import * as ReportUtils from '@libs/ReportUtils'; +import updateMultilineInputRange from '@libs/updateMultilineInputRange'; +import * as Report from '@userActions/Report'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; +import withReportOrNotFound from './home/report/withReportOrNotFound'; +import reportPropTypes from './reportPropTypes'; +import {policyDefaultProps, policyPropTypes} from './workspace/withPolicy'; + +const propTypes = { + ...withLocalizePropTypes, + ...policyPropTypes, + + /** The report currently being looked at */ + report: reportPropTypes.isRequired, + + /** Route params */ + route: PropTypes.shape({ + params: PropTypes.shape({ + /** Report ID passed via route r/:reportID/roomDescription */ + reportID: PropTypes.string, + }), + }).isRequired, +}; + +const defaultProps = { + ...policyDefaultProps, +}; + +function RoomDescriptionPage(props) { + const styles = useThemeStyles(); + const parser = new ExpensiMark(); + const [description, setdescription] = useState(() => parser.htmlToMarkdown(props.report.description)); + const reportDescriptionInputRef = useRef(null); + const focusTimeoutRef = useRef(null); + + const handleReportDescriptionChange = useCallback((value) => { + setdescription(value); + }, []); + + const submitForm = useCallback(() => { + Report.updateDescription(props.report.reportID, props.report.description, description.trim()); + }, [props.report.reportID, props.report.description, description]); + + useFocusEffect( + useCallback(() => { + focusTimeoutRef.current = setTimeout(() => { + if (reportDescriptionInputRef.current) { + reportDescriptionInputRef.current.focus(); + } + return () => { + if (!focusTimeoutRef.current) { + return; + } + clearTimeout(focusTimeoutRef.current); + }; + }, CONST.ANIMATED_TRANSITION); + }, []), + ); + + return ( + + + Navigation.goBack(ROUTES.REPORT_SETTINGS.getRoute(props.report.reportID))} + /> + + {props.translate('reportDescriptionPage.explainerText')} + + { + if (!el) { + return; + } + reportDescriptionInputRef.current = el; + updateMultilineInputRange(reportDescriptionInputRef.current); + }} + value={description} + onChangeText={handleReportDescriptionChange} + autoCapitalize="none" + containerStyles={[styles.autoGrowHeightMultilineInput]} + /> + + + + + ); +} + +RoomDescriptionPage.displayName = 'RoomDescriptionPage'; +RoomDescriptionPage.propTypes = propTypes; +RoomDescriptionPage.defaultProps = defaultProps; + +export default compose( + withLocalize, + withReportOrNotFound(), + withOnyx({ + policy: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, + }, + }), +)(RoomDescriptionPage); From dd340521434d2ac37e0f5cc1c96309f846e7fe22 Mon Sep 17 00:00:00 2001 From: someone-here Date: Fri, 19 Jan 2024 22:32:20 +0530 Subject: [PATCH 088/249] Fix lint --- src/libs/ReportUtils.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 06d63e552acc..7761ab9cdfed 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4730,7 +4730,6 @@ export { canEditReportDescription, doesTransactionThreadHaveViolations, hasViolations, - shouldDisableWelcomeMessage, navigateToPrivateNotes, canEditWriteCapability, hasSmartscanError, From 0c6a9e4f12c4fa431b8bc1d60452891570039caf Mon Sep 17 00:00:00 2001 From: someone-here Date: Fri, 19 Jan 2024 22:42:54 +0530 Subject: [PATCH 089/249] Fix TS --- src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx | 1 - src/libs/Navigation/types.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index 39b977d99946..1b28de32671a 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -136,7 +136,6 @@ const ReportSettingsModalStackNavigator = createModalStackNavigator({ [SCREENS.TASK.TITLE]: () => require('../../../pages/tasks/TaskTitlePage').default as React.ComponentType, - [SCREENS.TASK.DESCRIPTION]: () => require('../../../pages/tasks/TaskDescriptionPage').default as React.ComponentType, [SCREENS.TASK.ASSIGNEE]: () => require('../../../pages/tasks/TaskAssigneeSelectorModal').default as React.ComponentType, }); diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 7f47b95b3562..ae121c6083c0 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -270,7 +270,6 @@ type TeachersUniteNavigatorParamList = { type TaskDetailsNavigatorParamList = { [SCREENS.TASK.TITLE]: undefined; - [SCREENS.TASK.DESCRIPTION]: undefined; [SCREENS.TASK.ASSIGNEE]: { reportID: string; }; From 87131a3bb3473a1439b6e8595b34f08fe347f5b8 Mon Sep 17 00:00:00 2001 From: someone-here Date: Sat, 20 Jan 2024 00:03:24 +0530 Subject: [PATCH 090/249] Fix permission --- src/libs/ReportUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 7761ab9cdfed..0f87e6e73f5e 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4453,7 +4453,7 @@ function getRoom(type: ValueOf, policyID: string) * We only want policy owners and admins to be able to modify the report description, but not in thread chat. */ function canEditReportDescription(report: OnyxEntry, policy: OnyxEntry): boolean { - return !isMoneyRequestReport(report) && !isArchivedRoom(report) && isChatRoom(report) && !isChatThread(report) && isEmpty(policy); + return !isMoneyRequestReport(report) && !isArchivedRoom(report) && isChatRoom(report) && !isChatThread(report) && !isEmpty(policy); } /** * Checks if report action has error when smart scanning From d078c1051b3b1cf6d77cbea025f4bbffd757e4d6 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Fri, 19 Jan 2024 19:39:12 +0100 Subject: [PATCH 091/249] Update types PART-1 --- src/components/KYCWall/types.ts | 9 +++------ src/components/SettlementButton.tsx | 5 +++-- src/libs/actions/Policy.ts | 7 +++++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/components/KYCWall/types.ts b/src/components/KYCWall/types.ts index aee5b569cc46..2144dc1a878e 100644 --- a/src/components/KYCWall/types.ts +++ b/src/components/KYCWall/types.ts @@ -5,6 +5,8 @@ import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; import type {Route} from '@src/ROUTES'; import type {Report} from '@src/types/onyx'; +import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; +import type {EmptyObject} from '@src/types/utils/EmptyObject'; type Source = ValueOf; @@ -14,11 +16,6 @@ type DOMRectProperties = 'top' | 'bottom' | 'left' | 'right' | 'height' | 'x' | type DomRect = Pick; -type AnchorAlignment = { - horizontal: ValueOf; - vertical: ValueOf; -}; - type AnchorPosition = { anchorPositionVertical: number; anchorPositionHorizontal: number; @@ -49,7 +46,7 @@ type KYCWallProps = { chatReportID?: string; /** The IOU/Expense report we are paying */ - iouReport?: OnyxEntry; + iouReport?: OnyxEntry | EmptyObject; /** Where the popover should be positioned relative to the anchor points. */ anchorAlignment?: AnchorAlignment; diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index 82da026d4014..32dd4ffec7e7 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -12,6 +12,7 @@ import * as PaymentMethods from '@userActions/PaymentMethods'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type {Route} from '@src/ROUTES'; import type {ButtonSizeValue} from '@src/styles/utils/types'; import type {LastPaymentMethod, Report} from '@src/types/onyx'; import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; @@ -72,10 +73,10 @@ type SettlementButtonProps = SettlementButtonOnyxProps & { buttonSize?: ButtonSizeValue; /** Route for the Add Bank Account screen for a given navigation stack */ - addBankAccountRoute?: string; + addBankAccountRoute?: Route; /** Route for the Add Debit Card screen for a given navigation stack */ - addDebitCardRoute?: string; + addDebitCardRoute?: Route; /** Whether the button should be disabled */ isDisabled?: boolean; diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 263d5fb68529..b6e729d3698e 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -22,6 +22,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalDetailsList, Policy, PolicyMember, PolicyTags, RecentlyUsedCategories, RecentlyUsedTags, ReimbursementAccount, Report, ReportAction, Transaction} from '@src/types/onyx'; import type {Errors} from '@src/types/onyx/OnyxCommon'; import type {CustomUnit} from '@src/types/onyx/Policy'; +import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; type AnnounceRoomMembersOnyxData = { @@ -1589,12 +1590,14 @@ function buildOptimisticPolicyRecentlyUsedTags(policyID: string, tag: string): R * * @returns policyID of the workspace we have created */ -function createWorkspaceFromIOUPayment(iouReport: Report): string | undefined { +function createWorkspaceFromIOUPayment(iouReportParam: Report | EmptyObject): string | undefined { // This flow only works for IOU reports - if (!ReportUtils.isIOUReport(iouReport)) { + if (!ReportUtils.isIOUReport(iouReportParam)) { return; } + const iouReport = iouReportParam as Report; + // Generate new variables for the policy const policyID = generatePolicyID(); const workspaceName = generateDefaultWorkspaceName(sessionEmail); From ef7ee749731703376bf2c046e62081ca06a9ebeb Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Sun, 21 Jan 2024 22:49:12 +0300 Subject: [PATCH 092/249] add comment --- src/pages/signin/LoginForm/BaseLoginForm.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/signin/LoginForm/BaseLoginForm.js b/src/pages/signin/LoginForm/BaseLoginForm.js index 5a6c8aed5050..c0f8abee710a 100644 --- a/src/pages/signin/LoginForm/BaseLoginForm.js +++ b/src/pages/signin/LoginForm/BaseLoginForm.js @@ -277,6 +277,8 @@ function LoginForm(props) { id="username" name="username" onBlur={() => + // This delay is to avoid the validate being called before google iframe is rendered to + // avoid error message appearing after pressing google signin button. setTimeout(() => { if (firstBlurred.current || !Visibility.isVisible() || !Visibility.hasFocus()) { return; From 2d7f408065cf2135a9ef7aecccca55dd0d65c69f Mon Sep 17 00:00:00 2001 From: Yauheni Date: Sun, 21 Jan 2024 21:52:18 +0100 Subject: [PATCH 093/249] Update types PART-2 --- src/components/MoneyReportHeader.tsx | 2 -- src/libs/ReportUtils.ts | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index afdc62218f95..88e368a8bbbb 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -127,7 +127,6 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, nextSt {shouldShowSettlementButton && !isSmallScreenWidth && ( ): boolean { * If the report is a policy expense, the route should be for adding bank account for that policy * else since the report is a personal IOU, the route should be for personal bank account. */ -function getBankAccountRoute(report: OnyxEntry): string { +function getBankAccountRoute(report: OnyxEntry): Route { return isPolicyExpenseChat(report) ? ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute('', report?.policyID) : ROUTES.SETTINGS_ADD_BANK_ACCOUNT; } From 44e688c476bae6216f883c85cd1362566edb1e0a Mon Sep 17 00:00:00 2001 From: Yauheni Date: Mon, 22 Jan 2024 10:12:48 +0100 Subject: [PATCH 094/249] Update types PART-3 --- src/components/KYCWall/BaseKYCWall.tsx | 2 +- src/components/KYCWall/types.ts | 4 ++-- src/components/SettlementButton.tsx | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/KYCWall/BaseKYCWall.tsx b/src/components/KYCWall/BaseKYCWall.tsx index 04c8397bc33b..17e00af3b2ce 100644 --- a/src/components/KYCWall/BaseKYCWall.tsx +++ b/src/components/KYCWall/BaseKYCWall.tsx @@ -203,7 +203,7 @@ function KYCWall({ Log.info('[KYC Wallet] User has valid payment method and passed KYC checks or did not need them'); - onSuccessfulKYC(currentSource, iouPaymentType); + onSuccessfulKYC(iouPaymentType, currentSource); }, [ bankAccountList, diff --git a/src/components/KYCWall/types.ts b/src/components/KYCWall/types.ts index 2144dc1a878e..7147f86814fa 100644 --- a/src/components/KYCWall/types.ts +++ b/src/components/KYCWall/types.ts @@ -10,7 +10,7 @@ import type {EmptyObject} from '@src/types/utils/EmptyObject'; type Source = ValueOf; -type TransferMethod = ValueOf; +type TransferMethod = ValueOf; type DOMRectProperties = 'top' | 'bottom' | 'left' | 'right' | 'height' | 'x' | 'y'; @@ -61,7 +61,7 @@ type KYCWallProps = { shouldShowPersonalBankAccountOption?: boolean; /** Callback for the end of the onContinue trigger on option selection */ - onSuccessfulKYC: (currentSource?: Source, iouPaymentType?: TransferMethod) => void; + onSuccessfulKYC: (iouPaymentType?: TransferMethod, currentSource?: Source) => void; /** Children to build the KYC */ children: (continueAction: (event: SyntheticEvent, method: TransferMethod) => void, anchorRef: ForwardedRef) => void; diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index 32dd4ffec7e7..82b9805620cc 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -26,7 +26,7 @@ type KYCFlowEvent = GestureResponderEvent | KeyboardEvent | undefined; type TriggerKYCFlow = (event: KYCFlowEvent, iouPaymentType: string) => void; -type PaymentType = DeepValueOf; +type PaymentType = DeepValueOf; type EnablePaymentsRoute = typeof ROUTES.ENABLE_PAYMENTS | typeof ROUTES.IOU_SEND_ENABLE_PAYMENTS | typeof ROUTES.SETTINGS_ENABLE_PAYMENTS; @@ -37,7 +37,7 @@ type SettlementButtonOnyxProps = { type SettlementButtonProps = SettlementButtonOnyxProps & { /** Callback to execute when this button is pressed. Receives a single payment type argument. */ - onPress: (paymentType: PaymentType) => void; + onPress: (paymentType?: PaymentType) => void; /** The route to redirect if user does not have a payment method setup */ enablePaymentsRoute: EnablePaymentsRoute; From 3fadd8aaff92edff3dbd8ce6194d12e55997bd89 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Mon, 22 Jan 2024 10:50:11 +0100 Subject: [PATCH 095/249] Update types PART-4 --- src/components/KYCWall/BaseKYCWall.tsx | 6 +++--- src/components/KYCWall/types.ts | 10 ++++++---- src/components/SettlementButton.tsx | 10 +++++----- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/components/KYCWall/BaseKYCWall.tsx b/src/components/KYCWall/BaseKYCWall.tsx index 17e00af3b2ce..939b87e22376 100644 --- a/src/components/KYCWall/BaseKYCWall.tsx +++ b/src/components/KYCWall/BaseKYCWall.tsx @@ -1,7 +1,7 @@ import React, {useCallback, useEffect, useRef, useState} from 'react'; import type {SyntheticEvent} from 'react'; import {Dimensions} from 'react-native'; -import type {EmitterSubscription, NativeTouchEvent} from 'react-native'; +import type {EmitterSubscription, GestureResponderEvent, NativeTouchEvent} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import AddPaymentMethodMenu from '@components/AddPaymentMethodMenu'; @@ -146,7 +146,7 @@ function KYCWall({ * */ const continueAction = useCallback( - (event?: SyntheticEvent, iouPaymentType?: TransferMethod) => { + (event?: GestureResponderEvent | KeyboardEvent | SyntheticEvent, iouPaymentType?: TransferMethod) => { const currentSource = walletTerms?.source ?? source; /** @@ -161,7 +161,7 @@ function KYCWall({ } // Use event target as fallback if anchorRef is null for safety - const targetElement = anchorRef.current ?? (event?.nativeEvent.target as HTMLDivElement); + const targetElement = anchorRef.current ?? ((event as SyntheticEvent)?.nativeEvent.target as HTMLDivElement); transferBalanceButtonRef.current = targetElement; diff --git a/src/components/KYCWall/types.ts b/src/components/KYCWall/types.ts index 7147f86814fa..c0b738746985 100644 --- a/src/components/KYCWall/types.ts +++ b/src/components/KYCWall/types.ts @@ -1,16 +1,17 @@ -import type {ForwardedRef, SyntheticEvent} from 'react'; -import type {NativeTouchEvent} from 'react-native'; +import type {ForwardedRef} from 'react'; +import type {GestureResponderEvent} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; import type {Route} from '@src/ROUTES'; import type {Report} from '@src/types/onyx'; import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; +import type DeepValueOf from '@src/types/utils/DeepValueOf'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; type Source = ValueOf; -type TransferMethod = ValueOf; +type TransferMethod = DeepValueOf; type DOMRectProperties = 'top' | 'bottom' | 'left' | 'right' | 'height' | 'x' | 'y'; @@ -64,7 +65,8 @@ type KYCWallProps = { onSuccessfulKYC: (iouPaymentType?: TransferMethod, currentSource?: Source) => void; /** Children to build the KYC */ - children: (continueAction: (event: SyntheticEvent, method: TransferMethod) => void, anchorRef: ForwardedRef) => void; + children: (continueAction: (event?: GestureResponderEvent | KeyboardEvent, method?: TransferMethod) => void, anchorRef: ForwardedRef) => void; + // }; export type {AnchorPosition, KYCWallProps, PaymentMethod, TransferMethod, DomRect}; diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index 82b9805620cc..8124509ec4f3 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -1,4 +1,4 @@ -import type {RefObject} from 'react'; +import type {ForwardedRef, RefObject} from 'react'; import React, {useEffect, useMemo} from 'react'; import type {GestureResponderEvent, StyleProp, View, ViewStyle} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; @@ -24,10 +24,10 @@ import KYCWall from './KYCWall'; type KYCFlowEvent = GestureResponderEvent | KeyboardEvent | undefined; -type TriggerKYCFlow = (event: KYCFlowEvent, iouPaymentType: string) => void; - type PaymentType = DeepValueOf; +type TriggerKYCFlow = (event: KYCFlowEvent, iouPaymentType: PaymentType) => void; + type EnablePaymentsRoute = typeof ROUTES.ENABLE_PAYMENTS | typeof ROUTES.IOU_SEND_ENABLE_PAYMENTS | typeof ROUTES.SETTINGS_ENABLE_PAYMENTS; type SettlementButtonOnyxProps = { @@ -213,9 +213,9 @@ function SettlementButton({ anchorAlignment={kycWallAnchorAlignment} shouldShowPersonalBankAccountOption={shouldShowPersonalBankAccountOption} > - {(triggerKYCFlow: TriggerKYCFlow, buttonRef: RefObject) => ( + {(triggerKYCFlow: TriggerKYCFlow, buttonRef: ForwardedRef) => ( } isDisabled={isDisabled} isLoading={isLoading} onPress={(event: KYCFlowEvent, iouPaymentType: PaymentType) => selectPaymentType(event, iouPaymentType, triggerKYCFlow)} From 907ece0712d4ae652cd6452fea6a10b9193a5778 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Mon, 22 Jan 2024 10:51:35 +0100 Subject: [PATCH 096/249] Update types PART-5 --- src/components/KYCWall/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/KYCWall/types.ts b/src/components/KYCWall/types.ts index c0b738746985..ebf9cd3b0a43 100644 --- a/src/components/KYCWall/types.ts +++ b/src/components/KYCWall/types.ts @@ -65,7 +65,7 @@ type KYCWallProps = { onSuccessfulKYC: (iouPaymentType?: TransferMethod, currentSource?: Source) => void; /** Children to build the KYC */ - children: (continueAction: (event?: GestureResponderEvent | KeyboardEvent, method?: TransferMethod) => void, anchorRef: ForwardedRef) => void; + children: (continueAction: (event?: GestureResponderEvent | KeyboardEvent, method?: TransferMethod) => void, anchorRef: ForwardedRef) => void; // }; From 9cb7f8a41b67877a69fd1a1310962538cdfdeb1f Mon Sep 17 00:00:00 2001 From: Yauheni Date: Mon, 22 Jan 2024 10:52:13 +0100 Subject: [PATCH 097/249] Update types PART-6 --- src/components/KYCWall/types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/KYCWall/types.ts b/src/components/KYCWall/types.ts index ebf9cd3b0a43..d0e5c2e32e2f 100644 --- a/src/components/KYCWall/types.ts +++ b/src/components/KYCWall/types.ts @@ -66,7 +66,6 @@ type KYCWallProps = { /** Children to build the KYC */ children: (continueAction: (event?: GestureResponderEvent | KeyboardEvent, method?: TransferMethod) => void, anchorRef: ForwardedRef) => void; - // }; export type {AnchorPosition, KYCWallProps, PaymentMethod, TransferMethod, DomRect}; From 0b5eccdaf9c92fcbba6734c2da34893049e239aa Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 22 Jan 2024 11:12:43 +0100 Subject: [PATCH 098/249] 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 d7fdf8010bea5f2aa1222b79365d70d57552c29e Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 22 Jan 2024 16:59:38 +0530 Subject: [PATCH 099/249] added full screen loader for better UX --- .../step/IOURequestStepConfirmation.js | 80 +++++++++++-------- 1 file changed, 48 insertions(+), 32 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.js b/src/pages/iou/request/step/IOURequestStepConfirmation.js index 9df2564ae38d..84adf87bbae2 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.js +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.js @@ -5,6 +5,7 @@ import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; import categoryPropTypes from '@components/categoryPropTypes'; +import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; import MoneyRequestConfirmationList from '@components/MoneyTemporaryForRefactorRequestConfirmationList'; @@ -103,6 +104,15 @@ function IOURequestStepConfirmation({ ); const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(report)), [report]); + useEffect(() => { + if (!transaction || !transaction.originalCurrency) { + return; + } + // If user somehow lands on this page without the currency reset, then reset it here. + IOU.setMoneyRequestCurrency_temporaryForRefactor(transactionID, transaction.originalCurrency, true); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + useEffect(() => { const policyExpenseChat = _.find(participants, (participant) => participant.isPolicyExpenseChat); if (policyExpenseChat) { @@ -318,6 +328,8 @@ function IOURequestStepConfirmation({ IOU.setMoneyRequestBillable_temporaryForRefactor(transactionID, billable); }; + const isLoading = !!(transaction && transaction.originalCurrency); + return ( - + {isLoading ? ( + + ) : ( + + )} )} From 74eb19989385ead4d84568062c89b54134e643a1 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 23 Jan 2024 11:35:38 +0100 Subject: [PATCH 100/249] 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 61d6fcf64a5e6eb0a645fcfd4fa16a8b6388ddba Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Wed, 24 Jan 2024 12:08:27 +0100 Subject: [PATCH 101/249] feat: add offline handling for money reports with various currencies --- src/components/MoneyReportHeader.tsx | 3 +++ src/components/ReportActionItem/MoneyReportView.tsx | 3 ++- src/libs/ReportUtils.ts | 13 +++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index afdc62218f95..d072dea34356 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -55,6 +55,7 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, nextSt const reimbursableTotal = ReportUtils.getMoneyRequestReimbursableTotal(moneyRequestReport); const isApproved = ReportUtils.isReportApproved(moneyRequestReport); const isSettled = ReportUtils.isSettled(moneyRequestReport.reportID); + const canAllowSettlement = ReportUtils.hasUpdatedTotal(moneyRequestReport); const policyType = policy?.type; const isPolicyAdmin = policyType !== CONST.POLICY.TYPE.PERSONAL && policy?.role === CONST.POLICY.ROLE.ADMIN; const isPaidGroupPolicy = ReportUtils.isPaidGroupPolicy(moneyRequestReport); @@ -140,6 +141,7 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, nextSt shouldShowApproveButton={shouldShowApproveButton} style={[styles.pv2]} formattedAmount={formattedAmount} + isDisabled={!canAllowSettlement} /> )} @@ -171,6 +173,7 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, nextSt shouldHidePaymentOptions={!shouldShowPayButton} shouldShowApproveButton={shouldShowApproveButton} formattedAmount={formattedAmount} + isDisabled={!canAllowSettlement} /> )} diff --git a/src/components/ReportActionItem/MoneyReportView.tsx b/src/components/ReportActionItem/MoneyReportView.tsx index 3d1710de1432..ecc5ef0df831 100644 --- a/src/components/ReportActionItem/MoneyReportView.tsx +++ b/src/components/ReportActionItem/MoneyReportView.tsx @@ -40,6 +40,7 @@ function MoneyReportView({report, policyReportFields, shouldShowHorizontalRule}: const {isSmallScreenWidth} = useWindowDimensions(); const {canUseReportFields} = usePermissions(); const isSettled = ReportUtils.isSettled(report.reportID); + const isTotalUpdated = ReportUtils.hasUpdatedTotal(report); const {totalDisplaySpend, nonReimbursableSpend, reimbursableSpend} = ReportUtils.getMoneyRequestSpendBreakdown(report); @@ -110,7 +111,7 @@ function MoneyReportView({report, policyReportFields, shouldShowHorizontalRule}: )} {formattedTotalAmount} diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 91fa7b35e824..10b7ce8965dd 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4540,6 +4540,18 @@ function shouldDisplayThreadReplies(reportAction: OnyxEntry, repor return hasReplies && !!reportAction?.childCommenterCount && !isThreadFirstChat(reportAction, reportID); } +/** + * Check if money report has any transactions updated optimistically + */ +function hasUpdatedTotal(report: Report): boolean { + const transactions = TransactionUtils.getAllReportTransactions(report.reportID); + + const hasPendingTransaction = transactions.some((transaction) => !!transaction.pendingAction); + const hasTransactionWithDifferentCurrency = transactions.some((transaction) => transaction.currency !== report.currency); + + return !(hasPendingTransaction && hasTransactionWithDifferentCurrency); +} + /** * Disable reply in thread action if: * @@ -4748,6 +4760,7 @@ export { doesReportBelongToWorkspace, getChildReportNotificationPreference, isReportFieldOfTypeTitle, + hasUpdatedTotal, }; export type { From aa34234694a467d0fbc637052a31960d1f107973 Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Wed, 24 Jan 2024 16:05:50 +0100 Subject: [PATCH 102/249] fix: change the way settlement button on ReportPreview is handled --- src/components/ReportActionItem/ReportPreview.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/ReportActionItem/ReportPreview.js b/src/components/ReportActionItem/ReportPreview.js index 204c9b5e31d4..f6d8ba34a8bc 100644 --- a/src/components/ReportActionItem/ReportPreview.js +++ b/src/components/ReportActionItem/ReportPreview.js @@ -166,6 +166,8 @@ function ReportPreview(props) { const isDraftExpenseReport = isPolicyExpenseChat && ReportUtils.isDraftExpenseReport(props.iouReport); const isApproved = ReportUtils.isReportApproved(props.iouReport); + const canAllowSettlement = ReportUtils.hasUpdatedTotal(props.iouReport); + console.log('%%%%%\n', 'canAllowSettlement: ', canAllowSettlement); const isMoneyRequestReport = ReportUtils.isMoneyRequestReport(props.iouReport); const transactionsWithReceipts = ReportUtils.getTransactionsWithReceipts(props.iouReportID); const numberOfScanningReceipts = _.filter(transactionsWithReceipts, (transaction) => TransactionUtils.isReceiptBeingScanned(transaction)).length; @@ -333,6 +335,7 @@ function ReportPreview(props) { horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT, vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM, }} + isDisabled={!canAllowSettlement} /> )} {shouldShowSubmitButton && ( From 870502329845d9d031137c4968a0609a1037d14b Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Wed, 24 Jan 2024 16:13:20 +0100 Subject: [PATCH 103/249] fix: remove console logs --- src/components/ReportActionItem/ReportPreview.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/ReportActionItem/ReportPreview.js b/src/components/ReportActionItem/ReportPreview.js index f6d8ba34a8bc..52847bf0366b 100644 --- a/src/components/ReportActionItem/ReportPreview.js +++ b/src/components/ReportActionItem/ReportPreview.js @@ -167,7 +167,6 @@ function ReportPreview(props) { const isApproved = ReportUtils.isReportApproved(props.iouReport); const canAllowSettlement = ReportUtils.hasUpdatedTotal(props.iouReport); - console.log('%%%%%\n', 'canAllowSettlement: ', canAllowSettlement); const isMoneyRequestReport = ReportUtils.isMoneyRequestReport(props.iouReport); const transactionsWithReceipts = ReportUtils.getTransactionsWithReceipts(props.iouReportID); const numberOfScanningReceipts = _.filter(transactionsWithReceipts, (transaction) => TransactionUtils.isReceiptBeingScanned(transaction)).length; From e3afca1a5fae2ede960201ac031ff70ec05b7934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Wed, 24 Jan 2024 17:23:50 +0100 Subject: [PATCH 104/249] header fix --- .../MoneyTemporaryForRefactorRequestParticipantsSelector.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js b/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js index 0949081435c4..34048e4dd7bc 100644 --- a/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js +++ b/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js @@ -229,7 +229,7 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({ const headerMessage = useMemo( () => OptionsListUtils.getHeaderMessage( - _.get(newChatOptions, 'personalDetails.length', 0) + _.get(newChatOptions, 'recentReports.length', 0) !== 0, + _.get(newChatOptions, 'personalDetails', []).length + _.get(newChatOptions, 'recentReports', []).length !== 0, Boolean(newChatOptions.userToInvite), searchTerm.trim(), maxParticipantsReached, From 7e7f40335ef2b90bcede320b5680d88965c35df1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Wed, 24 Jan 2024 17:30:01 +0100 Subject: [PATCH 105/249] header fix on second component --- .../MoneyRequestParticipantsSelector.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js index 9567b17ecdf5..12dd2df5c784 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js @@ -249,13 +249,13 @@ function MoneyRequestParticipantsSelector({ const headerMessage = useMemo( () => OptionsListUtils.getHeaderMessage( - newChatOptions.personalDetails.length + newChatOptions.recentReports.length !== 0, + _.get(newChatOptions, 'personalDetails', []).length + _.get(newChatOptions, 'recentReports', []).length !== 0, Boolean(newChatOptions.userToInvite), searchTerm.trim(), maxParticipantsReached, _.some(participants, (participant) => participant.searchText.toLowerCase().includes(searchTerm.trim().toLowerCase())), ), - [maxParticipantsReached, newChatOptions.personalDetails.length, newChatOptions.recentReports.length, newChatOptions.userToInvite, participants, searchTerm], + [maxParticipantsReached, newChatOptions, participants, searchTerm], ); // When search term updates we will fetch any reports From 8e934fabeb192e867f80585c5758b4f4995ad9b1 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Wed, 24 Jan 2024 17:44:05 +0100 Subject: [PATCH 106/249] Update createWorkspaceFromIOUPayment --- src/libs/actions/Policy.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 2c9dbcee371c..ec9cb6d7cae8 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -1612,14 +1612,12 @@ function buildOptimisticPolicyRecentlyUsedTags(policyID: string, tag: string): R * * @returns policyID of the workspace we have created */ -function createWorkspaceFromIOUPayment(iouReportParam: Report | EmptyObject): string | undefined { +function createWorkspaceFromIOUPayment(iouReport: Report | EmptyObject): string | undefined { // This flow only works for IOU reports - if (!ReportUtils.isIOUReport(iouReportParam)) { + if (isEmptyObject(iouReport) || !ReportUtils.isIOUReport(iouReport)) { return; } - const iouReport = iouReportParam as Report; - // Generate new variables for the policy const policyID = generatePolicyID(); const workspaceName = generateDefaultWorkspaceName(sessionEmail); From 41bc02b041f2047db87d055199bf4382cb625903 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 25 Jan 2024 14:46:50 +0700 Subject: [PATCH 107/249] remove MoneyRequestTagPae --- src/ROUTES.ts | 10 +- src/SCREENS.ts | 1 - ...oraryForRefactorRequestConfirmationList.js | 39 +++--- .../ReportActionItem/MoneyRequestView.js | 4 +- .../AppNavigator/ModalStackNavigators.tsx | 1 - src/libs/Navigation/linkingConfig.ts | 1 - src/libs/Navigation/types.ts | 9 +- src/pages/iou/MoneyRequestTagPage.js | 127 ------------------ .../iou/request/step/IOURequestStepTag.js | 15 ++- 9 files changed, 48 insertions(+), 159 deletions(-) delete mode 100644 src/pages/iou/MoneyRequestTagPage.js diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 9c4375b84ab6..eb2c1728d596 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -287,10 +287,6 @@ const ROUTES = { route: ':iouType/new/category/:reportID?', getRoute: (iouType: string, reportID = '') => `${iouType}/new/category/${reportID}` as const, }, - MONEY_REQUEST_TAG: { - route: ':iouType/new/tag/:reportID?', - getRoute: (iouType: string, reportID = '') => `${iouType}/new/tag/${reportID}` as const, - }, MONEY_REQUEST_MERCHANT: { route: ':iouType/new/merchant/:reportID?', getRoute: (iouType: string, reportID = '') => `${iouType}/new/merchant/${reportID}` as const, @@ -374,9 +370,9 @@ const ROUTES = { getUrlWithBackToParam(`${action}/${iouType}/scan/${transactionID}/${reportID}`, backTo), }, MONEY_REQUEST_STEP_TAG: { - route: 'create/:iouType/tag/:transactionID/:reportID', - getRoute: (iouType: ValueOf, transactionID: string, reportID: string, backTo = '') => - getUrlWithBackToParam(`create/${iouType}/tag/${transactionID}/${reportID}`, backTo), + route: ':action/:iouType/tag/:transactionID/:reportID', + getRoute: (action: ValueOf, iouType: ValueOf, transactionID: string, reportID: string, backTo = '') => + getUrlWithBackToParam(`${action}/${iouType}/tag/${transactionID}/${reportID}`, backTo), }, MONEY_REQUEST_STEP_WAYPOINT: { route: ':action/:iouType/waypoint/:transactionID/:reportID/:pageIndex', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 2bf40caede57..ded041b0f5b3 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -146,7 +146,6 @@ const SCREENS = { DATE: 'Money_Request_Date', DESCRIPTION: 'Money_Request_Description', CATEGORY: 'Money_Request_Category', - TAG: 'Money_Request_Tag', MERCHANT: 'Money_Request_Merchant', WAYPOINT: 'Money_Request_Waypoint', EDIT_WAYPOINT: 'Money_Request_Edit_Waypoint', diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js index 2aff0444a59e..bdd3fa98672f 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -810,21 +810,30 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ rightLabel={canUseViolations && Boolean(policy.requiresCategory) ? translate('common.required') : ''} /> )} - {shouldShowTags && ( - - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_TAG.getRoute(iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams())) - } - style={[styles.moneyRequestMenuItem]} - disabled={didConfirm} - interactive={!isReadOnly} - rightLabel={canUseViolations && Boolean(policy.requiresTag) ? translate('common.required') : ''} - /> - )} + {shouldShowTags || + (true && ( + + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_TAG.getRoute( + CONST.IOU.ACTION.CREATE, + iouType, + transaction.transactionID, + reportID, + Navigation.getActiveRouteWithoutParams(), + ), + ) + } + style={[styles.moneyRequestMenuItem]} + disabled={didConfirm} + interactive={!isReadOnly} + rightLabel={canUseViolations && Boolean(policy.requiresTag) ? translate('common.required') : ''} + /> + ))} {shouldShowTax && ( Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.TAG))} + onPress={() => + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_TAG.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.REQUEST, transaction.transactionID, report.reportID)) + } brickRoadIndicator={hasViolations('tag') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} /> {canUseViolations && } diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index c9325206e5b2..b9a3deb5f702 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -98,7 +98,6 @@ const MoneyRequestModalStackNavigator = createModalStackNavigator require('../../../pages/iou/MoneyRequestDatePage').default as React.ComponentType, [SCREENS.MONEY_REQUEST.DESCRIPTION]: () => require('../../../pages/iou/MoneyRequestDescriptionPage').default as React.ComponentType, [SCREENS.MONEY_REQUEST.CATEGORY]: () => require('../../../pages/iou/MoneyRequestCategoryPage').default as React.ComponentType, - [SCREENS.MONEY_REQUEST.TAG]: () => require('../../../pages/iou/MoneyRequestTagPage').default as React.ComponentType, [SCREENS.MONEY_REQUEST.MERCHANT]: () => require('../../../pages/iou/MoneyRequestMerchantPage').default as React.ComponentType, [SCREENS.IOU_SEND.ADD_BANK_ACCOUNT]: () => require('../../../pages/AddPersonalBankAccountPage').default as React.ComponentType, [SCREENS.IOU_SEND.ADD_DEBIT_CARD]: () => require('../../../pages/settings/Wallet/AddDebitCardPage').default as React.ComponentType, diff --git a/src/libs/Navigation/linkingConfig.ts b/src/libs/Navigation/linkingConfig.ts index 5df2bcf0e57b..6f184168b9f1 100644 --- a/src/libs/Navigation/linkingConfig.ts +++ b/src/libs/Navigation/linkingConfig.ts @@ -433,7 +433,6 @@ const linkingConfig: LinkingOptions = { [SCREENS.MONEY_REQUEST.CURRENCY]: ROUTES.MONEY_REQUEST_CURRENCY.route, [SCREENS.MONEY_REQUEST.DESCRIPTION]: ROUTES.MONEY_REQUEST_DESCRIPTION.route, [SCREENS.MONEY_REQUEST.CATEGORY]: ROUTES.MONEY_REQUEST_CATEGORY.route, - [SCREENS.MONEY_REQUEST.TAG]: ROUTES.MONEY_REQUEST_TAG.route, [SCREENS.MONEY_REQUEST.MERCHANT]: ROUTES.MONEY_REQUEST_MERCHANT.route, [SCREENS.MONEY_REQUEST.RECEIPT]: ROUTES.MONEY_REQUEST_RECEIPT.route, [SCREENS.MONEY_REQUEST.DISTANCE]: ROUTES.MONEY_REQUEST_DISTANCE.route, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 2371c764f42a..60bc0b54e41e 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -211,12 +211,15 @@ type MoneyRequestNavigatorParamList = { iouType: string; reportID: string; }; - [SCREENS.MONEY_REQUEST.TAG]: { + [SCREENS.MONEY_REQUEST.STEP_TAX_AMOUNT]: { iouType: string; + transactionID: string; reportID: string; + backTo: string; }; - [SCREENS.MONEY_REQUEST.STEP_TAX_AMOUNT]: { - iouType: string; + [SCREENS.MONEY_REQUEST.STEP_TAG]: { + action: ValueOf; + iouType: ValueOf; transactionID: string; reportID: string; backTo: string; diff --git a/src/pages/iou/MoneyRequestTagPage.js b/src/pages/iou/MoneyRequestTagPage.js deleted file mode 100644 index 60e40d665580..000000000000 --- a/src/pages/iou/MoneyRequestTagPage.js +++ /dev/null @@ -1,127 +0,0 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import React from 'react'; -import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import ScreenWrapper from '@components/ScreenWrapper'; -import TagPicker from '@components/TagPicker'; -import tagPropTypes from '@components/tagPropTypes'; -import Text from '@components/Text'; -import useLocalize from '@hooks/useLocalize'; -import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; -import Navigation from '@libs/Navigation/Navigation'; -import * as PolicyUtils from '@libs/PolicyUtils'; -import reportPropTypes from '@pages/reportPropTypes'; -import * as IOU from '@userActions/IOU'; -import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; -import {iouDefaultProps, iouPropTypes} from './propTypes'; - -const propTypes = { - /** Navigation route context info provided by react navigation */ - route: PropTypes.shape({ - /** Route specific parameters used on this screen via route :iouType/new/tag/:reportID? */ - params: PropTypes.shape({ - /** The type of IOU report, i.e. bill, request, send */ - iouType: PropTypes.string, - - /** The report ID of the IOU */ - reportID: PropTypes.string, - }), - }).isRequired, - - /* Onyx props */ - /** The report currently being used */ - report: reportPropTypes, - - /** Collection of tags attached to a policy */ - policyTags: tagPropTypes, - - /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ - iou: iouPropTypes, -}; - -const defaultProps = { - report: {}, - policyTags: {}, - iou: iouDefaultProps, -}; - -function MoneyRequestTagPage({route, report, policyTags, iou}) { - const styles = useThemeStyles(); - const {translate} = useLocalize(); - - const iouType = lodashGet(route, 'params.iouType', ''); - - // Fetches the first tag list of the policy - const tagListKey = _.first(_.keys(policyTags)); - const policyTagListName = PolicyUtils.getTagListName(policyTags) || translate('common.tag'); - - const navigateBack = () => { - Navigation.goBack(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report.reportID)); - }; - - const updateTag = (selectedTag) => { - if (selectedTag.searchText === iou.tag) { - IOU.resetMoneyRequestTag(); - } else { - IOU.setMoneyRequestTag(selectedTag.searchText); - } - navigateBack(); - }; - - return ( - - {({insets}) => ( - <> - - {translate('iou.tagSelection', {tagName: policyTagListName})} - - - )} - - ); -} - -MoneyRequestTagPage.displayName = 'MoneyRequestTagPage'; -MoneyRequestTagPage.propTypes = propTypes; -MoneyRequestTagPage.defaultProps = defaultProps; - -export default compose( - withOnyx({ - iou: { - key: ONYXKEYS.IOU, - }, - }), - // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file - withOnyx({ - report: { - key: ({route, iou}) => { - const reportID = IOU.getIOUReportID(iou, route); - - return `${ONYXKEYS.COLLECTION.REPORT}${reportID}`; - }, - }, - }), - // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file - withOnyx({ - policyTags: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, - }, - }), -)(MoneyRequestTagPage); diff --git a/src/pages/iou/request/step/IOURequestStepTag.js b/src/pages/iou/request/step/IOURequestStepTag.js index 7e2ccbe1a9dd..51bda8e232ce 100644 --- a/src/pages/iou/request/step/IOURequestStepTag.js +++ b/src/pages/iou/request/step/IOURequestStepTag.js @@ -12,6 +12,7 @@ import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; import reportPropTypes from '@pages/reportPropTypes'; import * as IOU from '@userActions/IOU'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import IOURequestStepRoutePropTypes from './IOURequestStepRoutePropTypes'; @@ -44,7 +45,7 @@ function IOURequestStepTag({ policyTags, report, route: { - params: {transactionID, backTo}, + params: {action, transactionID, backTo}, }, transaction: {tag}, }) { @@ -54,6 +55,7 @@ function IOURequestStepTag({ // Fetches the first tag list of the policy const tagListKey = _.first(_.keys(policyTags)); const policyTagListName = PolicyUtils.getTagListName(policyTags) || translate('common.tag'); + const isEditting = action === CONST.IOU.ACTION.EDIT; const navigateBack = () => { Navigation.goBack(backTo || ROUTES.HOME); @@ -64,10 +66,17 @@ function IOURequestStepTag({ * @param {String} selectedTag.searchText */ const updateTag = (selectedTag) => { - if (selectedTag.searchText === tag) { + const isSelectedTag = selectedTag.searchText === tag; + const updatedTag = !isSelectedTag ? selectedTag.searchText : ''; + if (isEditting) { + IOU.updateMoneyRequestTag(transactionID, report.reportID, updatedTag); + Navigation.dismissModal(); + return; + } + if (isSelectedTag) { IOU.resetMoneyRequestTag_temporaryForRefactor(transactionID); } else { - IOU.setMoneyRequestTag_temporaryForRefactor(transactionID, selectedTag.searchText); + IOU.setMoneyRequestTag_temporaryForRefactor(transactionID, updatedTag); } navigateBack(); }; From 9e4975c5b9d1666803728db3f6ca66b704f183ed Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 25 Jan 2024 16:39:54 +0700 Subject: [PATCH 108/249] add feature for native --- .../EmojiPicker/EmojiPickerMenu/index.js | 14 +++++++++++++- .../EmojiPicker/EmojiPickerMenu/index.native.js | 5 ++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js index c8ca9c6ac6d1..f6524fbe9d70 100755 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js @@ -370,7 +370,19 @@ function EmojiPickerMenu({forwardedRef, onEmojiSelected, activeEmoji}) { /> ); }, - [preferredSkinTone, highlightedIndex, isUsingKeyboardMovement, highlightFirstEmoji, singleExecution, translate, onEmojiSelected, isSmallScreenWidth, windowWidth, styles, activeEmoji], + [ + preferredSkinTone, + highlightedIndex, + isUsingKeyboardMovement, + highlightFirstEmoji, + singleExecution, + translate, + onEmojiSelected, + isSmallScreenWidth, + windowWidth, + styles, + activeEmoji, + ], ); return ( diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.native.js b/src/components/EmojiPicker/EmojiPickerMenu/index.native.js index 1463ce736699..02a71aec879e 100644 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.native.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.native.js @@ -10,6 +10,7 @@ import useSingleExecution from '@hooks/useSingleExecution'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; +import * as EmojiUtils from '@libs/EmojiUtils'; import CONST from '@src/CONST'; import BaseEmojiPickerMenu from './BaseEmojiPickerMenu'; import emojiPickerMenuPropTypes from './emojiPickerMenuPropTypes'; @@ -17,7 +18,7 @@ import useEmojiPickerMenu from './useEmojiPickerMenu'; const propTypes = emojiPickerMenuPropTypes; -function EmojiPickerMenu({onEmojiSelected}) { +function EmojiPickerMenu({onEmojiSelected, activeEmoji}) { const styles = useThemeStyles(); const {windowWidth, isSmallScreenWidth} = useWindowDimensions(); const {translate} = useLocalize(); @@ -94,11 +95,13 @@ function EmojiPickerMenu({onEmojiSelected}) { } const emojiCode = types && types[preferredSkinTone] ? types[preferredSkinTone] : code; + const shouldEmojiBeHighlighted = activeEmoji && EmojiUtils.getRemovedSkinToneEmoji(emojiCode) === EmojiUtils.getRemovedSkinToneEmoji(activeEmoji); return ( onEmojiSelected(emoji, item))} emoji={emojiCode} + isHighlighted={shouldEmojiBeHighlighted} /> ); }, From 3fe1ab1e529e51404150af875b33af457ba63bf7 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 25 Jan 2024 16:44:49 +0700 Subject: [PATCH 109/249] linting --- src/components/EmojiPicker/EmojiPickerMenu/index.native.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.native.js b/src/components/EmojiPicker/EmojiPickerMenu/index.native.js index 02a71aec879e..bfe52220ee3a 100644 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.native.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.native.js @@ -105,7 +105,7 @@ function EmojiPickerMenu({onEmojiSelected, activeEmoji}) { /> ); }, - [styles, windowWidth, preferredSkinTone, singleExecution, onEmojiSelected, translate], + [styles, windowWidth, preferredSkinTone, singleExecution, onEmojiSelected, translate, activeEmoji], ); return ( From 9645db7ef36b28137989ad01d8c8ba92ba9b9100 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 25 Jan 2024 17:30:31 +0700 Subject: [PATCH 110/249] wrap activeEmoji check with boolean --- src/components/EmojiPicker/EmojiPickerMenu/index.js | 2 +- src/components/EmojiPicker/EmojiPickerMenu/index.native.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js index f6524fbe9d70..3da605a47a55 100755 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js @@ -346,7 +346,7 @@ function EmojiPickerMenu({forwardedRef, onEmojiSelected, activeEmoji}) { const isEmojiFocused = index === highlightedIndex && isUsingKeyboardMovement; const shouldEmojiBeHighlighted = - (index === highlightedIndex && highlightFirstEmoji) || (activeEmoji && EmojiUtils.getRemovedSkinToneEmoji(emojiCode) === EmojiUtils.getRemovedSkinToneEmoji(activeEmoji)); + (index === highlightedIndex && highlightFirstEmoji) || (Boolean(activeEmoji) && EmojiUtils.getRemovedSkinToneEmoji(emojiCode) === EmojiUtils.getRemovedSkinToneEmoji(activeEmoji)); return ( Date: Thu, 25 Jan 2024 19:58:41 +0700 Subject: [PATCH 111/249] prettier --- src/components/EmojiPicker/EmojiPickerMenu/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js index 3da605a47a55..d2ff55a22b2f 100755 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js @@ -346,7 +346,8 @@ function EmojiPickerMenu({forwardedRef, onEmojiSelected, activeEmoji}) { const isEmojiFocused = index === highlightedIndex && isUsingKeyboardMovement; const shouldEmojiBeHighlighted = - (index === highlightedIndex && highlightFirstEmoji) || (Boolean(activeEmoji) && EmojiUtils.getRemovedSkinToneEmoji(emojiCode) === EmojiUtils.getRemovedSkinToneEmoji(activeEmoji)); + (index === highlightedIndex && highlightFirstEmoji) || + (Boolean(activeEmoji) && EmojiUtils.getRemovedSkinToneEmoji(emojiCode) === EmojiUtils.getRemovedSkinToneEmoji(activeEmoji)); return ( Date: Thu, 25 Jan 2024 16:38:41 +0100 Subject: [PATCH 112/249] Fix ts issue --- src/components/ThreeDotsMenu/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ThreeDotsMenu/index.tsx b/src/components/ThreeDotsMenu/index.tsx index 920b8f9f4130..e087456943ce 100644 --- a/src/components/ThreeDotsMenu/index.tsx +++ b/src/components/ThreeDotsMenu/index.tsx @@ -3,7 +3,6 @@ import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; -import type {AnchorAlignment} from '@components/Popover/types'; import type {PopoverMenuItem} from '@components/PopoverMenu'; import PopoverMenu from '@components/PopoverMenu'; import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; @@ -15,6 +14,7 @@ import * as Browser from '@libs/Browser'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import type {AnchorPosition} from '@src/styles'; +import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; import type IconAsset from '@src/types/utils/IconAsset'; type ThreeDotsMenuProps = { From 48748d1cbc18d1024f92b1f36866a1d583b40563 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Thu, 25 Jan 2024 18:29:08 +0100 Subject: [PATCH 113/249] Fix comments --- src/components/SettlementButton.tsx | 6 +++--- src/libs/ReportUtils.ts | 9 ++++++++- src/libs/actions/Policy.ts | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index 8124509ec4f3..7a2a94aff301 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -1,4 +1,4 @@ -import type {ForwardedRef, RefObject} from 'react'; +import type {RefObject} from 'react'; import React, {useEffect, useMemo} from 'react'; import type {GestureResponderEvent, StyleProp, View, ViewStyle} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; @@ -213,12 +213,12 @@ function SettlementButton({ anchorAlignment={kycWallAnchorAlignment} shouldShowPersonalBankAccountOption={shouldShowPersonalBankAccountOption} > - {(triggerKYCFlow: TriggerKYCFlow, buttonRef: ForwardedRef) => ( + {(triggerKYCFlow, buttonRef) => ( } isDisabled={isDisabled} isLoading={isLoading} - onPress={(event: KYCFlowEvent, iouPaymentType: PaymentType) => selectPaymentType(event, iouPaymentType, triggerKYCFlow)} + onPress={(event, iouPaymentType) => selectPaymentType(event, iouPaymentType, triggerKYCFlow)} pressOnEnter={pressOnEnter} options={paymentButtonOptions} style={style} diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 91a558e7ce4e..264cf665f599 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -604,13 +604,19 @@ function isExpenseReport(report: OnyxEntry | EmptyObject): boolean { } /** - * Checks if a report is an IOU report. + * Checks if a report is an IOU report using report or reportID */ function isIOUReport(reportOrID: OnyxEntry | string | EmptyObject): boolean { const report = typeof reportOrID === 'string' ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID; return report?.type === CONST.REPORT.TYPE.IOU; } +/** + * Checks if a report is an IOU report using report + */ +function isIOUReportUsingReport(report: OnyxEntry | EmptyObject): report is Report { + return report?.type === CONST.REPORT.TYPE.IOU; +} /** * Checks if a report is a task report. */ @@ -4812,6 +4818,7 @@ export { doesReportBelongToWorkspace, getChildReportNotificationPreference, isReportFieldOfTypeTitle, + isIOUReportUsingReport, }; export type { diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 86282312bed4..f00b0774d881 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -1615,7 +1615,7 @@ function buildOptimisticPolicyRecentlyUsedTags(policyID: string, tag: string): R */ function createWorkspaceFromIOUPayment(iouReport: Report | EmptyObject): string | undefined { // This flow only works for IOU reports - if (isEmptyObject(iouReport) || !ReportUtils.isIOUReport(iouReport)) { + if (!ReportUtils.isIOUReportUsingReport(iouReport)) { return; } From ee81374361e67c1d1c4e7b59aad5792da5d9d507 Mon Sep 17 00:00:00 2001 From: caitlinwhite1 Date: Thu, 25 Jan 2024 14:46:19 -0600 Subject: [PATCH 114/249] Delete docs/articles/expensify-classic/getting-started/Individual-Users.md moving to "Create a Workspace for Yourself" --- .../getting-started/Individual-Users.md | 43 ------------------- 1 file changed, 43 deletions(-) delete mode 100644 docs/articles/expensify-classic/getting-started/Individual-Users.md diff --git a/docs/articles/expensify-classic/getting-started/Individual-Users.md b/docs/articles/expensify-classic/getting-started/Individual-Users.md deleted file mode 100644 index 12029f80388b..000000000000 --- a/docs/articles/expensify-classic/getting-started/Individual-Users.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: Individual Users -description: Learn how Expensify can help you track and submit your personal or self-employed business expenses. ---- -# Overview -If you're an individual using Expensify, the Track and Submit plans are designed to assist self-employed users in effectively managing both their personal and business finances. - -# How to use the Track plan - -The Track plan is tailored for solo Expensify users who don't require expense submission to others. Individuals or sole proprietors can choose the Track plan to customize their Individual Workspace to align with their personal expense tracking requirements. - -You can select the Track plan from the Workspace settings. Navigate to **Settings > Workspace > Individual > *[Workspace Name]* > Plan** to select Track. -You can also do this from the Pricing page at https://www.expensify.com/pricing. - -The Track plan includes a predefined set of categories designed to align with IRS Schedule C expense categories. However, you have the flexibility to add extra categories as needed. For a more detailed breakdown, you can also set up tags to create another layer of coding. - -The Track plan offers 25 free SmartScans per month. If you require more than 25 SmartScans, you can upgrade to a Monthly Individual subscription at a cost of $4.99 USD per month. - -# How to use the Submit plan -The Submit plan is designed for individuals who need to keep track of their expenses and share them with someone else, such as their boss, accountant, or even a housemate. It's specifically tailored for single users who want to both track and submit their expenses efficiently. - -You can select the Track plan from the Workspace settings. Navigate to **Settings > Workspaces > Individual > *[Workspace Name]* > Plan** to select "Submit" or from the Pricing page at https://www.expensify.com/pricing. - -You will select who your expenses get sent to under **Settings > Workspace > Individual > *[Workspace Name]* > Reports**. If the recipient already has an Expensify account, they'll be able to see the report directly in the Expensify app. Otherwise, non-Expensify users will receive a PDF copy of the report attached to the email so it can be processed. - -The Submit plan includes a predefined set of categories designed to align with IRS Schedule C expense categories. However, you have the flexibility to add extra categories as needed. For a more detailed breakdown, you can also set up tags to create another layer of coding. - -The Submit plan offers 25 free SmartScans per month.If you require more than 25 SmartScans, you can upgrade to a Monthly Individual subscription at a cost of $4.99 USD per month. - -# FAQ - -## Who should use the Track plan? -An individual who wants to store receipts, look to track spending by category to help with budgeting and a self-employed user who needs to track receipts and mileage for tax purposes. - -## Who should use the Submit plan? -An individual who seeks to utilize the features of the track plan to monitor their expenses while also requiring the ability to submit those expenses to someone else. - -## How can I keep track of personal and business expenses in the same account? -You have the capability to create distinct "business" and "personal" tags and assign them to your expenses for proper categorization. By doing so, you can effectively code your expenses based on their nature. Additionally, you can utilize filters to ensure that you only view the expenses that are relevant to your specific needs, whether they are business-related or personal. - -## How can I export expenses for tax purposes? -From the expense page, you have the option to select all of your expenses and export them to a CSV (Comma-Separated Values) file. This CSV file can be conveniently imported directly into your tax software for easier tax preparation. - From 356571da6ff339527b3231e3b4fdfbadea139b49 Mon Sep 17 00:00:00 2001 From: someone-here Date: Fri, 26 Jan 2024 10:55:14 +0530 Subject: [PATCH 115/249] Fix conflict --- src/libs/ReportUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 0945225372e4..f31f1e8ab1ac 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2552,7 +2552,7 @@ function getReportDescriptionText(report: Report): string { return parser.htmlToText(report.description); } -function buildOptimisticAddCommentReportAction(text?: string, file?: File): OptimisticReportAction { +function buildOptimisticAddCommentReportAction(text?: string, file?: File, actorAccountID?: number): OptimisticReportAction { const parser = new ExpensiMark(); const commentText = getParsedComment(text ?? ''); const isAttachment = !text && file !== undefined; From 39dd76bb7356db248d6d6660fb335f7e8618ab53 Mon Sep 17 00:00:00 2001 From: someone-here Date: Fri, 26 Jan 2024 11:58:21 +0530 Subject: [PATCH 116/249] Migrate TS --- src/libs/ReportUtils.ts | 2 +- src/libs/updateMultilineInputRange/types.ts | 3 +- ...riptionPage.js => RoomDescriptionPage.tsx} | 80 +++++++------------ .../home/report/withReportOrNotFound.tsx | 4 + 4 files changed, 35 insertions(+), 54 deletions(-) rename src/pages/{RoomDescriptionPage.js => RoomDescriptionPage.tsx} (59%) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index f31f1e8ab1ac..bca7cbe4e445 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4507,7 +4507,7 @@ function getRoom(type: ValueOf, policyID: string) /** * We only want policy owners and admins to be able to modify the report description, but not in thread chat. */ -function canEditReportDescription(report: OnyxEntry, policy: OnyxEntry): boolean { +function canEditReportDescription(report: OnyxEntry, policy: OnyxEntry | undefined | null): boolean { return !isMoneyRequestReport(report) && !isArchivedRoom(report) && isChatRoom(report) && !isChatThread(report) && !isEmpty(policy); } /** diff --git a/src/libs/updateMultilineInputRange/types.ts b/src/libs/updateMultilineInputRange/types.ts index ce8f553c51f8..3646c64e4845 100644 --- a/src/libs/updateMultilineInputRange/types.ts +++ b/src/libs/updateMultilineInputRange/types.ts @@ -1,5 +1,6 @@ import type {TextInput} from 'react-native'; +import type {BaseTextInputRef} from '@components/TextInput/BaseTextInput/types'; -type UpdateMultilineInputRange = (input: HTMLInputElement | TextInput | null, shouldAutoFocus?: boolean) => void; +type UpdateMultilineInputRange = (input: HTMLInputElement | BaseTextInputRef | TextInput | null, shouldAutoFocus?: boolean) => void; export default UpdateMultilineInputRange; diff --git a/src/pages/RoomDescriptionPage.js b/src/pages/RoomDescriptionPage.tsx similarity index 59% rename from src/pages/RoomDescriptionPage.js rename to src/pages/RoomDescriptionPage.tsx index f7c6e621454b..22864334777c 100644 --- a/src/pages/RoomDescriptionPage.js +++ b/src/pages/RoomDescriptionPage.tsx @@ -1,9 +1,8 @@ import {useFocusEffect} from '@react-navigation/native'; import ExpensiMark from 'expensify-common/lib/ExpensiMark'; -import PropTypes from 'prop-types'; import React, {useCallback, useRef, useState} from 'react'; import {View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; +import type {OnyxCollection} from 'react-native-onyx'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; @@ -11,9 +10,9 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; import TextInput from '@components/TextInput'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; +import type {BaseTextInputRef} from '@components/TextInput/BaseTextInput/types'; +import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import updateMultilineInputRange from '@libs/updateMultilineInputRange'; @@ -21,51 +20,38 @@ import * as Report from '@userActions/Report'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type * as OnyxTypes from '@src/types/onyx'; import withReportOrNotFound from './home/report/withReportOrNotFound'; -import reportPropTypes from './reportPropTypes'; -import {policyDefaultProps, policyPropTypes} from './workspace/withPolicy'; -const propTypes = { - ...withLocalizePropTypes, - ...policyPropTypes, +type RoomDescriptionPageProps = { + /** Policy for the current report */ + policies: OnyxCollection; /** The report currently being looked at */ - report: reportPropTypes.isRequired, - - /** Route params */ - route: PropTypes.shape({ - params: PropTypes.shape({ - /** Report ID passed via route r/:reportID/roomDescription */ - reportID: PropTypes.string, - }), - }).isRequired, -}; - -const defaultProps = { - ...policyDefaultProps, + report: OnyxTypes.Report; }; -function RoomDescriptionPage(props) { +function RoomDescriptionPage({report, policies}: RoomDescriptionPageProps) { const styles = useThemeStyles(); const parser = new ExpensiMark(); - const [description, setdescription] = useState(() => parser.htmlToMarkdown(props.report.description)); - const reportDescriptionInputRef = useRef(null); - const focusTimeoutRef = useRef(null); + const [description, setdescription] = useState(() => parser.htmlToMarkdown(report?.description ?? '')); + const reportDescriptionInputRef = useRef(null); + const focusTimeoutRef = useRef | null>(null); + const {translate} = useLocalize(); + const policy = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`]; - const handleReportDescriptionChange = useCallback((value) => { + const handleReportDescriptionChange = useCallback((value: string) => { setdescription(value); }, []); const submitForm = useCallback(() => { - Report.updateDescription(props.report.reportID, props.report.description, description.trim()); - }, [props.report.reportID, props.report.description, description]); + Report.updateDescription(report.reportID, report?.description ?? '', description.trim()); + }, [report.reportID, report.description, description]); useFocusEffect( useCallback(() => { focusTimeoutRef.current = setTimeout(() => { - if (reportDescriptionInputRef.current) { - reportDescriptionInputRef.current.focus(); - } + reportDescriptionInputRef.current?.focus(); return () => { if (!focusTimeoutRef.current) { return; @@ -82,34 +68,34 @@ function RoomDescriptionPage(props) { includeSafeAreaPaddingBottom={false} testID={RoomDescriptionPage.displayName} > - + Navigation.goBack(ROUTES.REPORT_SETTINGS.getRoute(props.report.reportID))} + title={translate('reportDescriptionPage.roomDescription')} + onBackButtonPress={() => Navigation.goBack(ROUTES.REPORT_SETTINGS.getRoute(report.reportID))} /> - {props.translate('reportDescriptionPage.explainerText')} + {translate('reportDescriptionPage.explainerText')} { + ref={(el: BaseTextInputRef | null): void => { if (!el) { return; } reportDescriptionInputRef.current = el; - updateMultilineInputRange(reportDescriptionInputRef.current); + updateMultilineInputRange(el); }} value={description} onChangeText={handleReportDescriptionChange} @@ -124,15 +110,5 @@ function RoomDescriptionPage(props) { } RoomDescriptionPage.displayName = 'RoomDescriptionPage'; -RoomDescriptionPage.propTypes = propTypes; -RoomDescriptionPage.defaultProps = defaultProps; -export default compose( - withLocalize, - withReportOrNotFound(), - withOnyx({ - policy: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, - }, - }), -)(RoomDescriptionPage); +export default withReportOrNotFound()(RoomDescriptionPage); diff --git a/src/pages/home/report/withReportOrNotFound.tsx b/src/pages/home/report/withReportOrNotFound.tsx index 7613bafeacdc..8476482f8067 100644 --- a/src/pages/home/report/withReportOrNotFound.tsx +++ b/src/pages/home/report/withReportOrNotFound.tsx @@ -23,7 +23,11 @@ type OnyxProps = { }; type ComponentProps = OnyxProps & { + /** Route params */ route: RouteProp<{params: {reportID: string}}>; + + /** The report currently being looked at */ + report: OnyxTypes.Report; }; export default function ( From 7c313591e39c9f45a340da91f751d5f6b919a82f Mon Sep 17 00:00:00 2001 From: someone-here Date: Fri, 26 Jan 2024 12:09:53 +0530 Subject: [PATCH 117/249] Fix TS --- ...ptionPage.js => ReportDescriptionPage.tsx} | 22 +++++++++---------- src/pages/RoomDescriptionPage.tsx | 3 +-- .../home/report/ReportActionItemCreated.tsx | 3 ++- 3 files changed, 13 insertions(+), 15 deletions(-) rename src/pages/{ReportDescriptionPage.js => ReportDescriptionPage.tsx} (64%) diff --git a/src/pages/ReportDescriptionPage.js b/src/pages/ReportDescriptionPage.tsx similarity index 64% rename from src/pages/ReportDescriptionPage.js rename to src/pages/ReportDescriptionPage.tsx index 9b9680e1e81d..3ccabf30c1b7 100644 --- a/src/pages/ReportDescriptionPage.js +++ b/src/pages/ReportDescriptionPage.tsx @@ -1,25 +1,24 @@ -import PropTypes from 'prop-types'; +import type {RouteProp} from '@react-navigation/native'; import React from 'react'; +import type {OnyxCollection} from 'react-native-onyx'; import * as ReportUtils from '@libs/ReportUtils'; +import type * as OnyxTypes from '@src/types/onyx'; import withReportOrNotFound from './home/report/withReportOrNotFound'; -import reportPropTypes from './reportPropTypes'; import RoomDescriptionPage from './RoomDescriptionPage'; import TaskDescriptionPage from './tasks/TaskDescriptionPage'; -const propTypes = { +type ReportDescriptionPageProps = { /** The report currently being looked at */ - report: reportPropTypes.isRequired, + report: OnyxTypes.Report; + + /** Policy for the current report */ + policies: OnyxCollection; /** Route params */ - route: PropTypes.shape({ - params: PropTypes.shape({ - /** Report ID passed via route r/:reportID/roomDescription */ - reportID: PropTypes.string, - }), - }).isRequired, + route: RouteProp<{params: {reportID: string}}>; }; -function ReportDescriptionPage(props) { +function ReportDescriptionPage(props: ReportDescriptionPageProps) { const isTask = ReportUtils.isTaskReport(props.report); if (isTask) { @@ -32,6 +31,5 @@ function ReportDescriptionPage(props) { } ReportDescriptionPage.displayName = 'ReportDescriptionPage'; -ReportDescriptionPage.propTypes = propTypes; export default withReportOrNotFound()(ReportDescriptionPage); diff --git a/src/pages/RoomDescriptionPage.tsx b/src/pages/RoomDescriptionPage.tsx index 22864334777c..57d5302939ed 100644 --- a/src/pages/RoomDescriptionPage.tsx +++ b/src/pages/RoomDescriptionPage.tsx @@ -21,7 +21,6 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; -import withReportOrNotFound from './home/report/withReportOrNotFound'; type RoomDescriptionPageProps = { /** Policy for the current report */ @@ -111,4 +110,4 @@ function RoomDescriptionPage({report, policies}: RoomDescriptionPageProps) { RoomDescriptionPage.displayName = 'RoomDescriptionPage'; -export default withReportOrNotFound()(RoomDescriptionPage); +export default RoomDescriptionPage; diff --git a/src/pages/home/report/ReportActionItemCreated.tsx b/src/pages/home/report/ReportActionItemCreated.tsx index 82c6bebd9ba1..48ded284f7df 100644 --- a/src/pages/home/report/ReportActionItemCreated.tsx +++ b/src/pages/home/report/ReportActionItemCreated.tsx @@ -115,6 +115,7 @@ export default withOnyx Date: Fri, 26 Jan 2024 12:10:48 +0100 Subject: [PATCH 118/249] limit gyroscope animation and add reduce motion --- src/CONST.ts | 2 ++ src/libs/Accessibility/index.ts | 10 ++++++++++ src/libs/NumberUtils.ts | 14 +------------- .../home/report/AnimatedEmptyStateBackground.tsx | 13 +++++++------ 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index ff3934c31943..f4a66b8fe1ba 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -46,6 +46,8 @@ const CONST = { IN: 'in', OUT: 'out', }, + // Multiplier for gyroscope animation in order to make it a bit more subtle + ANIMATION_GYROSCOPE_VALUE: 0.65, ARROW_HIDE_DELAY: 3000, API_ATTACHMENT_VALIDATIONS: { diff --git a/src/libs/Accessibility/index.ts b/src/libs/Accessibility/index.ts index 167634acce56..e98b15948023 100644 --- a/src/libs/Accessibility/index.ts +++ b/src/libs/Accessibility/index.ts @@ -18,6 +18,15 @@ const useScreenReaderStatus = (): boolean => { return isScreenReaderEnabled; }; +const useReduceMotionStatus = (): boolean => { + const [isScreenReaderEnabled, setIsScreenReaderEnabled] = useState(false); + useEffect(() => { + AccessibilityInfo.isReduceMotionEnabled().then(enabled => setIsScreenReaderEnabled(enabled)) + }, []); + + return isScreenReaderEnabled; +}; + const getHitSlopForSize = ({x, y}: HitSlop) => { /* according to https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/adaptivity-and-layout/ the minimum tappable area is 44x44 points */ @@ -49,5 +58,6 @@ const useAutoHitSlop = () => { export default { moveAccessibilityFocus, useScreenReaderStatus, + useReduceMotionStatus, useAutoHitSlop, }; diff --git a/src/libs/NumberUtils.ts b/src/libs/NumberUtils.ts index ddbd42243758..d7eb87a2ed1e 100644 --- a/src/libs/NumberUtils.ts +++ b/src/libs/NumberUtils.ts @@ -47,18 +47,6 @@ function generateHexadecimalValue(num: number): string { return result.join('').toUpperCase(); } -/** - * Clamp a number in a range. - * This is a worklet so it should be used only from UI thread. - - * @returns clamped value between min and max - */ -function clampWorklet(num: number, min: number, max: number): number { - 'worklet'; - - return Math.min(Math.max(num, min), max); -} - /** * Generates a random integer between a and b * It's and equivalent of _.random(a, b) @@ -81,4 +69,4 @@ function parseFloatAnyLocale(value: string): number { return parseFloat(value ? value.replace(',', '.') : value); } -export {rand64, generateHexadecimalValue, generateRandomInt, clampWorklet, parseFloatAnyLocale}; +export {rand64, generateHexadecimalValue, generateRandomInt, parseFloatAnyLocale}; diff --git a/src/pages/home/report/AnimatedEmptyStateBackground.tsx b/src/pages/home/report/AnimatedEmptyStateBackground.tsx index 7e259b7473cf..47edab5457d3 100644 --- a/src/pages/home/report/AnimatedEmptyStateBackground.tsx +++ b/src/pages/home/report/AnimatedEmptyStateBackground.tsx @@ -1,9 +1,9 @@ import React from 'react'; -import Animated, {SensorType, useAnimatedSensor, useAnimatedStyle, useSharedValue, withSpring} from 'react-native-reanimated'; +import Animated, {clamp, SensorType, useAnimatedSensor, useAnimatedStyle, useSharedValue, withSpring} from 'react-native-reanimated'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeIllustrations from '@hooks/useThemeIllustrations'; import useWindowDimensions from '@hooks/useWindowDimensions'; -import * as NumberUtils from '@libs/NumberUtils'; +import Accessibility from '@libs/Accessibility'; import variables from '@styles/variables'; import CONST from '@src/CONST'; @@ -22,10 +22,11 @@ function AnimatedEmptyStateBackground() { const animatedSensor = useAnimatedSensor(SensorType.GYROSCOPE); const xOffset = useSharedValue(0); const yOffset = useSharedValue(0); + const isReducedMotionEnabled = Accessibility.useReduceMotionStatus(); // Apply data to create style object const animatedStyles = useAnimatedStyle(() => { - if (!isSmallScreenWidth) { + if (!isSmallScreenWidth || isReducedMotionEnabled) { return {}; } /* @@ -34,12 +35,12 @@ function AnimatedEmptyStateBackground() { */ const {x, y} = animatedSensor.sensor.value; // The x vs y here seems wrong but is the way to make it feel right to the user - xOffset.value = NumberUtils.clampWorklet(xOffset.value + y, -IMAGE_OFFSET_X, IMAGE_OFFSET_X); - yOffset.value = NumberUtils.clampWorklet(yOffset.value - x, -IMAGE_OFFSET_Y, IMAGE_OFFSET_Y); + xOffset.value = clamp(xOffset.value + y * CONST.ANIMATION_GYROSCOPE_VALUE, -IMAGE_OFFSET_X, IMAGE_OFFSET_X); + yOffset.value = clamp(yOffset.value - x * CONST.ANIMATION_GYROSCOPE_VALUE, -IMAGE_OFFSET_Y, IMAGE_OFFSET_Y); return { transform: [{translateX: withSpring(-IMAGE_OFFSET_X - xOffset.value)}, {translateY: withSpring(yOffset.value)}], }; - }, []); + }, [isReducedMotionEnabled]); return ( Date: Fri, 26 Jan 2024 12:23:45 +0100 Subject: [PATCH 119/249] fix prettier --- src/libs/Accessibility/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Accessibility/index.ts b/src/libs/Accessibility/index.ts index e98b15948023..7c7d2a71ad92 100644 --- a/src/libs/Accessibility/index.ts +++ b/src/libs/Accessibility/index.ts @@ -21,7 +21,7 @@ const useScreenReaderStatus = (): boolean => { const useReduceMotionStatus = (): boolean => { const [isScreenReaderEnabled, setIsScreenReaderEnabled] = useState(false); useEffect(() => { - AccessibilityInfo.isReduceMotionEnabled().then(enabled => setIsScreenReaderEnabled(enabled)) + AccessibilityInfo.isReduceMotionEnabled().then((enabled) => setIsScreenReaderEnabled(enabled)); }, []); return isScreenReaderEnabled; From f0f114420272e0db2875b1dc546b826bc2f6e439 Mon Sep 17 00:00:00 2001 From: staszekscp Date: Fri, 26 Jan 2024 15:06:29 +0100 Subject: [PATCH 120/249] use useRedusedMotion from reanimated --- src/libs/Accessibility/index.ts | 10 ---------- src/pages/home/report/AnimatedEmptyStateBackground.tsx | 5 ++--- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/libs/Accessibility/index.ts b/src/libs/Accessibility/index.ts index 7c7d2a71ad92..167634acce56 100644 --- a/src/libs/Accessibility/index.ts +++ b/src/libs/Accessibility/index.ts @@ -18,15 +18,6 @@ const useScreenReaderStatus = (): boolean => { return isScreenReaderEnabled; }; -const useReduceMotionStatus = (): boolean => { - const [isScreenReaderEnabled, setIsScreenReaderEnabled] = useState(false); - useEffect(() => { - AccessibilityInfo.isReduceMotionEnabled().then((enabled) => setIsScreenReaderEnabled(enabled)); - }, []); - - return isScreenReaderEnabled; -}; - const getHitSlopForSize = ({x, y}: HitSlop) => { /* according to https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/adaptivity-and-layout/ the minimum tappable area is 44x44 points */ @@ -58,6 +49,5 @@ const useAutoHitSlop = () => { export default { moveAccessibilityFocus, useScreenReaderStatus, - useReduceMotionStatus, useAutoHitSlop, }; diff --git a/src/pages/home/report/AnimatedEmptyStateBackground.tsx b/src/pages/home/report/AnimatedEmptyStateBackground.tsx index 47edab5457d3..c2ae6ddeb54c 100644 --- a/src/pages/home/report/AnimatedEmptyStateBackground.tsx +++ b/src/pages/home/report/AnimatedEmptyStateBackground.tsx @@ -1,9 +1,8 @@ import React from 'react'; -import Animated, {clamp, SensorType, useAnimatedSensor, useAnimatedStyle, useSharedValue, withSpring} from 'react-native-reanimated'; +import Animated, {clamp, SensorType, useAnimatedSensor, useAnimatedStyle, useReducedMotion, useSharedValue, withSpring} from 'react-native-reanimated'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeIllustrations from '@hooks/useThemeIllustrations'; import useWindowDimensions from '@hooks/useWindowDimensions'; -import Accessibility from '@libs/Accessibility'; import variables from '@styles/variables'; import CONST from '@src/CONST'; @@ -22,7 +21,7 @@ function AnimatedEmptyStateBackground() { const animatedSensor = useAnimatedSensor(SensorType.GYROSCOPE); const xOffset = useSharedValue(0); const yOffset = useSharedValue(0); - const isReducedMotionEnabled = Accessibility.useReduceMotionStatus(); + const isReducedMotionEnabled = useReducedMotion(); // Apply data to create style object const animatedStyles = useAnimatedStyle(() => { From 9b4d4819b335002186b1a1f8ab1eefcc423201e9 Mon Sep 17 00:00:00 2001 From: someone-here Date: Fri, 26 Jan 2024 21:16:57 +0530 Subject: [PATCH 121/249] Pressable redirect --- src/components/ReportWelcomeText.tsx | 10 +++++++++- src/pages/home/HeaderView.js | 20 +++++++++++++++----- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/components/ReportWelcomeText.tsx b/src/components/ReportWelcomeText.tsx index 2a8d70e81830..0de290db768f 100644 --- a/src/components/ReportWelcomeText.tsx +++ b/src/components/ReportWelcomeText.tsx @@ -12,6 +12,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {PersonalDetailsList, Policy, Report} from '@src/types/onyx'; +import {PressableWithoutFeedback} from './Pressable'; import RenderHTML from './RenderHTML'; import Text from './Text'; import UserDetailsTooltip from './UserDetailsTooltip'; @@ -71,7 +72,14 @@ function ReportWelcomeText({report, policy, personalDetails}: ReportWelcomeTextP {isChatRoom && ( <> {report?.description ? ( - + { + Navigation.navigate(ROUTES.REPORT_DESCRIPTION.getRoute(report.reportID)); + }} + accessibilityLabel={translate('reportDescriptionPage.roomDescription')} + > + + ) : ( <> {roomWelcomeMessage.phrase1} diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index 44a1c5f9f9a3..de2e7d5b3ceb 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -26,6 +26,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import {getGroupChatName} from '@libs/GroupChatUtils'; import * as HeaderUtils from '@libs/HeaderUtils'; +import Navigation from '@libs/Navigation/Navigation'; import reportWithoutHasDraftSelector from '@libs/OnyxSelectors/reportWithoutHasDraftSelector'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; @@ -37,6 +38,7 @@ import * as Session from '@userActions/Session'; import * as Task from '@userActions/Task'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; const propTypes = { /** Toggles the navigationMenu open and closed */ @@ -317,12 +319,20 @@ function HeaderView(props) { )} {!_.isEmpty(reportDescription) && _.isEmpty(parentNavigationSubtitleData) && ( - { + Navigation.navigate(ROUTES.REPORT_DESCRIPTION.getRoute(props.reportID)); + }} + style={[styles.alignSelfStart, styles.mw100]} + accessibilityLabel={translate('reportDescriptionPage.roomDescription')} > - {reportDescription} - + + {reportDescription} + + )} {brickRoadIndicator === CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR && ( From 300a161fbdfe521a5f804d129e3df9f114ff8882 Mon Sep 17 00:00:00 2001 From: someone-here Date: Fri, 26 Jan 2024 21:26:28 +0530 Subject: [PATCH 122/249] Fix --- src/libs/ReportUtils.ts | 2 +- src/pages/RoomDescriptionPage.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index bca7cbe4e445..1cd3e04c7cda 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4507,7 +4507,7 @@ function getRoom(type: ValueOf, policyID: string) /** * We only want policy owners and admins to be able to modify the report description, but not in thread chat. */ -function canEditReportDescription(report: OnyxEntry, policy: OnyxEntry | undefined | null): boolean { +function canEditReportDescription(report: OnyxEntry, policy: OnyxEntry | undefined): boolean { return !isMoneyRequestReport(report) && !isArchivedRoom(report) && isChatRoom(report) && !isChatThread(report) && !isEmpty(policy); } /** diff --git a/src/pages/RoomDescriptionPage.tsx b/src/pages/RoomDescriptionPage.tsx index 57d5302939ed..c9615be6d77e 100644 --- a/src/pages/RoomDescriptionPage.tsx +++ b/src/pages/RoomDescriptionPage.tsx @@ -70,7 +70,7 @@ function RoomDescriptionPage({report, policies}: RoomDescriptionPageProps) { Navigation.goBack(ROUTES.REPORT_SETTINGS.getRoute(report.reportID))} + onBackButtonPress={() => Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID))} /> Date: Fri, 26 Jan 2024 21:43:41 +0530 Subject: [PATCH 123/249] Make permission changes --- src/components/ReportWelcomeText.tsx | 6 +++++- src/libs/ReportUtils.ts | 9 ++++++++- src/pages/home/HeaderView.js | 6 +++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/components/ReportWelcomeText.tsx b/src/components/ReportWelcomeText.tsx index 0de290db768f..5151639ce1be 100644 --- a/src/components/ReportWelcomeText.tsx +++ b/src/components/ReportWelcomeText.tsx @@ -74,7 +74,11 @@ function ReportWelcomeText({report, policy, personalDetails}: ReportWelcomeTextP {report?.description ? ( { - Navigation.navigate(ROUTES.REPORT_DESCRIPTION.getRoute(report.reportID)); + if (ReportUtils.canEditReportDescription(report, policy)) { + Navigation.navigate(ROUTES.REPORT_DESCRIPTION.getRoute(report.reportID)); + return; + } + Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID)); }} accessibilityLabel={translate('reportDescriptionPage.roomDescription')} > diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 1cd3e04c7cda..1a5c2e8ee436 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4508,7 +4508,14 @@ function getRoom(type: ValueOf, policyID: string) * We only want policy owners and admins to be able to modify the report description, but not in thread chat. */ function canEditReportDescription(report: OnyxEntry, policy: OnyxEntry | undefined): boolean { - return !isMoneyRequestReport(report) && !isArchivedRoom(report) && isChatRoom(report) && !isChatThread(report) && !isEmpty(policy); + return ( + !isMoneyRequestReport(report) && + !isArchivedRoom(report) && + isChatRoom(report) && + !isChatThread(report) && + !isEmpty(policy) && + getVisibleMemberIDs(report).includes(currentUserAccountID ?? 0) + ); } /** * Checks if report action has error when smart scanning diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index de2e7d5b3ceb..6efd71e0b683 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -321,7 +321,11 @@ function HeaderView(props) { {!_.isEmpty(reportDescription) && _.isEmpty(parentNavigationSubtitleData) && ( { - Navigation.navigate(ROUTES.REPORT_DESCRIPTION.getRoute(props.reportID)); + if (ReportUtils.canEditReportDescription(props.report, props.policy)) { + Navigation.navigate(ROUTES.REPORT_DESCRIPTION.getRoute(props.reportID)); + return; + } + Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(props.reportID)); }} style={[styles.alignSelfStart, styles.mw100]} accessibilityLabel={translate('reportDescriptionPage.roomDescription')} From 4459b37bb3762b41bf2a4eed338e761424fd0a6a Mon Sep 17 00:00:00 2001 From: Shahe Shahinyan Date: Fri, 26 Jan 2024 21:07:39 +0400 Subject: [PATCH 124/249] Init changes to migrate --- src/ONYXKEYS.ts | 2 +- src/components/DisplayNames/types.ts | 2 +- src/languages/en.ts | 1 + src/libs/ErrorUtils.ts | 2 +- src/libs/PolicyUtils.ts | 2 +- src/libs/ReportUtils.ts | 6 +- src/libs/ValidationUtils.ts | 5 +- src/libs/actions/Report.ts | 4 +- .../home/report/withReportOrNotFound.tsx | 8 +- .../Report/NotificationPreferencePage.js | 59 -------------- .../Report/NotificationPreferencePage.tsx | 55 +++++++++++++ ...SettingsPage.js => ReportSettingsPage.tsx} | 80 +++++-------------- .../{RoomNamePage.js => RoomNamePage.tsx} | 53 ++++++------ ...abilityPage.js => WriteCapabilityPage.tsx} | 49 ++++++------ src/types/onyx/Form.ts | 6 +- src/types/onyx/index.ts | 3 +- 16 files changed, 149 insertions(+), 188 deletions(-) delete mode 100644 src/pages/settings/Report/NotificationPreferencePage.js create mode 100644 src/pages/settings/Report/NotificationPreferencePage.tsx rename src/pages/settings/Report/{ReportSettingsPage.js => ReportSettingsPage.tsx} (78%) rename src/pages/settings/Report/{RoomNamePage.js => RoomNamePage.tsx} (80%) rename src/pages/settings/Report/{WriteCapabilityPage.js => WriteCapabilityPage.tsx} (52%) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 7abf6db1769d..3c9c3aba11b7 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -486,7 +486,7 @@ type OnyxValues = { [ONYXKEYS.FORMS.PROFILE_SETTINGS_FORM_DRAFT]: OnyxTypes.Form; [ONYXKEYS.FORMS.DISPLAY_NAME_FORM]: OnyxTypes.DisplayNameForm; [ONYXKEYS.FORMS.DISPLAY_NAME_FORM_DRAFT]: OnyxTypes.DisplayNameForm; - [ONYXKEYS.FORMS.ROOM_NAME_FORM]: OnyxTypes.Form; + [ONYXKEYS.FORMS.ROOM_NAME_FORM]: OnyxTypes.RoomNameForm; [ONYXKEYS.FORMS.ROOM_NAME_FORM_DRAFT]: OnyxTypes.Form; [ONYXKEYS.FORMS.WELCOME_MESSAGE_FORM]: OnyxTypes.Form; [ONYXKEYS.FORMS.WELCOME_MESSAGE_FORM_DRAFT]: OnyxTypes.Form; diff --git a/src/components/DisplayNames/types.ts b/src/components/DisplayNames/types.ts index 2e6f36d5cc07..7da1819c9f01 100644 --- a/src/components/DisplayNames/types.ts +++ b/src/components/DisplayNames/types.ts @@ -20,7 +20,7 @@ type DisplayNamesProps = { fullTitle: string; /** Array of objects that map display names to their corresponding tooltip */ - displayNamesWithTooltips: DisplayNameWithTooltip[]; + displayNamesWithTooltips?: DisplayNameWithTooltip[]; /** Number of lines before wrapping */ numberOfLines: number; diff --git a/src/languages/en.ts b/src/languages/en.ts index 8a959b5da550..80c73f547e99 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -673,6 +673,7 @@ export default { always: 'Immediately', daily: 'Daily', mute: 'Mute', + hidden: 'Hidden', }, }, loginField: { diff --git a/src/libs/ErrorUtils.ts b/src/libs/ErrorUtils.ts index 18aa262c2079..29db104c322d 100644 --- a/src/libs/ErrorUtils.ts +++ b/src/libs/ErrorUtils.ts @@ -101,7 +101,7 @@ type ErrorsList = Record; * @param errors - An object containing current errors in the form * @param message - Message to assign to the inputID errors */ -function addErrorMessage(errors: ErrorsList, inputID?: string, message?: TKey) { +function addErrorMessage(errors: ErrorsList, inputID?: string, message?: TKey | [TKey, Record] ) { if (!message || !inputID) { return; } diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index b8ed62f93082..0d406bd78bd9 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): 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 fa51ca06e68e..eef3e894e4ec 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4222,7 +4222,7 @@ function getWorkspaceChats(policyID: string, accountIDs: number[]): Array, policy: OnyxEntry): boolean { +function shouldDisableRename(report: OnyxEntry, policy?: OnyxEntry): boolean { if (isDefaultRoom(report) || isArchivedRoom(report) || isThread(report) || isMoneyRequestReport(report) || isPolicyExpenseChat(report)) { return true; } @@ -4241,7 +4241,7 @@ function shouldDisableRename(report: OnyxEntry, policy: OnyxEntry, policy: OnyxEntry): boolean { +function canEditWriteCapability(report: OnyxEntry, policy?: OnyxEntry): boolean { return PolicyUtils.isPolicyAdmin(policy) && !isAdminRoom(report) && !isArchivedRoom(report) && !isThread(report); } @@ -4499,7 +4499,7 @@ function getRoom(type: ValueOf, policyID: string) /** * We only want policy owners and admins to be able to modify the welcome message, but not in thread chat. */ -function shouldDisableWelcomeMessage(report: OnyxEntry, policy: OnyxEntry): boolean { +function shouldDisableWelcomeMessage(report: OnyxEntry, policy?: OnyxEntry): boolean { return isMoneyRequestReport(report) || isArchivedRoom(report) || !isChatRoom(report) || isChatThread(report) || !PolicyUtils.isPolicyAdmin(policy); } /** diff --git a/src/libs/ValidationUtils.ts b/src/libs/ValidationUtils.ts index 7eff51c354df..ee8234f946c1 100644 --- a/src/libs/ValidationUtils.ts +++ b/src/libs/ValidationUtils.ts @@ -11,6 +11,7 @@ import DateUtils from './DateUtils'; import * as LoginUtils from './LoginUtils'; import {parsePhoneNumber} from './PhoneNumber'; import StringUtils from './StringUtils'; +import type {OnyxCollection} from "react-native-onyx"; /** * Implements the Luhn Algorithm, a checksum formula used to validate credit card @@ -354,8 +355,8 @@ function isReservedRoomName(roomName: string): boolean { /** * Checks if the room name already exists. */ -function isExistingRoomName(roomName: string, reports: Record, policyID: string): boolean { - return Object.values(reports).some((report) => report && report.policyID === policyID && report.reportName === roomName); +function isExistingRoomName(roomName: string, reports: OnyxCollection, policyID?: string): boolean { + return Object.values(reports ?? {}).some((report) => report && report.policyID === policyID && report.reportName === roomName); } /** diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index e084a99df0c7..54f20e672e5b 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -1729,7 +1729,7 @@ function navigateToConciergeChatAndDeleteReport(reportID: string) { /** * @param policyRoomName The updated name for the policy room */ -function updatePolicyRoomNameAndNavigate(policyRoomReport: Report, policyRoomName: string) { +function updatePolicyRoomNameAndNavigate(policyRoomReport: Report, policyRoomName?: string) { const reportID = policyRoomReport.reportID; const previousName = policyRoomReport.reportName; @@ -1777,7 +1777,7 @@ function updatePolicyRoomNameAndNavigate(policyRoomReport: Report, policyRoomNam type UpdatePolicyRoomNameParameters = { reportID: string; - policyRoomName: string; + policyRoomName?: string; }; const parameters: UpdatePolicyRoomNameParameters = {reportID, policyRoomName}; diff --git a/src/pages/home/report/withReportOrNotFound.tsx b/src/pages/home/report/withReportOrNotFound.tsx index 7613bafeacdc..a8facc3e1c76 100644 --- a/src/pages/home/report/withReportOrNotFound.tsx +++ b/src/pages/home/report/withReportOrNotFound.tsx @@ -22,16 +22,16 @@ type OnyxProps = { isLoadingReportData: OnyxEntry; }; -type ComponentProps = OnyxProps & { +type WithReportOrNotFoundProps = OnyxProps & { route: RouteProp<{params: {reportID: string}}>; }; export default function ( shouldRequireReportID = true, -): ( +): ( WrappedComponent: React.ComponentType>, ) => React.ComponentType, keyof OnyxProps>> { - return function (WrappedComponent: ComponentType>) { + return function (WrappedComponent: ComponentType>) { function WithReportOrNotFound(props: TProps, ref: ForwardedRef) { const contentShown = React.useRef(false); @@ -89,3 +89,5 @@ export default function ( })(React.forwardRef(WithReportOrNotFound)); }; } + +export type {WithReportOrNotFoundProps}; diff --git a/src/pages/settings/Report/NotificationPreferencePage.js b/src/pages/settings/Report/NotificationPreferencePage.js deleted file mode 100644 index c6044bd81efe..000000000000 --- a/src/pages/settings/Report/NotificationPreferencePage.js +++ /dev/null @@ -1,59 +0,0 @@ -import React from 'react'; -import _ from 'underscore'; -import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import ScreenWrapper from '@components/ScreenWrapper'; -import SelectionList from '@components/SelectionList'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; -import compose from '@libs/compose'; -import * as ReportUtils from '@libs/ReportUtils'; -import withReportOrNotFound from '@pages/home/report/withReportOrNotFound'; -import reportPropTypes from '@pages/reportPropTypes'; -import * as Report from '@userActions/Report'; -import CONST from '@src/CONST'; - -const propTypes = { - ...withLocalizePropTypes, - - /** The report for which we are setting notification preferences */ - report: reportPropTypes.isRequired, -}; - -function NotificationPreferencePage(props) { - const shouldDisableNotificationPreferences = ReportUtils.isArchivedRoom(props.report); - const notificationPreferenceOptions = _.map( - _.filter(_.values(CONST.REPORT.NOTIFICATION_PREFERENCE), (pref) => pref !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN), - (preference) => ({ - value: preference, - text: props.translate(`notificationPreferencesPage.notificationPreferences.${preference}`), - keyForList: preference, - isSelected: preference === props.report.notificationPreference, - }), - ); - - return ( - - - ReportUtils.goBackToDetailsPage(props.report)} - /> - - Report.updateNotificationPreference(props.report.reportID, props.report.notificationPreference, option.value, true, undefined, undefined, props.report) - } - initiallyFocusedOptionKey={_.find(notificationPreferenceOptions, (locale) => locale.isSelected).keyForList} - /> - - - ); -} - -NotificationPreferencePage.displayName = 'NotificationPreferencePage'; -NotificationPreferencePage.propTypes = propTypes; - -export default compose(withLocalize, withReportOrNotFound())(NotificationPreferencePage); diff --git a/src/pages/settings/Report/NotificationPreferencePage.tsx b/src/pages/settings/Report/NotificationPreferencePage.tsx new file mode 100644 index 000000000000..8d3ed23f6845 --- /dev/null +++ b/src/pages/settings/Report/NotificationPreferencePage.tsx @@ -0,0 +1,55 @@ +import React from 'react'; +import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import SelectionList from '@components/SelectionList'; +import * as ReportUtils from '@libs/ReportUtils'; +import withReportOrNotFound from '@pages/home/report/withReportOrNotFound'; +import type {WithReportOrNotFoundProps} from '@pages/home/report/withReportOrNotFound'; +import * as ReportActions from '@userActions/Report'; +import CONST from '@src/CONST'; +import useLocalize from "@hooks/useLocalize"; +import type {Report} from '@src/types/onyx'; + +type NotificationPreferencePageProps = WithReportOrNotFoundProps & { + report: Report; +} + +function NotificationPreferencePage({report}:NotificationPreferencePageProps) { + const {translate} = useLocalize() + const shouldDisableNotificationPreferences = ReportUtils.isArchivedRoom(report); + const notificationPreferenceOptions = + Object.values(CONST.REPORT.NOTIFICATION_PREFERENCE).filter((pref) => pref !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) + .map((preference) => ({ + value: preference, + text: translate(`notificationPreferencesPage.notificationPreferences.${preference}`), + keyForList: preference, + isSelected: preference === report.notificationPreference, + }) + ); + + return ( + + + ReportUtils.goBackToDetailsPage(report)} + /> + + ReportActions.updateNotificationPreference(report.reportID, report.notificationPreference, option.value, true, undefined, undefined, report) + } + initiallyFocusedOptionKey={Object.values(notificationPreferenceOptions ?? {}).find((locale) => locale.isSelected)?.keyForList} + /> + + + ); +} + +NotificationPreferencePage.displayName = 'NotificationPreferencePage'; + +export default withReportOrNotFound()(NotificationPreferencePage); diff --git a/src/pages/settings/Report/ReportSettingsPage.js b/src/pages/settings/Report/ReportSettingsPage.tsx similarity index 78% rename from src/pages/settings/Report/ReportSettingsPage.js rename to src/pages/settings/Report/ReportSettingsPage.tsx index c7cfd9c7850d..7d4598d549ff 100644 --- a/src/pages/settings/Report/ReportSettingsPage.js +++ b/src/pages/settings/Report/ReportSettingsPage.tsx @@ -1,9 +1,6 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; +import isEmpty from 'lodash/isEmpty'; import React, {useMemo} from 'react'; import {ScrollView, View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import DisplayNames from '@components/DisplayNames'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; @@ -15,71 +12,46 @@ import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; import {getGroupChatName} from '@libs/GroupChatUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import withReportOrNotFound from '@pages/home/report/withReportOrNotFound'; -import reportPropTypes from '@pages/reportPropTypes'; -import * as Report from '@userActions/Report'; +import type {WithReportOrNotFoundProps} from '@pages/home/report/withReportOrNotFound'; +import * as ReportActions from '@userActions/Report'; import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type {Report} from '@src/types/onyx'; -const propTypes = { - /** Route params */ - route: PropTypes.shape({ - params: PropTypes.shape({ - /** Report ID passed via route r/:reportID/settings */ - reportID: PropTypes.string, - }), - }).isRequired, - /* Onyx Props */ - - /** The active report */ - report: reportPropTypes.isRequired, - - /** The policies which the user has access to and which the report could be tied to */ - policies: PropTypes.shape({ - /** The policy name */ - name: PropTypes.string, - - /** ID of the policy */ - id: PropTypes.string, - }), -}; - -const defaultProps = { - policies: {}, -}; +type ReportSettingsPageProps = WithReportOrNotFoundProps & { + report: Report +} -function ReportSettingsPage(props) { +function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { const styles = useThemeStyles(); - const {report, policies} = props; const {translate} = useLocalize(); // The workspace the report is on, null if the user isn't a member of the workspace - const linkedWorkspace = useMemo(() => _.find(policies, (policy) => policy && policy.id === report.policyID), [policies, report.policyID]); + const linkedWorkspace = useMemo(() => Object.values(policies ?? {}).find( (policy) => policy && policy.id === report.policyID), [policies, report.policyID]); const shouldDisableRename = useMemo(() => ReportUtils.shouldDisableRename(report, linkedWorkspace), [report, linkedWorkspace]); const isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report); // We only want policy owners and admins to be able to modify the welcome message, but not in thread chat const shouldDisableWelcomeMessage = ReportUtils.shouldDisableWelcomeMessage(report, linkedWorkspace); - const shouldDisableSettings = _.isEmpty(report) || ReportUtils.isArchivedRoom(report); + const shouldDisableSettings = isEmpty(report) || ReportUtils.isArchivedRoom(report); const shouldShowRoomName = !ReportUtils.isPolicyExpenseChat(report) && !ReportUtils.isChatThread(report); const notificationPreference = - report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN + report.notificationPreference && report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN ? translate(`notificationPreferencesPage.notificationPreferences.${report.notificationPreference}`) : ''; - const writeCapability = ReportUtils.isAdminRoom(report) ? CONST.REPORT.WRITE_CAPABILITIES.ADMINS : report.writeCapability || CONST.REPORT.WRITE_CAPABILITIES.ALL; + const writeCapability = ReportUtils.isAdminRoom(report) ? CONST.REPORT.WRITE_CAPABILITIES.ADMINS : report.writeCapability ?? CONST.REPORT.WRITE_CAPABILITIES.ALL; const writeCapabilityText = translate(`writeCapabilityPage.writeCapability.${writeCapability}`); const shouldAllowWriteCapabilityEditing = useMemo(() => ReportUtils.canEditWriteCapability(report, linkedWorkspace), [report, linkedWorkspace]); const shouldShowNotificationPref = !isMoneyRequestReport && report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; const roomNameLabel = translate(isMoneyRequestReport ? 'workspace.editor.nameInputLabel' : 'newRoomPage.roomName'); - const reportName = ReportUtils.isGroupChat(props.report) ? getGroupChatName(props.report) : ReportUtils.getReportName(props.report); + const reportName = ReportUtils.isGroupChat(report) ? getGroupChatName(report) : ReportUtils.getReportName(report); const shouldShowWriteCapability = !isMoneyRequestReport; @@ -101,10 +73,10 @@ function ReportSettingsPage(props) { )} {shouldShowRoomName && ( Report.clearPolicyRoomNameErrors(report.reportID)} + onClose={() => ReportActions.clearPolicyRoomNameErrors(report.reportID)} > {shouldDisableRename ? ( @@ -115,7 +87,7 @@ function ReportSettingsPage(props) { {roomNameLabel} - {translate(`newRoomPage.visibilityOptions.${report.visibility}`)} + {report.visibility && translate(`newRoomPage.visibilityOptions.${report.visibility}`)} - {translate(`newRoomPage.${report.visibility}Description`)} + {report.visibility && translate(`newRoomPage.${report.visibility}Description`)} )} @@ -206,14 +178,6 @@ function ReportSettingsPage(props) { ); } -ReportSettingsPage.propTypes = propTypes; -ReportSettingsPage.defaultProps = defaultProps; ReportSettingsPage.displayName = 'ReportSettingsPage'; -export default compose( - withReportOrNotFound(), - withOnyx({ - policies: { - key: ONYXKEYS.COLLECTION.POLICY, - }, - }), -)(ReportSettingsPage); + +export default withReportOrNotFound()(ReportSettingsPage); diff --git a/src/pages/settings/Report/RoomNamePage.js b/src/pages/settings/Report/RoomNamePage.tsx similarity index 80% rename from src/pages/settings/Report/RoomNamePage.js rename to src/pages/settings/Report/RoomNamePage.tsx index 5f64faca50fc..793fb04ca68c 100644 --- a/src/pages/settings/Report/RoomNamePage.js +++ b/src/pages/settings/Report/RoomNamePage.tsx @@ -1,15 +1,14 @@ import {useIsFocused} from '@react-navigation/native'; -import PropTypes from 'prop-types'; import React, {useCallback, useRef} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; +import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import RoomNameInput from '@components/RoomNameInput'; import ScreenWrapper from '@components/ScreenWrapper'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import compose from '@libs/compose'; import * as ErrorUtils from '@libs/ErrorUtils'; @@ -17,39 +16,37 @@ import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import * as ValidationUtils from '@libs/ValidationUtils'; import withReportOrNotFound from '@pages/home/report/withReportOrNotFound'; -import reportPropTypes from '@pages/reportPropTypes'; -import * as Report from '@userActions/Report'; +import type {WithReportOrNotFoundProps} from '@pages/home/report/withReportOrNotFound'; +import * as ReportActions from '@userActions/Report'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import useLocalize from "@hooks/useLocalize"; +import type {Policy, Report} from "@src/types/onyx"; +import type {OnyxFormValuesFields} from "@components/Form/types"; +import type {AnimatedTextInputRef} from "@components/RNTextInput"; -const propTypes = { - ...withLocalizePropTypes, - - /** The room report for which the name is being edited */ - report: reportPropTypes.isRequired, - +type RoomNamePageOnyxProps = { /** All reports shared with the user */ - reports: PropTypes.objectOf(reportPropTypes), + reports: OnyxCollection, /** Policy of the report for which the name is being edited */ - policy: PropTypes.shape({ - role: PropTypes.string, - owner: PropTypes.string, - }), -}; -const defaultProps = { - reports: {}, - policy: {}, + policy: OnyxEntry +} + +type RoomNamePageProps = RoomNamePageOnyxProps & WithReportOrNotFoundProps & { + /** The room report for which the name is being edited */ + report: Report }; -function RoomNamePage({policy, report, reports, translate}) { +function RoomNamePage({ report, policy, reports }: RoomNamePageProps) { const styles = useThemeStyles(); - const roomNameInputRef = useRef(null); + const roomNameInputRef = useRef(null); const isFocused = useIsFocused(); + const {translate} = useLocalize() const validate = useCallback( - (values) => { + (values: OnyxFormValuesFields) => { const errors = {}; // We should skip validation hence we return an empty errors and we skip Form submission on the onSubmit method @@ -78,7 +75,7 @@ function RoomNamePage({policy, report, reports, translate}) { return ( roomNameInputRef.current && roomNameInputRef.current.focus()} + onEntryTransitionEnd={() => roomNameInputRef.current?.focus()} includeSafeAreaPaddingBottom={false} testID={RoomNamePage.displayName} > @@ -90,7 +87,7 @@ function RoomNamePage({policy, report, reports, translate}) { Report.updatePolicyRoomNameAndNavigate(report, values.roomName)} + onSubmit={(values) => ReportActions.updatePolicyRoomNameAndNavigate(report, values.roomName)} validate={validate} submitButtonText={translate('common.save')} enabledWhenOffline @@ -110,14 +107,10 @@ function RoomNamePage({policy, report, reports, translate}) { ); } -RoomNamePage.propTypes = propTypes; -RoomNamePage.defaultProps = defaultProps; RoomNamePage.displayName = 'RoomNamePage'; export default compose( - withLocalize, - withReportOrNotFound(), - withOnyx({ + withOnyx({ reports: { key: ONYXKEYS.COLLECTION.REPORT, }, @@ -125,4 +118,6 @@ export default compose( key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, }, }), + withReportOrNotFound(), + )(RoomNamePage); diff --git a/src/pages/settings/Report/WriteCapabilityPage.js b/src/pages/settings/Report/WriteCapabilityPage.tsx similarity index 52% rename from src/pages/settings/Report/WriteCapabilityPage.js rename to src/pages/settings/Report/WriteCapabilityPage.tsx index fc587b028f7d..244a47fee113 100644 --- a/src/pages/settings/Report/WriteCapabilityPage.js +++ b/src/pages/settings/Report/WriteCapabilityPage.tsx @@ -1,43 +1,43 @@ import React from 'react'; import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; +import type {OnyxEntry} from 'react-native-onyx'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; import compose from '@libs/compose'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import withReportOrNotFound from '@pages/home/report/withReportOrNotFound'; -import reportPropTypes from '@pages/reportPropTypes'; -import {policyDefaultProps, policyPropTypes} from '@pages/workspace/withPolicy'; -import * as Report from '@userActions/Report'; +import type {WithReportOrNotFoundProps} from '@pages/home/report/withReportOrNotFound'; +import * as ReportActions from '@userActions/Report'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import useLocalize from "@hooks/useLocalize"; +import type {Policy, Report} from "@src/types/onyx"; -const propTypes = { - ...withLocalizePropTypes, - ...policyPropTypes, +type WriteCapabilityPageOnyxProps = { + /** The policy object for the current route */ + policy: OnyxEntry; +}; +type WriteCapabilityPageProps = WriteCapabilityPageOnyxProps & WithReportOrNotFoundProps & { /** The report for which we are setting write capability */ - report: reportPropTypes.isRequired, + report: Report, }; -const defaultProps = { - ...policyDefaultProps, -}; -function WriteCapabilityPage(props) { - const writeCapabilityOptions = _.map(CONST.REPORT.WRITE_CAPABILITIES, (value) => ({ +function WriteCapabilityPage({report, policy}: WriteCapabilityPageProps) { + const {translate} = useLocalize() + const writeCapabilityOptions = Object.values(CONST.REPORT.WRITE_CAPABILITIES).map((value) => ({ value, - text: props.translate(`writeCapabilityPage.writeCapability.${value}`), + text: translate(`writeCapabilityPage.writeCapability.${value}`), keyForList: value, - isSelected: value === (props.report.writeCapability || CONST.REPORT.WRITE_CAPABILITIES.ALL), + isSelected: value === (report.writeCapability ?? CONST.REPORT.WRITE_CAPABILITIES.ALL), })); - const isAbleToEdit = ReportUtils.canEditWriteCapability(props.report, props.policy); + const isAbleToEdit = ReportUtils.canEditWriteCapability(report, policy); return ( Navigation.goBack(ROUTES.REPORT_SETTINGS.getRoute(props.report.reportID))} + onBackButtonPress={() => Navigation.goBack(ROUTES.REPORT_SETTINGS.getRoute(report.reportID))} /> Report.updateWriteCapabilityAndNavigate(props.report, option.value)} - initiallyFocusedOptionKey={_.find(writeCapabilityOptions, (locale) => locale.isSelected).keyForList} + onSelectRow={(option) => ReportActions.updateWriteCapabilityAndNavigate(report, option.value)} + initiallyFocusedOptionKey={Object.values(writeCapabilityOptions).find((locale) => locale.isSelected)?.keyForList} /> @@ -61,15 +61,12 @@ function WriteCapabilityPage(props) { } WriteCapabilityPage.displayName = 'WriteCapabilityPage'; -WriteCapabilityPage.propTypes = propTypes; -WriteCapabilityPage.defaultProps = defaultProps; export default compose( - withLocalize, - withReportOrNotFound(), - withOnyx({ + withOnyx({ policy: { key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, }, }), + withReportOrNotFound(), )(WriteCapabilityPage); diff --git a/src/types/onyx/Form.ts b/src/types/onyx/Form.ts index c3bcec2a2d3b..142984d7f4b1 100644 --- a/src/types/onyx/Form.ts +++ b/src/types/onyx/Form.ts @@ -54,6 +54,10 @@ type PrivateNotesForm = Form<{ privateNotes: string; }>; +type RoomNameForm = Form<{ + roomName?: string; +}>; + export default Form; -export type {AddDebitCardForm, DateOfBirthForm, PrivateNotesForm, DisplayNameForm, FormValueType, NewRoomForm, BaseForm, IKnowATeacherForm, IntroSchoolPrincipalForm}; +export type {AddDebitCardForm, DateOfBirthForm, PrivateNotesForm, DisplayNameForm, FormValueType, NewRoomForm, BaseForm, IKnowATeacherForm, IntroSchoolPrincipalForm, RoomNameForm}; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 5b04cae58671..a003b8d87e87 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -9,7 +9,7 @@ import type Credentials from './Credentials'; import type Currency from './Currency'; import type CustomStatusDraft from './CustomStatusDraft'; import type Download from './Download'; -import type {AddDebitCardForm, DateOfBirthForm, DisplayNameForm, IKnowATeacherForm, IntroSchoolPrincipalForm, NewRoomForm, PrivateNotesForm} from './Form'; +import type {AddDebitCardForm, DateOfBirthForm, DisplayNameForm, IKnowATeacherForm, IntroSchoolPrincipalForm, NewRoomForm, PrivateNotesForm, RoomNameForm} from './Form'; import type Form from './Form'; import type FrequentlyUsedEmoji from './FrequentlyUsedEmoji'; import type {FundList} from './Fund'; @@ -151,4 +151,5 @@ export type { IKnowATeacherForm, IntroSchoolPrincipalForm, PrivateNotesForm, + RoomNameForm }; From 7fe93d8869167fe7a4dba8e0db101a5451f26990 Mon Sep 17 00:00:00 2001 From: staszekscp Date: Mon, 29 Jan 2024 09:39:21 +0100 Subject: [PATCH 125/249] add adjustments --- src/CONST.ts | 2 +- src/pages/home/report/ReportActionItem.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index f4a66b8fe1ba..cbb99833fcce 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -47,7 +47,7 @@ const CONST = { OUT: 'out', }, // Multiplier for gyroscope animation in order to make it a bit more subtle - ANIMATION_GYROSCOPE_VALUE: 0.65, + ANIMATION_GYROSCOPE_VALUE: 0.4, ARROW_HIDE_DELAY: 3000, API_ATTACHMENT_VALIDATIONS: { diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 80fb341a2cf8..3a333576965d 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -619,7 +619,7 @@ function ReportActionItem(props) { if (ReportUtils.isTaskReport(props.report)) { if (ReportUtils.isCanceledTaskReport(props.report, parentReportAction)) { return ( - <> + - + ); } return ( - <> + - + ); } if (ReportUtils.isExpenseReport(props.report) || ReportUtils.isIOUReport(props.report)) { From 4be927fb1d0811d50e98ce4ae5c8510d79b16037 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 29 Jan 2024 12:10:14 +0100 Subject: [PATCH 126/249] 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 127/249] 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 128/249] 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 853932d0963bd48fe779b706d16c0bd95c6b061c Mon Sep 17 00:00:00 2001 From: Shahe Shahinyan Date: Mon, 29 Jan 2024 20:51:12 +0400 Subject: [PATCH 129/249] Fix screens crash --- src/pages/settings/Report/RoomNamePage.tsx | 2 +- src/pages/settings/Report/WriteCapabilityPage.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/settings/Report/RoomNamePage.tsx b/src/pages/settings/Report/RoomNamePage.tsx index 793fb04ca68c..091db8f247f6 100644 --- a/src/pages/settings/Report/RoomNamePage.tsx +++ b/src/pages/settings/Report/RoomNamePage.tsx @@ -110,6 +110,7 @@ function RoomNamePage({ report, policy, reports }: RoomNamePageProps) { RoomNamePage.displayName = 'RoomNamePage'; export default compose( + withReportOrNotFound(), withOnyx({ reports: { key: ONYXKEYS.COLLECTION.REPORT, @@ -118,6 +119,5 @@ export default compose( key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, }, }), - withReportOrNotFound(), )(RoomNamePage); diff --git a/src/pages/settings/Report/WriteCapabilityPage.tsx b/src/pages/settings/Report/WriteCapabilityPage.tsx index 244a47fee113..b4de7518f7ba 100644 --- a/src/pages/settings/Report/WriteCapabilityPage.tsx +++ b/src/pages/settings/Report/WriteCapabilityPage.tsx @@ -63,10 +63,10 @@ function WriteCapabilityPage({report, policy}: WriteCapabilityPageProps) { WriteCapabilityPage.displayName = 'WriteCapabilityPage'; export default compose( + withReportOrNotFound(), withOnyx({ policy: { key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, }, }), - withReportOrNotFound(), )(WriteCapabilityPage); From b544a69c5066a160919f246889f50b7dd112c78d Mon Sep 17 00:00:00 2001 From: Shahe Shahinyan Date: Mon, 29 Jan 2024 20:58:08 +0400 Subject: [PATCH 130/249] add translation key for es --- src/languages/es.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/languages/es.ts b/src/languages/es.ts index 16686f54f1e1..f99765a66673 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -668,6 +668,7 @@ export default { always: 'Inmediatamente', daily: 'Cada día', mute: 'Nunca', + hidden: 'Oculta', }, }, loginField: { From ff010eb9ffb9cec9248c3a5a4c7cec8a5876daf8 Mon Sep 17 00:00:00 2001 From: Shahe Shahinyan Date: Mon, 29 Jan 2024 21:19:53 +0400 Subject: [PATCH 131/249] Fix TS and lint errors --- src/libs/ValidationUtils.ts | 2 +- src/libs/actions/Report.ts | 2 +- src/pages/settings/Report/RoomNamePage.tsx | 8 +++----- src/pages/settings/Report/WriteCapabilityPage.tsx | 7 +++---- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/libs/ValidationUtils.ts b/src/libs/ValidationUtils.ts index ee8234f946c1..bc5caa92bbbd 100644 --- a/src/libs/ValidationUtils.ts +++ b/src/libs/ValidationUtils.ts @@ -6,12 +6,12 @@ import isObject from 'lodash/isObject'; import CONST from '@src/CONST'; import type {Report} from '@src/types/onyx'; import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; +import type {OnyxCollection} from "react-native-onyx"; import * as CardUtils from './CardUtils'; import DateUtils from './DateUtils'; import * as LoginUtils from './LoginUtils'; import {parsePhoneNumber} from './PhoneNumber'; import StringUtils from './StringUtils'; -import type {OnyxCollection} from "react-native-onyx"; /** * Implements the Luhn Algorithm, a checksum formula used to validate credit card diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 6222c09a898e..f2744f8a8269 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -1673,7 +1673,7 @@ function navigateToConciergeChatAndDeleteReport(reportID: string) { /** * @param policyRoomName The updated name for the policy room */ -function updatePolicyRoomNameAndNavigate(policyRoomReport: Report, policyRoomName: string) { +function updatePolicyRoomNameAndNavigate(policyRoomReport: Report, policyRoomName?: string) { const reportID = policyRoomReport.reportID; const previousName = policyRoomReport.reportName; diff --git a/src/pages/settings/Report/RoomNamePage.tsx b/src/pages/settings/Report/RoomNamePage.tsx index 091db8f247f6..1daf20013731 100644 --- a/src/pages/settings/Report/RoomNamePage.tsx +++ b/src/pages/settings/Report/RoomNamePage.tsx @@ -109,8 +109,7 @@ function RoomNamePage({ report, policy, reports }: RoomNamePageProps) { RoomNamePage.displayName = 'RoomNamePage'; -export default compose( - withReportOrNotFound(), +export default withReportOrNotFound()( withOnyx({ reports: { key: ONYXKEYS.COLLECTION.REPORT, @@ -118,6 +117,5 @@ export default compose( policy: { key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, }, - }), - -)(RoomNamePage); + })(RoomNamePage) +); diff --git a/src/pages/settings/Report/WriteCapabilityPage.tsx b/src/pages/settings/Report/WriteCapabilityPage.tsx index b4de7518f7ba..14526ba3c0ac 100644 --- a/src/pages/settings/Report/WriteCapabilityPage.tsx +++ b/src/pages/settings/Report/WriteCapabilityPage.tsx @@ -62,11 +62,10 @@ function WriteCapabilityPage({report, policy}: WriteCapabilityPageProps) { WriteCapabilityPage.displayName = 'WriteCapabilityPage'; -export default compose( - withReportOrNotFound(), +export default withReportOrNotFound()( withOnyx({ policy: { key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, }, - }), -)(WriteCapabilityPage); + })(WriteCapabilityPage), +); From 52670ab458bfa5ca6ef9354db8287c08915c4312 Mon Sep 17 00:00:00 2001 From: Shahe Shahinyan Date: Mon, 29 Jan 2024 21:31:52 +0400 Subject: [PATCH 132/249] Fix Ts error --- src/components/DisplayNames/DisplayNamesWithTooltip.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/DisplayNames/DisplayNamesWithTooltip.tsx b/src/components/DisplayNames/DisplayNamesWithTooltip.tsx index ce0ae7ddcf4f..1cacb0e20c5d 100644 --- a/src/components/DisplayNames/DisplayNamesWithTooltip.tsx +++ b/src/components/DisplayNames/DisplayNamesWithTooltip.tsx @@ -56,7 +56,7 @@ function DisplayNamesWithToolTip({shouldUseFullTitle, fullTitle, displayNamesWit > {shouldUseFullTitle ? ReportUtils.formatReportLastMessageText(fullTitle) - : displayNamesWithTooltips.map(({displayName, accountID, avatar, login}, index) => ( + : displayNamesWithTooltips?.map(({displayName, accountID, avatar, login}, index) => ( // eslint-disable-next-line react/no-array-index-key Date: Mon, 29 Jan 2024 21:41:25 +0400 Subject: [PATCH 133/249] Fix lint errors --- src/pages/settings/Report/RoomNamePage.tsx | 1 - src/pages/settings/Report/WriteCapabilityPage.tsx | 1 - 2 files changed, 2 deletions(-) diff --git a/src/pages/settings/Report/RoomNamePage.tsx b/src/pages/settings/Report/RoomNamePage.tsx index 1daf20013731..a3e24de4c325 100644 --- a/src/pages/settings/Report/RoomNamePage.tsx +++ b/src/pages/settings/Report/RoomNamePage.tsx @@ -10,7 +10,6 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton'; import RoomNameInput from '@components/RoomNameInput'; import ScreenWrapper from '@components/ScreenWrapper'; import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; diff --git a/src/pages/settings/Report/WriteCapabilityPage.tsx b/src/pages/settings/Report/WriteCapabilityPage.tsx index 14526ba3c0ac..f03415a2a56f 100644 --- a/src/pages/settings/Report/WriteCapabilityPage.tsx +++ b/src/pages/settings/Report/WriteCapabilityPage.tsx @@ -5,7 +5,6 @@ import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; -import compose from '@libs/compose'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import withReportOrNotFound from '@pages/home/report/withReportOrNotFound'; From fe014b76fefdb9c68718a587dfb223a6d4860fa3 Mon Sep 17 00:00:00 2001 From: Shahe Shahinyan Date: Mon, 29 Jan 2024 21:46:15 +0400 Subject: [PATCH 134/249] Run prettier --- src/libs/ErrorUtils.ts | 2 +- src/libs/ValidationUtils.ts | 2 +- .../Report/NotificationPreferencePage.tsx | 19 +++++------- .../settings/Report/ReportSettingsPage.tsx | 9 +++--- src/pages/settings/Report/RoomNamePage.tsx | 31 ++++++++++--------- .../settings/Report/WriteCapabilityPage.tsx | 18 +++++------ src/types/onyx/index.ts | 2 +- 7 files changed, 40 insertions(+), 43 deletions(-) diff --git a/src/libs/ErrorUtils.ts b/src/libs/ErrorUtils.ts index 9acda5ec722a..8eff66c10751 100644 --- a/src/libs/ErrorUtils.ts +++ b/src/libs/ErrorUtils.ts @@ -101,7 +101,7 @@ type ErrorsList = Record; * @param errors - An object containing current errors in the form * @param message - Message to assign to the inputID errors */ -function addErrorMessage(errors: ErrorsList, inputID?: string, message?: TKey | [TKey, Record] ) { +function addErrorMessage(errors: ErrorsList, inputID?: string, message?: TKey | [TKey, Record]) { if (!message || !inputID) { return; } diff --git a/src/libs/ValidationUtils.ts b/src/libs/ValidationUtils.ts index bc5caa92bbbd..af9e394e0b7f 100644 --- a/src/libs/ValidationUtils.ts +++ b/src/libs/ValidationUtils.ts @@ -3,10 +3,10 @@ import {URL_REGEX_WITH_REQUIRED_PROTOCOL} from 'expensify-common/lib/Url'; import isDate from 'lodash/isDate'; import isEmpty from 'lodash/isEmpty'; import isObject from 'lodash/isObject'; +import type {OnyxCollection} from 'react-native-onyx'; import CONST from '@src/CONST'; import type {Report} from '@src/types/onyx'; import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; -import type {OnyxCollection} from "react-native-onyx"; import * as CardUtils from './CardUtils'; import DateUtils from './DateUtils'; import * as LoginUtils from './LoginUtils'; diff --git a/src/pages/settings/Report/NotificationPreferencePage.tsx b/src/pages/settings/Report/NotificationPreferencePage.tsx index 8d3ed23f6845..c5fdaa25fac5 100644 --- a/src/pages/settings/Report/NotificationPreferencePage.tsx +++ b/src/pages/settings/Report/NotificationPreferencePage.tsx @@ -3,30 +3,29 @@ import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; +import useLocalize from '@hooks/useLocalize'; import * as ReportUtils from '@libs/ReportUtils'; import withReportOrNotFound from '@pages/home/report/withReportOrNotFound'; import type {WithReportOrNotFoundProps} from '@pages/home/report/withReportOrNotFound'; import * as ReportActions from '@userActions/Report'; import CONST from '@src/CONST'; -import useLocalize from "@hooks/useLocalize"; import type {Report} from '@src/types/onyx'; type NotificationPreferencePageProps = WithReportOrNotFoundProps & { report: Report; -} +}; -function NotificationPreferencePage({report}:NotificationPreferencePageProps) { - const {translate} = useLocalize() +function NotificationPreferencePage({report}: NotificationPreferencePageProps) { + const {translate} = useLocalize(); const shouldDisableNotificationPreferences = ReportUtils.isArchivedRoom(report); - const notificationPreferenceOptions = - Object.values(CONST.REPORT.NOTIFICATION_PREFERENCE).filter((pref) => pref !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) + const notificationPreferenceOptions = Object.values(CONST.REPORT.NOTIFICATION_PREFERENCE) + .filter((pref) => pref !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) .map((preference) => ({ value: preference, text: translate(`notificationPreferencesPage.notificationPreferences.${preference}`), keyForList: preference, isSelected: preference === report.notificationPreference, - }) - ); + })); return ( - ReportActions.updateNotificationPreference(report.reportID, report.notificationPreference, option.value, true, undefined, undefined, report) - } + onSelectRow={(option) => ReportActions.updateNotificationPreference(report.reportID, report.notificationPreference, option.value, true, undefined, undefined, report)} initiallyFocusedOptionKey={Object.values(notificationPreferenceOptions ?? {}).find((locale) => locale.isSelected)?.keyForList} /> diff --git a/src/pages/settings/Report/ReportSettingsPage.tsx b/src/pages/settings/Report/ReportSettingsPage.tsx index 7d4598d549ff..d6f3a30c9d63 100644 --- a/src/pages/settings/Report/ReportSettingsPage.tsx +++ b/src/pages/settings/Report/ReportSettingsPage.tsx @@ -22,16 +22,15 @@ import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type {Report} from '@src/types/onyx'; - type ReportSettingsPageProps = WithReportOrNotFoundProps & { - report: Report -} + report: Report; +}; function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); // The workspace the report is on, null if the user isn't a member of the workspace - const linkedWorkspace = useMemo(() => Object.values(policies ?? {}).find( (policy) => policy && policy.id === report.policyID), [policies, report.policyID]); + const linkedWorkspace = useMemo(() => Object.values(policies ?? {}).find((policy) => policy && policy.id === report.policyID), [policies, report.policyID]); const shouldDisableRename = useMemo(() => ReportUtils.shouldDisableRename(report, linkedWorkspace), [report, linkedWorkspace]); const isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report); @@ -87,7 +86,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { {roomNameLabel} , + reports: OnyxCollection; /** Policy of the report for which the name is being edited */ - policy: OnyxEntry -} - -type RoomNamePageProps = RoomNamePageOnyxProps & WithReportOrNotFoundProps & { - /** The room report for which the name is being edited */ - report: Report + policy: OnyxEntry; }; -function RoomNamePage({ report, policy, reports }: RoomNamePageProps) { +type RoomNamePageProps = RoomNamePageOnyxProps & + WithReportOrNotFoundProps & { + /** The room report for which the name is being edited */ + report: Report; + }; + +function RoomNamePage({report, policy, reports}: RoomNamePageProps) { const styles = useThemeStyles(); const roomNameInputRef = useRef(null); const isFocused = useIsFocused(); - const {translate} = useLocalize() + const {translate} = useLocalize(); const validate = useCallback( - (values: OnyxFormValuesFields) => { + (values: OnyxFormValuesFields) => { const errors = {}; // We should skip validation hence we return an empty errors and we skip Form submission on the onSubmit method @@ -116,5 +117,5 @@ export default withReportOrNotFound()( policy: { key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, }, - })(RoomNamePage) + })(RoomNamePage), ); diff --git a/src/pages/settings/Report/WriteCapabilityPage.tsx b/src/pages/settings/Report/WriteCapabilityPage.tsx index f03415a2a56f..49accdff8e13 100644 --- a/src/pages/settings/Report/WriteCapabilityPage.tsx +++ b/src/pages/settings/Report/WriteCapabilityPage.tsx @@ -5,6 +5,7 @@ import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; +import useLocalize from '@hooks/useLocalize'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import withReportOrNotFound from '@pages/home/report/withReportOrNotFound'; @@ -13,22 +14,21 @@ import * as ReportActions from '@userActions/Report'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import useLocalize from "@hooks/useLocalize"; -import type {Policy, Report} from "@src/types/onyx"; +import type {Policy, Report} from '@src/types/onyx'; type WriteCapabilityPageOnyxProps = { /** The policy object for the current route */ - policy: OnyxEntry; -}; - -type WriteCapabilityPageProps = WriteCapabilityPageOnyxProps & WithReportOrNotFoundProps & { - /** The report for which we are setting write capability */ - report: Report, + policy: OnyxEntry; }; +type WriteCapabilityPageProps = WriteCapabilityPageOnyxProps & + WithReportOrNotFoundProps & { + /** The report for which we are setting write capability */ + report: Report; + }; function WriteCapabilityPage({report, policy}: WriteCapabilityPageProps) { - const {translate} = useLocalize() + const {translate} = useLocalize(); const writeCapabilityOptions = Object.values(CONST.REPORT.WRITE_CAPABILITIES).map((value) => ({ value, text: translate(`writeCapabilityPage.writeCapability.${value}`), diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index a003b8d87e87..223681de1521 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -151,5 +151,5 @@ export type { IKnowATeacherForm, IntroSchoolPrincipalForm, PrivateNotesForm, - RoomNameForm + RoomNameForm, }; From 1609194b5ddec696afb3e8474c1a05784ddf3184 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Tue, 30 Jan 2024 12:43:31 +0800 Subject: [PATCH 135/249] fix rbr doesn't show --- src/libs/SidebarUtils.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index ec6abe1e48b2..ace326b533db 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -276,7 +276,7 @@ function getOptionData({ const result: ReportUtils.OptionData = { text: '', alternateText: null, - allReportErrors: undefined, + allReportErrors: OptionsListUtils.getAllReportErrors(report, reportActions), brickRoadIndicator: null, tooltipText: null, subtitle: null, @@ -318,7 +318,6 @@ 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); result.brickRoadIndicator = hasErrors || hasViolations ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''; result.ownerAccountID = report.ownerAccountID; result.managerID = report.managerID; From b871e06773a54c0d466c175ed23fc59986e53b9c Mon Sep 17 00:00:00 2001 From: Dylan Date: Tue, 30 Jan 2024 14:40:35 +0700 Subject: [PATCH 136/249] hide error if request is paid --- src/components/ReportActionItem/MoneyRequestView.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index 3121328138ee..dcf602a293d9 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -313,8 +313,8 @@ function MoneyRequestView({report, parentReport, parentReportActions, policyCate shouldShowRightIcon={canEditMerchant} titleStyle={styles.flex1} onPress={() => Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.MERCHANT))} - brickRoadIndicator={hasViolations('merchant') || (hasErrors && isEmptyMerchant && isPolicyExpenseChat) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} - error={hasErrors && isPolicyExpenseChat && isEmptyMerchant ? translate('common.error.enterMerchant') : ''} + brickRoadIndicator={hasViolations('merchant') || (!isSettled && !isCancelled && hasErrors && isEmptyMerchant && isPolicyExpenseChat) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + error={!isSettled && !isCancelled && hasErrors && isPolicyExpenseChat && isEmptyMerchant ? translate('common.error.enterMerchant') : ''} /> {canUseViolations && } From 56c81389396909c9c63a71d9e0a63a074634b5a8 Mon Sep 17 00:00:00 2001 From: Amarparab2024 <156438377+Amarparab2024@users.noreply.github.com> Date: Tue, 30 Jan 2024 13:54:07 +0530 Subject: [PATCH 137/249] @Amarparab2024 pass shouldEnableMaxHeight as prop --- src/pages/SearchPage.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/SearchPage.js b/src/pages/SearchPage.js index c420371f5a65..11b48645b57d 100755 --- a/src/pages/SearchPage.js +++ b/src/pages/SearchPage.js @@ -174,6 +174,7 @@ function SearchPage({betas, personalDetails, reports, isSearchingForReports, nav testID={SearchPage.displayName} onEntryTransitionEnd={updateOptions} navigation={navigation} + shouldEnableMaxHeight > {({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => ( <> From b0970b6357bd36ac23899ff00cc7e010130c86a5 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Tue, 30 Jan 2024 09:15:14 +0000 Subject: [PATCH 138/249] fix: remove params --- src/libs/PersonalDetailsUtils.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/libs/PersonalDetailsUtils.ts b/src/libs/PersonalDetailsUtils.ts index 945c0b581b16..2391874c83f3 100644 --- a/src/libs/PersonalDetailsUtils.ts +++ b/src/libs/PersonalDetailsUtils.ts @@ -203,10 +203,6 @@ function getEffectiveDisplayName(personalDetail?: PersonalDetails): string | und /** * Creates a new displayName for a user based on passed personal details or login. - * - * @param login - user's login - * @param passedPersonalDetails - details object with firstName and lastName - * @returns - The effective display name */ function createDisplayName(login: string, passedPersonalDetails: Pick | OnyxEntry): string { // If we have a number like +15857527441@expensify.sms then let's remove @expensify.sms and format it @@ -229,11 +225,6 @@ function createDisplayName(login: string, passedPersonalDetails: Pick Date: Tue, 30 Jan 2024 17:09:43 +0700 Subject: [PATCH 139/249] fix lint --- src/components/ReportActionItem/MoneyRequestView.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index dcf602a293d9..f8be53e101cc 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -313,7 +313,11 @@ function MoneyRequestView({report, parentReport, parentReportActions, policyCate shouldShowRightIcon={canEditMerchant} titleStyle={styles.flex1} onPress={() => Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.MERCHANT))} - brickRoadIndicator={hasViolations('merchant') || (!isSettled && !isCancelled && hasErrors && isEmptyMerchant && isPolicyExpenseChat) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + brickRoadIndicator={ + hasViolations('merchant') || (!isSettled && !isCancelled && hasErrors && isEmptyMerchant && isPolicyExpenseChat) + ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR + : '' + } error={!isSettled && !isCancelled && hasErrors && isPolicyExpenseChat && isEmptyMerchant ? translate('common.error.enterMerchant') : ''} /> {canUseViolations && } From cfc6291bb64e83a13ac93f4b191a92b6bfe52ea2 Mon Sep 17 00:00:00 2001 From: staszekscp Date: Tue, 30 Jan 2024 11:12:03 +0100 Subject: [PATCH 140/249] fix test --- tests/ui/UnreadIndicatorsTest.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js index e4d4d877f66b..6da7005bfb77 100644 --- a/tests/ui/UnreadIndicatorsTest.js +++ b/tests/ui/UnreadIndicatorsTest.js @@ -43,6 +43,7 @@ jest.mock('react-native/Libraries/LogBox/LogBox', () => ({ jest.mock('react-native-reanimated', () => ({ ...jest.requireActual('react-native-reanimated/mock'), createAnimatedPropAdapter: jest.fn, + useReducedMotion: jest.fn, })); /** From 1dd6943016b8eec1f5f9d07ae34b9dbc28a0475b Mon Sep 17 00:00:00 2001 From: someone-here Date: Tue, 30 Jan 2024 18:31:04 +0530 Subject: [PATCH 141/249] Fix conflict --- src/libs/API/parameters/AddWorkspaceRoomParams.ts | 2 +- src/libs/API/parameters/UpdateRoomDescriptionParams.ts | 6 ++++++ src/libs/API/parameters/UpdateWelcomeMessageParams.ts | 6 ------ src/libs/API/parameters/index.ts | 2 +- src/libs/API/types.ts | 4 ++-- src/libs/actions/Report.ts | 6 +++--- 6 files changed, 13 insertions(+), 13 deletions(-) create mode 100644 src/libs/API/parameters/UpdateRoomDescriptionParams.ts delete mode 100644 src/libs/API/parameters/UpdateWelcomeMessageParams.ts diff --git a/src/libs/API/parameters/AddWorkspaceRoomParams.ts b/src/libs/API/parameters/AddWorkspaceRoomParams.ts index f7cbff9565ef..847324586cb5 100644 --- a/src/libs/API/parameters/AddWorkspaceRoomParams.ts +++ b/src/libs/API/parameters/AddWorkspaceRoomParams.ts @@ -9,7 +9,7 @@ type AddWorkspaceRoomParams = { reportName?: string; visibility?: ValueOf; writeCapability?: WriteCapability; - welcomeMessage?: string; + description?: string; }; export default AddWorkspaceRoomParams; diff --git a/src/libs/API/parameters/UpdateRoomDescriptionParams.ts b/src/libs/API/parameters/UpdateRoomDescriptionParams.ts new file mode 100644 index 000000000000..4d78d07a9189 --- /dev/null +++ b/src/libs/API/parameters/UpdateRoomDescriptionParams.ts @@ -0,0 +1,6 @@ +type UpdateRoomDescriptionParams = { + reportID: string; + description: string; +}; + +export default UpdateRoomDescriptionParams; diff --git a/src/libs/API/parameters/UpdateWelcomeMessageParams.ts b/src/libs/API/parameters/UpdateWelcomeMessageParams.ts deleted file mode 100644 index a2d3b59fe3fa..000000000000 --- a/src/libs/API/parameters/UpdateWelcomeMessageParams.ts +++ /dev/null @@ -1,6 +0,0 @@ -type UpdateWelcomeMessageParams = { - reportID: string; - welcomeMessage: string; -}; - -export default UpdateWelcomeMessageParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 039398c0fbf6..58b1e4fa9d3c 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -83,7 +83,7 @@ export type {default as TogglePinnedChatParams} from './TogglePinnedChatParams'; export type {default as DeleteCommentParams} from './DeleteCommentParams'; export type {default as UpdateCommentParams} from './UpdateCommentParams'; export type {default as UpdateReportNotificationPreferenceParams} from './UpdateReportNotificationPreferenceParams'; -export type {default as UpdateWelcomeMessageParams} from './UpdateWelcomeMessageParams'; +export type {default as UpdateRoomDescriptionParams} from './UpdateRoomDescriptionParams'; export type {default as UpdateReportWriteCapabilityParams} from './UpdateReportWriteCapabilityParams'; export type {default as AddWorkspaceRoomParams} from './AddWorkspaceRoomParams'; export type {default as UpdatePolicyRoomNameParams} from './UpdatePolicyRoomNameParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index f58ebc30b4a2..203bac4eecc6 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -84,7 +84,7 @@ const WRITE_COMMANDS = { DELETE_COMMENT: 'DeleteComment', UPDATE_COMMENT: 'UpdateComment', UPDATE_REPORT_NOTIFICATION_PREFERENCE: 'UpdateReportNotificationPreference', - UPDATE_WELCOME_MESSAGE: 'UpdateWelcomeMessage', + UPDATE_ROOM_DESCRIPTION: 'UpdateRoomDescription', UPDATE_REPORT_WRITE_CAPABILITY: 'UpdateReportWriteCapability', ADD_WORKSPACE_ROOM: 'AddWorkspaceRoom', UPDATE_POLICY_ROOM_NAME: 'UpdatePolicyRoomName', @@ -192,7 +192,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.DELETE_COMMENT]: Parameters.DeleteCommentParams; [WRITE_COMMANDS.UPDATE_COMMENT]: Parameters.UpdateCommentParams; [WRITE_COMMANDS.UPDATE_REPORT_NOTIFICATION_PREFERENCE]: Parameters.UpdateReportNotificationPreferenceParams; - [WRITE_COMMANDS.UPDATE_WELCOME_MESSAGE]: Parameters.UpdateWelcomeMessageParams; + [WRITE_COMMANDS.UPDATE_ROOM_DESCRIPTION]: Parameters.UpdateRoomDescriptionParams; [WRITE_COMMANDS.UPDATE_REPORT_WRITE_CAPABILITY]: Parameters.UpdateReportWriteCapabilityParams; [WRITE_COMMANDS.ADD_WORKSPACE_ROOM]: Parameters.AddWorkspaceRoomParams; [WRITE_COMMANDS.UPDATE_POLICY_ROOM_NAME]: Parameters.UpdatePolicyRoomNameParams; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 40644276722a..dd8d6f4ed186 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -38,7 +38,7 @@ import type { UpdateReportNotificationPreferenceParams, UpdateReportPrivateNoteParams, UpdateReportWriteCapabilityParams, - UpdateWelcomeMessageParams, + UpdateRoomDescriptionParams, } from '@libs/API/parameters'; import {READ_COMMANDS, SIDE_EFFECT_REQUEST_COMMANDS, WRITE_COMMANDS} from '@libs/API/types'; import * as CollectionUtils from '@libs/CollectionUtils'; @@ -1486,9 +1486,9 @@ function updateDescription(reportID: string, previousValue: string, newValue: st }, ]; - const parameters: UpdateWelcomeMessageParams = {reportID, description: parsedDescription}; + const parameters: UpdateRoomDescriptionParams = {reportID, description: parsedDescription}; - API.write(WRITE_COMMANDS.UPDATE_WELCOME_MESSAGE, parameters, {optimisticData, failureData}); + API.write(WRITE_COMMANDS.UPDATE_ROOM_DESCRIPTION, parameters, {optimisticData, failureData}); Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(reportID)); } From e63e68c1f9945355a078dbc594395b90dbed3329 Mon Sep 17 00:00:00 2001 From: mkhutornyi Date: Tue, 30 Jan 2024 14:53:17 +0100 Subject: [PATCH 142/249] remove unused popover ref callbacks --- src/components/PopoverProvider/index.tsx | 6 ------ src/components/PopoverProvider/types.ts | 2 -- 2 files changed, 8 deletions(-) diff --git a/src/components/PopoverProvider/index.tsx b/src/components/PopoverProvider/index.tsx index a738d1f9798a..69728d7be126 100644 --- a/src/components/PopoverProvider/index.tsx +++ b/src/components/PopoverProvider/index.tsx @@ -27,9 +27,6 @@ function PopoverContextProvider(props: PopoverContextProps) { } activePopoverRef.current.close(); - if (activePopoverRef.current.onCloseCallback) { - activePopoverRef.current.onCloseCallback(); - } activePopoverRef.current = null; setIsOpen(false); }, []); @@ -107,9 +104,6 @@ function PopoverContextProvider(props: PopoverContextProps) { closePopover(activePopoverRef.current.anchorRef); } activePopoverRef.current = popoverParams; - if (popoverParams?.onOpenCallback) { - popoverParams.onOpenCallback(); - } setIsOpen(true); }, [closePopover], diff --git a/src/components/PopoverProvider/types.ts b/src/components/PopoverProvider/types.ts index 49705d7ea7a8..2a366ae2a712 100644 --- a/src/components/PopoverProvider/types.ts +++ b/src/components/PopoverProvider/types.ts @@ -16,8 +16,6 @@ type AnchorRef = { ref: RefObject; close: (anchorRef?: RefObject) => void; anchorRef: RefObject; - onOpenCallback?: () => void; - onCloseCallback?: () => void; }; export type {PopoverContextProps, PopoverContextValue, AnchorRef}; From 93dd12ac1376f002abc1a7a1f88507f62079e763 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 30 Jan 2024 14:58:17 +0100 Subject: [PATCH 143/249] 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 144/249] 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 7fa751411ff362974c35cd4e48b6116729e8c627 Mon Sep 17 00:00:00 2001 From: someone-here Date: Tue, 30 Jan 2024 21:55:46 +0530 Subject: [PATCH 145/249] Limit characters to 1024 --- src/CONST.ts | 4 ++++ src/pages/RoomDescriptionPage.tsx | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/CONST.ts b/src/CONST.ts index 02b8717d9644..cfab40253380 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -99,6 +99,10 @@ const CONST = { MAX_LENGTH: 40, }, + REPORT_DESCRIPTION: { + MAX_LENGTH: 1024, + }, + PULL_REQUEST_NUMBER, MERCHANT_NAME_MAX_LENGTH: 255, diff --git a/src/pages/RoomDescriptionPage.tsx b/src/pages/RoomDescriptionPage.tsx index c9615be6d77e..ac56076c809d 100644 --- a/src/pages/RoomDescriptionPage.tsx +++ b/src/pages/RoomDescriptionPage.tsx @@ -6,6 +6,7 @@ import type {OnyxCollection} from 'react-native-onyx'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; +import type {OnyxFormValuesFields} from '@components/Form/types'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; @@ -21,6 +22,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; +import type {Errors} from '@src/types/onyx/OnyxCommon'; type RoomDescriptionPageProps = { /** Policy for the current report */ @@ -61,6 +63,14 @@ function RoomDescriptionPage({report, policies}: RoomDescriptionPageProps) { }, []), ); + const limitCharacters = (values: OnyxFormValuesFields) => { + const errors: Errors = {}; + if (String(values.reportDescription).length > CONST.REPORT_DESCRIPTION.MAX_LENGTH) { + errors['reportDescription'] = translate('common.error.characterLimit', {limit: CONST.REPORT_DESCRIPTION.MAX_LENGTH}); + } + return errors; + }; + return ( {translate('reportDescriptionPage.explainerText')} From 2efe2db14d72427c7d594843b434ae3f6f23b0d5 Mon Sep 17 00:00:00 2001 From: someone-here Date: Tue, 30 Jan 2024 22:02:41 +0530 Subject: [PATCH 146/249] Fix lint --- src/pages/RoomDescriptionPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/RoomDescriptionPage.tsx b/src/pages/RoomDescriptionPage.tsx index ac56076c809d..969d19f58a67 100644 --- a/src/pages/RoomDescriptionPage.tsx +++ b/src/pages/RoomDescriptionPage.tsx @@ -66,7 +66,7 @@ function RoomDescriptionPage({report, policies}: RoomDescriptionPageProps) { const limitCharacters = (values: OnyxFormValuesFields) => { const errors: Errors = {}; if (String(values.reportDescription).length > CONST.REPORT_DESCRIPTION.MAX_LENGTH) { - errors['reportDescription'] = translate('common.error.characterLimit', {limit: CONST.REPORT_DESCRIPTION.MAX_LENGTH}); + errors.reportDescription = translate('common.error.characterLimit', {limit: CONST.REPORT_DESCRIPTION.MAX_LENGTH}); } return errors; }; From 71dda56c541df3b029175f7d9644826f318b2e34 Mon Sep 17 00:00:00 2001 From: someone-here Date: Tue, 30 Jan 2024 23:23:03 +0530 Subject: [PATCH 147/249] Improvement of header for small screens --- .../DisplayNames/DisplayNamesWithTooltip.tsx | 3 +- .../DisplayNamesWithoutTooltip.tsx | 7 +++- src/components/DisplayNames/index.tsx | 4 +- src/components/DisplayNames/types.ts | 4 ++ src/pages/home/HeaderView.js | 40 +++++++------------ 5 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/components/DisplayNames/DisplayNamesWithTooltip.tsx b/src/components/DisplayNames/DisplayNamesWithTooltip.tsx index ce0ae7ddcf4f..77396b4d8999 100644 --- a/src/components/DisplayNames/DisplayNamesWithTooltip.tsx +++ b/src/components/DisplayNames/DisplayNamesWithTooltip.tsx @@ -11,7 +11,7 @@ import type DisplayNamesProps from './types'; type HTMLElementWithText = HTMLElement & RNText; -function DisplayNamesWithToolTip({shouldUseFullTitle, fullTitle, displayNamesWithTooltips, textStyles = [], numberOfLines = 1}: DisplayNamesProps) { +function DisplayNamesWithToolTip({shouldUseFullTitle, fullTitle, displayNamesWithTooltips, textStyles = [], numberOfLines = 1, AdditionalComponent}: DisplayNamesProps) { const styles = useThemeStyles(); const containerRef = useRef(null); const childRefs = useRef([]); @@ -72,6 +72,7 @@ function DisplayNamesWithToolTip({shouldUseFullTitle, fullTitle, displayNamesWit {index < displayNamesWithTooltips.length - 1 && } ))} + {AdditionalComponent && } {Boolean(isEllipsisActive) && ( diff --git a/src/components/DisplayNames/DisplayNamesWithoutTooltip.tsx b/src/components/DisplayNames/DisplayNamesWithoutTooltip.tsx index 177bdb6a9fc4..e3a2dc503666 100644 --- a/src/components/DisplayNames/DisplayNamesWithoutTooltip.tsx +++ b/src/components/DisplayNames/DisplayNamesWithoutTooltip.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import type {ComponentType} from 'react'; import type {StyleProp, TextStyle} from 'react-native'; import Text from '@components/Text'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -12,9 +13,12 @@ type DisplayNamesWithoutTooltipProps = { /** Number of lines before wrapping */ numberOfLines?: number; + + /** Additional component to render after the text */ + AdditionalComponent?: ComponentType; }; -function DisplayNamesWithoutTooltip({textStyles = [], numberOfLines = 1, fullTitle = ''}: DisplayNamesWithoutTooltipProps) { +function DisplayNamesWithoutTooltip({textStyles = [], numberOfLines = 1, fullTitle = '', AdditionalComponent}: DisplayNamesWithoutTooltipProps) { const styles = useThemeStyles(); return ( {fullTitle} + {AdditionalComponent && } ); } diff --git a/src/components/DisplayNames/index.tsx b/src/components/DisplayNames/index.tsx index 155193368cc5..73439ea02396 100644 --- a/src/components/DisplayNames/index.tsx +++ b/src/components/DisplayNames/index.tsx @@ -4,7 +4,7 @@ import DisplayNamesWithoutTooltip from './DisplayNamesWithoutTooltip'; import DisplayNamesWithToolTip from './DisplayNamesWithTooltip'; import type DisplayNamesProps from './types'; -function DisplayNames({fullTitle, tooltipEnabled, textStyles, numberOfLines, shouldUseFullTitle, displayNamesWithTooltips}: DisplayNamesProps) { +function DisplayNames({fullTitle, tooltipEnabled, textStyles, numberOfLines, shouldUseFullTitle, displayNamesWithTooltips, AdditionalComponent}: DisplayNamesProps) { const {translate} = useLocalize(); const title = fullTitle || translate('common.hidden'); @@ -14,6 +14,7 @@ function DisplayNames({fullTitle, tooltipEnabled, textStyles, numberOfLines, sho textStyles={textStyles} numberOfLines={numberOfLines} fullTitle={title} + AdditionalComponent={AdditionalComponent} /> ); } @@ -25,6 +26,7 @@ function DisplayNames({fullTitle, tooltipEnabled, textStyles, numberOfLines, sho displayNamesWithTooltips={displayNamesWithTooltips} textStyles={textStyles} numberOfLines={numberOfLines} + AdditionalComponent={AdditionalComponent} /> ); } diff --git a/src/components/DisplayNames/types.ts b/src/components/DisplayNames/types.ts index 2e6f36d5cc07..26bd263bdbd8 100644 --- a/src/components/DisplayNames/types.ts +++ b/src/components/DisplayNames/types.ts @@ -1,3 +1,4 @@ +import type {ComponentType} from 'react'; import type {StyleProp, TextStyle} from 'react-native'; import type {AvatarSource} from '@libs/UserUtils'; @@ -39,6 +40,9 @@ type DisplayNamesProps = { /** If the full title needs to be displayed */ shouldUseFullTitle?: boolean; + + /** Additional component to display after the display names */ + AdditionalComponent?: ComponentType; }; export default DisplayNamesProps; diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index 611eab5375bd..bc7ec0abc19d 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -278,33 +278,23 @@ function HeaderView(props) { /> )} - - - {!_.isEmpty(policyName) && - !_.isEmpty(reportDescription) && ( // code for the policyName display + + !_.isEmpty(policyName) && + !_.isEmpty(reportDescription) && ( <> - - {translate('threads.in')} - - - {policyName} - + {translate('threads.in')} + {policyName} - )} - + ) + } + /> {!_.isEmpty(parentNavigationSubtitleData) && ( Date: Tue, 30 Jan 2024 23:33:22 +0530 Subject: [PATCH 148/249] Add offline pattern --- src/libs/actions/Report.ts | 13 ++++++++++--- src/pages/ReportDetailsPage.js | 19 +++++++++++-------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index dd8d6f4ed186..ccc4c6ebc065 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -1475,20 +1475,27 @@ function updateDescription(reportID: string, previousValue: string, newValue: st { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, - value: {description: parsedDescription}, + value: {description: parsedDescription, pendingFields: {description: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}}, }, ]; const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, - value: {description: previousValue}, + value: {description: previousValue, pendingFields: {description: null}}, + }, + ]; + const successData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: {pendingFields: {description: null}}, }, ]; const parameters: UpdateRoomDescriptionParams = {reportID, description: parsedDescription}; - API.write(WRITE_COMMANDS.UPDATE_ROOM_DESCRIPTION, parameters, {optimisticData, failureData}); + API.write(WRITE_COMMANDS.UPDATE_ROOM_DESCRIPTION, parameters, {optimisticData, failureData, successData}); Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(reportID)); } diff --git a/src/pages/ReportDetailsPage.js b/src/pages/ReportDetailsPage.js index 55ab85e8c3e5..effc51a9a2ec 100644 --- a/src/pages/ReportDetailsPage.js +++ b/src/pages/ReportDetailsPage.js @@ -10,6 +10,7 @@ import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import MultipleAvatars from '@components/MultipleAvatars'; +import OfflineWithFeedback from '@components/OfflineWithFeedback'; import {withNetwork} from '@components/OnyxProvider'; import ParentNavigationSubtitle from '@components/ParentNavigationSubtitle'; import participantPropTypes from '@components/participantPropTypes'; @@ -242,14 +243,16 @@ function ReportDetailsPage(props) { {shouldShowReportDescription && ( - Navigation.navigate(ROUTES.REPORT_DESCRIPTION.getRoute(props.report.reportID))} - /> + + Navigation.navigate(ROUTES.REPORT_DESCRIPTION.getRoute(props.report.reportID))} + /> + )} {_.map(menuItems, (item) => { const brickRoadIndicator = From b33dae63c9c4233b24f9f76f6431a775d7546b8c Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 30 Jan 2024 22:32:12 +0100 Subject: [PATCH 149/249] 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 414136a8d9e7299b3cc6217893bc98e37307f2a5 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Wed, 31 Jan 2024 11:15:51 +0700 Subject: [PATCH 150/249] 34612 --- ...oraryForRefactorRequestConfirmationList.js | 47 +++++++++---------- .../iou/request/step/IOURequestStepTag.js | 4 +- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js index bdd3fa98672f..98be34c41bf9 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -810,30 +810,29 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ rightLabel={canUseViolations && Boolean(policy.requiresCategory) ? translate('common.required') : ''} /> )} - {shouldShowTags || - (true && ( - - Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_TAG.getRoute( - CONST.IOU.ACTION.CREATE, - iouType, - transaction.transactionID, - reportID, - Navigation.getActiveRouteWithoutParams(), - ), - ) - } - style={[styles.moneyRequestMenuItem]} - disabled={didConfirm} - interactive={!isReadOnly} - rightLabel={canUseViolations && Boolean(policy.requiresTag) ? translate('common.required') : ''} - /> - ))} + {shouldShowTags && ( + + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_TAG.getRoute( + CONST.IOU.ACTION.CREATE, + iouType, + transaction.transactionID, + reportID, + Navigation.getActiveRouteWithoutParams(), + ), + ) + } + style={[styles.moneyRequestMenuItem]} + disabled={didConfirm} + interactive={!isReadOnly} + rightLabel={canUseViolations && lodashGet(policy, 'requiresTag', false) ? translate('common.required') : ''} + /> + )} {shouldShowTax && ( { Navigation.goBack(backTo || ROUTES.HOME); @@ -68,7 +68,7 @@ function IOURequestStepTag({ const updateTag = (selectedTag) => { const isSelectedTag = selectedTag.searchText === tag; const updatedTag = !isSelectedTag ? selectedTag.searchText : ''; - if (isEditting) { + if (isEditing) { IOU.updateMoneyRequestTag(transactionID, report.reportID, updatedTag); Navigation.dismissModal(); return; From 17f3d4844c2db4ca8a52d8e8bc990be39aaba1e1 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Wed, 31 Jan 2024 14:21:08 +0700 Subject: [PATCH 151/249] fix lint --- .../MoneyTemporaryForRefactorRequestConfirmationList.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js index 98be34c41bf9..122001861827 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -818,13 +818,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ numberOfLinesTitle={2} onPress={() => Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_TAG.getRoute( - CONST.IOU.ACTION.CREATE, - iouType, - transaction.transactionID, - reportID, - Navigation.getActiveRouteWithoutParams(), - ), + ROUTES.MONEY_REQUEST_STEP_TAG.getRoute(CONST.IOU.ACTION.CREATE, iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams()), ) } style={[styles.moneyRequestMenuItem]} From bb2886307eb4f2276df271b246a1fabd52bcd04a Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 31 Jan 2024 16:38:02 +0700 Subject: [PATCH 152/249] fix: 34961 --- .../SelectionList/RadioListItem.tsx | 31 ++++---------- src/components/SelectionList/UserListItem.tsx | 31 ++++---------- .../TextWithTooltip/index.native.tsx | 18 ++++++++ src/components/TextWithTooltip/index.tsx | 41 +++++++++++++++++++ src/components/TextWithTooltip/types.ts | 9 ++++ 5 files changed, 86 insertions(+), 44 deletions(-) create mode 100644 src/components/TextWithTooltip/index.native.tsx create mode 100644 src/components/TextWithTooltip/index.tsx create mode 100644 src/components/TextWithTooltip/types.ts diff --git a/src/components/SelectionList/RadioListItem.tsx b/src/components/SelectionList/RadioListItem.tsx index 769eaa80df4b..ca0ae859c3ad 100644 --- a/src/components/SelectionList/RadioListItem.tsx +++ b/src/components/SelectionList/RadioListItem.tsx @@ -1,7 +1,6 @@ import React from 'react'; import {View} from 'react-native'; -import Text from '@components/Text'; -import Tooltip from '@components/Tooltip'; +import TextWithTooltip from '@components/TextWithTooltip'; import useThemeStyles from '@hooks/useThemeStyles'; import type {RadioListItemProps} from './types'; @@ -10,30 +9,18 @@ function RadioListItem({item, showTooltip, textStyles, alternateTextStyles}: Rad return ( - - - {item.text} - - + textStyles={textStyles} + /> {!!item.alternateText && ( - - - {item.alternateText} - - + textStyles={alternateTextStyles} + /> )} ); diff --git a/src/components/SelectionList/UserListItem.tsx b/src/components/SelectionList/UserListItem.tsx index 3c973ad0bbea..11ef03bec33d 100644 --- a/src/components/SelectionList/UserListItem.tsx +++ b/src/components/SelectionList/UserListItem.tsx @@ -1,8 +1,7 @@ import React from 'react'; import {View} from 'react-native'; import SubscriptAvatar from '@components/SubscriptAvatar'; -import Text from '@components/Text'; -import Tooltip from '@components/Tooltip'; +import TextWithTooltip from '@components/TextWithTooltip'; import useThemeStyles from '@hooks/useThemeStyles'; import type {UserListItemProps} from './types'; @@ -18,29 +17,17 @@ function UserListItem({item, textStyles, alternateTextStyles, showTooltip, style /> )} - - - {item.text} - - + textStyles={[textStyles, style]} + /> {!!item.alternateText && ( - - - {item.alternateText} - - + textStyles={[alternateTextStyles, style]} + /> )} {!!item.rightElement && item.rightElement} diff --git a/src/components/TextWithTooltip/index.native.tsx b/src/components/TextWithTooltip/index.native.tsx new file mode 100644 index 000000000000..f8013ae00e4c --- /dev/null +++ b/src/components/TextWithTooltip/index.native.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import Text from '@components/Text'; +import type TextWithTooltipProps from './types'; + +function TextWithTooltip({text, textStyles}: TextWithTooltipProps) { + return ( + + {text} + + ); +} + +TextWithTooltip.displayName = 'TextWithTooltip'; + +export default TextWithTooltip; diff --git a/src/components/TextWithTooltip/index.tsx b/src/components/TextWithTooltip/index.tsx new file mode 100644 index 000000000000..fd202db8de64 --- /dev/null +++ b/src/components/TextWithTooltip/index.tsx @@ -0,0 +1,41 @@ +import React, {useState} from 'react'; +import Text from '@components/Text'; +import Tooltip from '@components/Tooltip'; +import type TextWithTooltipProps from './types'; + +type LayoutChangeEvent = { + target: HTMLElement; +}; + +function TextWithTooltip({text, shouldShowTooltip, textStyles}: TextWithTooltipProps) { + const [showTooltip, setShowTooltip] = useState(false); + + return ( + + { + const target = (e.nativeEvent as unknown as LayoutChangeEvent).target; + if (!shouldShowTooltip) { + return; + } + if (target.scrollWidth > target.offsetWidth) { + setShowTooltip(true); + return; + } + setShowTooltip(false); + }} + > + {text} + + + ); +} + +TextWithTooltip.displayName = 'TextWithTooltip'; + +export default TextWithTooltip; diff --git a/src/components/TextWithTooltip/types.ts b/src/components/TextWithTooltip/types.ts new file mode 100644 index 000000000000..80517b0b2acf --- /dev/null +++ b/src/components/TextWithTooltip/types.ts @@ -0,0 +1,9 @@ +import type {StyleProp, TextStyle} from 'react-native'; + +type TextWithTooltipProps = { + text: string; + shouldShowTooltip: boolean; + textStyles?: StyleProp; +}; + +export default TextWithTooltipProps; From 7e6042dbc70a468a9fdf19bd467500f5a40bdb13 Mon Sep 17 00:00:00 2001 From: staszekscp Date: Wed, 31 Jan 2024 12:37:01 +0100 Subject: [PATCH 153/249] rename const money_report --- src/CONST.ts | 2 +- src/styles/utils/index.ts | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 86be7997b25c..0bb24c68928e 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -147,7 +147,7 @@ const CONST = { CONTAINER_MINHEIGHT: 500, VIEW_HEIGHT: 275, }, - MONEY_REPORT: { + MONEY_OR_TASK_REPORT: { SMALL_SCREEN: { IMAGE_HEIGHT: 300, CONTAINER_MINHEIGHT: 280, diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts index a0f8f52927b9..79e3809108b4 100644 --- a/src/styles/utils/index.ts +++ b/src/styles/utils/index.ts @@ -699,8 +699,8 @@ function getHorizontalStackedOverlayAvatarStyle(oneAvatarSize: AvatarSize, oneAv /** * Gets the correct size for the empty state background image based on screen dimensions */ -function getReportWelcomeBackgroundImageStyle(isSmallScreenWidth: boolean, isMoneyReport = false): ImageStyle { - const emptyStateBackground = isMoneyReport ? CONST.EMPTY_STATE_BACKGROUND.MONEY_REPORT : CONST.EMPTY_STATE_BACKGROUND; +function getReportWelcomeBackgroundImageStyle(isSmallScreenWidth: boolean, isMoneyOrTaskReport = false): ImageStyle { + const emptyStateBackground = isMoneyOrTaskReport ? CONST.EMPTY_STATE_BACKGROUND.MONEY_OR_TASK_REPORT : CONST.EMPTY_STATE_BACKGROUND; if (isSmallScreenWidth) { return { @@ -720,8 +720,8 @@ function getReportWelcomeBackgroundImageStyle(isSmallScreenWidth: boolean, isMon /** * Gets the correct top margin size for the chat welcome message based on screen dimensions */ -function getReportWelcomeTopMarginStyle(isSmallScreenWidth: boolean, isMoneyReport = false): ViewStyle { - const emptyStateBackground = isMoneyReport ? CONST.EMPTY_STATE_BACKGROUND.MONEY_REPORT : CONST.EMPTY_STATE_BACKGROUND; +function getReportWelcomeTopMarginStyle(isSmallScreenWidth: boolean, isMoneyOrTaskReport = false): ViewStyle { + const emptyStateBackground = isMoneyOrTaskReport ? CONST.EMPTY_STATE_BACKGROUND.MONEY_OR_TASK_REPORT : CONST.EMPTY_STATE_BACKGROUND; if (isSmallScreenWidth) { return { marginTop: emptyStateBackground.SMALL_SCREEN.VIEW_HEIGHT, @@ -754,8 +754,8 @@ function getLineHeightStyle(lineHeight: number): TextStyle { /** * Gets the correct size for the empty state container based on screen dimensions */ -function getReportWelcomeContainerStyle(isSmallScreenWidth: boolean, isMoneyReport = false): ViewStyle { - const emptyStateBackground = isMoneyReport ? CONST.EMPTY_STATE_BACKGROUND.MONEY_REPORT : CONST.EMPTY_STATE_BACKGROUND; +function getReportWelcomeContainerStyle(isSmallScreenWidth: boolean, isMoneyOrTaskReport = false): ViewStyle { + const emptyStateBackground = isMoneyOrTaskReport ? CONST.EMPTY_STATE_BACKGROUND.MONEY_OR_TASK_REPORT : CONST.EMPTY_STATE_BACKGROUND; if (isSmallScreenWidth) { return { minHeight: emptyStateBackground.SMALL_SCREEN.CONTAINER_MINHEIGHT, From c2ad5db8ab4eeff30cb0569d68dd905138ad0864 Mon Sep 17 00:00:00 2001 From: someone-here Date: Wed, 31 Jan 2024 17:25:21 +0530 Subject: [PATCH 154/249] Fix new task description --- src/libs/Navigation/linkingConfig.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/Navigation/linkingConfig.ts b/src/libs/Navigation/linkingConfig.ts index d6e0aeabf5d6..df0ee800ec38 100644 --- a/src/libs/Navigation/linkingConfig.ts +++ b/src/libs/Navigation/linkingConfig.ts @@ -337,6 +337,7 @@ const linkingConfig: LinkingOptions = { [SCREENS.NEW_TASK.TASK_SHARE_DESTINATION_SELECTOR]: ROUTES.NEW_TASK_SHARE_DESTINATION, [SCREENS.NEW_TASK.DETAILS]: ROUTES.NEW_TASK_DETAILS, [SCREENS.NEW_TASK.TITLE]: ROUTES.NEW_TASK_TITLE, + [SCREENS.NEW_TASK.DESCRIPTION]: ROUTES.NEW_TASK_DESCRIPTION, }, }, [SCREENS.RIGHT_MODAL.TEACHERS_UNITE]: { From 52db819f43e7e1ecc5eda1a574d9d52d7ae20849 Mon Sep 17 00:00:00 2001 From: someone-here Date: Wed, 31 Jan 2024 17:29:54 +0530 Subject: [PATCH 155/249] hide description menuItem for tasks --- src/pages/ReportDetailsPage.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/ReportDetailsPage.js b/src/pages/ReportDetailsPage.js index effc51a9a2ec..6db4cf4cf3b7 100644 --- a/src/pages/ReportDetailsPage.js +++ b/src/pages/ReportDetailsPage.js @@ -68,11 +68,12 @@ function ReportDetailsPage(props) { const shouldUseFullTitle = useMemo(() => ReportUtils.shouldUseFullTitleToDisplay(props.report), [props.report]); const isChatRoom = useMemo(() => ReportUtils.isChatRoom(props.report), [props.report]); const isThread = useMemo(() => ReportUtils.isChatThread(props.report), [props.report]); + const isTask = useMemo(() => ReportUtils.isTaskReport(props.report), [props.report]); const isUserCreatedPolicyRoom = useMemo(() => ReportUtils.isUserCreatedPolicyRoom(props.report), [props.report]); const isArchivedRoom = useMemo(() => ReportUtils.isArchivedRoom(props.report), [props.report]); const isMoneyRequestReport = useMemo(() => ReportUtils.isMoneyRequestReport(props.report), [props.report]); const canEditReportDescription = useMemo(() => ReportUtils.canEditReportDescription(props.report, policy), [props.report, policy]); - const shouldShowReportDescription = canEditReportDescription || !_.isEmpty(props.report.description); + const shouldShowReportDescription = !isTask && (canEditReportDescription || !_.isEmpty(props.report.description)); // eslint-disable-next-line react-hooks/exhaustive-deps -- policy is a dependency because `getChatRoomSubtitle` calls `getPolicyName` which in turn retrieves the value from the `policy` value stored in Onyx const chatRoomSubtitle = useMemo(() => ReportUtils.getChatRoomSubtitle(props.report), [props.report, policy]); From 0dffd611153236052abf098521b8bc8c0c344f98 Mon Sep 17 00:00:00 2001 From: someone-here Date: Wed, 31 Jan 2024 17:47:18 +0530 Subject: [PATCH 156/249] rename AdditionalComponent -> renderAdditionalText --- .../DisplayNames/DisplayNamesWithTooltip.tsx | 4 ++-- .../DisplayNamesWithoutTooltip.tsx | 8 +++---- src/components/DisplayNames/index.tsx | 6 ++--- src/components/DisplayNames/types.ts | 4 ++-- src/pages/home/HeaderView.js | 22 +++++++++++-------- 5 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/components/DisplayNames/DisplayNamesWithTooltip.tsx b/src/components/DisplayNames/DisplayNamesWithTooltip.tsx index 77396b4d8999..6efb256123a4 100644 --- a/src/components/DisplayNames/DisplayNamesWithTooltip.tsx +++ b/src/components/DisplayNames/DisplayNamesWithTooltip.tsx @@ -11,7 +11,7 @@ import type DisplayNamesProps from './types'; type HTMLElementWithText = HTMLElement & RNText; -function DisplayNamesWithToolTip({shouldUseFullTitle, fullTitle, displayNamesWithTooltips, textStyles = [], numberOfLines = 1, AdditionalComponent}: DisplayNamesProps) { +function DisplayNamesWithToolTip({shouldUseFullTitle, fullTitle, displayNamesWithTooltips, textStyles = [], numberOfLines = 1, renderAdditionalText}: DisplayNamesProps) { const styles = useThemeStyles(); const containerRef = useRef(null); const childRefs = useRef([]); @@ -72,7 +72,7 @@ function DisplayNamesWithToolTip({shouldUseFullTitle, fullTitle, displayNamesWit {index < displayNamesWithTooltips.length - 1 && } ))} - {AdditionalComponent && } + {renderAdditionalText?.()} {Boolean(isEllipsisActive) && ( diff --git a/src/components/DisplayNames/DisplayNamesWithoutTooltip.tsx b/src/components/DisplayNames/DisplayNamesWithoutTooltip.tsx index e3a2dc503666..a636df025523 100644 --- a/src/components/DisplayNames/DisplayNamesWithoutTooltip.tsx +++ b/src/components/DisplayNames/DisplayNamesWithoutTooltip.tsx @@ -14,11 +14,11 @@ type DisplayNamesWithoutTooltipProps = { /** Number of lines before wrapping */ numberOfLines?: number; - /** Additional component to render after the text */ - AdditionalComponent?: ComponentType; + /** Additional Text component to render after the displayNames */ + renderAdditionalText?: () => React.ReactNode; }; -function DisplayNamesWithoutTooltip({textStyles = [], numberOfLines = 1, fullTitle = '', AdditionalComponent}: DisplayNamesWithoutTooltipProps) { +function DisplayNamesWithoutTooltip({textStyles = [], numberOfLines = 1, fullTitle = '', renderAdditionalText}: DisplayNamesWithoutTooltipProps) { const styles = useThemeStyles(); return ( {fullTitle} - {AdditionalComponent && } + {renderAdditionalText?.()} ); } diff --git a/src/components/DisplayNames/index.tsx b/src/components/DisplayNames/index.tsx index 73439ea02396..e85e068976f9 100644 --- a/src/components/DisplayNames/index.tsx +++ b/src/components/DisplayNames/index.tsx @@ -4,7 +4,7 @@ import DisplayNamesWithoutTooltip from './DisplayNamesWithoutTooltip'; import DisplayNamesWithToolTip from './DisplayNamesWithTooltip'; import type DisplayNamesProps from './types'; -function DisplayNames({fullTitle, tooltipEnabled, textStyles, numberOfLines, shouldUseFullTitle, displayNamesWithTooltips, AdditionalComponent}: DisplayNamesProps) { +function DisplayNames({fullTitle, tooltipEnabled, textStyles, numberOfLines, shouldUseFullTitle, displayNamesWithTooltips, renderAdditionalText}: DisplayNamesProps) { const {translate} = useLocalize(); const title = fullTitle || translate('common.hidden'); @@ -14,7 +14,7 @@ function DisplayNames({fullTitle, tooltipEnabled, textStyles, numberOfLines, sho textStyles={textStyles} numberOfLines={numberOfLines} fullTitle={title} - AdditionalComponent={AdditionalComponent} + renderAdditionalText={renderAdditionalText} /> ); } @@ -26,7 +26,7 @@ function DisplayNames({fullTitle, tooltipEnabled, textStyles, numberOfLines, sho displayNamesWithTooltips={displayNamesWithTooltips} textStyles={textStyles} numberOfLines={numberOfLines} - AdditionalComponent={AdditionalComponent} + renderAdditionalText={renderAdditionalText} /> ); } diff --git a/src/components/DisplayNames/types.ts b/src/components/DisplayNames/types.ts index 26bd263bdbd8..69be2f01a530 100644 --- a/src/components/DisplayNames/types.ts +++ b/src/components/DisplayNames/types.ts @@ -41,8 +41,8 @@ type DisplayNamesProps = { /** If the full title needs to be displayed */ shouldUseFullTitle?: boolean; - /** Additional component to display after the display names */ - AdditionalComponent?: ComponentType; + /** Additional Text component to render after the displayNames */ + renderAdditionalText?: () => React.ReactNode; }; export default DisplayNamesProps; diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index bc7ec0abc19d..56839abb3e14 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -187,6 +187,18 @@ function HeaderView(props) { /> ); + const renderAdditionalText = () => { + if (_.isEmpty(policyName) || _.isEmpty(reportDescription)) { + return null; + } + return ( + <> + {translate('threads.in')} + {policyName} + + ); + }; + threeDotMenuItems.push(HeaderUtils.getPinMenuItem(props.report)); if (isConcierge && props.guideCalendarLink) { @@ -285,15 +297,7 @@ function HeaderView(props) { numberOfLines={1} textStyles={[styles.headerText, styles.pre]} shouldUseFullTitle={isChatRoom || isPolicyExpenseChat || isChatThread || isTaskReport} - AdditionalComponent={() => - !_.isEmpty(policyName) && - !_.isEmpty(reportDescription) && ( - <> - {translate('threads.in')} - {policyName} - - ) - } + renderAdditionalText={renderAdditionalText} /> {!_.isEmpty(parentNavigationSubtitleData) && ( Date: Wed, 31 Jan 2024 17:48:37 +0530 Subject: [PATCH 157/249] Fix lint --- src/components/DisplayNames/DisplayNamesWithoutTooltip.tsx | 1 - src/components/DisplayNames/types.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/components/DisplayNames/DisplayNamesWithoutTooltip.tsx b/src/components/DisplayNames/DisplayNamesWithoutTooltip.tsx index a636df025523..c66d1698bbd6 100644 --- a/src/components/DisplayNames/DisplayNamesWithoutTooltip.tsx +++ b/src/components/DisplayNames/DisplayNamesWithoutTooltip.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import type {ComponentType} from 'react'; import type {StyleProp, TextStyle} from 'react-native'; import Text from '@components/Text'; import useThemeStyles from '@hooks/useThemeStyles'; diff --git a/src/components/DisplayNames/types.ts b/src/components/DisplayNames/types.ts index 69be2f01a530..d76c8b671975 100644 --- a/src/components/DisplayNames/types.ts +++ b/src/components/DisplayNames/types.ts @@ -1,4 +1,3 @@ -import type {ComponentType} from 'react'; import type {StyleProp, TextStyle} from 'react-native'; import type {AvatarSource} from '@libs/UserUtils'; From d4f9e1ec591b9ee4ab68bc9caf29643fcbb00eee Mon Sep 17 00:00:00 2001 From: someone-here Date: Wed, 31 Jan 2024 18:10:32 +0530 Subject: [PATCH 158/249] Fix header --- src/pages/home/HeaderView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index 56839abb3e14..ab7021542f14 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -188,7 +188,7 @@ function HeaderView(props) { ); const renderAdditionalText = () => { - if (_.isEmpty(policyName) || _.isEmpty(reportDescription)) { + if (_.isEmpty(policyName) || _.isEmpty(reportDescription) || !_.isEmpty(parentNavigationSubtitleData)) { return null; } return ( From 2a7f09799678ba6f9d6f7b4b54011bfb64e8b856 Mon Sep 17 00:00:00 2001 From: someone-here Date: Wed, 31 Jan 2024 18:31:09 +0530 Subject: [PATCH 159/249] Make in lowercase --- src/languages/en.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 73be93af5a93..e8fdd4689b31 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1950,7 +1950,7 @@ export default { replies: 'Replies', reply: 'Reply', from: 'From', - in: 'In', + in: 'in', parentNavigationSummary: ({rootReportName, workspaceName}: ParentNavigationSummaryParams) => `From ${rootReportName}${workspaceName ? ` in ${workspaceName}` : ''}`, }, qrCodes: { From c614c34627680953444272448282666fdaacd23d Mon Sep 17 00:00:00 2001 From: someone-here Date: Wed, 31 Jan 2024 19:05:46 +0530 Subject: [PATCH 160/249] Fixed 'in' bold issue --- src/components/MenuItem.tsx | 2 +- src/pages/home/HeaderView.js | 2 +- src/styles/index.ts | 4 ++++ src/styles/utils/FontUtils/index.ts | 1 + 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx index e53c7915da8a..23ce3017522a 100644 --- a/src/components/MenuItem.tsx +++ b/src/components/MenuItem.tsx @@ -378,7 +378,7 @@ function MenuItem( {(isHovered) => ( shouldBlockSelection && isSmallScreenWidth && DeviceCapabilities.canUseTouchScreen() && ControlSelection.block()} onPressOut={ControlSelection.unblock} onSecondaryInteraction={onSecondaryInteraction} diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index ab7021542f14..90b12b9ff969 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -193,7 +193,7 @@ function HeaderView(props) { } return ( <> - {translate('threads.in')} + {translate('threads.in')} {policyName} ); diff --git a/src/styles/index.ts b/src/styles/index.ts index d52e876d2e8e..6bc80e847626 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -415,6 +415,10 @@ const styles = (theme: ThemeColors) => fontWeight: FontUtils.fontWeight.bold, }, + fontWeightNormal: { + fontWeight: FontUtils.fontWeight.normal, + }, + textHeadline: { ...headlineFont, ...whiteSpace.preWrap, diff --git a/src/styles/utils/FontUtils/index.ts b/src/styles/utils/FontUtils/index.ts index ac07fdbf026e..b93655fdf63d 100644 --- a/src/styles/utils/FontUtils/index.ts +++ b/src/styles/utils/FontUtils/index.ts @@ -11,6 +11,7 @@ const FontUtils = { }, fontWeight: { bold: fontWeightBold, + normal: '400', }, }; From 8e0b7dc6164fca0e42041ca283b6ffd855d9f14f Mon Sep 17 00:00:00 2001 From: someone-here Date: Wed, 31 Jan 2024 19:58:52 +0530 Subject: [PATCH 161/249] Change condition --- src/pages/ReportDetailsPage.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/ReportDetailsPage.js b/src/pages/ReportDetailsPage.js index 6db4cf4cf3b7..4f880c29c2b4 100644 --- a/src/pages/ReportDetailsPage.js +++ b/src/pages/ReportDetailsPage.js @@ -68,12 +68,11 @@ function ReportDetailsPage(props) { const shouldUseFullTitle = useMemo(() => ReportUtils.shouldUseFullTitleToDisplay(props.report), [props.report]); const isChatRoom = useMemo(() => ReportUtils.isChatRoom(props.report), [props.report]); const isThread = useMemo(() => ReportUtils.isChatThread(props.report), [props.report]); - const isTask = useMemo(() => ReportUtils.isTaskReport(props.report), [props.report]); const isUserCreatedPolicyRoom = useMemo(() => ReportUtils.isUserCreatedPolicyRoom(props.report), [props.report]); const isArchivedRoom = useMemo(() => ReportUtils.isArchivedRoom(props.report), [props.report]); const isMoneyRequestReport = useMemo(() => ReportUtils.isMoneyRequestReport(props.report), [props.report]); const canEditReportDescription = useMemo(() => ReportUtils.canEditReportDescription(props.report, policy), [props.report, policy]); - const shouldShowReportDescription = !isTask && (canEditReportDescription || !_.isEmpty(props.report.description)); + const shouldShowReportDescription = isChatRoom && (canEditReportDescription || !_.isEmpty(props.report.description)); // eslint-disable-next-line react-hooks/exhaustive-deps -- policy is a dependency because `getChatRoomSubtitle` calls `getPolicyName` which in turn retrieves the value from the `policy` value stored in Onyx const chatRoomSubtitle = useMemo(() => ReportUtils.getChatRoomSubtitle(props.report), [props.report, policy]); From ecbfc7255c470c22aed915923de438c7748dc77b Mon Sep 17 00:00:00 2001 From: someone-here Date: Wed, 31 Jan 2024 20:49:13 +0530 Subject: [PATCH 162/249] Remove welcome message --- src/types/onyx/Form.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/onyx/Form.ts b/src/types/onyx/Form.ts index c015627bfbc2..a8c837570142 100644 --- a/src/types/onyx/Form.ts +++ b/src/types/onyx/Form.ts @@ -33,7 +33,7 @@ type DisplayNameForm = Form<{ type NewRoomForm = Form<{ roomName?: string; - welcomeMessage?: string; + reportDescription?: string; policyID?: string; writeCapability?: string; visibility?: string; From 000d9ab4fb06d169dc7af4f362d7af58d1840218 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Wed, 31 Jan 2024 18:25:07 +0100 Subject: [PATCH 163/249] Update types --- src/components/KYCWall/BaseKYCWall.tsx | 10 ++++++---- src/components/KYCWall/types.ts | 14 ++++++-------- src/components/ReportActionItem/ReportPreview.tsx | 3 +-- src/components/SettlementButton.tsx | 15 ++++++--------- src/libs/actions/PaymentMethods.ts | 4 ++-- src/types/onyx/OriginalMessage.ts | 2 +- 6 files changed, 22 insertions(+), 26 deletions(-) diff --git a/src/components/KYCWall/BaseKYCWall.tsx b/src/components/KYCWall/BaseKYCWall.tsx index 89cceadc0fb0..ab2d217deb0e 100644 --- a/src/components/KYCWall/BaseKYCWall.tsx +++ b/src/components/KYCWall/BaseKYCWall.tsx @@ -17,7 +17,9 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {BankAccountList, FundList, ReimbursementAccount, UserWallet, WalletTerms} from '@src/types/onyx'; -import type {AnchorPosition, DomRect, KYCWallProps, PaymentMethod, TransferMethod} from './types'; +import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; +import viewRef from '@src/types/utils/viewRef'; +import type {AnchorPosition, DomRect, KYCWallProps, PaymentMethod} from './types'; // This sets the Horizontal anchor position offset for POPOVER MENU. const POPOVER_MENU_ANCHOR_POSITION_HORIZONTAL_OFFSET = 20; @@ -67,7 +69,7 @@ function KYCWall({ walletTerms, shouldShowPersonalBankAccountOption = false, }: BaseKYCWallProps) { - const anchorRef = useRef(null); + const anchorRef = useRef(null); const transferBalanceButtonRef = useRef(null); const [shouldShowAddPaymentMenu, setShouldShowAddPaymentMenu] = useState(false); @@ -145,7 +147,7 @@ function KYCWall({ * */ const continueAction = useCallback( - (event?: GestureResponderEvent | KeyboardEvent, iouPaymentType?: TransferMethod) => { + (event?: GestureResponderEvent | KeyboardEvent, iouPaymentType?: PaymentMethodType) => { const currentSource = walletTerms?.source ?? source; /** @@ -259,7 +261,7 @@ function KYCWall({ }} shouldShowPersonalBankAccountOption={shouldShowPersonalBankAccountOption} /> - {children(continueAction, anchorRef)} + {children(continueAction, viewRef(anchorRef))} ); } diff --git a/src/components/KYCWall/types.ts b/src/components/KYCWall/types.ts index 1e6aae3299b1..1ee8010574c3 100644 --- a/src/components/KYCWall/types.ts +++ b/src/components/KYCWall/types.ts @@ -1,18 +1,16 @@ -import type {ForwardedRef} from 'react'; -import type {GestureResponderEvent} from 'react-native'; +import type {RefObject} from 'react'; +import type {GestureResponderEvent, View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; import type {Route} from '@src/ROUTES'; import type {Report} from '@src/types/onyx'; +import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; -import type DeepValueOf from '@src/types/utils/DeepValueOf'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; type Source = ValueOf; -type TransferMethod = DeepValueOf; - type DOMRectProperties = 'top' | 'bottom' | 'left' | 'right' | 'height' | 'x' | 'y'; type DomRect = Pick; @@ -62,10 +60,10 @@ type KYCWallProps = { shouldShowPersonalBankAccountOption?: boolean; /** Callback for the end of the onContinue trigger on option selection */ - onSuccessfulKYC: (iouPaymentType?: TransferMethod, currentSource?: Source) => void; + onSuccessfulKYC: (iouPaymentType?: PaymentMethodType, currentSource?: Source) => void; /** Children to build the KYC */ - children: (continueAction: (event: GestureResponderEvent | KeyboardEvent | undefined, method: TransferMethod) => void, anchorRef: ForwardedRef) => void; + children: (continueAction: (event: GestureResponderEvent | KeyboardEvent | undefined, method: PaymentMethodType) => void, anchorRef: RefObject) => void; }; -export type {AnchorPosition, KYCWallProps, PaymentMethod, TransferMethod, DomRect}; +export type {AnchorPosition, KYCWallProps, PaymentMethod, DomRect}; diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index b2fece085f57..46dbd87e55f1 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -285,12 +285,11 @@ function ReportPreview({ )} {shouldShowSettlementButton && ( chatReport && iouReport && IOU.payMoneyRequest(paymentType, chatReport, iouReport)} + onPress={(paymentType?: PaymentMethodType) => chatReport && iouReport && paymentType && IOU.payMoneyRequest(paymentType, chatReport, iouReport)} enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS} addBankAccountRoute={bankAccountRoute} shouldHidePaymentOptions={!shouldShowPayButton} diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index 7a2a94aff301..02f51c67c64d 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -1,6 +1,5 @@ -import type {RefObject} from 'react'; import React, {useEffect, useMemo} from 'react'; -import type {GestureResponderEvent, StyleProp, View, ViewStyle} from 'react-native'; +import type {GestureResponderEvent, StyleProp, ViewStyle} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import useLocalize from '@hooks/useLocalize'; @@ -15,8 +14,8 @@ import ROUTES from '@src/ROUTES'; import type {Route} from '@src/ROUTES'; import type {ButtonSizeValue} from '@src/styles/utils/types'; import type {LastPaymentMethod, Report} from '@src/types/onyx'; +import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; -import type DeepValueOf from '@src/types/utils/DeepValueOf'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; import * as Expensicons from './Icon/Expensicons'; @@ -24,9 +23,7 @@ import KYCWall from './KYCWall'; type KYCFlowEvent = GestureResponderEvent | KeyboardEvent | undefined; -type PaymentType = DeepValueOf; - -type TriggerKYCFlow = (event: KYCFlowEvent, iouPaymentType: PaymentType) => void; +type TriggerKYCFlow = (event: KYCFlowEvent, iouPaymentType: PaymentMethodType) => void; type EnablePaymentsRoute = typeof ROUTES.ENABLE_PAYMENTS | typeof ROUTES.IOU_SEND_ENABLE_PAYMENTS | typeof ROUTES.SETTINGS_ENABLE_PAYMENTS; @@ -37,7 +34,7 @@ type SettlementButtonOnyxProps = { type SettlementButtonProps = SettlementButtonOnyxProps & { /** Callback to execute when this button is pressed. Receives a single payment type argument. */ - onPress: (paymentType?: PaymentType) => void; + onPress: (paymentType?: PaymentMethodType) => void; /** The route to redirect if user does not have a payment method setup */ enablePaymentsRoute: EnablePaymentsRoute; @@ -185,7 +182,7 @@ function SettlementButton({ return buttonOptions; }, [currency, formattedAmount, iouReport, nvpLastPaymentMethod, policyID, translate, shouldHidePaymentOptions, shouldShowApproveButton]); - const selectPaymentType = (event: KYCFlowEvent, iouPaymentType: PaymentType, triggerKYCFlow: TriggerKYCFlow) => { + const selectPaymentType = (event: KYCFlowEvent, iouPaymentType: PaymentMethodType, triggerKYCFlow: TriggerKYCFlow) => { if (iouPaymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY || iouPaymentType === CONST.IOU.PAYMENT_TYPE.VBBA) { triggerKYCFlow(event, iouPaymentType); BankAccounts.setPersonalBankAccountContinueKYCOnSuccess(ROUTES.ENABLE_PAYMENTS); @@ -215,7 +212,7 @@ function SettlementButton({ > {(triggerKYCFlow, buttonRef) => ( } + buttonRef={buttonRef} isDisabled={isDisabled} isLoading={isLoading} onPress={(event, iouPaymentType) => selectPaymentType(event, iouPaymentType, triggerKYCFlow)} diff --git a/src/libs/actions/PaymentMethods.ts b/src/libs/actions/PaymentMethods.ts index cbc5778187a1..2199c5768612 100644 --- a/src/libs/actions/PaymentMethods.ts +++ b/src/libs/actions/PaymentMethods.ts @@ -3,7 +3,6 @@ import type {MutableRefObject} from 'react'; import type {GestureResponderEvent} from 'react-native'; import type {OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; -import type {TransferMethod} from '@components/KYCWall/types'; import * as API from '@libs/API'; import type {AddPaymentCardParams, DeletePaymentCardParams, MakeDefaultPaymentMethodParams, PaymentCardParams, TransferWalletBalanceParams} from '@libs/API/parameters'; import {READ_COMMANDS, WRITE_COMMANDS} from '@libs/API/types'; @@ -14,11 +13,12 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Route} from '@src/ROUTES'; import type {BankAccountList, FundList} from '@src/types/onyx'; +import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import type PaymentMethod from '@src/types/onyx/PaymentMethod'; import type {FilterMethodPaymentType} from '@src/types/onyx/WalletTransfer'; type KYCWallRef = { - continueAction?: (event?: GestureResponderEvent | KeyboardEvent, iouPaymentType?: TransferMethod) => void; + continueAction?: (event?: GestureResponderEvent | KeyboardEvent, iouPaymentType?: PaymentMethodType) => void; }; /** diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index 070b91e2d920..baa5c8d6c904 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -2,7 +2,7 @@ import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; import type DeepValueOf from '@src/types/utils/DeepValueOf'; -type PaymentMethodType = DeepValueOf; +type PaymentMethodType = DeepValueOf; type ActionName = DeepValueOf; type OriginalMessageActionName = From c78b434b5da6f1ba7e2f7f35d0a4967b2c9fb8fc Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 1 Feb 2024 11:32:12 +0700 Subject: [PATCH 164/249] refactor logic to update tag and implement for split flow --- .../MoneyRequestConfirmationList.js | 10 +++++++- ...oraryForRefactorRequestConfirmationList.js | 2 +- src/libs/actions/IOU.js | 24 +------------------ .../step/IOURequestStepParticipants.js | 2 +- .../iou/request/step/IOURequestStepTag.js | 14 ++++++----- .../MoneyRequestParticipantsPage.js | 1 - 6 files changed, 20 insertions(+), 33 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index afabb40fd9f4..7508943d4769 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -769,7 +769,15 @@ function MoneyRequestConfirmationList(props) { numberOfLinesTitle={2} onPress={() => { if (props.isEditingSplitBill) { - Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(props.reportID, props.reportActionID, CONST.EDIT_REQUEST_FIELD.TAG)); + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_TAG.getRoute( + CONST.IOU.ACTION.EDIT, + CONST.IOU.TYPE.SPLIT, + props.transaction.transactionID, + props.reportID, + Navigation.getActiveRouteWithoutParams(), + ), + ); return; } Navigation.navigate(ROUTES.MONEY_REQUEST_TAG.getRoute(props.iouType, props.reportID)); diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js index 122001861827..8dc9d3e419c0 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -258,7 +258,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const shouldCalculateDistanceAmount = isDistanceRequest && iouAmount === 0; // A flag for showing the categories field - const shouldShowCategories = isPolicyExpenseChat && (iouCategory || OptionsListUtils.hasEnabledOptions(_.values(policyCategories))); + const shouldShowCategories = iouCategory || OptionsListUtils.hasEnabledOptions(_.values(policyCategories)); // A flag and a toggler for showing the rest of the form fields const [shouldExpandFields, toggleShouldExpandFields] = useReducer((state) => !state, false); diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 5b503e4a5046..8c771149c5f3 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -234,17 +234,10 @@ function resetMoneyRequestCategory_temporaryForRefactor(transactionID) { * @param {String} transactionID * @param {String} tag */ -function setMoneyRequestTag_temporaryForRefactor(transactionID, tag) { +function setMoneyRequestTag(transactionID, tag) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {tag}); } -/* - * @param {String} transactionID - */ -function resetMoneyRequestTag_temporaryForRefactor(transactionID) { - Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {tag: null}); -} - /** * @param {String} transactionID * @param {Boolean} billable @@ -3635,17 +3628,6 @@ function resetMoneyRequestCategory() { Onyx.merge(ONYXKEYS.IOU, {category: ''}); } -/* - * @param {String} tag - */ -function setMoneyRequestTag(tag) { - Onyx.merge(ONYXKEYS.IOU, {tag}); -} - -function resetMoneyRequestTag() { - Onyx.merge(ONYXKEYS.IOU, {tag: ''}); -} - /** * @param {String} transactionID * @param {Object} taxRate @@ -3726,7 +3708,6 @@ function navigateToNextPage(iou, iouType, report, path = '') { .value(); setMoneyRequestParticipants(participants); resetMoneyRequestCategory(); - resetMoneyRequestTag(); } Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report.reportID)); return; @@ -3795,8 +3776,6 @@ export { resetMoneyRequestCategory, resetMoneyRequestCategory_temporaryForRefactor, resetMoneyRequestInfo, - resetMoneyRequestTag, - resetMoneyRequestTag_temporaryForRefactor, clearMoneyRequest, setMoneyRequestAmount_temporaryForRefactor, setMoneyRequestBillable_temporaryForRefactor, @@ -3807,7 +3786,6 @@ export { setMoneyRequestMerchant_temporaryForRefactor, setMoneyRequestParticipants_temporaryForRefactor, setMoneyRequestReceipt, - setMoneyRequestTag_temporaryForRefactor, setMoneyRequestAmount, setMoneyRequestBillable, setMoneyRequestCategory, diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.js b/src/pages/iou/request/step/IOURequestStepParticipants.js index 0d1177e231c4..5f1b22cab128 100644 --- a/src/pages/iou/request/step/IOURequestStepParticipants.js +++ b/src/pages/iou/request/step/IOURequestStepParticipants.js @@ -70,7 +70,7 @@ function IOURequestStepParticipants({ const goToNextStep = useCallback(() => { const nextStepIOUType = numberOfParticipants.current === 1 ? iouType : CONST.IOU.TYPE.SPLIT; - IOU.resetMoneyRequestTag_temporaryForRefactor(transactionID); + IOU.setMoneyRequestTag(transactionID, ''); IOU.resetMoneyRequestCategory_temporaryForRefactor(transactionID); Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(nextStepIOUType, transactionID, selectedReportID.current || reportID)); }, [iouType, transactionID, reportID]); diff --git a/src/pages/iou/request/step/IOURequestStepTag.js b/src/pages/iou/request/step/IOURequestStepTag.js index 31dadf624f61..e4390c5abbde 100644 --- a/src/pages/iou/request/step/IOURequestStepTag.js +++ b/src/pages/iou/request/step/IOURequestStepTag.js @@ -45,7 +45,7 @@ function IOURequestStepTag({ policyTags, report, route: { - params: {action, transactionID, backTo}, + params: {action, transactionID, backTo, iouType}, }, transaction: {tag}, }) { @@ -56,6 +56,7 @@ function IOURequestStepTag({ const tagListKey = _.first(_.keys(policyTags)); const policyTagListName = PolicyUtils.getTagListName(policyTags) || translate('common.tag'); const isEditing = action === CONST.IOU.ACTION.EDIT; + const isBillSplit = iouType === CONST.IOU.TYPE.SPLIT; const navigateBack = () => { Navigation.goBack(backTo || ROUTES.HOME); @@ -68,16 +69,17 @@ function IOURequestStepTag({ const updateTag = (selectedTag) => { const isSelectedTag = selectedTag.searchText === tag; const updatedTag = !isSelectedTag ? selectedTag.searchText : ''; + if (isBillSplit) { + IOU.setDraftSplitTransaction(transactionID, {tag: selectedTag.searchText}); + navigateBack(); + return; + } if (isEditing) { IOU.updateMoneyRequestTag(transactionID, report.reportID, updatedTag); Navigation.dismissModal(); return; } - if (isSelectedTag) { - IOU.resetMoneyRequestTag_temporaryForRefactor(transactionID); - } else { - IOU.setMoneyRequestTag_temporaryForRefactor(transactionID, updatedTag); - } + IOU.setMoneyRequestTag(transactionID, updatedTag); navigateBack(); }; diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js index 216154be9cd4..ea57d88579ae 100644 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js @@ -88,7 +88,6 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route, transaction}) { const navigateToConfirmationStep = (moneyRequestType) => { IOU.setMoneyRequestId(moneyRequestType); IOU.resetMoneyRequestCategory(); - IOU.resetMoneyRequestTag(); Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(moneyRequestType, reportID)); }; From 1b811d1bb1b01f12a57b721c3b8c68990a98bbdb Mon Sep 17 00:00:00 2001 From: someone-here Date: Thu, 1 Feb 2024 14:16:25 +0530 Subject: [PATCH 165/249] Fix android --- src/components/DisplayNames/index.native.tsx | 4 +++- src/components/ReportWelcomeText.tsx | 5 +++-- src/pages/home/HeaderView.js | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/components/DisplayNames/index.native.tsx b/src/components/DisplayNames/index.native.tsx index b3eceb794bcb..02b18de3892f 100644 --- a/src/components/DisplayNames/index.native.tsx +++ b/src/components/DisplayNames/index.native.tsx @@ -2,9 +2,10 @@ import React from 'react'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import type DisplayNamesProps from './types'; +import {View} from 'react-native'; // As we don't have to show tooltips of the Native platform so we simply render the full display names list. -function DisplayNames({accessibilityLabel, fullTitle, textStyles = [], numberOfLines = 1}: DisplayNamesProps) { +function DisplayNames({accessibilityLabel, fullTitle, textStyles = [], numberOfLines = 1, renderAdditionalText}: DisplayNamesProps) { const {translate} = useLocalize(); return ( {fullTitle || translate('common.hidden')} + {renderAdditionalText?.()} ); } diff --git a/src/components/ReportWelcomeText.tsx b/src/components/ReportWelcomeText.tsx index 5151639ce1be..21abf2742f43 100644 --- a/src/components/ReportWelcomeText.tsx +++ b/src/components/ReportWelcomeText.tsx @@ -59,7 +59,7 @@ function ReportWelcomeText({report, policy, personalDetails}: ReportWelcomeTextP {isChatRoom ? translate('reportActionsView.welcomeToRoom', {roomName: ReportUtils.getReportName(report)}) : translate('reportActionsView.sayHello')} - + {isPolicyExpenseChat && ( <> {translate('reportActionsView.beginningOfChatHistoryPolicyExpenseChatPartOne')} @@ -80,6 +80,7 @@ function ReportWelcomeText({report, policy, personalDetails}: ReportWelcomeTextP } Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID)); }} + style={styles.mw100} accessibilityLabel={translate('reportDescriptionPage.roomDescription')} > @@ -131,7 +132,7 @@ function ReportWelcomeText({report, policy, personalDetails}: ReportWelcomeTextP {(moneyRequestOptions.includes(CONST.IOU.TYPE.SEND) || moneyRequestOptions.includes(CONST.IOU.TYPE.REQUEST)) && ( {translate('reportActionsView.usePlusButton', {additionalText})} )} - + ); } diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index 90b12b9ff969..a336ab17edeb 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -193,8 +193,8 @@ function HeaderView(props) { } return ( <> - {translate('threads.in')} - {policyName} + {translate('threads.in')} + {policyName} ); }; From 23d88069a3e7be1e6b94054e1b1247b1bbebc997 Mon Sep 17 00:00:00 2001 From: someone-here Date: Thu, 1 Feb 2024 15:02:48 +0530 Subject: [PATCH 166/249] Fix chat mast head text --- src/components/ReportWelcomeText.tsx | 9 ++++----- src/languages/en.ts | 2 +- src/languages/es.ts | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/components/ReportWelcomeText.tsx b/src/components/ReportWelcomeText.tsx index 21abf2742f43..a979833001cd 100644 --- a/src/components/ReportWelcomeText.tsx +++ b/src/components/ReportWelcomeText.tsx @@ -61,13 +61,13 @@ function ReportWelcomeText({report, policy, personalDetails}: ReportWelcomeTextP {isPolicyExpenseChat && ( - <> + {translate('reportActionsView.beginningOfChatHistoryPolicyExpenseChatPartOne')} {ReportUtils.getDisplayNameForParticipant(report?.ownerAccountID)} {translate('reportActionsView.beginningOfChatHistoryPolicyExpenseChatPartTwo')} {ReportUtils.getPolicyName(report)} {translate('reportActionsView.beginningOfChatHistoryPolicyExpenseChatPartThree')} - + )} {isChatRoom && ( <> @@ -80,13 +80,12 @@ function ReportWelcomeText({report, policy, personalDetails}: ReportWelcomeTextP } Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID)); }} - style={styles.mw100} accessibilityLabel={translate('reportDescriptionPage.roomDescription')} > ) : ( - <> + {roomWelcomeMessage.phrase1} {roomWelcomeMessage.showReportName && ( )} {roomWelcomeMessage.phrase2 !== undefined && {roomWelcomeMessage.phrase2}} - + )} )} diff --git a/src/languages/en.ts b/src/languages/en.ts index b4bad56608d2..ed91b9776aa8 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -488,7 +488,7 @@ export default { chatWithAccountManager: 'Chat with your account manager here', sayHello: 'Say hello!', welcomeToRoom: ({roomName}: WelcomeToRoomParams) => `Welcome to ${roomName}!`, - usePlusButton: ({additionalText}: UsePlusButtonParams) => `\n\nYou can also use the + button to ${additionalText}, or assign a task!`, + usePlusButton: ({additionalText}: UsePlusButtonParams) => `\nYou can also use the + button to ${additionalText}, or assign a task!`, iouTypes: { send: 'send money', split: 'split a bill', diff --git a/src/languages/es.ts b/src/languages/es.ts index 9a4d85a1b366..1ef02df63f15 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -480,7 +480,7 @@ export default { chatWithAccountManager: 'Chatea con tu gestor de cuenta aquí', sayHello: '¡Saluda!', welcomeToRoom: ({roomName}: WelcomeToRoomParams) => `¡Bienvenido a ${roomName}!`, - usePlusButton: ({additionalText}: UsePlusButtonParams) => `\n\n¡También puedes usar el botón + de abajo para ${additionalText}, o asignar una tarea!`, + usePlusButton: ({additionalText}: UsePlusButtonParams) => `\n¡También puedes usar el botón + de abajo para ${additionalText}, o asignar una tarea!`, iouTypes: { send: 'enviar dinero', split: 'dividir una factura', From 2d8818093601520554a7ab037b884e0a713b00dd Mon Sep 17 00:00:00 2001 From: someone-here Date: Thu, 1 Feb 2024 15:04:11 +0530 Subject: [PATCH 167/249] Fix lint --- src/components/DisplayNames/index.native.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/DisplayNames/index.native.tsx b/src/components/DisplayNames/index.native.tsx index 02b18de3892f..ceee34586e8b 100644 --- a/src/components/DisplayNames/index.native.tsx +++ b/src/components/DisplayNames/index.native.tsx @@ -2,7 +2,6 @@ import React from 'react'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import type DisplayNamesProps from './types'; -import {View} from 'react-native'; // As we don't have to show tooltips of the Native platform so we simply render the full display names list. function DisplayNames({accessibilityLabel, fullTitle, textStyles = [], numberOfLines = 1, renderAdditionalText}: DisplayNamesProps) { From 901d57e28dc72200867992d7f6dc3c1c610c33df Mon Sep 17 00:00:00 2001 From: someone-here Date: Thu, 1 Feb 2024 15:35:10 +0530 Subject: [PATCH 168/249] Fix tests --- tests/ui/UnreadIndicatorsTest.js | 12 +-- tests/unit/SidebarFilterTest.js | 12 +-- tests/unit/SidebarOrderTest.js | 124 +++++++++++++++---------------- tests/unit/SidebarTest.js | 5 +- 4 files changed, 77 insertions(+), 76 deletions(-) diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js index e4d4d877f66b..9bf5d9ef49e4 100644 --- a/tests/ui/UnreadIndicatorsTest.js +++ b/tests/ui/UnreadIndicatorsTest.js @@ -438,11 +438,11 @@ describe('Unread Indicators', () => { expect(displayNameTexts).toHaveLength(2); const firstReportOption = displayNameTexts[0]; expect(lodashGet(firstReportOption, ['props', 'style', 'fontWeight'])).toBe(FontUtils.fontWeight.bold); - expect(lodashGet(firstReportOption, ['props', 'children'])).toBe('C User'); + expect(lodashGet(firstReportOption, ['props', 'children', 0])).toBe('C User'); const secondReportOption = displayNameTexts[1]; expect(lodashGet(secondReportOption, ['props', 'style', 'fontWeight'])).toBe(FontUtils.fontWeight.bold); - expect(lodashGet(secondReportOption, ['props', 'children'])).toBe('B User'); + expect(lodashGet(secondReportOption, ['props', 'children', 0])).toBe('B User'); // Tap the new report option and navigate back to the sidebar again via the back button return navigateToSidebarOption(0); @@ -455,9 +455,9 @@ describe('Unread Indicators', () => { const displayNameTexts = screen.queryAllByLabelText(hintText); expect(displayNameTexts).toHaveLength(2); expect(lodashGet(displayNameTexts[0], ['props', 'style', 'fontWeight'])).toBe(undefined); - expect(lodashGet(displayNameTexts[0], ['props', 'children'])).toBe('C User'); + expect(lodashGet(displayNameTexts[0], ['props', 'children', 0])).toBe('C User'); expect(lodashGet(displayNameTexts[1], ['props', 'style', 'fontWeight'])).toBe(FontUtils.fontWeight.bold); - expect(lodashGet(displayNameTexts[1], ['props', 'children'])).toBe('B User'); + expect(lodashGet(displayNameTexts[1], ['props', 'children', 0])).toBe('B User'); })); xit('Manually marking a chat message as unread shows the new line indicator and updates the LHN', () => @@ -489,7 +489,7 @@ describe('Unread Indicators', () => { const displayNameTexts = screen.queryAllByLabelText(hintText); expect(displayNameTexts).toHaveLength(1); expect(lodashGet(displayNameTexts[0], ['props', 'style', 'fontWeight'])).toBe(FontUtils.fontWeight.bold); - expect(lodashGet(displayNameTexts[0], ['props', 'children'])).toBe('B User'); + expect(lodashGet(displayNameTexts[0], ['props', 'children', 0])).toBe('B User'); // Navigate to the report again and back to the sidebar return navigateToSidebarOption(0); @@ -501,7 +501,7 @@ describe('Unread Indicators', () => { const displayNameTexts = screen.queryAllByLabelText(hintText); expect(displayNameTexts).toHaveLength(1); expect(lodashGet(displayNameTexts[0], ['props', 'style', 'fontWeight'])).toBe(undefined); - expect(lodashGet(displayNameTexts[0], ['props', 'children'])).toBe('B User'); + expect(lodashGet(displayNameTexts[0], ['props', 'children', 0])).toBe('B User'); // Navigate to the report again and verify the new line indicator is missing return navigateToSidebarOption(0); diff --git a/tests/unit/SidebarFilterTest.js b/tests/unit/SidebarFilterTest.js index 0a219667c97b..2e86858baeb6 100644 --- a/tests/unit/SidebarFilterTest.js +++ b/tests/unit/SidebarFilterTest.js @@ -338,7 +338,7 @@ describe('Sidebar', () => { const navigatesToChatHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); expect(screen.queryAllByAccessibilityHint(navigatesToChatHintText)).toHaveLength(1); expect(displayNames).toHaveLength(1); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Three, Four'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Three, Four'); } else { // Both reports visible const navigatesToChatHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); @@ -379,8 +379,8 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(2); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('One, Two'); - expect(lodashGet(displayNames, [1, 'props', 'children'])).toBe('Three, Four'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('One, Two'); + expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Three, Four'); }) // When report3 becomes unread @@ -449,8 +449,8 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(2); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Three, Four'); - expect(lodashGet(displayNames, [1, 'props', 'children'])).toBe('One, Two'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Three, Four'); + expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('One, Two'); }) ); }); @@ -662,7 +662,7 @@ describe('Sidebar', () => { const navigatesToChatHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); expect(screen.queryAllByAccessibilityHint(navigatesToChatHintText)).toHaveLength(1); expect(displayNames).toHaveLength(1); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Three, Four'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Three, Four'); } else { // Both reports visible const navigatesToChatHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); diff --git a/tests/unit/SidebarOrderTest.js b/tests/unit/SidebarOrderTest.js index ed0f210d1da6..7ae8c4e1e9b3 100644 --- a/tests/unit/SidebarOrderTest.js +++ b/tests/unit/SidebarOrderTest.js @@ -140,9 +140,9 @@ describe('Sidebar', () => { const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(3); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Five, Six'); - expect(lodashGet(displayNames, [1, 'props', 'children'])).toBe('Three, Four'); - expect(lodashGet(displayNames, [2, 'props', 'children'])).toBe('One, Two'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Five, Six'); + expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Three, Four'); + expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('One, Two'); }) ); }); @@ -189,9 +189,9 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(3); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('One, Two'); // this has `hasDraft` flag enabled so it will be on top - expect(lodashGet(displayNames, [1, 'props', 'children'])).toBe('Five, Six'); - expect(lodashGet(displayNames, [2, 'props', 'children'])).toBe('Three, Four'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('One, Two'); // this has `hasDraft` flag enabled so it will be on top + expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Five, Six'); + expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Three, Four'); }) ); }); @@ -236,9 +236,9 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(3); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('One, Two'); - expect(lodashGet(displayNames, [1, 'props', 'children'])).toBe('Five, Six'); - expect(lodashGet(displayNames, [2, 'props', 'children'])).toBe('Three, Four'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('One, Two'); + expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Five, Six'); + expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Three, Four'); }) ); }); @@ -286,10 +286,10 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(4); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe(taskReportName); - expect(lodashGet(displayNames, [1, 'props', 'children'])).toBe('Five, Six'); - expect(lodashGet(displayNames, [2, 'props', 'children'])).toBe('Three, Four'); - expect(lodashGet(displayNames, [3, 'props', 'children'])).toBe('One, Two'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe(taskReportName); + expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Five, Six'); + expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Three, Four'); + expect(lodashGet(displayNames, [3, 'props', 'children', 0])).toBe('One, Two'); }) ); }); @@ -346,10 +346,10 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(4); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Email Two owes $100.00'); - expect(lodashGet(displayNames, [1, 'props', 'children'])).toBe('Five, Six'); - expect(lodashGet(displayNames, [2, 'props', 'children'])).toBe('Three, Four'); - expect(lodashGet(displayNames, [3, 'props', 'children'])).toBe('One, Two'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Email Two owes $100.00'); + expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Five, Six'); + expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Three, Four'); + expect(lodashGet(displayNames, [3, 'props', 'children', 0])).toBe('One, Two'); }) ); }); @@ -410,10 +410,10 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(4); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Workspace owes $100.00'); - expect(lodashGet(displayNames, [1, 'props', 'children'])).toBe('Email Five'); - expect(lodashGet(displayNames, [2, 'props', 'children'])).toBe('Three, Four'); - expect(lodashGet(displayNames, [3, 'props', 'children'])).toBe('One, Two'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Workspace owes $100.00'); + expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Email Five'); + expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Three, Four'); + expect(lodashGet(displayNames, [3, 'props', 'children', 0])).toBe('One, Two'); }) ); }); @@ -465,9 +465,9 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(3); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Three, Four'); - expect(lodashGet(displayNames, [1, 'props', 'children'])).toBe('Five, Six'); - expect(lodashGet(displayNames, [2, 'props', 'children'])).toBe('One, Two'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Three, Four'); + expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Five, Six'); + expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('One, Two'); }) ); }); @@ -607,9 +607,9 @@ describe('Sidebar', () => { expect(displayNames).toHaveLength(3); expect(screen.queryAllByTestId('Pin Icon')).toHaveLength(1); expect(screen.queryAllByTestId('Pencil Icon')).toHaveLength(1); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Email Two owes $100.00'); - expect(lodashGet(displayNames, [1, 'props', 'children'])).toBe('One, Two'); - expect(lodashGet(displayNames, [2, 'props', 'children'])).toBe('Three, Four'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Email Two owes $100.00'); + expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('One, Two'); + expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Three, Four'); }) ); }); @@ -653,9 +653,9 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(3); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Five, Six'); - expect(lodashGet(displayNames, [1, 'props', 'children'])).toBe('One, Two'); - expect(lodashGet(displayNames, [2, 'props', 'children'])).toBe('Three, Four'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Five, Six'); + expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('One, Two'); + expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Three, Four'); }) // When a new report is added @@ -666,10 +666,10 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(4); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Five, Six'); - expect(lodashGet(displayNames, [1, 'props', 'children'])).toBe('One, Two'); - expect(lodashGet(displayNames, [2, 'props', 'children'])).toBe('Seven, Eight'); - expect(lodashGet(displayNames, [3, 'props', 'children'])).toBe('Three, Four'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Five, Six'); + expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('One, Two'); + expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Seven, Eight'); + expect(lodashGet(displayNames, [3, 'props', 'children', 0])).toBe('Three, Four'); }) ); }); @@ -713,9 +713,9 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(3); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Five, Six'); - expect(lodashGet(displayNames, [1, 'props', 'children'])).toBe('One, Two'); - expect(lodashGet(displayNames, [2, 'props', 'children'])).toBe('Three, Four'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Five, Six'); + expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('One, Two'); + expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Three, Four'); }) // When a new report is added @@ -726,10 +726,10 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(4); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Five, Six'); - expect(lodashGet(displayNames, [1, 'props', 'children'])).toBe('One, Two'); - expect(lodashGet(displayNames, [2, 'props', 'children'])).toBe('Seven, Eight'); - expect(lodashGet(displayNames, [3, 'props', 'children'])).toBe('Three, Four'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Five, Six'); + expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('One, Two'); + expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Seven, Eight'); + expect(lodashGet(displayNames, [3, 'props', 'children', 0])).toBe('Three, Four'); }) ); }); @@ -773,9 +773,9 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(3); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Five, Six'); - expect(lodashGet(displayNames, [1, 'props', 'children'])).toBe('Three, Four'); - expect(lodashGet(displayNames, [2, 'props', 'children'])).toBe('Report (archived)'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Five, Six'); + expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Three, Four'); + expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Report (archived)'); }) ); }); @@ -810,9 +810,9 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(3); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Five, Six'); - expect(lodashGet(displayNames, [1, 'props', 'children'])).toBe('One, Two'); - expect(lodashGet(displayNames, [2, 'props', 'children'])).toBe('Three, Four'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Five, Six'); + expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('One, Two'); + expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Three, Four'); }) // When a new report is added @@ -823,10 +823,10 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(4); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Five, Six'); - expect(lodashGet(displayNames, [1, 'props', 'children'])).toBe('One, Two'); - expect(lodashGet(displayNames, [2, 'props', 'children'])).toBe('Seven, Eight'); - expect(lodashGet(displayNames, [3, 'props', 'children'])).toBe('Three, Four'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Five, Six'); + expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('One, Two'); + expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Seven, Eight'); + expect(lodashGet(displayNames, [3, 'props', 'children', 0])).toBe('Three, Four'); }) ); }); @@ -865,9 +865,9 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(3); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Five, Six'); - expect(lodashGet(displayNames, [1, 'props', 'children'])).toBe('Three, Four'); - expect(lodashGet(displayNames, [2, 'props', 'children'])).toBe('Report (archived)'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Five, Six'); + expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Three, Four'); + expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Report (archived)'); }) ); }); @@ -1000,11 +1000,11 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(5); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Email Five owes $100.00'); - expect(lodashGet(displayNames, [1, 'props', 'children'])).toBe('Email Four owes $1,000.00'); - expect(lodashGet(displayNames, [2, 'props', 'children'])).toBe('Email Six owes $100.00'); - expect(lodashGet(displayNames, [3, 'props', 'children'])).toBe('Email Three owes $100.00'); - expect(lodashGet(displayNames, [4, 'props', 'children'])).toBe('Email Two owes $100.00'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Email Five owes $100.00'); + expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Email Four owes $1,000.00'); + expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Email Six owes $100.00'); + expect(lodashGet(displayNames, [3, 'props', 'children', 0])).toBe('Email Three owes $100.00'); + expect(lodashGet(displayNames, [4, 'props', 'children', 0])).toBe('Email Two owes $100.00'); }) ); }); @@ -1050,9 +1050,9 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(3); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Five, Six'); - expect(lodashGet(displayNames, [1, 'props', 'children'])).toBe('One, Two'); - expect(lodashGet(displayNames, [2, 'props', 'children'])).toBe('Three, Four'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Five, Six'); + expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('One, Two'); + expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Three, Four'); }) ); }); diff --git a/tests/unit/SidebarTest.js b/tests/unit/SidebarTest.js index dba1365626ba..eb4e8f1c2b4e 100644 --- a/tests/unit/SidebarTest.js +++ b/tests/unit/SidebarTest.js @@ -83,7 +83,8 @@ describe('Sidebar', () => { .then(() => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Report (archived)'); + console.log(displayNames); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Report (archived)'); const hintMessagePreviewText = Localize.translateLocal('accessibilityHints.lastChatMessagePreview'); const messagePreviewTexts = screen.queryAllByLabelText(hintMessagePreviewText); @@ -127,7 +128,7 @@ describe('Sidebar', () => { .then(() => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); - expect(lodashGet(displayNames, [0, 'props', 'children'])).toBe('Report (archived)'); + expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Report (archived)'); const hintMessagePreviewText = Localize.translateLocal('accessibilityHints.lastChatMessagePreview'); const messagePreviewTexts = screen.queryAllByLabelText(hintMessagePreviewText); From fcd576303a7389f030bd2157fca75186ac6da9f2 Mon Sep 17 00:00:00 2001 From: someone-here Date: Thu, 1 Feb 2024 15:39:49 +0530 Subject: [PATCH 169/249] Fix lint --- tests/unit/SidebarTest.js | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/SidebarTest.js b/tests/unit/SidebarTest.js index eb4e8f1c2b4e..6a813ef1fa8c 100644 --- a/tests/unit/SidebarTest.js +++ b/tests/unit/SidebarTest.js @@ -83,7 +83,6 @@ describe('Sidebar', () => { .then(() => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); - console.log(displayNames); expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Report (archived)'); const hintMessagePreviewText = Localize.translateLocal('accessibilityHints.lastChatMessagePreview'); From e645f46476a4c6e6a55a8d957fabf69597cd598e Mon Sep 17 00:00:00 2001 From: Yauheni Date: Thu, 1 Feb 2024 11:25:56 +0100 Subject: [PATCH 170/249] Fix lint issue --- src/components/SettlementButton.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index 95218e0783a6..c2a22fa04bfe 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -163,7 +163,7 @@ function SettlementButton({ // To achieve the one tap pay experience we need to choose the correct payment type as default. // If the user has previously chosen a specific payment option or paid for some request or expense, // let's use the last payment method or use default. - const paymentMethod = nvpLastPaymentMethod?.[policyID] || ''; + const paymentMethod = nvpLastPaymentMethod?.[policyID] ?? ''; if (canUseWallet) { buttonOptions.push(paymentMethods[CONST.IOU.PAYMENT_TYPE.EXPENSIFY]); } From 17f25fc09548849e11291aef361fcdfa8482d66f Mon Sep 17 00:00:00 2001 From: Shahe Shahinyan Date: Thu, 1 Feb 2024 17:47:11 +0400 Subject: [PATCH 171/249] Addressed to reviewer comments --- src/ONYXKEYS.ts | 2 +- src/languages/es.ts | 2 +- src/libs/PolicyUtils.ts | 2 +- src/libs/ReportUtils.ts | 6 +++--- src/libs/actions/Report.ts | 4 ++-- src/pages/home/report/withReportOrNotFound.tsx | 8 ++++---- src/types/onyx/Form.ts | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index c4f66138cffc..ab5ae384a5be 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -491,7 +491,7 @@ type OnyxValues = { [ONYXKEYS.FORMS.DISPLAY_NAME_FORM]: OnyxTypes.DisplayNameForm; [ONYXKEYS.FORMS.DISPLAY_NAME_FORM_DRAFT]: OnyxTypes.DisplayNameForm; [ONYXKEYS.FORMS.ROOM_NAME_FORM]: OnyxTypes.RoomNameForm; - [ONYXKEYS.FORMS.ROOM_NAME_FORM_DRAFT]: OnyxTypes.Form; + [ONYXKEYS.FORMS.ROOM_NAME_FORM_DRAFT]: OnyxTypes.RoomNameForm; [ONYXKEYS.FORMS.WELCOME_MESSAGE_FORM]: OnyxTypes.Form; [ONYXKEYS.FORMS.WELCOME_MESSAGE_FORM_DRAFT]: OnyxTypes.Form; [ONYXKEYS.FORMS.LEGAL_NAME_FORM]: OnyxTypes.Form; diff --git a/src/languages/es.ts b/src/languages/es.ts index f99765a66673..52e49e75fdd4 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -668,7 +668,7 @@ export default { always: 'Inmediatamente', daily: 'Cada día', mute: 'Nunca', - hidden: 'Oculta', + hidden: 'Oculto', }, }, loginField: { diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 0d406bd78bd9..2f0a6367041d 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 | undefined): 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 40842492eb0a..feb3a1baf3c4 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4199,7 +4199,7 @@ function getWorkspaceChats(policyID: string, accountIDs: number[]): Array, policy?: OnyxEntry): boolean { +function shouldDisableRename(report: OnyxEntry, policy: OnyxEntry | undefined): boolean { if (isDefaultRoom(report) || isArchivedRoom(report) || isThread(report) || isMoneyRequestReport(report) || isPolicyExpenseChat(report)) { return true; } @@ -4218,7 +4218,7 @@ function shouldDisableRename(report: OnyxEntry, policy?: OnyxEntry, policy?: OnyxEntry): boolean { +function canEditWriteCapability(report: OnyxEntry, policy: OnyxEntry | undefined): boolean { return PolicyUtils.isPolicyAdmin(policy) && !isAdminRoom(report) && !isArchivedRoom(report) && !isThread(report); } @@ -4506,7 +4506,7 @@ function getRoom(type: ValueOf, policyID: string) /** * We only want policy owners and admins to be able to modify the welcome message, but not in thread chat. */ -function shouldDisableWelcomeMessage(report: OnyxEntry, policy?: OnyxEntry): boolean { +function shouldDisableWelcomeMessage(report: OnyxEntry, policy: OnyxEntry | undefined): boolean { return isMoneyRequestReport(report) || isArchivedRoom(report) || !isChatRoom(report) || isChatThread(report) || !PolicyUtils.isPolicyAdmin(policy); } /** diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index f2744f8a8269..72fc73fc1d5a 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -1673,7 +1673,7 @@ function navigateToConciergeChatAndDeleteReport(reportID: string) { /** * @param policyRoomName The updated name for the policy room */ -function updatePolicyRoomNameAndNavigate(policyRoomReport: Report, policyRoomName?: string) { +function updatePolicyRoomNameAndNavigate(policyRoomReport: Report, policyRoomName: string | undefined) { const reportID = policyRoomReport.reportID; const previousName = policyRoomReport.reportName; @@ -1719,7 +1719,7 @@ function updatePolicyRoomNameAndNavigate(policyRoomReport: Report, policyRoomNam }, ]; - const parameters: UpdatePolicyRoomNameParams = {reportID, policyRoomName}; + const parameters: UpdatePolicyRoomNameParams = {reportID, policyRoomName: policyRoomName ?? ''}; API.write(WRITE_COMMANDS.UPDATE_POLICY_ROOM_NAME, parameters, {optimisticData, successData, failureData}); Navigation.goBack(ROUTES.REPORT_SETTINGS.getRoute(reportID)); diff --git a/src/pages/home/report/withReportOrNotFound.tsx b/src/pages/home/report/withReportOrNotFound.tsx index a8facc3e1c76..385280c9d2c2 100644 --- a/src/pages/home/report/withReportOrNotFound.tsx +++ b/src/pages/home/report/withReportOrNotFound.tsx @@ -11,7 +11,7 @@ import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; import ONYXKEYS from '@src/ONYXKEYS'; import type * as OnyxTypes from '@src/types/onyx'; -type OnyxProps = { +type WithReportOrNotFoundOnyxProps = { /** The report currently being looked at */ report: OnyxEntry; /** The policies which the user has access to */ @@ -22,7 +22,7 @@ type OnyxProps = { isLoadingReportData: OnyxEntry; }; -type WithReportOrNotFoundProps = OnyxProps & { +type WithReportOrNotFoundProps = WithReportOrNotFoundOnyxProps & { route: RouteProp<{params: {reportID: string}}>; }; @@ -30,7 +30,7 @@ export default function ( shouldRequireReportID = true, ): ( WrappedComponent: React.ComponentType>, -) => React.ComponentType, keyof OnyxProps>> { +) => React.ComponentType, keyof WithReportOrNotFoundOnyxProps>> { return function (WrappedComponent: ComponentType>) { function WithReportOrNotFound(props: TProps, ref: ForwardedRef) { const contentShown = React.useRef(false); @@ -73,7 +73,7 @@ export default function ( WithReportOrNotFound.displayName = `withReportOrNotFound(${getComponentDisplayName(WrappedComponent)})`; - return withOnyx, OnyxProps>({ + return withOnyx, WithReportOrNotFoundOnyxProps>({ report: { key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`, }, diff --git a/src/types/onyx/Form.ts b/src/types/onyx/Form.ts index 142984d7f4b1..6aeeeb72e3a8 100644 --- a/src/types/onyx/Form.ts +++ b/src/types/onyx/Form.ts @@ -55,7 +55,7 @@ type PrivateNotesForm = Form<{ }>; type RoomNameForm = Form<{ - roomName?: string; + roomName: string; }>; export default Form; From 7456ffd6caf36141e85dddcd8a9d64a2d64d5ea7 Mon Sep 17 00:00:00 2001 From: tienifr Date: Thu, 1 Feb 2024 21:12:36 +0700 Subject: [PATCH 172/249] fix: remove zero width space when copying email --- .../HTMLRenderers/NextStepEmailRenderer.tsx | 9 ++++++++- src/libs/SelectionScraper/index.ts | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/NextStepEmailRenderer.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/NextStepEmailRenderer.tsx index b8292cad60a2..f172a56a03c3 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/NextStepEmailRenderer.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/NextStepEmailRenderer.tsx @@ -11,7 +11,14 @@ type NextStepEmailRendererProps = { function NextStepEmailRenderer({tnode}: NextStepEmailRendererProps) { const styles = useThemeStyles(); - return {tnode.data}; + return ( + + {tnode.data} + + ); } NextStepEmailRenderer.displayName = 'NextStepEmailRenderer'; diff --git a/src/libs/SelectionScraper/index.ts b/src/libs/SelectionScraper/index.ts index 955fe693c856..4a2166156594 100644 --- a/src/libs/SelectionScraper/index.ts +++ b/src/libs/SelectionScraper/index.ts @@ -112,6 +112,9 @@ const replaceNodes = (dom: Node, isChildOfEditorElement: boolean): Node => { // Encoding HTML chars '< >' in the text, because any HTML will be removed in stripHTML method. if (dom.type.toString() === 'text' && dom instanceof DataNode) { data = Str.htmlEncode(dom.data); + if (dom.parent instanceof Element && dom.parent?.attribs?.[tagAttribute] === 'email-with-break-opportunities') { + data = data.replaceAll('\u200b', ''); + } } else if (dom instanceof Element) { domName = dom.name; if (dom.attribs?.[tagAttribute]) { From 87efe2f161d7efbac3fec21050288025d3240a8c Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 1 Feb 2024 21:18:56 +0700 Subject: [PATCH 173/249] run prettier --- src/components/EmojiPicker/EmojiPickerMenu/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js index d6a56d44c19f..cfce6b04f859 100755 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js @@ -260,7 +260,8 @@ function EmojiPickerMenu({forwardedRef, onEmojiSelected, activeEmoji}) { const emojiCode = types && types[preferredSkinTone] ? types[preferredSkinTone] : code; const isEmojiFocused = index === focusedIndex && isUsingKeyboardMovement; - const shouldEmojiBeHighlighted = index === focusedIndex && highlightEmoji || (Boolean(activeEmoji) && EmojiUtils.getRemovedSkinToneEmoji(emojiCode) === EmojiUtils.getRemovedSkinToneEmoji(activeEmoji)); + const shouldEmojiBeHighlighted = + (index === focusedIndex && highlightEmoji) || (Boolean(activeEmoji) && EmojiUtils.getRemovedSkinToneEmoji(emojiCode) === EmojiUtils.getRemovedSkinToneEmoji(activeEmoji)); const shouldFirstEmojiBeHighlighted = index === 0 && highlightFirstEmoji; return ( From 7495142498a18e70e8b21add51272229d7c72964 Mon Sep 17 00:00:00 2001 From: Shahe Shahinyan Date: Thu, 1 Feb 2024 19:44:00 +0400 Subject: [PATCH 174/249] Addressed to reviewer comments --- src/libs/ErrorUtils.ts | 2 +- .../Report/NotificationPreferencePage.tsx | 14 ++++--- .../settings/Report/ReportSettingsPage.tsx | 40 +++++++++---------- src/pages/settings/Report/RoomNamePage.tsx | 22 +++++----- .../settings/Report/WriteCapabilityPage.tsx | 20 +++++----- 5 files changed, 51 insertions(+), 47 deletions(-) diff --git a/src/libs/ErrorUtils.ts b/src/libs/ErrorUtils.ts index 8eff66c10751..f0f94839de21 100644 --- a/src/libs/ErrorUtils.ts +++ b/src/libs/ErrorUtils.ts @@ -101,7 +101,7 @@ type ErrorsList = Record; * @param errors - An object containing current errors in the form * @param message - Message to assign to the inputID errors */ -function addErrorMessage(errors: ErrorsList, inputID?: string, message?: TKey | [TKey, Record]) { +function addErrorMessage(errors: ErrorsList, inputID?: string, message?: TKey | Localize.MaybePhraseKey) { if (!message || !inputID) { return; } diff --git a/src/pages/settings/Report/NotificationPreferencePage.tsx b/src/pages/settings/Report/NotificationPreferencePage.tsx index c5fdaa25fac5..30b9ffa3c2d2 100644 --- a/src/pages/settings/Report/NotificationPreferencePage.tsx +++ b/src/pages/settings/Report/NotificationPreferencePage.tsx @@ -1,3 +1,4 @@ +import type {StackScreenProps} from '@react-navigation/stack'; import React from 'react'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; @@ -5,15 +6,14 @@ import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; import useLocalize from '@hooks/useLocalize'; import * as ReportUtils from '@libs/ReportUtils'; +import type {ReportSettingsNavigatorParamList} from '@navigation/types'; import withReportOrNotFound from '@pages/home/report/withReportOrNotFound'; import type {WithReportOrNotFoundProps} from '@pages/home/report/withReportOrNotFound'; import * as ReportActions from '@userActions/Report'; import CONST from '@src/CONST'; -import type {Report} from '@src/types/onyx'; +import type SCREENS from '@src/SCREENS'; -type NotificationPreferencePageProps = WithReportOrNotFoundProps & { - report: Report; -}; +type NotificationPreferencePageProps = WithReportOrNotFoundProps & StackScreenProps; function NotificationPreferencePage({report}: NotificationPreferencePageProps) { const {translate} = useLocalize(); @@ -24,7 +24,7 @@ function NotificationPreferencePage({report}: NotificationPreferencePageProps) { value: preference, text: translate(`notificationPreferencesPage.notificationPreferences.${preference}`), keyForList: preference, - isSelected: preference === report.notificationPreference, + isSelected: preference === report?.notificationPreference, })); return ( @@ -39,7 +39,9 @@ function NotificationPreferencePage({report}: NotificationPreferencePageProps) { /> ReportActions.updateNotificationPreference(report.reportID, report.notificationPreference, option.value, true, undefined, undefined, report)} + onSelectRow={(option) => + ReportActions.updateNotificationPreference(report?.reportID ?? '', report?.notificationPreference, option.value, true, undefined, undefined, report) + } initiallyFocusedOptionKey={Object.values(notificationPreferenceOptions ?? {}).find((locale) => locale.isSelected)?.keyForList} /> diff --git a/src/pages/settings/Report/ReportSettingsPage.tsx b/src/pages/settings/Report/ReportSettingsPage.tsx index d6f3a30c9d63..790f61c0503e 100644 --- a/src/pages/settings/Report/ReportSettingsPage.tsx +++ b/src/pages/settings/Report/ReportSettingsPage.tsx @@ -1,3 +1,4 @@ +import type {StackScreenProps} from '@react-navigation/stack'; import isEmpty from 'lodash/isEmpty'; import React, {useMemo} from 'react'; import {ScrollView, View} from 'react-native'; @@ -15,22 +16,21 @@ import useThemeStyles from '@hooks/useThemeStyles'; import {getGroupChatName} from '@libs/GroupChatUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; +import type {ReportSettingsNavigatorParamList} from '@navigation/types'; import withReportOrNotFound from '@pages/home/report/withReportOrNotFound'; import type {WithReportOrNotFoundProps} from '@pages/home/report/withReportOrNotFound'; import * as ReportActions from '@userActions/Report'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; -import type {Report} from '@src/types/onyx'; +import type SCREENS from '@src/SCREENS'; -type ReportSettingsPageProps = WithReportOrNotFoundProps & { - report: Report; -}; +type ReportSettingsPageProps = WithReportOrNotFoundProps & StackScreenProps; function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); // The workspace the report is on, null if the user isn't a member of the workspace - const linkedWorkspace = useMemo(() => Object.values(policies ?? {}).find((policy) => policy && policy.id === report.policyID), [policies, report.policyID]); + const linkedWorkspace = useMemo(() => Object.values(policies ?? {}).find((policy) => policy && policy.id === report?.policyID), [policies, report?.policyID]); const shouldDisableRename = useMemo(() => ReportUtils.shouldDisableRename(report, linkedWorkspace), [report, linkedWorkspace]); const isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report); @@ -40,15 +40,15 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { const shouldDisableSettings = isEmpty(report) || ReportUtils.isArchivedRoom(report); const shouldShowRoomName = !ReportUtils.isPolicyExpenseChat(report) && !ReportUtils.isChatThread(report); const notificationPreference = - report.notificationPreference && report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN + report?.notificationPreference && report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN ? translate(`notificationPreferencesPage.notificationPreferences.${report.notificationPreference}`) : ''; - const writeCapability = ReportUtils.isAdminRoom(report) ? CONST.REPORT.WRITE_CAPABILITIES.ADMINS : report.writeCapability ?? CONST.REPORT.WRITE_CAPABILITIES.ALL; + const writeCapability = ReportUtils.isAdminRoom(report) ? CONST.REPORT.WRITE_CAPABILITIES.ADMINS : report?.writeCapability ?? CONST.REPORT.WRITE_CAPABILITIES.ALL; const writeCapabilityText = translate(`writeCapabilityPage.writeCapability.${writeCapability}`); const shouldAllowWriteCapabilityEditing = useMemo(() => ReportUtils.canEditWriteCapability(report, linkedWorkspace), [report, linkedWorkspace]); - const shouldShowNotificationPref = !isMoneyRequestReport && report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; + const shouldShowNotificationPref = !isMoneyRequestReport && report?.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; const roomNameLabel = translate(isMoneyRequestReport ? 'workspace.editor.nameInputLabel' : 'newRoomPage.roomName'); const reportName = ReportUtils.isGroupChat(report) ? getGroupChatName(report) : ReportUtils.getReportName(report); @@ -59,7 +59,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID))} + onBackButtonPress={() => Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report?.reportID ?? ''))} /> {shouldShowNotificationPref && ( @@ -67,15 +67,15 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { shouldShowRightIcon title={notificationPreference} description={translate('notificationPreferencesPage.label')} - onPress={() => Navigation.navigate(ROUTES.REPORT_SETTINGS_NOTIFICATION_PREFERENCES.getRoute(report.reportID))} + onPress={() => Navigation.navigate(ROUTES.REPORT_SETTINGS_NOTIFICATION_PREFERENCES.getRoute(report?.reportID ?? ''))} /> )} {shouldShowRoomName && ( ReportActions.clearPolicyRoomNameErrors(report.reportID)} + onClose={() => ReportActions.clearPolicyRoomNameErrors(report?.reportID ?? '')} > {shouldDisableRename ? ( @@ -96,9 +96,9 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { ) : ( Navigation.navigate(ROUTES.REPORT_SETTINGS_ROOM_NAME.getRoute(report.reportID))} + onPress={() => Navigation.navigate(ROUTES.REPORT_SETTINGS_ROOM_NAME.getRoute(report?.reportID ?? ''))} /> )} @@ -109,7 +109,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { shouldShowRightIcon title={writeCapabilityText} description={translate('writeCapabilityPage.label')} - onPress={() => Navigation.navigate(ROUTES.REPORT_SETTINGS_WRITE_CAPABILITY.getRoute(report.reportID))} + onPress={() => Navigation.navigate(ROUTES.REPORT_SETTINGS_WRITE_CAPABILITY.getRoute(report?.reportID ?? ''))} /> ) : ( @@ -145,7 +145,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { /> )} - {Boolean(report.visibility) && ( + {Boolean(report?.visibility) && ( - {report.visibility && translate(`newRoomPage.visibilityOptions.${report.visibility}`)} + {report?.visibility && translate(`newRoomPage.visibilityOptions.${report.visibility}`)} - {report.visibility && translate(`newRoomPage.${report.visibility}Description`)} + {report?.visibility && translate(`newRoomPage.${report.visibility}Description`)} )} @@ -167,7 +167,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { Navigation.navigate(ROUTES.REPORT_WELCOME_MESSAGE.getRoute(report.reportID))} + onPress={() => Navigation.navigate(ROUTES.REPORT_WELCOME_MESSAGE.getRoute(report?.reportID ?? ''))} shouldShowRightIcon /> )} diff --git a/src/pages/settings/Report/RoomNamePage.tsx b/src/pages/settings/Report/RoomNamePage.tsx index 2e4a91e7f861..759147f95d95 100644 --- a/src/pages/settings/Report/RoomNamePage.tsx +++ b/src/pages/settings/Report/RoomNamePage.tsx @@ -1,4 +1,5 @@ import {useIsFocused} from '@react-navigation/native'; +import type {StackScreenProps} from '@react-navigation/stack'; import React, {useCallback, useRef} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; @@ -17,13 +18,16 @@ import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import * as ValidationUtils from '@libs/ValidationUtils'; +import type {ReportSettingsNavigatorParamList} from '@navigation/types'; import withReportOrNotFound from '@pages/home/report/withReportOrNotFound'; import type {WithReportOrNotFoundProps} from '@pages/home/report/withReportOrNotFound'; import * as ReportActions from '@userActions/Report'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type SCREENS from '@src/SCREENS'; import type {Policy, Report} from '@src/types/onyx'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; type RoomNamePageOnyxProps = { /** All reports shared with the user */ @@ -33,11 +37,7 @@ type RoomNamePageOnyxProps = { policy: OnyxEntry; }; -type RoomNamePageProps = RoomNamePageOnyxProps & - WithReportOrNotFoundProps & { - /** The room report for which the name is being edited */ - report: Report; - }; +type RoomNamePageProps = RoomNamePageOnyxProps & WithReportOrNotFoundProps & StackScreenProps; function RoomNamePage({report, policy, reports}: RoomNamePageProps) { const styles = useThemeStyles(); @@ -50,7 +50,7 @@ function RoomNamePage({report, policy, reports}: RoomNamePageProps) { const errors = {}; // We should skip validation hence we return an empty errors and we skip Form submission on the onSubmit method - if (values.roomName === report.reportName) { + if (values.roomName === report?.reportName) { return errors; } @@ -63,7 +63,7 @@ function RoomNamePage({report, policy, reports}: RoomNamePageProps) { } else if (ValidationUtils.isReservedRoomName(values.roomName)) { // Certain names are reserved for default rooms and should not be used for policy rooms. ErrorUtils.addErrorMessage(errors, 'roomName', ['newRoomPage.roomNameReservedError', {reservedName: values.roomName}]); - } else if (ValidationUtils.isExistingRoomName(values.roomName, reports, report.policyID)) { + } else if (ValidationUtils.isExistingRoomName(values.roomName, reports, report?.policyID)) { // The room name can't be set to one that already exists on the policy ErrorUtils.addErrorMessage(errors, 'roomName', 'newRoomPage.roomAlreadyExistsError'); } @@ -82,12 +82,12 @@ function RoomNamePage({report, policy, reports}: RoomNamePageProps) { Navigation.goBack(ROUTES.REPORT_SETTINGS.getRoute(report.reportID))} + onBackButtonPress={() => Navigation.goBack(ROUTES.REPORT_SETTINGS.getRoute(report?.reportID ?? ''))} /> ReportActions.updatePolicyRoomNameAndNavigate(report, values.roomName)} + onSubmit={(values) => !isEmptyObject(report) && ReportActions.updatePolicyRoomNameAndNavigate(report, values.roomName)} validate={validate} submitButtonText={translate('common.save')} enabledWhenOffline @@ -97,7 +97,7 @@ function RoomNamePage({report, policy, reports}: RoomNamePageProps) { InputComponent={RoomNameInput} ref={roomNameInputRef} inputID="roomName" - defaultValue={report.reportName} + defaultValue={report?.reportName} isFocused={isFocused} /> @@ -115,7 +115,7 @@ export default withReportOrNotFound()( key: ONYXKEYS.COLLECTION.REPORT, }, policy: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`, }, })(RoomNamePage), ); diff --git a/src/pages/settings/Report/WriteCapabilityPage.tsx b/src/pages/settings/Report/WriteCapabilityPage.tsx index 49accdff8e13..7af951d685d4 100644 --- a/src/pages/settings/Report/WriteCapabilityPage.tsx +++ b/src/pages/settings/Report/WriteCapabilityPage.tsx @@ -1,3 +1,4 @@ +import type {StackScreenProps} from '@react-navigation/stack'; import React from 'react'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; @@ -8,13 +9,16 @@ import SelectionList from '@components/SelectionList'; import useLocalize from '@hooks/useLocalize'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; +import type {ReportSettingsNavigatorParamList} from '@navigation/types'; import withReportOrNotFound from '@pages/home/report/withReportOrNotFound'; import type {WithReportOrNotFoundProps} from '@pages/home/report/withReportOrNotFound'; import * as ReportActions from '@userActions/Report'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {Policy, Report} from '@src/types/onyx'; +import type SCREENS from '@src/SCREENS'; +import type {Policy} from '@src/types/onyx'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; type WriteCapabilityPageOnyxProps = { /** The policy object for the current route */ @@ -22,10 +26,8 @@ type WriteCapabilityPageOnyxProps = { }; type WriteCapabilityPageProps = WriteCapabilityPageOnyxProps & - WithReportOrNotFoundProps & { - /** The report for which we are setting write capability */ - report: Report; - }; + WithReportOrNotFoundProps & + StackScreenProps; function WriteCapabilityPage({report, policy}: WriteCapabilityPageProps) { const {translate} = useLocalize(); @@ -33,7 +35,7 @@ function WriteCapabilityPage({report, policy}: WriteCapabilityPageProps) { value, text: translate(`writeCapabilityPage.writeCapability.${value}`), keyForList: value, - isSelected: value === (report.writeCapability ?? CONST.REPORT.WRITE_CAPABILITIES.ALL), + isSelected: value === (report?.writeCapability ?? CONST.REPORT.WRITE_CAPABILITIES.ALL), })); const isAbleToEdit = ReportUtils.canEditWriteCapability(report, policy); @@ -47,11 +49,11 @@ function WriteCapabilityPage({report, policy}: WriteCapabilityPageProps) { Navigation.goBack(ROUTES.REPORT_SETTINGS.getRoute(report.reportID))} + onBackButtonPress={() => Navigation.goBack(ROUTES.REPORT_SETTINGS.getRoute(report?.reportID ?? ''))} /> ReportActions.updateWriteCapabilityAndNavigate(report, option.value)} + onSelectRow={(option) => !isEmptyObject(report) && ReportActions.updateWriteCapabilityAndNavigate(report, option.value)} initiallyFocusedOptionKey={Object.values(writeCapabilityOptions).find((locale) => locale.isSelected)?.keyForList} /> @@ -64,7 +66,7 @@ WriteCapabilityPage.displayName = 'WriteCapabilityPage'; export default withReportOrNotFound()( withOnyx({ policy: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`, }, })(WriteCapabilityPage), ); From e2c935ce0b148c01b4b72c1c50599a3505309c71 Mon Sep 17 00:00:00 2001 From: Shahe Shahinyan Date: Thu, 1 Feb 2024 19:55:48 +0400 Subject: [PATCH 175/249] run prettier --- src/types/onyx/Form.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/onyx/Form.ts b/src/types/onyx/Form.ts index 905270427ac8..fd0af2e5139f 100644 --- a/src/types/onyx/Form.ts +++ b/src/types/onyx/Form.ts @@ -77,5 +77,5 @@ export type { IntroSchoolPrincipalForm, PersonalBankAccountForm, ReportFieldEditForm, - RoomNameForm + RoomNameForm, }; From 38e656ced21bab4994aa94b78bac741bbdb00626 Mon Sep 17 00:00:00 2001 From: Pavlo Tsimura Date: Thu, 1 Feb 2024 17:09:42 +0100 Subject: [PATCH 176/249] Remove the "Leave thread" option from the context menu --- .../report/ContextMenu/ContextMenuActions.tsx | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx index ffa6c0adf3b8..58e0794d796d 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx @@ -301,38 +301,6 @@ const ContextMenuActions: ContextMenuAction[] = [ }, getDescription: () => {}, }, - { - isAnonymousAction: false, - textTranslateKey: 'reportActionContextMenu.leaveThread', - icon: Expensicons.BellSlash, - shouldShow: (type, reportAction, isArchivedRoom, betas, menuTarget, isChronosReport, reportID) => { - const childReportNotificationPreference = ReportUtils.getChildReportNotificationPreference(reportAction); - const isDeletedAction = ReportActionsUtils.isDeletedAction(reportAction); - const shouldDisplayThreadReplies = ReportUtils.shouldDisplayThreadReplies(reportAction, reportID); - const subscribed = childReportNotificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; - if (type !== CONST.CONTEXT_MENU_TYPES.REPORT_ACTION) { - return false; - } - const isCommentAction = reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT && !ReportUtils.isThreadFirstChat(reportAction, reportID); - const isReportPreviewAction = reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW; - const isIOUAction = reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && !ReportActionsUtils.isSplitBillAction(reportAction); - return subscribed && (isCommentAction || isReportPreviewAction || isIOUAction) && (!isDeletedAction || shouldDisplayThreadReplies); - }, - onPress: (closePopover, {reportAction, reportID}) => { - const childReportNotificationPreference = ReportUtils.getChildReportNotificationPreference(reportAction); - if (closePopover) { - hideContextMenu(false, () => { - ReportActionComposeFocusManager.focus(); - Report.toggleSubscribeToChildReport(reportAction?.childReportID ?? '0', reportAction, reportID, childReportNotificationPreference); - }); - return; - } - - ReportActionComposeFocusManager.focus(); - Report.toggleSubscribeToChildReport(reportAction?.childReportID ?? '0', reportAction, reportID, childReportNotificationPreference); - }, - getDescription: () => {}, - }, { isAnonymousAction: true, textTranslateKey: 'reportActionContextMenu.copyURLToClipboard', From ba70fc913ea282749ad6d6b831f348ab39a4bb26 Mon Sep 17 00:00:00 2001 From: Shahe Shahinyan Date: Thu, 1 Feb 2024 20:18:23 +0400 Subject: [PATCH 177/249] Addressed to reviewer comments --- src/pages/settings/Report/ReportSettingsPage.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/pages/settings/Report/ReportSettingsPage.tsx b/src/pages/settings/Report/ReportSettingsPage.tsx index 790f61c0503e..3dd096c96a7c 100644 --- a/src/pages/settings/Report/ReportSettingsPage.tsx +++ b/src/pages/settings/Report/ReportSettingsPage.tsx @@ -27,6 +27,7 @@ import type SCREENS from '@src/SCREENS'; type ReportSettingsPageProps = WithReportOrNotFoundProps & StackScreenProps; function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { + const reportID = report?.reportID ?? ''; const styles = useThemeStyles(); const {translate} = useLocalize(); // The workspace the report is on, null if the user isn't a member of the workspace @@ -59,7 +60,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report?.reportID ?? ''))} + onBackButtonPress={() => Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(reportID ?? ''))} /> {shouldShowNotificationPref && ( @@ -67,7 +68,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { shouldShowRightIcon title={notificationPreference} description={translate('notificationPreferencesPage.label')} - onPress={() => Navigation.navigate(ROUTES.REPORT_SETTINGS_NOTIFICATION_PREFERENCES.getRoute(report?.reportID ?? ''))} + onPress={() => Navigation.navigate(ROUTES.REPORT_SETTINGS_NOTIFICATION_PREFERENCES.getRoute(reportID ?? ''))} /> )} {shouldShowRoomName && ( @@ -75,7 +76,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { pendingAction={report?.pendingFields?.reportName} errors={report?.errorFields?.reportName} errorRowStyles={[styles.ph5]} - onClose={() => ReportActions.clearPolicyRoomNameErrors(report?.reportID ?? '')} + onClose={() => ReportActions.clearPolicyRoomNameErrors(reportID ?? '')} > {shouldDisableRename ? ( @@ -98,7 +99,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { shouldShowRightIcon title={report?.reportName} description={translate('newRoomPage.roomName')} - onPress={() => Navigation.navigate(ROUTES.REPORT_SETTINGS_ROOM_NAME.getRoute(report?.reportID ?? ''))} + onPress={() => Navigation.navigate(ROUTES.REPORT_SETTINGS_ROOM_NAME.getRoute(reportID ?? ''))} /> )} @@ -109,7 +110,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { shouldShowRightIcon title={writeCapabilityText} description={translate('writeCapabilityPage.label')} - onPress={() => Navigation.navigate(ROUTES.REPORT_SETTINGS_WRITE_CAPABILITY.getRoute(report?.reportID ?? ''))} + onPress={() => Navigation.navigate(ROUTES.REPORT_SETTINGS_WRITE_CAPABILITY.getRoute(reportID ?? ''))} /> ) : ( @@ -167,7 +168,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { Navigation.navigate(ROUTES.REPORT_WELCOME_MESSAGE.getRoute(report?.reportID ?? ''))} + onPress={() => Navigation.navigate(ROUTES.REPORT_WELCOME_MESSAGE.getRoute(reportID ?? ''))} shouldShowRightIcon /> )} From 7d0e9d342c3bb6c38f44ee5047605751def6e2c9 Mon Sep 17 00:00:00 2001 From: Pavlo Tsimura Date: Thu, 1 Feb 2024 18:02:01 +0100 Subject: [PATCH 178/249] TEMP: re-trigger CI --- src/pages/home/report/ContextMenu/ContextMenuActions.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx index 58e0794d796d..93cd1acfa2a6 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx @@ -301,6 +301,7 @@ const ContextMenuActions: ContextMenuAction[] = [ }, getDescription: () => {}, }, + // Trigger CI { isAnonymousAction: true, textTranslateKey: 'reportActionContextMenu.copyURLToClipboard', From 1d7ec0086ee6cd3a2c4af089cd7b5343ad60b4fe Mon Sep 17 00:00:00 2001 From: Pavlo Tsimura Date: Thu, 1 Feb 2024 18:02:30 +0100 Subject: [PATCH 179/249] TEMP: re-trigger CI --- src/pages/home/report/ContextMenu/ContextMenuActions.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx index 93cd1acfa2a6..58e0794d796d 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx @@ -301,7 +301,6 @@ const ContextMenuActions: ContextMenuAction[] = [ }, getDescription: () => {}, }, - // Trigger CI { isAnonymousAction: true, textTranslateKey: 'reportActionContextMenu.copyURLToClipboard', From d07a1d54323ef1ca78e47b8f0eebf96eae0ebc9e Mon Sep 17 00:00:00 2001 From: Shahe Shahinyan Date: Thu, 1 Feb 2024 21:20:14 +0400 Subject: [PATCH 180/249] Addressed to reviewer comments --- src/libs/ReportUtils.ts | 6 +++--- src/libs/ValidationUtils.ts | 2 +- src/libs/actions/Report.ts | 2 +- src/pages/settings/Report/ReportSettingsPage.tsx | 2 +- src/pages/settings/Report/RoomNamePage.tsx | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index acbe2472fea5..3d21911c83e8 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4269,7 +4269,7 @@ function getWorkspaceChats(policyID: string, accountIDs: number[]): Array, policy: OnyxEntry | undefined): boolean { +function shouldDisableRename(report: OnyxEntry, policy: OnyxEntry): boolean { if (isDefaultRoom(report) || isArchivedRoom(report) || isThread(report) || isMoneyRequestReport(report) || isPolicyExpenseChat(report)) { return true; } @@ -4287,7 +4287,7 @@ function shouldDisableRename(report: OnyxEntry, policy: OnyxEntry, policy: OnyxEntry | undefined): boolean { +function canEditWriteCapability(report: OnyxEntry, policy: OnyxEntry): boolean { return PolicyUtils.isPolicyAdmin(policy) && !isAdminRoom(report) && !isArchivedRoom(report) && !isThread(report); } @@ -4575,7 +4575,7 @@ function getRoom(type: ValueOf, policyID: string) /** * We only want policy owners and admins to be able to modify the welcome message, but not in thread chat. */ -function shouldDisableWelcomeMessage(report: OnyxEntry, policy: OnyxEntry | undefined): boolean { +function shouldDisableWelcomeMessage(report: OnyxEntry, policy: OnyxEntry): boolean { return isMoneyRequestReport(report) || isArchivedRoom(report) || !isChatRoom(report) || isChatThread(report) || !PolicyUtils.isPolicyAdmin(policy); } /** diff --git a/src/libs/ValidationUtils.ts b/src/libs/ValidationUtils.ts index af9e394e0b7f..132fed6d1ada 100644 --- a/src/libs/ValidationUtils.ts +++ b/src/libs/ValidationUtils.ts @@ -355,7 +355,7 @@ function isReservedRoomName(roomName: string): boolean { /** * Checks if the room name already exists. */ -function isExistingRoomName(roomName: string, reports: OnyxCollection, policyID?: string): boolean { +function isExistingRoomName(roomName: string, reports: OnyxCollection, policyID: string): boolean { return Object.values(reports ?? {}).some((report) => report && report.policyID === policyID && report.reportName === roomName); } diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 2eedd090b90c..3d375ec26413 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -1806,7 +1806,7 @@ function navigateToConciergeChatAndDeleteReport(reportID: string) { /** * @param policyRoomName The updated name for the policy room */ -function updatePolicyRoomNameAndNavigate(policyRoomReport: Report, policyRoomName: string | undefined) { +function updatePolicyRoomNameAndNavigate(policyRoomReport: Report, policyRoomName: string) { const reportID = policyRoomReport.reportID; const previousName = policyRoomReport.reportName; diff --git a/src/pages/settings/Report/ReportSettingsPage.tsx b/src/pages/settings/Report/ReportSettingsPage.tsx index 3dd096c96a7c..28d189359860 100644 --- a/src/pages/settings/Report/ReportSettingsPage.tsx +++ b/src/pages/settings/Report/ReportSettingsPage.tsx @@ -31,7 +31,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); // The workspace the report is on, null if the user isn't a member of the workspace - const linkedWorkspace = useMemo(() => Object.values(policies ?? {}).find((policy) => policy && policy.id === report?.policyID), [policies, report?.policyID]); + const linkedWorkspace = useMemo(() => Object.values(policies ?? {}).find((policy) => policy && policy.id === report?.policyID) ?? null, [policies, report?.policyID]); const shouldDisableRename = useMemo(() => ReportUtils.shouldDisableRename(report, linkedWorkspace), [report, linkedWorkspace]); const isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report); diff --git a/src/pages/settings/Report/RoomNamePage.tsx b/src/pages/settings/Report/RoomNamePage.tsx index 759147f95d95..6b2fd751f01f 100644 --- a/src/pages/settings/Report/RoomNamePage.tsx +++ b/src/pages/settings/Report/RoomNamePage.tsx @@ -63,7 +63,7 @@ function RoomNamePage({report, policy, reports}: RoomNamePageProps) { } else if (ValidationUtils.isReservedRoomName(values.roomName)) { // Certain names are reserved for default rooms and should not be used for policy rooms. ErrorUtils.addErrorMessage(errors, 'roomName', ['newRoomPage.roomNameReservedError', {reservedName: values.roomName}]); - } else if (ValidationUtils.isExistingRoomName(values.roomName, reports, report?.policyID)) { + } else if (ValidationUtils.isExistingRoomName(values.roomName, reports, report?.policyID ?? '')) { // The room name can't be set to one that already exists on the policy ErrorUtils.addErrorMessage(errors, 'roomName', 'newRoomPage.roomAlreadyExistsError'); } From cf691f46881595605e8bef0a86bbd91459037928 Mon Sep 17 00:00:00 2001 From: Ionatan Wiznia Date: Thu, 1 Feb 2024 18:20:46 +0100 Subject: [PATCH 181/249] Revert "[CP Staging] Revert "[NO QA] Remove areChatRoomsEnabled checks"" --- src/libs/PolicyUtils.ts | 5 +---- src/types/onyx/Policy.ts | 3 --- tests/utils/LHNTestUtils.js | 1 - tests/utils/collections/policies.ts | 1 - 4 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index b8ed62f93082..5a8fe907d479 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -15,10 +15,7 @@ type UnitRate = {rate: number}; * These are policies that we can use to create reports with in NewDot. */ function getActivePolicies(policies: OnyxCollection): Policy[] | undefined { - return Object.values(policies ?? {}).filter( - (policy): policy is Policy => - policy !== null && policy && (policy.isPolicyExpenseChatEnabled || policy.areChatRoomsEnabled) && policy.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, - ); + return Object.values(policies ?? {}).filter((policy): policy is Policy => policy !== null && policy && policy.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE); } /** diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index fe50bbb497d2..39c5f5e9c78e 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -76,9 +76,6 @@ type Policy = { /** The custom units data for this policy */ customUnits?: Record; - /** Whether chat rooms can be created and used on this policy. Enabled manually by CQ/JS snippet. Always true for free policies. */ - areChatRoomsEnabled: boolean; - /** Whether policy expense chats can be created and used on this policy. Enabled manually by CQ/JS snippet. Always true for free policies. */ isPolicyExpenseChatEnabled: boolean; diff --git a/tests/utils/LHNTestUtils.js b/tests/utils/LHNTestUtils.js index 04246c1c438a..3e40063dd040 100644 --- a/tests/utils/LHNTestUtils.js +++ b/tests/utils/LHNTestUtils.js @@ -252,7 +252,6 @@ function getFakePolicy(id = 1, name = 'Workspace-Test-001') { avatar: '', employeeList: [], isPolicyExpenseChatEnabled: true, - areChatRoomsEnabled: true, lastModified: 1697323926777105, autoReporting: true, autoReportingFrequency: 'immediate', diff --git a/tests/utils/collections/policies.ts b/tests/utils/collections/policies.ts index 4223c7e41941..7ecf152122d3 100644 --- a/tests/utils/collections/policies.ts +++ b/tests/utils/collections/policies.ts @@ -7,7 +7,6 @@ export default function createRandomPolicy(index: number): Policy { id: index.toString(), name: randWord(), type: rand(Object.values(CONST.POLICY.TYPE)), - areChatRoomsEnabled: randBoolean(), autoReporting: randBoolean(), isPolicyExpenseChatEnabled: randBoolean(), autoReportingFrequency: rand(Object.values(CONST.POLICY.AUTO_REPORTING_FREQUENCIES)), From db8de4dfe3fb2ab5f8ccb7ff4750c7c7862b35a1 Mon Sep 17 00:00:00 2001 From: Ionatan Wiznia Date: Thu, 1 Feb 2024 14:22:55 -0300 Subject: [PATCH 182/249] Remove more usages --- src/libs/actions/Policy.ts | 3 --- src/libs/actions/TeachersUnite.ts | 1 - 2 files changed, 4 deletions(-) diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index fbe92aeb378d..dfc5f4c705b8 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -1160,7 +1160,6 @@ function createDraftInitialWorkspace(policyOwnerEmail = '', policyName = '', pol isPolicyExpenseChatEnabled: true, outputCurrency, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - areChatRoomsEnabled: true, customUnits, makeMeAdmin, }, @@ -1221,7 +1220,6 @@ function createWorkspace(policyOwnerEmail = '', makeMeAdmin = false, policyName isPolicyExpenseChatEnabled: true, outputCurrency, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - areChatRoomsEnabled: true, customUnits, }, }, @@ -1600,7 +1598,6 @@ function createWorkspaceFromIOUPayment(iouReport: Report): string | undefined { // Setting the currency to USD as we can only add the VBBA for this policy currency right now outputCurrency: CONST.CURRENCY.USD, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - areChatRoomsEnabled: true, customUnits, }; diff --git a/src/libs/actions/TeachersUnite.ts b/src/libs/actions/TeachersUnite.ts index 055d1f2b53a2..ab48609e2d53 100644 --- a/src/libs/actions/TeachersUnite.ts +++ b/src/libs/actions/TeachersUnite.ts @@ -91,7 +91,6 @@ function addSchoolPrincipal(firstName: string, partnerUserID: string, lastName: value: { id: policyID, isPolicyExpenseChatEnabled: true, - areChatRoomsEnabled: true, type: CONST.POLICY.TYPE.CORPORATE, name: policyName, role: CONST.POLICY.ROLE.USER, From d4f2e9f75d0dcfd5d2b2c359837f1adbe1a26dca Mon Sep 17 00:00:00 2001 From: Ishpaul Singh Date: Fri, 2 Feb 2024 04:25:28 +0530 Subject: [PATCH 183/249] fixes crash on long press expensify classic option --- src/pages/settings/InitialSettingsPage.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/pages/settings/InitialSettingsPage.js b/src/pages/settings/InitialSettingsPage.js index dfa4262549fc..3997fe0bec75 100755 --- a/src/pages/settings/InitialSettingsPage.js +++ b/src/pages/settings/InitialSettingsPage.js @@ -171,7 +171,7 @@ function InitialSettingsPage(props) { action: () => { Link.openOldDotLink(CONST.OLDDOT_URLS.INBOX); }, - link: Link.buildOldDotURL(CONST.OLDDOT_URLS.INBOX), + link: () => Link.buildOldDotURL(CONST.OLDDOT_URLS.INBOX), }, { translationKey: 'initialSettingsPage.signOut', @@ -225,6 +225,15 @@ function InitialSettingsPage(props) { * @returns {String|undefined} the user's wallet balance */ const getWalletBalance = (isPaymentItem) => (isPaymentItem ? CurrencyUtils.convertToDisplayString(props.userWallet.currentBalance) : undefined); + + const onSecondaryInteraction = (link, event) => { + if (typeof link === 'function') { + link().then((url) => ReportActionContextMenu.showContextMenu(CONST.CONTEXT_MENU_TYPES.LINK, event, url, popoverAnchor.current)); + } else if (link) { + ReportActionContextMenu.showContextMenu(CONST.CONTEXT_MENU_TYPES.LINK, event, link, popoverAnchor.current); + } + }; + return ( {translate(menuItemsData.sectionTranslationKey)} @@ -259,9 +268,7 @@ function InitialSettingsPage(props) { ref={popoverAnchor} hoverAndPressStyle={styles.hoveredComponentBG} shouldBlockSelection={Boolean(item.link)} - onSecondaryInteraction={ - !_.isEmpty(item.link) ? (e) => ReportActionContextMenu.showContextMenu(CONST.CONTEXT_MENU_TYPES.LINK, e, item.link, popoverAnchor.current) : undefined - } + onSecondaryInteraction={item.link ? (event) => onSecondaryInteraction(item.link, event) : undefined} focused={activeRoute && item.routeName && activeRoute.toLowerCase().replaceAll('_', '') === item.routeName.toLowerCase().replaceAll('/', '')} isPaneMenu /> From ff3aee9ce7f6b38b94ebb97277da3f4a0e048ef8 Mon Sep 17 00:00:00 2001 From: Ishpaul Singh Date: Fri, 2 Feb 2024 04:43:20 +0530 Subject: [PATCH 184/249] fixes variable naming --- src/pages/settings/InitialSettingsPage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/settings/InitialSettingsPage.js b/src/pages/settings/InitialSettingsPage.js index 3997fe0bec75..8dfce10fc081 100755 --- a/src/pages/settings/InitialSettingsPage.js +++ b/src/pages/settings/InitialSettingsPage.js @@ -226,7 +226,7 @@ function InitialSettingsPage(props) { */ const getWalletBalance = (isPaymentItem) => (isPaymentItem ? CurrencyUtils.convertToDisplayString(props.userWallet.currentBalance) : undefined); - const onSecondaryInteraction = (link, event) => { + const openPopover = (link, event) => { if (typeof link === 'function') { link().then((url) => ReportActionContextMenu.showContextMenu(CONST.CONTEXT_MENU_TYPES.LINK, event, url, popoverAnchor.current)); } else if (link) { @@ -268,7 +268,7 @@ function InitialSettingsPage(props) { ref={popoverAnchor} hoverAndPressStyle={styles.hoveredComponentBG} shouldBlockSelection={Boolean(item.link)} - onSecondaryInteraction={item.link ? (event) => onSecondaryInteraction(item.link, event) : undefined} + onSecondaryInteraction={item.link ? (event) => openPopover(item.link, event) : undefined} focused={activeRoute && item.routeName && activeRoute.toLowerCase().replaceAll('_', '') === item.routeName.toLowerCase().replaceAll('/', '')} isPaneMenu /> From db641ff82f3a3051d1666773235fd8c6fc3f0095 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Thu, 1 Feb 2024 18:25:26 -0800 Subject: [PATCH 185/249] fix typo --- src/pages/workspace/WorkspacesListPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index 9b763120b30d..2ff71af530f2 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -340,7 +340,7 @@ function WorkspacesListPage({policies, allPolicyMembers, reimbursementAccount, r subtitle={translate('workspace.emptyWorkspace.subtitle')} ctaText={translate('workspace.new.newWorkspace')} ctaAccessibilityLabel={translate('workspace.new.newWorkspace')} - onCtaPress={() => App.createWorkspaceWithPolicyDraftAndNavigateToIt()} + onCTAPress={() => App.createWorkspaceWithPolicyDraftAndNavigateToIt()} // @ts-expect-error TODO: Remove once FeatureList (https://github.com/Expensify/App/issues/25039) is migrated to TS illustration={LottieAnimations.WorkspacePlanet} illustrationBackgroundColor={theme.PAGE_THEMES[SCREENS.SETTINGS.WORKSPACES].backgroundColor} From 53e3ae8bc685cf29314872422732bada5f2e17bb Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 2 Feb 2024 10:28:33 +0700 Subject: [PATCH 186/249] revert hard code and rename variable --- ...oraryForRefactorRequestConfirmationList.js | 2 +- .../iou/request/step/IOURequestStepTag.js | 23 +++++++++++-------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js index 8dc9d3e419c0..122001861827 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -258,7 +258,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const shouldCalculateDistanceAmount = isDistanceRequest && iouAmount === 0; // A flag for showing the categories field - const shouldShowCategories = iouCategory || OptionsListUtils.hasEnabledOptions(_.values(policyCategories)); + const shouldShowCategories = isPolicyExpenseChat && (iouCategory || OptionsListUtils.hasEnabledOptions(_.values(policyCategories))); // A flag and a toggler for showing the rest of the form fields const [shouldExpandFields, toggleShouldExpandFields] = useReducer((state) => !state, false); diff --git a/src/pages/iou/request/step/IOURequestStepTag.js b/src/pages/iou/request/step/IOURequestStepTag.js index e4390c5abbde..1297b98a0814 100644 --- a/src/pages/iou/request/step/IOURequestStepTag.js +++ b/src/pages/iou/request/step/IOURequestStepTag.js @@ -56,7 +56,7 @@ function IOURequestStepTag({ const tagListKey = _.first(_.keys(policyTags)); const policyTagListName = PolicyUtils.getTagListName(policyTags) || translate('common.tag'); const isEditing = action === CONST.IOU.ACTION.EDIT; - const isBillSplit = iouType === CONST.IOU.TYPE.SPLIT; + const isSplitBill = iouType === CONST.IOU.TYPE.SPLIT; const navigateBack = () => { Navigation.goBack(backTo || ROUTES.HOME); @@ -69,7 +69,7 @@ function IOURequestStepTag({ const updateTag = (selectedTag) => { const isSelectedTag = selectedTag.searchText === tag; const updatedTag = !isSelectedTag ? selectedTag.searchText : ''; - if (isBillSplit) { + if (isSplitBill) { IOU.setDraftSplitTransaction(transactionID, {tag: selectedTag.searchText}); navigateBack(); return; @@ -90,13 +90,18 @@ function IOURequestStepTag({ shouldShowWrapper testID={IOURequestStepTag.displayName} > - {translate('iou.tagSelection', {tagName: policyTagListName})} - + {({insets}) => ( + <> + {translate('iou.tagSelection', {tagName: policyTagListName})} + + + )} ); } From 88686d48330bd268b52ba2479e79a53b76366cd5 Mon Sep 17 00:00:00 2001 From: Filip Solecki Date: Fri, 2 Feb 2024 10:03:38 +0100 Subject: [PATCH 187/249] Adjustments after merge --- src/libs/UserUtils.ts | 2 +- src/pages/ShareCodePage.tsx | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/libs/UserUtils.ts b/src/libs/UserUtils.ts index f5973e854fd4..a8c918bc5def 100644 --- a/src/libs/UserUtils.ts +++ b/src/libs/UserUtils.ts @@ -176,7 +176,7 @@ function getAvatar(avatarSource?: AvatarSource, accountID?: number): AvatarSourc * @param avatarURL - the avatar source from user's personalDetails * @param accountID - the accountID of the user */ -function getAvatarUrl(avatarSource: AvatarSource, accountID: number): AvatarSource { +function getAvatarUrl(avatarSource: AvatarSource | undefined, accountID: number): AvatarSource { return isDefaultAvatar(avatarSource) ? getDefaultAvatarURL(accountID) : avatarSource; } diff --git a/src/pages/ShareCodePage.tsx b/src/pages/ShareCodePage.tsx index 62368b2520e6..831f0eb8f1d8 100644 --- a/src/pages/ShareCodePage.tsx +++ b/src/pages/ShareCodePage.tsx @@ -15,6 +15,7 @@ import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentU import useEnvironment from '@hooks/useEnvironment'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; +import useWindowDimensions from '@hooks/useWindowDimensions'; import Clipboard from '@libs/Clipboard'; import getPlatform from '@libs/getPlatform'; import Navigation from '@libs/Navigation/Navigation'; @@ -40,6 +41,7 @@ function ShareCodePage({report, session, currentUserPersonalDetails}: ShareCodeP const {translate} = useLocalize(); const {environmentURL} = useEnvironment(); const qrCodeRef = useRef(null); + const {isSmallScreenWidth} = useWindowDimensions(); const isReport = !!report?.reportID; @@ -69,14 +71,17 @@ function ShareCodePage({report, session, currentUserPersonalDetails}: ShareCodeP const isNative = platform === CONST.PLATFORM.IOS || platform === CONST.PLATFORM.ANDROID; return ( - + Navigation.goBack(isReport ? ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID) : ROUTES.SETTINGS)} + shouldShowBackButton={isReport || isSmallScreenWidth} /> - - + Clipboard.setString(url)} + shouldLimitWidth={false} /> {isNative && ( @@ -103,7 +109,7 @@ function ShareCodePage({report, session, currentUserPersonalDetails}: ShareCodeP isAnonymousAction title={translate('common.download')} icon={Expensicons.Download} - onPress={() => qrCodeRef.current?.download()} + onPress={qrCodeRef.current?.download} /> )} From 8e0f7733317986e8dad4ae1771a5c8a730e5d1b5 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 2 Feb 2024 16:09:17 +0700 Subject: [PATCH 188/249] fix extra padding of back button and tooltip --- src/components/HeaderWithBackButton/index.tsx | 4 ++-- src/components/ReportHeaderSkeletonView.tsx | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/HeaderWithBackButton/index.tsx b/src/components/HeaderWithBackButton/index.tsx index 078cb37c7e0d..64fe512eaff2 100755 --- a/src/components/HeaderWithBackButton/index.tsx +++ b/src/components/HeaderWithBackButton/index.tsx @@ -70,7 +70,7 @@ function HeaderWithBackButton({ // Hover on some part of close icons will not work on Electron if dragArea is true // https://github.com/Expensify/App/issues/29598 dataSet={{dragArea: false}} - style={[styles.headerBar, shouldShowBorderBottom && styles.borderBottom, shouldShowBackButton ? styles.pl0 : styles.pl5, shouldOverlay && StyleSheet.absoluteFillObject]} + style={[styles.headerBar, shouldShowBorderBottom && styles.borderBottom, shouldShowBackButton && styles.pl2, shouldOverlay && StyleSheet.absoluteFillObject]} > {shouldShowBackButton && ( @@ -87,7 +87,7 @@ function HeaderWithBackButton({ onBackButtonPress(); } }} - style={[styles.LHNToggle]} + style={[styles.touchableButtonImage]} role="button" accessibilityLabel={translate('common.back')} nativeID={CONST.BACK_BUTTON_NATIVE_ID} diff --git a/src/components/ReportHeaderSkeletonView.tsx b/src/components/ReportHeaderSkeletonView.tsx index 2113abd85e88..5332e0c5032c 100644 --- a/src/components/ReportHeaderSkeletonView.tsx +++ b/src/components/ReportHeaderSkeletonView.tsx @@ -24,12 +24,12 @@ function ReportHeaderSkeletonView({shouldAnimate = true, onBackButtonPress = () const {isSmallScreenWidth} = useWindowDimensions(); return ( - - + + {isSmallScreenWidth && ( From 0b2f0e6e1b0b73a9c3e649f086aae7afdfc06164 Mon Sep 17 00:00:00 2001 From: Shahe Shahinyan Date: Fri, 2 Feb 2024 14:17:17 +0400 Subject: [PATCH 189/249] Addressed to reviewer comments --- src/libs/API/parameters/UpdatePolicyRoomNameParams.ts | 2 +- src/libs/actions/Report.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/API/parameters/UpdatePolicyRoomNameParams.ts b/src/libs/API/parameters/UpdatePolicyRoomNameParams.ts index 74f936cbbb46..65b858b7c20f 100644 --- a/src/libs/API/parameters/UpdatePolicyRoomNameParams.ts +++ b/src/libs/API/parameters/UpdatePolicyRoomNameParams.ts @@ -1,6 +1,6 @@ type UpdatePolicyRoomNameParams = { reportID: string; - policyRoomName?: string; + policyRoomName: string; }; export default UpdatePolicyRoomNameParams; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 3d375ec26413..221c7f8d4f88 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -1852,7 +1852,7 @@ function updatePolicyRoomNameAndNavigate(policyRoomReport: Report, policyRoomNam }, ]; - const parameters: UpdatePolicyRoomNameParams = {reportID, policyRoomName: policyRoomName ?? ''}; + const parameters: UpdatePolicyRoomNameParams = {reportID, policyRoomName}; API.write(WRITE_COMMANDS.UPDATE_POLICY_ROOM_NAME, parameters, {optimisticData, successData, failureData}); Navigation.goBack(ROUTES.REPORT_SETTINGS.getRoute(reportID)); From fe8ca0afd5db6ac7dd7a85fa27da4ebc5529f198 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Thu, 1 Feb 2024 09:19:55 +0100 Subject: [PATCH 190/249] 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 191/249] 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 192/249] 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 9b0250793fa22d4366b38c4899e5bdcfcdce1ce0 Mon Sep 17 00:00:00 2001 From: someone-here Date: Fri, 2 Feb 2024 18:34:33 +0530 Subject: [PATCH 193/249] Limit length --- src/pages/RoomDescriptionPage.tsx | 11 +---------- src/pages/workspace/WorkspaceNewRoomPage.js | 2 +- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/pages/RoomDescriptionPage.tsx b/src/pages/RoomDescriptionPage.tsx index 969d19f58a67..e0a287df912f 100644 --- a/src/pages/RoomDescriptionPage.tsx +++ b/src/pages/RoomDescriptionPage.tsx @@ -63,14 +63,6 @@ function RoomDescriptionPage({report, policies}: RoomDescriptionPageProps) { }, []), ); - const limitCharacters = (values: OnyxFormValuesFields) => { - const errors: Errors = {}; - if (String(values.reportDescription).length > CONST.REPORT_DESCRIPTION.MAX_LENGTH) { - errors.reportDescription = translate('common.error.characterLimit', {limit: CONST.REPORT_DESCRIPTION.MAX_LENGTH}); - } - return errors; - }; - return ( {translate('reportDescriptionPage.explainerText')} @@ -99,7 +90,7 @@ function RoomDescriptionPage({report, policies}: RoomDescriptionPageProps) { accessibilityLabel={translate('reportDescriptionPage.roomDescription')} role={CONST.ROLE.PRESENTATION} autoGrowHeight - maxLength={CONST.MAX_COMMENT_LENGTH} + maxLength={CONST.REPORT_DESCRIPTION.MAX_LENGTH} ref={(el: BaseTextInputRef | null): void => { if (!el) { return; diff --git a/src/pages/workspace/WorkspaceNewRoomPage.js b/src/pages/workspace/WorkspaceNewRoomPage.js index 56cb89899d92..32ec99320d6b 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.js +++ b/src/pages/workspace/WorkspaceNewRoomPage.js @@ -308,7 +308,7 @@ function WorkspaceNewRoomPage(props) { accessibilityLabel={translate('reportDescriptionPage.roomDescriptionOptional')} role={CONST.ACCESSIBILITY_ROLE.TEXT} autoGrowHeight - maxLength={CONST.MAX_COMMENT_LENGTH} + maxLength={CONST.REPORT_DESCRIPTION.MAX_LENGTH} autoCapitalize="none" containerStyles={[styles.autoGrowHeightMultilineInput]} /> From c67793ee7d39fdf25c705f099884736101512f84 Mon Sep 17 00:00:00 2001 From: someone-here Date: Fri, 2 Feb 2024 19:14:26 +0530 Subject: [PATCH 194/249] Fix lint --- src/pages/RoomDescriptionPage.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pages/RoomDescriptionPage.tsx b/src/pages/RoomDescriptionPage.tsx index e0a287df912f..7e96fc44a983 100644 --- a/src/pages/RoomDescriptionPage.tsx +++ b/src/pages/RoomDescriptionPage.tsx @@ -6,7 +6,6 @@ import type {OnyxCollection} from 'react-native-onyx'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; -import type {OnyxFormValuesFields} from '@components/Form/types'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; @@ -22,7 +21,6 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; -import type {Errors} from '@src/types/onyx/OnyxCommon'; type RoomDescriptionPageProps = { /** Policy for the current report */ From f56e6c8b8da9272069003549e47d19cdb27c26a3 Mon Sep 17 00:00:00 2001 From: someone-here Date: Fri, 2 Feb 2024 19:50:20 +0530 Subject: [PATCH 195/249] wrap html --- src/components/ReportWelcomeText.tsx | 1 + src/styles/index.ts | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/components/ReportWelcomeText.tsx b/src/components/ReportWelcomeText.tsx index a979833001cd..5e39e0adb93d 100644 --- a/src/components/ReportWelcomeText.tsx +++ b/src/components/ReportWelcomeText.tsx @@ -80,6 +80,7 @@ function ReportWelcomeText({report, policy, personalDetails}: ReportWelcomeTextP } Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID)); }} + style={styles.renderHTML} accessibilityLabel={translate('reportDescriptionPage.roomDescription')} > diff --git a/src/styles/index.ts b/src/styles/index.ts index 6bc80e847626..87d5a3665b25 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -1778,6 +1778,12 @@ const styles = (theme: ThemeColors) => ...wordBreak.breakWord, }, + renderHTML: { + maxWidth: '100%', + ...whiteSpace.preWrap, + ...wordBreak.breakWord, + }, + chatItemComposeWithFirstRow: { minHeight: 90, }, From 18796cc55342f0d6017bbfd9bd5e5e74b49d710b Mon Sep 17 00:00:00 2001 From: Ionatan Wiznia Date: Fri, 2 Feb 2024 12:10:42 -0300 Subject: [PATCH 196/249] Filter out personal policies in room page --- src/pages/workspace/WorkspaceNewRoomPage.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/pages/workspace/WorkspaceNewRoomPage.js b/src/pages/workspace/WorkspaceNewRoomPage.js index b616b519ff32..fa128b2bfce6 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.js +++ b/src/pages/workspace/WorkspaceNewRoomPage.js @@ -106,11 +106,14 @@ function WorkspaceNewRoomPage(props) { const workspaceOptions = useMemo( () => - _.map(PolicyUtils.getActivePolicies(props.policies), (policy) => ({ - label: policy.name, - key: policy.id, - value: policy.id, - })), + _.map( + _.filter(PolicyUtils.getActivePolicies(props.policies), (policy) => policy.type !== CONST.POLICY.TYPE.PERSONAL), + (policy) => ({ + label: policy.name, + key: policy.id, + value: policy.id, + }), + ), [props.policies], ); const [policyID, setPolicyID] = useState(() => { From 9e8dd6d12d746146b49c11833dc061cb9cc46599 Mon Sep 17 00:00:00 2001 From: someone-here Date: Fri, 2 Feb 2024 21:47:16 +0530 Subject: [PATCH 197/249] Fix conflicts --- src/libs/Navigation/linkingConfig/config.ts | 5 ++--- src/libs/ReportUtils.ts | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index f1c9c316fe93..afac2bde8ad6 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -280,9 +280,9 @@ const config: LinkingOptions['config'] = { }, }, }, - [SCREENS.RIGHT_MODAL.REPORT_WELCOME_MESSAGE]: { + [SCREENS.RIGHT_MODAL.REPORT_DESCRIPTION]: { screens: { - [SCREENS.REPORT_WELCOME_MESSAGE_ROOT]: ROUTES.REPORT_WELCOME_MESSAGE.route, + [SCREENS.REPORT_DESCRIPTION_ROOT]: ROUTES.REPORT_DESCRIPTION.route, }, }, [SCREENS.RIGHT_MODAL.NEW_CHAT]: { @@ -425,7 +425,6 @@ const config: LinkingOptions['config'] = { [SCREENS.RIGHT_MODAL.TASK_DETAILS]: { screens: { [SCREENS.TASK.TITLE]: ROUTES.TASK_TITLE.route, - [SCREENS.TASK.DESCRIPTION]: ROUTES.TASK_DESCRIPTION.route, [SCREENS.TASK.ASSIGNEE]: ROUTES.TASK_ASSIGNEE.route, }, }, diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index a5265f036db4..a6b3f1839eda 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4593,7 +4593,7 @@ function canEditReportDescription(report: OnyxEntry, policy: OnyxEntry

Date: Sat, 3 Feb 2024 08:02:43 +0530 Subject: [PATCH 198/249] Disable enter prop --- src/components/Form/FormWrapper.tsx | 3 ++- src/components/Form/types.ts | 3 +++ src/pages/workspace/WorkspaceNewRoomPage.js | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/Form/FormWrapper.tsx b/src/components/Form/FormWrapper.tsx index d5b47761e4c0..7630cea4ff2d 100644 --- a/src/components/Form/FormWrapper.tsx +++ b/src/components/Form/FormWrapper.tsx @@ -54,6 +54,7 @@ function FormWrapper({ formID, scrollContextEnabled = false, shouldHideFixErrorsAlert = false, + disablePressOnEnter = true, }: FormWrapperProps) { const styles = useThemeStyles(); const formRef = useRef(null); @@ -112,7 +113,7 @@ function FormWrapper({ containerStyles={[styles.mh0, styles.mt5, styles.flex1, submitButtonStyles]} enabledWhenOffline={enabledWhenOffline} isSubmitActionDangerous={isSubmitActionDangerous} - disablePressOnEnter + disablePressOnEnter={disablePressOnEnter} /> )} diff --git a/src/components/Form/types.ts b/src/components/Form/types.ts index 447f3205ad68..b2c7aea3f3cf 100644 --- a/src/components/Form/types.ts +++ b/src/components/Form/types.ts @@ -84,6 +84,9 @@ type FormProps = { /** Custom content to display in the footer after submit button */ footerContent?: ReactNode; + + /** Disable press on enter for submit button */ + disablePressOnEnter?: boolean; }; type RegisterInput = (inputID: keyof Form, inputProps: TInputProps) => TInputProps; diff --git a/src/pages/workspace/WorkspaceNewRoomPage.js b/src/pages/workspace/WorkspaceNewRoomPage.js index 32ec99320d6b..b32637e8e219 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.js +++ b/src/pages/workspace/WorkspaceNewRoomPage.js @@ -289,6 +289,7 @@ function WorkspaceNewRoomPage(props) { validate={validate} onSubmit={submit} enabledWhenOffline + disablePressOnEnter={false} > Date: Sat, 3 Feb 2024 08:07:21 +0530 Subject: [PATCH 199/249] Fix lint --- src/components/Form/FormWrapper.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/Form/FormWrapper.tsx b/src/components/Form/FormWrapper.tsx index 7630cea4ff2d..aa3aa5b40b5a 100644 --- a/src/components/Form/FormWrapper.tsx +++ b/src/components/Form/FormWrapper.tsx @@ -138,6 +138,7 @@ function FormWrapper({ submitButtonText, shouldHideFixErrorsAlert, onFixTheErrorsLinkPressed, + disablePressOnEnter, ], ); From 2bf606f75475c0d07b0634ffc3a452dde69a4ac8 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sat, 3 Feb 2024 09:24:10 +0530 Subject: [PATCH 200/249] added comment --- src/pages/iou/request/step/IOURequestStepConfirmation.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.js b/src/pages/iou/request/step/IOURequestStepConfirmation.js index 84adf87bbae2..c177e4dfd585 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.js +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.js @@ -328,6 +328,8 @@ function IOURequestStepConfirmation({ IOU.setMoneyRequestBillable_temporaryForRefactor(transactionID, billable); }; + // This loading indicator is shown because the transaction originalCurrency is being updated later than the component mounts. + // To prevent the component from rendering with the wrong currency, we show a loading indicator until the correct currency is set. const isLoading = !!(transaction && transaction.originalCurrency); return ( From 1bcc02ec155aac3f83fd157aa1ced07652f30270 Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Sat, 3 Feb 2024 12:23:27 +0300 Subject: [PATCH 201/249] update to validate on non-native only --- src/pages/signin/LoginForm/BaseLoginForm.js | 26 +++++++++++++-------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/pages/signin/LoginForm/BaseLoginForm.js b/src/pages/signin/LoginForm/BaseLoginForm.js index 1da92d447c5b..b126219e44db 100644 --- a/src/pages/signin/LoginForm/BaseLoginForm.js +++ b/src/pages/signin/LoginForm/BaseLoginForm.js @@ -28,6 +28,7 @@ import {parsePhoneNumber} from '@libs/PhoneNumber'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ValidationUtils from '@libs/ValidationUtils'; import Visibility from '@libs/Visibility'; +import willBlurTextInputOnTapOutside from '@libs/willBlurTextInputOnTapOutside'; import * as CloseAccount from '@userActions/CloseAccount'; import * as MemoryOnlyKeys from '@userActions/MemoryOnlyKeys/MemoryOnlyKeys'; import * as Session from '@userActions/Session'; @@ -277,16 +278,21 @@ function LoginForm(props) { id="username" name="username" testID="username" - onBlur={() => - // This delay is to avoid the validate being called before google iframe is rendered to - // avoid error message appearing after pressing google signin button. - setTimeout(() => { - if (firstBlurred.current || !Visibility.isVisible() || !Visibility.hasFocus()) { - return; - } - firstBlurred.current = true; - validate(login); - }, 500) + onBlur={ + // As we have only two signin buttons (Apple/Google) other than the text input, + // for natives onBlur is called only when the buttons are pressed and we don't need + // to validate in those case as the user has opted for other signin flow. + willBlurTextInputOnTapOutside() && + (() => + // This delay is to avoid the validate being called before google iframe is rendered to + // avoid error message appearing after pressing google signin button. + setTimeout(() => { + if (firstBlurred.current || !Visibility.isVisible() || !Visibility.hasFocus()) { + return; + } + firstBlurred.current = true; + validate(login); + }, 500)) } onChangeText={onTextInput} onSubmitEditing={validateAndSubmitForm} From c445c5e0b94d3bb8d3f8de0508f6f24a7619ae10 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Sat, 3 Feb 2024 12:10:35 +0100 Subject: [PATCH 202/249] 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 203/249] 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 25207b4bde089e2ea61ed47b23d242ada76f97f0 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Sat, 3 Feb 2024 19:22:44 +0300 Subject: [PATCH 204/249] rm extra ul --- .../getting-started/Join-your-company's-workspace.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/articles/expensify-classic/getting-started/Join-your-company's-workspace.md b/docs/articles/expensify-classic/getting-started/Join-your-company's-workspace.md index 099f381e6010..a31b972e683c 100644 --- a/docs/articles/expensify-classic/getting-started/Join-your-company's-workspace.md +++ b/docs/articles/expensify-classic/getting-started/Join-your-company's-workspace.md @@ -212,7 +212,6 @@ Once you’ve created your expenses, they may be automatically added to an expen

  • Attach PDF: Select this checkbox to attach a copy of your report to the email.
  • Tap Submit.
  • - {% include end-option.html %} @@ -255,4 +254,4 @@ Add an extra layer of security to help keep your financial data safe and secure When you log in to Expensify in the future, you’ll open your authenticator app to get the code and enter it into Expensify. A new code regenerates every few seconds, so the code is always different. If the code time runs out, you can generate a new code as needed. - \ No newline at end of file + From 53dcfc1c0f8e38f60203a56e39f3278ba7b3d34c Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Sat, 3 Feb 2024 21:28:21 +0100 Subject: [PATCH 205/249] fix: remove empty line --- src/libs/ReportUtils.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index af6c9372f27a..c3de0f9f749f 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4657,7 +4657,6 @@ function hasUpdatedTotal(report: OnyxEntry): boolean { } const transactions = TransactionUtils.getAllReportTransactions(report.reportID); - const hasPendingTransaction = transactions.some((transaction) => !!transaction.pendingAction); const hasTransactionWithDifferentCurrency = transactions.some((transaction) => transaction.currency !== report.currency); From 8a37b8e8de044cb980e8eab579f7fab3af22cdb1 Mon Sep 17 00:00:00 2001 From: pradeepkumar Date: Fri, 26 Jan 2024 12:10:08 +0530 Subject: [PATCH 206/249] patch fix --- patches/react-native-pdf+6.7.3.patch | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 patches/react-native-pdf+6.7.3.patch diff --git a/patches/react-native-pdf+6.7.3.patch b/patches/react-native-pdf+6.7.3.patch new file mode 100644 index 000000000000..63024e7d4c1f --- /dev/null +++ b/patches/react-native-pdf+6.7.3.patch @@ -0,0 +1,23 @@ +diff --git a/node_modules/react-native-pdf/index.js b/node_modules/react-native-pdf/index.js +index c05de52..bea7af8 100644 +--- a/node_modules/react-native-pdf/index.js ++++ b/node_modules/react-native-pdf/index.js +@@ -367,11 +367,17 @@ export default class Pdf extends Component { + message[4] = message.splice(4).join('|'); + } + if (message[0] === 'loadComplete') { ++ let tableContents; ++ try { ++ tableContents = message[4]&&JSON.parse(message[4]); ++ } catch(e) { ++ tableContents = message[4]; ++ } + this.props.onLoadComplete && this.props.onLoadComplete(Number(message[1]), this.state.path, { + width: Number(message[2]), + height: Number(message[3]), + }, +- message[4]&&JSON.parse(message[4])); ++ tableContents); + } else if (message[0] === 'pageChanged') { + this.props.onPageChanged && this.props.onPageChanged(Number(message[1]), Number(message[2])); + } else if (message[0] === 'error') { From fc60fa62c9584f1db0a89ad1a0cf9dd7caa361e7 Mon Sep 17 00:00:00 2001 From: someone-here Date: Sun, 4 Feb 2024 14:29:08 +0530 Subject: [PATCH 207/249] Anonymous action check --- src/components/MenuItem.tsx | 2 +- src/pages/ReportDetailsPage.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx index fd4afdfbc948..cc0de763f515 100644 --- a/src/components/MenuItem.tsx +++ b/src/components/MenuItem.tsx @@ -386,7 +386,7 @@ function MenuItem( {(isHovered) => ( shouldBlockSelection && isSmallScreenWidth && DeviceCapabilities.canUseTouchScreen() && ControlSelection.block()} onPressOut={ControlSelection.unblock} onSecondaryInteraction={onSecondaryInteraction} diff --git a/src/pages/ReportDetailsPage.js b/src/pages/ReportDetailsPage.js index 19162bb756e3..99e1cea8280a 100644 --- a/src/pages/ReportDetailsPage.js +++ b/src/pages/ReportDetailsPage.js @@ -249,6 +249,7 @@ function ReportDetailsPage(props) { interactive={canEditReportDescription} title={props.report.description} shouldRenderAsHTML + shouldCheckActionAllowedOnPress={false} description={props.translate('reportDescriptionPage.roomDescription')} onPress={() => Navigation.navigate(ROUTES.REPORT_DESCRIPTION.getRoute(props.report.reportID))} /> From b742d6642e2c94d6accdbaf9322fd8e6bc77ff4a Mon Sep 17 00:00:00 2001 From: Shahe Shahinyan Date: Sun, 4 Feb 2024 14:23:24 +0400 Subject: [PATCH 208/249] Addressed to reviewer comments --- src/libs/PolicyUtils.ts | 2 +- .../Report/NotificationPreferencePage.tsx | 4 +-- .../settings/Report/ReportSettingsPage.tsx | 26 +++++++++---------- src/pages/settings/Report/RoomNamePage.tsx | 3 +-- .../settings/Report/WriteCapabilityPage.tsx | 5 ++-- 5 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 426071a81894..b6ee4ab3a353 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -107,7 +107,7 @@ function isExpensifyGuideTeam(email: string): boolean { /** * Checks if the current user is an admin of the policy. */ -const isPolicyAdmin = (policy: OnyxEntry | undefined): boolean => policy?.role === CONST.POLICY.ROLE.ADMIN; +const isPolicyAdmin = (policy: OnyxEntry): 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/pages/settings/Report/NotificationPreferencePage.tsx b/src/pages/settings/Report/NotificationPreferencePage.tsx index 30b9ffa3c2d2..05f3483f7ce8 100644 --- a/src/pages/settings/Report/NotificationPreferencePage.tsx +++ b/src/pages/settings/Report/NotificationPreferencePage.tsx @@ -40,9 +40,9 @@ function NotificationPreferencePage({report}: NotificationPreferencePageProps) { - ReportActions.updateNotificationPreference(report?.reportID ?? '', report?.notificationPreference, option.value, true, undefined, undefined, report) + report && ReportActions.updateNotificationPreference(report.reportID, report.notificationPreference, option.value, true, undefined, undefined, report) } - initiallyFocusedOptionKey={Object.values(notificationPreferenceOptions ?? {}).find((locale) => locale.isSelected)?.keyForList} + initiallyFocusedOptionKey={notificationPreferenceOptions.find((locale) => locale.isSelected)?.keyForList} />
    diff --git a/src/pages/settings/Report/ReportSettingsPage.tsx b/src/pages/settings/Report/ReportSettingsPage.tsx index 28d189359860..37408ef61df2 100644 --- a/src/pages/settings/Report/ReportSettingsPage.tsx +++ b/src/pages/settings/Report/ReportSettingsPage.tsx @@ -1,5 +1,4 @@ import type {StackScreenProps} from '@react-navigation/stack'; -import isEmpty from 'lodash/isEmpty'; import React, {useMemo} from 'react'; import {ScrollView, View} from 'react-native'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; @@ -23,6 +22,7 @@ import * as ReportActions from '@userActions/Report'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; type ReportSettingsPageProps = WithReportOrNotFoundProps & StackScreenProps; @@ -38,7 +38,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { // We only want policy owners and admins to be able to modify the welcome message, but not in thread chat const shouldDisableWelcomeMessage = ReportUtils.shouldDisableWelcomeMessage(report, linkedWorkspace); - const shouldDisableSettings = isEmpty(report) || ReportUtils.isArchivedRoom(report); + const shouldDisableSettings = isEmptyObject(report) || ReportUtils.isArchivedRoom(report); const shouldShowRoomName = !ReportUtils.isPolicyExpenseChat(report) && !ReportUtils.isChatThread(report); const notificationPreference = report?.notificationPreference && report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN @@ -60,7 +60,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(reportID ?? ''))} + onBackButtonPress={() => Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(reportID))} /> {shouldShowNotificationPref && ( @@ -68,7 +68,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { shouldShowRightIcon title={notificationPreference} description={translate('notificationPreferencesPage.label')} - onPress={() => Navigation.navigate(ROUTES.REPORT_SETTINGS_NOTIFICATION_PREFERENCES.getRoute(reportID ?? ''))} + onPress={() => Navigation.navigate(ROUTES.REPORT_SETTINGS_NOTIFICATION_PREFERENCES.getRoute(reportID))} /> )} {shouldShowRoomName && ( @@ -76,7 +76,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { pendingAction={report?.pendingFields?.reportName} errors={report?.errorFields?.reportName} errorRowStyles={[styles.ph5]} - onClose={() => ReportActions.clearPolicyRoomNameErrors(reportID ?? '')} + onClose={() => ReportActions.clearPolicyRoomNameErrors(reportID)} > {shouldDisableRename ? ( @@ -99,7 +99,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { shouldShowRightIcon title={report?.reportName} description={translate('newRoomPage.roomName')} - onPress={() => Navigation.navigate(ROUTES.REPORT_SETTINGS_ROOM_NAME.getRoute(reportID ?? ''))} + onPress={() => Navigation.navigate(ROUTES.REPORT_SETTINGS_ROOM_NAME.getRoute(reportID))} /> )} @@ -110,7 +110,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { shouldShowRightIcon title={writeCapabilityText} description={translate('writeCapabilityPage.label')} - onPress={() => Navigation.navigate(ROUTES.REPORT_SETTINGS_WRITE_CAPABILITY.getRoute(reportID ?? ''))} + onPress={() => Navigation.navigate(ROUTES.REPORT_SETTINGS_WRITE_CAPABILITY.getRoute(reportID))} /> ) : ( @@ -129,7 +129,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { ))} - {Boolean(linkedWorkspace) && ( + {linkedWorkspace !== null && ( )} - {Boolean(report?.visibility) && ( + {report?.visibility !== undefined && ( - {report?.visibility && translate(`newRoomPage.visibilityOptions.${report.visibility}`)} + {translate(`newRoomPage.visibilityOptions.${report.visibility}`)} - {report?.visibility && translate(`newRoomPage.${report.visibility}Description`)} + {report.visibility && translate(`newRoomPage.${report.visibility}Description`)} )} @@ -168,7 +168,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { Navigation.navigate(ROUTES.REPORT_WELCOME_MESSAGE.getRoute(reportID ?? ''))} + onPress={() => Navigation.navigate(ROUTES.REPORT_WELCOME_MESSAGE.getRoute(reportID))} shouldShowRightIcon /> )} diff --git a/src/pages/settings/Report/RoomNamePage.tsx b/src/pages/settings/Report/RoomNamePage.tsx index 6b2fd751f01f..30226bc6f502 100644 --- a/src/pages/settings/Report/RoomNamePage.tsx +++ b/src/pages/settings/Report/RoomNamePage.tsx @@ -27,7 +27,6 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type {Policy, Report} from '@src/types/onyx'; -import {isEmptyObject} from '@src/types/utils/EmptyObject'; type RoomNamePageOnyxProps = { /** All reports shared with the user */ @@ -87,7 +86,7 @@ function RoomNamePage({report, policy, reports}: RoomNamePageProps) { !isEmptyObject(report) && ReportActions.updatePolicyRoomNameAndNavigate(report, values.roomName)} + onSubmit={(values) => report && ReportActions.updatePolicyRoomNameAndNavigate(report, values.roomName)} validate={validate} submitButtonText={translate('common.save')} enabledWhenOffline diff --git a/src/pages/settings/Report/WriteCapabilityPage.tsx b/src/pages/settings/Report/WriteCapabilityPage.tsx index 7af951d685d4..5f5fe73e5199 100644 --- a/src/pages/settings/Report/WriteCapabilityPage.tsx +++ b/src/pages/settings/Report/WriteCapabilityPage.tsx @@ -18,7 +18,6 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type {Policy} from '@src/types/onyx'; -import {isEmptyObject} from '@src/types/utils/EmptyObject'; type WriteCapabilityPageOnyxProps = { /** The policy object for the current route */ @@ -53,8 +52,8 @@ function WriteCapabilityPage({report, policy}: WriteCapabilityPageProps) { /> !isEmptyObject(report) && ReportActions.updateWriteCapabilityAndNavigate(report, option.value)} - initiallyFocusedOptionKey={Object.values(writeCapabilityOptions).find((locale) => locale.isSelected)?.keyForList} + onSelectRow={(option) => report && ReportActions.updateWriteCapabilityAndNavigate(report, option.value)} + initiallyFocusedOptionKey={writeCapabilityOptions.find((locale) => locale.isSelected)?.keyForList} /> From a2d628e21f5ddfedb4249c43d80b5025220a5116 Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Sun, 4 Feb 2024 19:53:45 +0530 Subject: [PATCH 209/249] fix: IOU - Enter click does not deselect/select user in split bill. Signed-off-by: Krishna Gupta --- src/components/ButtonWithDropdownMenu.tsx | 7 +++++++ src/components/MoneyRequestConfirmationList.js | 2 ++ .../MoneyTemporaryForRefactorRequestConfirmationList.js | 2 ++ src/components/SettlementButton.js | 6 ++++++ 4 files changed, 17 insertions(+) diff --git a/src/components/ButtonWithDropdownMenu.tsx b/src/components/ButtonWithDropdownMenu.tsx index 676912de6b60..18e30079094f 100644 --- a/src/components/ButtonWithDropdownMenu.tsx +++ b/src/components/ButtonWithDropdownMenu.tsx @@ -59,6 +59,9 @@ type ButtonWithDropdownMenuProps = { /* ref for the button */ buttonRef: RefObject; + + /** The priority to assign the enter key event listener to buttons. 0 is the highest priority. */ + enterKeyEventListenerPriority?: number; }; function ButtonWithDropdownMenu({ @@ -76,6 +79,7 @@ function ButtonWithDropdownMenu({ onPress, options, onOptionSelected, + enterKeyEventListenerPriority = 0, }: ButtonWithDropdownMenuProps) { const theme = useTheme(); const styles = useThemeStyles(); @@ -126,6 +130,7 @@ function ButtonWithDropdownMenu({ large={isButtonSizeLarge} medium={!isButtonSizeLarge} innerStyles={[innerStyleDropButton]} + enterKeyEventListenerPriority={enterKeyEventListenerPriority} />