From aae942d81a502471c4f84555bc977108d7af1036 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 29 May 2024 22:05:23 +0100 Subject: [PATCH 001/463] Cleanup optimistic data of unusued IOU report --- src/libs/actions/Report.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index aa134d47cf77..a3a5b3e0a76b 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -186,12 +186,12 @@ const allReportActions: OnyxCollection = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT_ACTIONS, - callback: (action, key) => { - if (!key || !action) { + callback: (actions, key) => { + if (!key || !actions) { return; } const reportID = CollectionUtils.extractCollectionItemID(key); - allReportActions[reportID] = action; + allReportActions[reportID] = actions; }, }); @@ -1282,6 +1282,14 @@ function handleReportChanged(report: OnyxEntry) { return; } + if (report?.reportID && report.preexistingReportID && ReportUtils.isMoneyRequestReport(report)) { + Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`, { + [report.parentReportActionID]: null, + }); + Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, null); + return; + } + // It is possible that we optimistically created a DM/group-DM for a set of users for which a report already exists. // In this case, the API will let us know by returning a preexistingReportID. // We should clear out the optimistically created report and re-route the user to the preexisting report. From e69dd460c76176e324a374bf6905fafa18f2d5cc Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 22 Jul 2024 16:09:51 +0530 Subject: [PATCH 002/463] Added pluralization system for lang translations --- src/components/MoneyReportHeader.tsx | 4 +- src/components/ProcessMoneyReportHoldMenu.tsx | 2 +- src/components/ReceiptAudit.tsx | 2 +- .../ExportWithDropdownMenu.tsx | 2 +- .../ReportActionItem/ReportPreview.tsx | 13 +- .../Search/SearchListWithHeader.tsx | 4 +- src/components/Search/SearchPageHeader.tsx | 2 +- src/languages/en.ts | 108 ++++++++++------ src/languages/es.ts | 115 +++++++++++------- src/languages/types.ts | 63 ++++++++-- src/libs/Localize/index.ts | 37 +++++- src/libs/PolicyUtils.ts | 5 +- src/libs/ReportActionsUtils.ts | 2 +- src/pages/ReportDetailsPage.tsx | 4 +- src/pages/ReportParticipantsPage.tsx | 2 +- src/pages/Search/SearchSelectedNarrow.tsx | 2 +- .../ReportActionCompose.tsx | 12 +- .../home/report/ReportDetailsExportPage.tsx | 2 +- .../FloatingActionButtonAndPopover.tsx | 2 +- src/pages/wallet/WalletStatementPage.tsx | 2 +- src/pages/workspace/WorkspaceMembersPage.tsx | 2 +- .../intacct/ExistingConnectionsPage.tsx | 4 +- .../intacct/import/SageIntacctImportPage.tsx | 2 +- .../NetSuiteExistingConnectionsPage.tsx | 4 +- .../categories/WorkspaceCategoriesPage.tsx | 2 +- .../PolicyDistanceRateDetailsPage.tsx | 2 +- .../distanceRates/PolicyDistanceRatesPage.tsx | 10 +- .../ReportFieldsListValuesPage.tsx | 2 +- .../WorkspaceReportFieldsPage.tsx | 2 +- .../workspace/tags/WorkspaceTagsPage.tsx | 2 +- .../workspace/tags/WorkspaceViewTagsPage.tsx | 2 +- .../workspace/taxes/WorkspaceTaxesPage.tsx | 2 +- 32 files changed, 273 insertions(+), 148 deletions(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 1acee187c67b..18a8c0b9e1a1 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -387,12 +387,12 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea /> )} setIsDeleteRequestModalVisible(false)} onModalHide={() => ReportUtils.navigateBackAfterDeleteTransaction(navigateBackToAfterDelete.current)} - prompt={translate('iou.deleteConfirmation')} + prompt={translate('iou.deleteConfirmation', undefined, 1)} confirmText={translate('common.delete')} cancelText={translate('common.cancel')} danger diff --git a/src/components/ProcessMoneyReportHoldMenu.tsx b/src/components/ProcessMoneyReportHoldMenu.tsx index 872464d8a5b0..ffc1150a454b 100644 --- a/src/components/ProcessMoneyReportHoldMenu.tsx +++ b/src/components/ProcessMoneyReportHoldMenu.tsx @@ -76,7 +76,7 @@ function ProcessMoneyReportHoldMenu({ if (nonHeldAmount) { return translate(isApprove ? 'iou.confirmApprovalAmount' : 'iou.confirmPayAmount'); } - return translate(isApprove ? 'iou.confirmApprovalAllHoldAmount' : 'iou.confirmPayAllHoldAmount', {transactionCount}); + return translate(isApprove ? 'iou.confirmApprovalAllHoldAmount' : 'iou.confirmPayAllHoldAmount', undefined, transactionCount); }, [nonHeldAmount, transactionCount, translate, isApprove]); return ( diff --git a/src/components/ReceiptAudit.tsx b/src/components/ReceiptAudit.tsx index bb704def1836..1057736621cd 100644 --- a/src/components/ReceiptAudit.tsx +++ b/src/components/ReceiptAudit.tsx @@ -22,7 +22,7 @@ function ReceiptAudit({notes, shouldShowAuditResult}: ReceiptAuditProps) { let auditText = ''; if (notes.length > 0 && shouldShowAuditResult) { - auditText = translate('iou.receiptIssuesFound', notes.length); + auditText = translate('iou.receiptIssuesFound', undefined, notes.length); } else if (!notes.length && shouldShowAuditResult) { auditText = translate('common.verified'); } diff --git a/src/components/ReportActionItem/ExportWithDropdownMenu.tsx b/src/components/ReportActionItem/ExportWithDropdownMenu.tsx index a13c0a266689..2906bee5758f 100644 --- a/src/components/ReportActionItem/ExportWithDropdownMenu.tsx +++ b/src/components/ReportActionItem/ExportWithDropdownMenu.tsx @@ -118,7 +118,7 @@ function ExportWithDropdownMenu({policy, report, connectionName}: ExportWithDrop title={translate('workspace.exportAgainModal.title')} onConfirm={confirmExport} onCancel={() => setModalStatus(null)} - prompt={translate('workspace.exportAgainModal.description', report?.reportName ?? '', connectionName)} + prompt={translate('workspace.exportAgainModal.description', {reportName: report?.reportName ?? '', connectionName})} confirmText={translate('workspace.exportAgainModal.confirmText')} cancelText={translate('workspace.exportAgainModal.cancelText')} isVisible={!!modalStatus} diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index ae6ace23c64e..c794113d0f50 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -328,11 +328,14 @@ function ReportPreview({ return {supportText: formattedMerchant}; } return { - supportText: translate('iou.expenseCount', { - count: numberOfRequests - numberOfScanningReceipts - numberOfPendingRequests, - scanningReceipts: numberOfScanningReceipts, - pendingReceipts: numberOfPendingRequests, - }), + supportText: translate( + 'iou.expenseCount', + { + scanningReceipts: numberOfScanningReceipts, + pendingReceipts: numberOfPendingRequests, + }, + numberOfRequests - numberOfScanningReceipts - numberOfPendingRequests, + ), }; }, [formattedMerchant, formattedDescription, moneyRequestComment, translate, numberOfRequests, numberOfScanningReceipts, numberOfPendingRequests]); diff --git a/src/components/Search/SearchListWithHeader.tsx b/src/components/Search/SearchListWithHeader.tsx index bd4b843bbd60..edfa55a53b26 100644 --- a/src/components/Search/SearchListWithHeader.tsx +++ b/src/components/Search/SearchListWithHeader.tsx @@ -213,8 +213,8 @@ function SearchListWithHeader( isVisible={deleteExpensesConfirmModalVisible} onConfirm={handleDeleteExpenses} onCancel={handleOnCancelConfirmModal} - title={translate('iou.deleteExpense', {count: selectedTransactionsToDelete.length})} - prompt={translate('iou.deleteConfirmation', {count: selectedTransactionsToDelete.length})} + title={translate('iou.deleteExpense', undefined, selectedTransactionsToDelete.length)} + prompt={translate('iou.deleteConfirmation', undefined, selectedTransactionsToDelete.length)} confirmText={translate('common.delete')} cancelText={translate('common.cancel')} danger diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx index bd1e053b1c7e..0f4843b52a58 100644 --- a/src/components/Search/SearchPageHeader.tsx +++ b/src/components/Search/SearchPageHeader.tsx @@ -221,7 +221,7 @@ function SearchPageHeader({ shouldAlwaysShowDropdownMenu pressOnEnter buttonSize={CONST.DROPDOWN_BUTTON_SIZE.MEDIUM} - customText={translate('workspace.common.selected', {selectedNumber: selectedTransactionsKeys.length})} + customText={translate('workspace.common.selected', undefined, selectedTransactionsKeys.length)} options={headerButtonsOptions} isSplitButton={false} /> diff --git a/src/languages/en.ts b/src/languages/en.ts index b49ad50421a4..5e3b9241aae9 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1,4 +1,4 @@ -import {CONST as COMMON_CONST, Str} from 'expensify-common'; +import {CONST as COMMON_CONST} from 'expensify-common'; import {startCase} from 'lodash'; import CONST from '@src/CONST'; import type {Country} from '@src/CONST'; @@ -17,25 +17,25 @@ import type { ChangePolicyParams, ChangeTypeParams, CharacterLimitParams, - ConfirmHoldExpenseParams, ConfirmThatParams, + CustomersOrJobsLabelTranslationParams, DateShouldBeAfterParams, DateShouldBeBeforeParams, DelegateSubmitParams, DeleteActionParams, DeleteConfirmationParams, - DeleteExpenseTranslationParams, DidSplitAmountMessageParams, - DistanceRateOperationsParams, EditActionParams, ElectronicFundsParams, EnterMagicCodeParams, + ExportAgainModalDescriptionTranslationParams, ExportedToIntegrationParams, FormattedMaxLengthParams, ForwardedParams, GoBackMessageParams, GoToRoomParams, InstantSummaryParams, + LastSyncDateTranslationParams, LocalTimeParams, LoggedInAsParams, LogSizeParams, @@ -66,6 +66,7 @@ import type { ReportArchiveReasonsMergedParams, ReportArchiveReasonsPolicyDeletedParams, ReportArchiveReasonsRemovedFromPolicyParams, + ReportIntegrationMessageTranslationParams, RequestAmountParams, RequestCountParams, RequestedAmountMessageParams, @@ -80,6 +81,7 @@ import type { SignUpNewFaceCodeParams, SizeExceededParams, SplitAmountParams, + StatementPageTitleTranslationParams, StepCounterParams, StripePaidParams, TaskCreatedActionParams, @@ -496,16 +498,14 @@ export default { sendAttachment: 'Send attachment', addAttachment: 'Add attachment', writeSomething: 'Write something...', - conciergePlaceholderOptions: [ - 'Ask for help!', - 'Ask me anything!', - 'Ask me to book travel!', - 'Ask me what I can do!', - 'Ask me how to pay people!', - 'Ask me how to send an invoice!', - 'Ask me how to scan a receipt!', - 'Ask me how to get a free corporate card!', - ], + conciergePlaceholderOptions: (isSmallScreenWidth: boolean) => { + // If we are on a small width device then don't show last 3 items from conciergePlaceholderOptions + const options = ['Ask for help!', 'Ask me anything!', 'Ask me to book travel!', 'Ask me what I can do!', 'Ask me how to pay people!']; + if (!isSmallScreenWidth) { + options.push('Ask me how to send an invoice!', 'Ask me how to scan a receipt!', 'Ask me how to get a free corporate card!'); + } + return options[Math.floor(Math.random() * options.length)]; + }, blockedFromConcierge: 'Communication is barred', fileUploadFailed: 'Upload failed. File is not supported.', localTime: ({user, time}: LocalTimeParams) => `It's ${time} for ${user}`, @@ -654,7 +654,7 @@ export default { splitBill: 'Split expense', splitScan: 'Split receipt', splitDistance: 'Split distance', - paySomeone: (name: string) => `Pay ${name ?? 'someone'}`, + paySomeone: ({name}: PaySomeoneParams) => `Pay ${name ?? 'someone'}`, assignTask: 'Assign task', header: 'Quick action', trackManual: 'Track expense', @@ -700,7 +700,10 @@ export default { receiptScanning: 'Receipt scanning...', receiptScanInProgress: 'Receipt scan in progress', receiptScanInProgressDescription: 'Receipt scan in progress. Check back later or enter the details now.', - receiptIssuesFound: (count: number) => `${count === 1 ? 'Issue' : 'Issues'} found`, + receiptIssuesFound: () => ({ + one: `Issue found`, + other: () => `Issues found`, + }), fieldPending: 'Pending...', defaultRate: 'Default rate', receiptMissingDetails: 'Receipt missing details', @@ -710,12 +713,19 @@ export default { receiptStatusText: "Only you can see this receipt when it's scanning. Check back later or enter the details now.", receiptScanningFailed: 'Receipt scanning failed. Please enter the details manually.', transactionPendingDescription: 'Transaction pending. It may take a few days to post.', - expenseCount: ({count, scanningReceipts = 0, pendingReceipts = 0}: RequestCountParams) => - `${count} ${Str.pluralize('expense', 'expenses', count)}${scanningReceipts > 0 ? `, ${scanningReceipts} scanning` : ''}${ - pendingReceipts > 0 ? `, ${pendingReceipts} pending` : '' - }`, - deleteExpense: ({count}: DeleteExpenseTranslationParams = {count: 1}) => `Delete ${Str.pluralize('expense', 'expenses', count)}`, - deleteConfirmation: ({count}: DeleteExpenseTranslationParams = {count: 1}) => `Are you sure that you want to delete ${Str.pluralize('this expense', 'these expenses', count)}?`, + expenseCount: ({scanningReceipts = 0, pendingReceipts = 0}: RequestCountParams) => ({ + zero: `0 expenses${scanningReceipts > 0 ? `, ${scanningReceipts} scanning` : ''}${pendingReceipts > 0 ? `, ${pendingReceipts} pending` : ''}`, + one: `1 expense${scanningReceipts > 0 ? `, ${scanningReceipts} scanning` : ''}${pendingReceipts > 0 ? `, ${pendingReceipts} pending` : ''}`, + other: (count: number) => `${count} expenses${scanningReceipts > 0 ? `, ${scanningReceipts} scanning` : ''}${pendingReceipts > 0 ? `, ${pendingReceipts} pending` : ''}`, + }), + deleteExpense: () => ({ + one: `Delete expense`, + other: () => `Delete expenses`, + }), + deleteConfirmation: () => ({ + one: `Are you sure that you want to delete this expense?`, + other: () => `Are you sure that you want to delete these expenses?`, + }), settledExpensify: 'Paid', settledElsewhere: 'Paid elsewhere', individual: 'Individual', @@ -808,12 +818,18 @@ export default { keepAll: 'Keep all', confirmApprove: 'Confirm approval amount', confirmApprovalAmount: 'Approve only compliant expenses, or approve the entire report.', - confirmApprovalAllHoldAmount: ({transactionCount}: ConfirmHoldExpenseParams) => - `${Str.pluralize('This expense is', 'These expenses are', transactionCount)} on hold. Do you want to approve anyway?`, + confirmApprovalAllHoldAmount: () => ({ + zero: `This expense is on hold. Do you want to approve anyway?`, + one: `This expense is on hold. Do you want to approve anyway?`, + other: () => `These expenses are on hold. Do you want to approve anyway?`, + }), confirmPay: 'Confirm payment amount', confirmPayAmount: "Pay what's not on hold, or pay the entire report.", - confirmPayAllHoldAmount: ({transactionCount}: ConfirmHoldExpenseParams) => - `${Str.pluralize('This expense is', 'These expenses are', transactionCount)} on hold. Do you want to pay anyway?`, + confirmPayAllHoldAmount: () => ({ + zero: `This expense is on hold. Do you want to pay anyway?`, + one: `This expense is on hold. Do you want to pay anyway?`, + other: () => `These expenses are on hold. Do you want to pay anyway?`, + }), payOnly: 'Pay only', approveOnly: 'Approve only', holdEducationalTitle: 'This expense is on', @@ -2040,7 +2056,10 @@ export default { testTransactions: 'Test transactions', issueAndManageCards: 'Issue and manage cards', reconcileCards: 'Reconcile cards', - selected: ({selectedNumber}) => `${selectedNumber} selected`, + selected: () => ({ + one: `1 selected`, + other: (count: number) => `${count} selected`, + }), settlementFrequency: 'Settlement frequency', deleteConfirmation: 'Are you sure you want to delete this workspace?', unavailable: 'Unavailable workspace', @@ -2075,7 +2094,7 @@ export default { createNewConnection: 'Create new connection', reuseExistingConnection: 'Reuse existing connection', existingConnections: 'Existing connections', - lastSyncDate: (connectionName: string, formattedDate: string) => `${connectionName} - Last synced ${formattedDate}`, + lastSyncDate: ({connectionName, formattedDate}: LastSyncDateTranslationParams) => `${connectionName} - Last synced ${formattedDate}`, }, qbo: { importDescription: 'Choose which coding configurations to import from QuickBooks Online to Expensify.', @@ -2507,7 +2526,7 @@ export default { importJobs: 'Import projects', customers: 'customers', jobs: 'projects', - label: (importFields: string[], importType: string) => `${importFields.join(' and ')}, ${importType}`, + label: ({importFields, importType}: CustomersOrJobsLabelTranslationParams) => `${importFields.join(' and ')}, ${importType}`, }, importTaxDescription: 'Import tax groups from NetSuite.', importCustomFields: { @@ -2629,7 +2648,10 @@ export default { addAUserDefinedDimension: 'Add a user-defined dimension', detailedInstructionsLink: 'View detailed instructions', detailedInstructionsRestOfSentence: ' on adding user-defined dimensions.', - userDimensionsAdded: (dimensionsCount: number) => `${dimensionsCount} ${Str.pluralize('UDD', `UDDs`, dimensionsCount)} added`, + userDimensionsAdded: () => ({ + one: `1 UDD added`, + other: (count: number) => `${count} UDDs added`, + }), mappingTitle: (mappingName: SageIntacctMappingName): string => { switch (mappingName) { case CONST.SAGE_INTACCT_CONFIG.MAPPINGS.DEPARTMENTS: @@ -3279,9 +3301,18 @@ export default { rate: 'Rate', addRate: 'Add rate', trackTax: 'Track tax', - deleteRates: ({count}: DistanceRateOperationsParams) => `Delete ${Str.pluralize('rate', 'rates', count)}`, - enableRates: ({count}: DistanceRateOperationsParams) => `Enable ${Str.pluralize('rate', 'rates', count)}`, - disableRates: ({count}: DistanceRateOperationsParams) => `Disable ${Str.pluralize('rate', 'rates', count)}`, + deleteRates: () => ({ + one: `Delete 1 rate`, + other: (count: number) => `Delete ${count} rates`, + }), + enableRates: () => ({ + one: `Enable 1 rate`, + other: (count: number) => `Enable ${count} rates`, + }), + disableRates: () => ({ + one: `Disable 1 rate`, + other: (count: number) => `Disable ${count} rates`, + }), enableRate: 'Enable rate', status: 'Status', unit: 'Unit', @@ -3289,7 +3320,10 @@ export default { changePromptMessage: ' to make that change.', defaultCategory: 'Default category', deleteDistanceRate: 'Delete distance rate', - areYouSureDelete: ({count}: DistanceRateOperationsParams) => `Are you sure you want to delete ${Str.pluralize('this rate', 'these rates', count)}?`, + areYouSureDelete: () => ({ + one: `Are you sure you want to delete 1 rate?`, + other: (count: number) => `Are you sure you want to delete ${count} rates?`, + }), }, editor: { descriptionInputLabel: 'Description', @@ -3376,7 +3410,7 @@ export default { }, exportAgainModal: { title: 'Careful!', - description: (reportName: string, connectionName: ConnectionName) => + description: ({reportName, connectionName}: ExportAgainModalDescriptionTranslationParams) => `The following reports have already been exported to ${CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[connectionName]}:\n\n${reportName}\n\nAre you sure you want to export them again?`, confirmText: 'Yes, export again', cancelText: 'Cancel', @@ -3530,7 +3564,7 @@ export default { deleteConfirmation: 'Are you sure you want to delete this task?', }, statementPage: { - title: (year, monthName) => `${monthName} ${year} statement`, + title: ({year, monthName}: StatementPageTitleTranslationParams) => `${monthName} ${year} statement`, generatingPDF: "We're generating your PDF right now. Please check back soon!", }, keyboardShortcutsPage: { @@ -3688,7 +3722,7 @@ export default { pending: ({label}: ExportedToIntegrationParams) => `started exporting this report to ${label}...`, }, forwarded: ({amount, currency}: ForwardedParams) => `approved ${currency}${amount}`, - integrationsMessage: (errorMessage: string, label: string) => `failed to export this report to ${label} ("${errorMessage}").`, + integrationsMessage: ({errorMessage, label}: ReportIntegrationMessageTranslationParams) => `failed to export this report to ${label} ("${errorMessage}").`, managerAttachReceipt: `added a receipt`, managerDetachReceipt: `removed a receipt`, markedReimbursed: ({amount, currency}: MarkedReimbursedParams) => `paid ${currency}${amount} elsewhere`, diff --git a/src/languages/es.ts b/src/languages/es.ts index ff06d4f4f97e..1ce4ac35586b 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1,4 +1,3 @@ -import {Str} from 'expensify-common'; import CONST from '@src/CONST'; import type {ConnectionName, PolicyConnectionSyncStage, SageIntacctMappingName} from '@src/types/onyx/Policy'; import type { @@ -15,26 +14,26 @@ import type { ChangePolicyParams, ChangeTypeParams, CharacterLimitParams, - ConfirmHoldExpenseParams, ConfirmThatParams, + CustomersOrJobsLabelTranslationParams, DateShouldBeAfterParams, DateShouldBeBeforeParams, DelegateSubmitParams, DeleteActionParams, DeleteConfirmationParams, - DeleteExpenseTranslationParams, DidSplitAmountMessageParams, - DistanceRateOperationsParams, EditActionParams, ElectronicFundsParams, EnglishTranslation, EnterMagicCodeParams, + ExportAgainModalDescriptionTranslationParams, ExportedToIntegrationParams, FormattedMaxLengthParams, ForwardedParams, GoBackMessageParams, GoToRoomParams, InstantSummaryParams, + LastSyncDateTranslationParams, LocalTimeParams, LoggedInAsParams, LogSizeParams, @@ -65,6 +64,7 @@ import type { ReportArchiveReasonsMergedParams, ReportArchiveReasonsPolicyDeletedParams, ReportArchiveReasonsRemovedFromPolicyParams, + ReportIntegrationMessageTranslationParams, RequestAmountParams, RequestCountParams, RequestedAmountMessageParams, @@ -79,6 +79,7 @@ import type { SignUpNewFaceCodeParams, SizeExceededParams, SplitAmountParams, + StatementPageTitleTranslationParams, StepCounterParams, StripePaidParams, TaskCreatedActionParams, @@ -487,16 +488,13 @@ export default { sendAttachment: 'Enviar adjunto', addAttachment: 'Añadir archivo adjunto', writeSomething: 'Escribe algo...', - conciergePlaceholderOptions: [ - '¡Pide ayuda!', - '¡Pregúntame lo que sea!', - '¡Pídeme que te reserve un viaje!', - '¡Pregúntame qué puedo hacer!', - '¡Pregúntame cómo pagar a la gente!', - '¡Pregúntame cómo enviar una factura!', - '¡Pregúntame cómo escanear un recibo!', - '¡Pregúntame cómo obtener una tarjeta de crédito corporativa gratis!', - ], + conciergePlaceholderOptions: (isSmallScreenWidth: boolean) => { + const options = ['¡Pide ayuda!', '¡Pregúntame lo que sea!', '¡Pídeme que te reserve un viaje!', '¡Pregúntame qué puedo hacer!', '¡Pregúntame cómo pagar a la gente!']; + if (!isSmallScreenWidth) { + options.push('¡Pregúntame cómo enviar una factura!', '¡Pregúntame cómo escanear un recibo!', '¡Pregúntame cómo obtener una tarjeta de crédito corporativa gratis!'); + } + return options[Math.floor(Math.random() * options.length)]; + }, blockedFromConcierge: 'Comunicación no permitida', fileUploadFailed: 'Subida fallida. El archivo no es compatible.', localTime: ({user, time}: LocalTimeParams) => `Son las ${time} para ${user}`, @@ -649,7 +647,7 @@ export default { splitBill: 'Dividir gasto', splitScan: 'Dividir recibo', splitDistance: 'Dividir distancia', - paySomeone: (name: string) => `Pagar a ${name ?? 'alguien'}`, + paySomeone: ({name}: PaySomeoneParams) => `Pagar a ${name ?? 'alguien'}`, assignTask: 'Assignar tarea', header: 'Acción rápida', trackManual: 'Crear gasto', @@ -692,7 +690,10 @@ export default { pendingMatchWithCreditCardDescription: 'Recibo pendiente de adjuntar con la transacción de la tarjeta. Márcalo como efectivo para cancelar.', markAsCash: 'Marcar como efectivo', routePending: 'Ruta pendiente...', - receiptIssuesFound: (count: number) => `${count === 1 ? 'Problema encontrado' : 'Problemas encontrados'}`, + receiptIssuesFound: () => ({ + one: `Problema encontrado`, + other: () => `Problemas encontrados`, + }), fieldPending: 'Pendiente...', receiptScanning: 'Escaneando recibo...', receiptScanInProgress: 'Escaneado de recibo en proceso', @@ -705,13 +706,19 @@ export default { receiptStatusText: 'Solo tú puedes ver este recibo cuando se está escaneando. Vuelve más tarde o introduce los detalles ahora.', receiptScanningFailed: 'El escaneo de recibo ha fallado. Introduce los detalles manualmente.', transactionPendingDescription: 'Transacción pendiente. Puede tardar unos días en contabilizarse.', - expenseCount: ({count, scanningReceipts = 0, pendingReceipts = 0}: RequestCountParams) => - `${count} ${Str.pluralize('gasto', 'gastos', count)}${scanningReceipts > 0 ? `, ${scanningReceipts} escaneando` : ''}${ - pendingReceipts > 0 ? `, ${pendingReceipts} pendiente` : '' - }`, - - deleteExpense: ({count}: DeleteExpenseTranslationParams = {count: 1}) => `Eliminar ${Str.pluralize('gasto', 'gastos', count)}`, - deleteConfirmation: ({count}: DeleteExpenseTranslationParams = {count: 1}) => `¿Estás seguro de que quieres eliminar ${Str.pluralize('esta solicitud', 'estas solicitudes', count)}?`, + expenseCount: ({scanningReceipts = 0, pendingReceipts = 0}: RequestCountParams) => ({ + zero: `0 gasto${scanningReceipts > 0 ? `, ${scanningReceipts} escaneando` : ''}${pendingReceipts > 0 ? `, ${pendingReceipts} pendiente` : ''}`, + one: `1 gasto${scanningReceipts > 0 ? `, ${scanningReceipts} escaneando` : ''}${pendingReceipts > 0 ? `, ${pendingReceipts} pendiente` : ''}`, + other: (count: number) => `${count} gastos${scanningReceipts > 0 ? `, ${scanningReceipts} escaneando` : ''}${pendingReceipts > 0 ? `, ${pendingReceipts} pendiente` : ''}`, + }), + deleteExpense: () => ({ + one: `Eliminar gasto`, + other: () => `Eliminar gastos`, + }), + deleteConfirmation: () => ({ + one: `¿Estás seguro de que quieres eliminar esta solicitud?`, + other: () => `¿Estás seguro de que quieres eliminar estas solicitudes?`, + }), settledExpensify: 'Pagado', settledElsewhere: 'Pagado de otra forma', individual: 'Individual', @@ -804,20 +811,18 @@ export default { keepAll: 'Mantener todos', confirmApprove: 'Confirmar importe a aprobar', confirmApprovalAmount: 'Aprueba sólo los gastos conformes, o aprueba todo el informe.', - confirmApprovalAllHoldAmount: ({transactionCount}: ConfirmHoldExpenseParams) => - `${Str.pluralize('Este gasto está bloqueado', 'Estos gastos están bloqueados', transactionCount)}. ¿Quieres ${Str.pluralize( - 'aprobar', - 'aprobarlos', - transactionCount, - )} de todos modos?`, + confirmApprovalAllHoldAmount: () => ({ + zero: `Ningún gasto está bloqueado. ¿Quieres aprobar todo el informe?`, + one: `Este gasto está bloqueado. ¿Quieres aprobarlo de todos modos?`, + other: () => `Estos gastos están bloqueados. ¿Quieres aprobarlos de todos modos?`, + }), confirmPay: 'Confirmar importe de pago', confirmPayAmount: 'Paga lo que no está bloqueado, o paga el informe completo.', - confirmPayAllHoldAmount: ({transactionCount}: ConfirmHoldExpenseParams) => - `${Str.pluralize('Este gasto está bloqueado', 'Estos gastos están bloqueados', transactionCount)}. ¿Quieres ${Str.pluralize( - 'pagar', - 'pagarlo', - transactionCount, - )} de todos modos?`, + confirmPayAllHoldAmount: () => ({ + zero: `Ningún gasto está bloqueado. ¿Quieres pagar todo el informe?`, + one: `Este gasto está bloqueado. ¿Quieres pagarlo de todos modos?`, + other: () => `Estos gastos están bloqueados. ¿Quieres pagarlos de todos modos?`, + }), payOnly: 'Solo pagar', approveOnly: 'Solo aprobar', hold: 'Bloquear', @@ -2074,7 +2079,10 @@ export default { testTransactions: 'Transacciones de prueba', issueAndManageCards: 'Emitir y gestionar tarjetas', reconcileCards: 'Reconciliar tarjetas', - selected: ({selectedNumber}) => `${selectedNumber} seleccionados`, + selected: () => ({ + one: `1 seleccionado`, + other: (count: number) => `${count} seleccionados`, + }), settlementFrequency: 'Frecuencia de liquidación', deleteConfirmation: '¿Estás seguro de que quieres eliminar este espacio de trabajo?', unavailable: 'Espacio de trabajo no disponible', @@ -2110,7 +2118,7 @@ export default { createNewConnection: 'Crear una nueva conexión', reuseExistingConnection: 'Reutilizar la conexión existente', existingConnections: 'Conexiones existentes', - lastSyncDate: (connectionName: string, formattedDate: string) => `${connectionName} - Última sincronización ${formattedDate}`, + lastSyncDate: ({connectionName, formattedDate}: LastSyncDateTranslationParams) => `${connectionName} - Última sincronización ${formattedDate}`, }, qbo: { importDescription: 'Elige que configuraciónes de codificación son importadas desde QuickBooks Online a Expensify.', @@ -2556,7 +2564,7 @@ export default { importJobs: 'Importar proyectos', customers: 'clientes', jobs: 'proyectos', - label: (importFields: string[], importType: string) => `${importFields.join(' y ')}, ${importType}`, + label: ({importFields, importType}: CustomersOrJobsLabelTranslationParams) => `${importFields.join(' y ')}, ${importType}`, }, importTaxDescription: 'Importar grupos de impuestos desde NetSuite.', importCustomFields: { @@ -2678,7 +2686,10 @@ export default { addAUserDefinedDimension: 'Añadir una dimensión definida por el usuario', detailedInstructionsLink: 'Ver instrucciones detalladas', detailedInstructionsRestOfSentence: ' para añadir dimensiones definidas por el usuario.', - userDimensionsAdded: (dimensionsCount: number) => `${dimensionsCount} ${Str.pluralize('UDD', `UDDs`, dimensionsCount)} añadido`, + userDimensionsAdded: () => ({ + one: `1 UDD añadido`, + other: (count: number) => `${count} UDDs añadido`, + }), mappingTitle: (mappingName: SageIntacctMappingName): string => { switch (mappingName) { case CONST.SAGE_INTACCT_CONFIG.MAPPINGS.DEPARTMENTS: @@ -3333,9 +3344,18 @@ export default { rate: 'Tasa', addRate: 'Agregar tasa', trackTax: 'Impuesto de seguimiento', - deleteRates: ({count}: DistanceRateOperationsParams) => `Eliminar ${Str.pluralize('tasa', 'tasas', count)}`, - enableRates: ({count}: DistanceRateOperationsParams) => `Activar ${Str.pluralize('tasa', 'tasas', count)}`, - disableRates: ({count}: DistanceRateOperationsParams) => `Desactivar ${Str.pluralize('tasa', 'tasas', count)}`, + deleteRates: () => ({ + one: `Eliminar 1 tasa`, + other: (count: number) => `Eliminar ${count} tasas`, + }), + enableRates: () => ({ + one: `Activar 1 tasa`, + other: (count: number) => `Activar ${count} tasas`, + }), + disableRates: () => ({ + one: `Desactivar 1 tasa`, + other: (count: number) => `Desactivar ${count} tasas`, + }), enableRate: 'Activar tasa', status: 'Estado', unit: 'Unidad', @@ -3343,7 +3363,10 @@ export default { changePromptMessage: ' para hacer ese cambio.', defaultCategory: 'Categoría predeterminada', deleteDistanceRate: 'Eliminar tasa de distancia', - areYouSureDelete: ({count}: DistanceRateOperationsParams) => `¿Estás seguro de que quieres eliminar ${Str.pluralize('esta tasa', 'estas tasas', count)}?`, + areYouSureDelete: () => ({ + one: `¿Estás seguro de que quieres eliminar 1 tasa?`, + other: (count: number) => `¿Estás seguro de que quieres eliminar ${count} tasas?`, + }), }, editor: { nameInputLabel: 'Nombre', @@ -3432,7 +3455,7 @@ export default { exportAgainModal: { title: '¡Cuidado!', - description: (reportName: string, connectionName: ConnectionName) => + description: ({reportName, connectionName}: ExportAgainModalDescriptionTranslationParams) => `Los siguientes informes ya se han exportado a ${CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[connectionName]}:\n\n${reportName}\n\n¿Estás seguro de que deseas exportarlos de nuevo?`, confirmText: 'Sí, exportar de nuevo', cancelText: 'Cancelar', @@ -3587,7 +3610,7 @@ export default { deleteConfirmation: '¿Estás seguro de que quieres eliminar esta tarea?', }, statementPage: { - title: (year, monthName) => `Estado de cuenta de ${monthName} ${year}`, + title: ({year, monthName}: StatementPageTitleTranslationParams) => `Estado de cuenta de ${monthName} ${year}`, generatingPDF: 'Estamos generando tu PDF ahora mismo. ¡Por favor, vuelve más tarde!', }, keyboardShortcutsPage: { @@ -3746,7 +3769,7 @@ export default { pending: ({label}: ExportedToIntegrationParams) => `comenzó a exportar este informe a ${label}...`, }, forwarded: ({amount, currency}: ForwardedParams) => `aprobado ${currency}${amount}`, - integrationsMessage: (errorMessage: string, label: string) => `no se pudo exportar este informe a ${label} ("${errorMessage}").`, + integrationsMessage: ({errorMessage, label}: ReportIntegrationMessageTranslationParams) => `no se pudo exportar este informe a ${label} ("${errorMessage}").`, managerAttachReceipt: `agregó un recibo`, managerDetachReceipt: `quitó un recibo`, markedReimbursed: ({amount, currency}: MarkedReimbursedParams) => `pagó ${currency}${amount} en otro lugar`, diff --git a/src/languages/types.ts b/src/languages/types.ts index 24117f257d8f..62c96beb323e 100644 --- a/src/languages/types.ts +++ b/src/languages/types.ts @@ -1,5 +1,5 @@ import type {OnyxInputOrEntry, ReportAction} from '@src/types/onyx'; -import type {Unit} from '@src/types/onyx/Policy'; +import type {ConnectionName, Unit} from '@src/types/onyx/Policy'; import type {ViolationDataType} from '@src/types/onyx/TransactionViolation'; import type en from './en'; @@ -96,7 +96,6 @@ type ReportArchiveReasonsPolicyDeletedParams = { }; type RequestCountParams = { - count: number; scanningReceipts: number; pendingReceipts: number; }; @@ -251,9 +250,21 @@ type PaySomeoneParams = {name?: string}; type TaskCreatedActionParams = {title: string}; +type PluralFormPhase = { + zero?: string; + one: string; + two?: string; + few?: (count: number) => string; + many?: (count: number) => string; + other: (count: number) => string; +}; + /* Translation Object types */ // eslint-disable-next-line @typescript-eslint/no-explicit-any -type TranslationBaseValue = string | string[] | ((...args: any[]) => string); +type TranslationPluralPhaseValue = (arg?: any) => PluralFormPhase; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type TranslationSingularFunctionValue = (arg?: any) => string; +type TranslationBaseValue = string | TranslationPluralPhaseValue | TranslationSingularFunctionValue; type TranslationBase = {[key: string]: TranslationBaseValue | TranslationBase}; @@ -261,7 +272,7 @@ type TranslationBase = {[key: string]: TranslationBaseValue | TranslationBase}; // Flattens an object and returns concatenations of all the keys of nested objects type FlattenObject = { // eslint-disable-next-line @typescript-eslint/no-explicit-any - [TKey in keyof TObject]: TObject[TKey] extends (...args: any[]) => any + [TKey in keyof TObject]: TObject[TKey] extends (arg?: any) => any ? `${TPrefix}${TKey & string}` : // eslint-disable-next-line @typescript-eslint/no-explicit-any TObject[TKey] extends any[] @@ -289,6 +300,11 @@ type TranslationFlatObject = { [TKey in TranslationPaths]: TranslateType; }; +type PluralTranslationFlatObject = Pick< + TranslationFlatObject, + {[K in keyof TranslationFlatObject]: TranslationFlatObject[K] extends TranslationPluralPhaseValue ? K : never}[keyof TranslationFlatObject] +>; + type TermsParams = {amount: string}; type ElectronicFundsParams = {percentage: string; amount: string}; @@ -297,12 +313,8 @@ type LogSizeParams = {size: number}; type HeldRequestParams = {comment: string}; -type DistanceRateOperationsParams = {count: number}; - type ReimbursementRateParams = {unit: Unit}; -type ConfirmHoldExpenseParams = {transactionCount: number}; - type ChangeFieldParams = {oldValue?: string; newValue: string; fieldName: string}; type ChangePolicyParams = {fromPolicy: string; toPolicy: string}; @@ -344,8 +356,29 @@ type RemoveMembersWarningPrompt = { ownerName: string; }; -type DeleteExpenseTranslationParams = { - count: number; +type LastSyncDateTranslationParams = { + connectionName: string; + formattedDate: string; +}; + +type CustomersOrJobsLabelTranslationParams = { + importFields: string[]; + importType: string; +}; + +type ExportAgainModalDescriptionTranslationParams = { + reportName: string; + connectionName: ConnectionName; +}; + +type StatementPageTitleTranslationParams = { + year: string | number; + monthName: string; +}; + +type ReportIntegrationMessageTranslationParams = { + errorMessage: string; + label: string; }; export type { @@ -359,14 +392,12 @@ export type { BeginningOfChatHistoryDomainRoomPartOneParams, CanceledRequestParams, CharacterLimitParams, - ConfirmHoldExpenseParams, ConfirmThatParams, DateShouldBeAfterParams, DateShouldBeBeforeParams, DeleteActionParams, DeleteConfirmationParams, DidSplitAmountMessageParams, - DistanceRateOperationsParams, EditActionParams, ElectronicFundsParams, EnglishTranslation, @@ -423,9 +454,11 @@ export type { ThreadSentMoneyReportNameParams, ToValidateLoginParams, TransferParams, + PluralFormPhase, TranslationBase, TranslationFlatObject, TranslationPaths, + PluralTranslationFlatObject, UntilTimeParams, UpdatedTheDistanceParams, UpdatedTheRequestParams, @@ -468,5 +501,9 @@ export type { StripePaidParams, UnapprovedParams, RemoveMembersWarningPrompt, - DeleteExpenseTranslationParams, + LastSyncDateTranslationParams, + CustomersOrJobsLabelTranslationParams, + ExportAgainModalDescriptionTranslationParams, + StatementPageTitleTranslationParams, + ReportIntegrationMessageTranslationParams, }; diff --git a/src/libs/Localize/index.ts b/src/libs/Localize/index.ts index c9eef3170245..f1b705398067 100644 --- a/src/libs/Localize/index.ts +++ b/src/libs/Localize/index.ts @@ -6,7 +6,7 @@ import type {MessageElementBase, MessageTextElement} from '@libs/MessageElement' import Config from '@src/CONFIG'; import CONST from '@src/CONST'; import translations from '@src/languages/translations'; -import type {TranslationFlatObject, TranslationPaths} from '@src/languages/types'; +import type {PluralFormPhase, TranslationFlatObject, TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Locale} from '@src/types/onyx'; import LocaleListener from './LocaleListener'; @@ -45,8 +45,8 @@ function init() { }, {}); } -type PhraseParameters = T extends (...args: infer A) => string ? A : never[]; -type Phrase = TranslationFlatObject[TKey] extends (...args: infer A) => unknown ? (...args: A) => string : string; +type PhraseParameters = T extends (arg: infer A) => string ? [A] : T extends (arg: infer A) => PluralFormPhase ? [A, number] : never[]; +type Phrase = TranslationFlatObject[TKey]; /** * Map to store translated values for each locale. @@ -70,6 +70,23 @@ const translationCache = new Map, Map, Map]>), ); +function handlePluralForm(translatedPhrase: PluralFormPhase, pluralForm: Intl.LDMLPluralRule, count: number) { + switch (pluralForm) { + case 'zero': + return translatedPhrase.zero; + case 'one': + return translatedPhrase.one; + case 'two': + return translatedPhrase.two; + case 'few': + return translatedPhrase.few?.(count); + case 'many': + return translatedPhrase.many?.(count); + default: + return translatedPhrase.other(count); + } +} + /** * Helper function to get the translated string for given * locale and phrase. This function is used to avoid @@ -106,11 +123,21 @@ function getTranslatedPhrase( return valueFromCache; } - const translatedPhrase = translations?.[language]?.[phraseKey] as Phrase; + const translatedPhrase = translations?.[language]?.[phraseKey]; if (translatedPhrase) { if (typeof translatedPhrase === 'function') { - return translatedPhrase(...phraseParameters); + const calledTranslatedPhrase = translatedPhrase(phraseParameters[0]); + if (typeof calledTranslatedPhrase === 'string') { + return calledTranslatedPhrase; + } + const count = phraseParameters[1] ?? 0; + const pluralForm = new Intl.PluralRules(language, {type: 'ordinal'}).select(count); + if (pluralForm in calledTranslatedPhrase) { + return handlePluralForm(calledTranslatedPhrase, pluralForm, count) ?? ''; + } + Log.alert(`Plural form ${pluralForm} is not found for ${phraseKey}, using 'other' form`); + return calledTranslatedPhrase.other(count); } // We set the translated value in the cache only for the phrases without parameters. diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index fe53a7bcd5ce..c3410fbd6516 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -649,7 +649,10 @@ function getCustomersOrJobsLabelNetSuite(policy: Policy | undefined, translate: importFields.push(translate('workspace.netsuite.import.customersOrJobs.jobs')); } - const importedValueLabel = translate(`workspace.netsuite.import.customersOrJobs.label`, importFields, translate(`workspace.accounting.importTypes.${importedValue}`).toLowerCase()); + const importedValueLabel = translate(`workspace.netsuite.import.customersOrJobs.label`, { + importFields, + importType: translate(`workspace.accounting.importTypes.${importedValue}`).toLowerCase(), + }); return importedValueLabel.charAt(0).toUpperCase() + importedValueLabel.slice(1); } diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 73784873201a..f4683abf6100 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -1248,7 +1248,7 @@ function getMessageOfOldDotReportAction(oldDotAction: PartialReportAction | OldD case CONST.REPORT.ACTIONS.TYPE.INTEGRATIONS_MESSAGE: { const {result, label} = originalMessage; const errorMessage = result?.messages?.join(', ') ?? ''; - return Localize.translateLocal('report.actions.type.integrationsMessage', errorMessage, label); + return Localize.translateLocal('report.actions.type.integrationsMessage', {errorMessage, label}); } case CONST.REPORT.ACTIONS.TYPE.MANAGER_ATTACH_RECEIPT: return Localize.translateLocal('report.actions.type.managerAttachReceipt'); diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 4e82900372b9..5e8c311a79e4 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -763,7 +763,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD shouldEnableNewFocusManagement /> setIsDeleteModalVisible(false)} @@ -779,7 +779,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD ReportUtils.navigateBackAfterDeleteTransaction(navigateBackToAfterDelete.current, true); } }} - prompt={caseID === CASES.DEFAULT ? translate('task.deleteConfirmation') : translate('iou.deleteConfirmation')} + prompt={caseID === CASES.DEFAULT ? translate('task.deleteConfirmation') : translate('iou.deleteConfirmation', undefined, 1)} confirmText={translate('common.delete')} cancelText={translate('common.cancel')} danger diff --git a/src/pages/ReportParticipantsPage.tsx b/src/pages/ReportParticipantsPage.tsx index 15dd063ec6ee..300122db9be5 100755 --- a/src/pages/ReportParticipantsPage.tsx +++ b/src/pages/ReportParticipantsPage.tsx @@ -268,7 +268,7 @@ function ReportParticipantsPage({report, personalDetails, session}: ReportPartic shouldAlwaysShowDropdownMenu pressOnEnter - customText={translate('workspace.common.selected', {selectedNumber: selectedMembers.length})} + customText={translate('workspace.common.selected', undefined, selectedMembers.length)} buttonSize={CONST.DROPDOWN_BUTTON_SIZE.MEDIUM} onPress={() => null} options={bulkActionsButtonOptions} diff --git a/src/pages/Search/SearchSelectedNarrow.tsx b/src/pages/Search/SearchSelectedNarrow.tsx index 1cc34d6bf53a..039c54dc609a 100644 --- a/src/pages/Search/SearchSelectedNarrow.tsx +++ b/src/pages/Search/SearchSelectedNarrow.tsx @@ -50,7 +50,7 @@ function SearchSelectedNarrow({options, itemsLength}: SearchSelectedNarrowProps) onPress={openMenu} ref={buttonRef} style={[styles.w100, styles.ph5]} - text={translate('workspace.common.selected', {selectedNumber: itemsLength})} + text={translate('workspace.common.selected', undefined, itemsLength)} isContentCentered iconRight={Expensicons.DownArrow} isDisabled={options.length === 0} diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index 6ff163f6ec37..403b7864102f 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -195,13 +195,6 @@ function ReportActionCompose({ const userBlockedFromConcierge = useMemo(() => User.isBlockedFromConcierge(blockedFromConcierge), [blockedFromConcierge]); const isBlockedFromConcierge = useMemo(() => includesConcierge && userBlockedFromConcierge, [includesConcierge, userBlockedFromConcierge]); - // If we are on a small width device then don't show last 3 items from conciergePlaceholderOptions - const conciergePlaceholderRandomIndex = useMemo( - () => Math.floor(Math.random() * (translate('reportActionCompose.conciergePlaceholderOptions').length - (isSmallScreenWidth ? 4 : 1) + 1)), - // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps - [], - ); - // Placeholder to display in the chat input. const inputPlaceholder = useMemo(() => { if (includesConcierge) { @@ -209,11 +202,12 @@ function ReportActionCompose({ return translate('reportActionCompose.blockedFromConcierge'); } - return translate('reportActionCompose.conciergePlaceholderOptions')[conciergePlaceholderRandomIndex]; + return translate('reportActionCompose.conciergePlaceholderOptions', isSmallScreenWidth); } return translate('reportActionCompose.writeSomething'); - }, [includesConcierge, translate, userBlockedFromConcierge, conciergePlaceholderRandomIndex]); + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps + }, [includesConcierge, translate, userBlockedFromConcierge]); const focus = () => { if (composerRef.current === null) { diff --git a/src/pages/home/report/ReportDetailsExportPage.tsx b/src/pages/home/report/ReportDetailsExportPage.tsx index 99b7305cc7a9..d6861bd54dd0 100644 --- a/src/pages/home/report/ReportDetailsExportPage.tsx +++ b/src/pages/home/report/ReportDetailsExportPage.tsx @@ -120,7 +120,7 @@ function ReportDetailsExportPage({route}: ReportDetailsExportPageProps) { title={translate('workspace.exportAgainModal.title')} onConfirm={confirmExport} onCancel={() => setModalStatus(null)} - prompt={translate('workspace.exportAgainModal.description', report?.reportName ?? '', connectionName)} + prompt={translate('workspace.exportAgainModal.description', {reportName: report?.reportName ?? '', connectionName})} confirmText={translate('workspace.exportAgainModal.confirmText')} cancelText={translate('workspace.exportAgainModal.cancelText')} isVisible={!!modalStatus} diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx index cde3750fc37f..ab18013d6b23 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx @@ -212,7 +212,7 @@ function FloatingActionButtonAndPopover( } if (quickAction?.action === CONST.QUICK_ACTIONS.SEND_MONEY && quickActionAvatars.length > 0) { const name: string = ReportUtils.getDisplayNameForParticipant(+(quickActionAvatars[0]?.id ?? -1), true) ?? ''; - return translate('quickAction.paySomeone', name); + return translate('quickAction.paySomeone', {name}); } const titleKey = getQuickActionTitle(quickAction?.action ?? ('' as QuickActionName)); return titleKey ? translate(titleKey) : ''; diff --git a/src/pages/wallet/WalletStatementPage.tsx b/src/pages/wallet/WalletStatementPage.tsx index 0db72877bd2e..54b601a00350 100644 --- a/src/pages/wallet/WalletStatementPage.tsx +++ b/src/pages/wallet/WalletStatementPage.tsx @@ -70,7 +70,7 @@ function WalletStatementPage({walletStatement, route}: WalletStatementPageProps) const year = yearMonth?.substring(0, 4) || getYear(new Date()); const month = yearMonth?.substring(4) || getMonth(new Date()); const monthName = format(new Date(Number(year), Number(month) - 1), CONST.DATE.MONTH_FORMAT); - const title = translate('statementPage.title', year, monthName); + const title = translate('statementPage.title', {year, monthName}); const url = `${CONFIG.EXPENSIFY.EXPENSIFY_URL}statement.php?period=${yearMonth}${themePreference === CONST.THEME.DARK ? '&isDarkMode=true' : ''}`; return ( diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index adbf5a664c82..8b2ca4e09ca1 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -503,7 +503,7 @@ function WorkspaceMembersPage({personalDetails, invitedEmailsToAccountIDsDraft, shouldAlwaysShowDropdownMenu pressOnEnter - customText={translate('workspace.common.selected', {selectedNumber: selectedEmployees.length})} + customText={translate('workspace.common.selected', undefined, selectedEmployees.length)} buttonSize={CONST.DROPDOWN_BUTTON_SIZE.MEDIUM} onPress={() => null} options={getBulkActionsButtonOptions()} diff --git a/src/pages/workspace/accounting/intacct/ExistingConnectionsPage.tsx b/src/pages/workspace/accounting/intacct/ExistingConnectionsPage.tsx index c55e46083470..3475d726ba84 100644 --- a/src/pages/workspace/accounting/intacct/ExistingConnectionsPage.tsx +++ b/src/pages/workspace/accounting/intacct/ExistingConnectionsPage.tsx @@ -30,7 +30,9 @@ function ExistingConnectionsPage({route}: ExistingConnectionsPageProps) { key: policy.id, icon: policy.avatarURL ? policy.avatarURL : ReportUtils.getDefaultWorkspaceAvatar(policy.name), iconType: policy.avatarURL ? CONST.ICON_TYPE_AVATAR : CONST.ICON_TYPE_WORKSPACE, - description: date ? translate('workspace.common.lastSyncDate', CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY.intacct, date) : translate('workspace.accounting.intacct'), + description: date + ? translate('workspace.common.lastSyncDate', {connectionName: CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY.intacct, formattedDate: date}) + : translate('workspace.accounting.intacct'), onPress: () => { copyExistingPolicyConnection(policy.id, policyID, CONST.POLICY.CONNECTIONS.NAME.SAGE_INTACCT); Navigation.dismissModal(); diff --git a/src/pages/workspace/accounting/intacct/import/SageIntacctImportPage.tsx b/src/pages/workspace/accounting/intacct/import/SageIntacctImportPage.tsx index 543d3f4d0154..958e35c5b572 100644 --- a/src/pages/workspace/accounting/intacct/import/SageIntacctImportPage.tsx +++ b/src/pages/workspace/accounting/intacct/import/SageIntacctImportPage.tsx @@ -128,7 +128,7 @@ function SageIntacctImportPage({policy}: WithPolicyProps) { 0 - ? translate('workspace.intacct.userDimensionsAdded', sageIntacctConfig?.mappings?.dimensions?.length) + ? translate('workspace.intacct.userDimensionsAdded', undefined, sageIntacctConfig?.mappings?.dimensions?.length) : undefined } description={translate('workspace.intacct.userDefinedDimensions')} diff --git a/src/pages/workspace/accounting/netsuite/NetSuiteTokenInput/NetSuiteExistingConnectionsPage.tsx b/src/pages/workspace/accounting/netsuite/NetSuiteTokenInput/NetSuiteExistingConnectionsPage.tsx index ef98625a64e2..5fdca30600c2 100644 --- a/src/pages/workspace/accounting/netsuite/NetSuiteTokenInput/NetSuiteExistingConnectionsPage.tsx +++ b/src/pages/workspace/accounting/netsuite/NetSuiteTokenInput/NetSuiteExistingConnectionsPage.tsx @@ -30,7 +30,9 @@ function NetSuiteExistingConnectionsPage({route}: ExistingConnectionsPageProps) key: policy.id, icon: policy.avatarURL ? policy.avatarURL : ReportUtils.getDefaultWorkspaceAvatar(policy.name), iconType: policy.avatarURL ? CONST.ICON_TYPE_AVATAR : CONST.ICON_TYPE_WORKSPACE, - description: date ? translate('workspace.common.lastSyncDate', CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY.netsuite, date) : translate('workspace.accounting.netsuite'), + description: date + ? translate('workspace.common.lastSyncDate', {connectionName: CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY.netsuite, formattedDate: date}) + : translate('workspace.accounting.netsuite'), onPress: () => { copyExistingPolicyConnection(policy.id, policyID, CONST.POLICY.CONNECTIONS.NAME.NETSUITE); Navigation.goBack(ROUTES.WORKSPACE_ACCOUNTING.getRoute(policyID)); diff --git a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx index 174251a80d5f..12f76fe15abb 100644 --- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx +++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx @@ -224,7 +224,7 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { shouldAlwaysShowDropdownMenu pressOnEnter buttonSize={CONST.DROPDOWN_BUTTON_SIZE.MEDIUM} - customText={translate('workspace.common.selected', {selectedNumber: selectedCategoriesArray.length})} + customText={translate('workspace.common.selected', undefined, selectedCategoriesArray.length)} options={options} isSplitButton={false} style={[shouldUseNarrowLayout && styles.flexGrow1, shouldUseNarrowLayout && styles.mb3]} diff --git a/src/pages/workspace/distanceRates/PolicyDistanceRateDetailsPage.tsx b/src/pages/workspace/distanceRates/PolicyDistanceRateDetailsPage.tsx index 00204d1e40c7..85e602228149 100644 --- a/src/pages/workspace/distanceRates/PolicyDistanceRateDetailsPage.tsx +++ b/src/pages/workspace/distanceRates/PolicyDistanceRateDetailsPage.tsx @@ -194,7 +194,7 @@ function PolicyDistanceRateDetailsPage({policy, route}: PolicyDistanceRateDetail isVisible={isDeleteModalVisible} onConfirm={deleteRate} onCancel={() => setIsDeleteModalVisible(false)} - prompt={translate('workspace.distanceRates.areYouSureDelete', {count: 1})} + prompt={translate('workspace.distanceRates.areYouSureDelete', undefined, 1)} confirmText={translate('common.delete')} cancelText={translate('common.cancel')} danger diff --git a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx index 1ef1319973a1..4749c3483571 100644 --- a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx +++ b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx @@ -200,7 +200,7 @@ function PolicyDistanceRatesPage({policy, route}: PolicyDistanceRatesPageProps) const getBulkActionsButtonOptions = () => { const options: Array> = [ { - text: translate('workspace.distanceRates.deleteRates', {count: selectedDistanceRates.length}), + text: translate('workspace.distanceRates.deleteRates', undefined, selectedDistanceRates.length), value: CONST.POLICY.BULK_ACTION_TYPES.DELETE, icon: Expensicons.Trashcan, onSelected: () => (canDisableOrDeleteSelectedRates ? setIsDeleteModalVisible(true) : setIsWarningModalVisible(true)), @@ -210,7 +210,7 @@ function PolicyDistanceRatesPage({policy, route}: PolicyDistanceRatesPageProps) const enabledRates = selectedDistanceRates.filter((rate) => rate.enabled); if (enabledRates.length > 0) { options.push({ - text: translate('workspace.distanceRates.disableRates', {count: enabledRates.length}), + text: translate('workspace.distanceRates.disableRates', undefined, enabledRates.length), value: CONST.POLICY.BULK_ACTION_TYPES.DISABLE, icon: Expensicons.DocumentSlash, onSelected: () => (canDisableOrDeleteSelectedRates ? disableRates() : setIsWarningModalVisible(true)), @@ -220,7 +220,7 @@ function PolicyDistanceRatesPage({policy, route}: PolicyDistanceRatesPageProps) const disabledRates = selectedDistanceRates.filter((rate) => !rate.enabled); if (disabledRates.length > 0) { options.push({ - text: translate('workspace.distanceRates.enableRates', {count: disabledRates.length}), + text: translate('workspace.distanceRates.enableRates', undefined, disabledRates.length), value: CONST.POLICY.BULK_ACTION_TYPES.ENABLE, icon: Expensicons.Document, onSelected: enableRates, @@ -257,7 +257,7 @@ function PolicyDistanceRatesPage({policy, route}: PolicyDistanceRatesPageProps) shouldAlwaysShowDropdownMenu pressOnEnter - customText={translate('workspace.common.selected', {selectedNumber: selectedDistanceRates.length})} + customText={translate('workspace.common.selected', undefined, selectedDistanceRates.length)} buttonSize={CONST.DROPDOWN_BUTTON_SIZE.MEDIUM} onPress={() => null} options={getBulkActionsButtonOptions()} @@ -332,7 +332,7 @@ function PolicyDistanceRatesPage({policy, route}: PolicyDistanceRatesPageProps) isVisible={isDeleteModalVisible} onConfirm={deleteRates} onCancel={() => setIsDeleteModalVisible(false)} - prompt={translate('workspace.distanceRates.areYouSureDelete', {count: selectedDistanceRates.length})} + prompt={translate('workspace.distanceRates.areYouSureDelete', undefined, selectedDistanceRates.length)} confirmText={translate('common.delete')} cancelText={translate('common.cancel')} danger diff --git a/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx b/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx index adbe33397950..0d5a6e617aec 100644 --- a/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx @@ -249,7 +249,7 @@ function ReportFieldsListValuesPage({ shouldAlwaysShowDropdownMenu pressOnEnter buttonSize={CONST.DROPDOWN_BUTTON_SIZE.MEDIUM} - customText={translate('workspace.common.selected', {selectedNumber: selectedValuesArray.length})} + customText={translate('workspace.common.selected', undefined, selectedValuesArray.length)} options={options} isSplitButton={false} style={[isSmallScreenWidth && styles.flexGrow1, isSmallScreenWidth && styles.mb3]} diff --git a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx index f4e3b01145da..4b231f1f2c5f 100644 --- a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx +++ b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx @@ -164,7 +164,7 @@ function WorkspaceReportFieldsPage({ shouldAlwaysShowDropdownMenu pressOnEnter buttonSize={CONST.DROPDOWN_BUTTON_SIZE.MEDIUM} - customText={translate('workspace.common.selected', {selectedNumber: selectedReportFields.length})} + customText={translate('workspace.common.selected', undefined, selectedReportFields.length)} options={options} isSplitButton={false} style={[shouldUseNarrowLayout && styles.flexGrow1, shouldUseNarrowLayout && styles.mb3]} diff --git a/src/pages/workspace/tags/WorkspaceTagsPage.tsx b/src/pages/workspace/tags/WorkspaceTagsPage.tsx index cf9952720fc9..dc0dab1634b0 100644 --- a/src/pages/workspace/tags/WorkspaceTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceTagsPage.tsx @@ -276,7 +276,7 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) { pressOnEnter isSplitButton={false} buttonSize={CONST.DROPDOWN_BUTTON_SIZE.MEDIUM} - customText={translate('workspace.common.selected', {selectedNumber: selectedTagsArray.length})} + customText={translate('workspace.common.selected', undefined, selectedTagsArray.length)} options={options} style={[isSmallScreenWidth && styles.flexGrow1, isSmallScreenWidth && styles.mb3]} /> diff --git a/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx b/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx index 9ac1fc7583ae..02a9ba0fe0c2 100644 --- a/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx @@ -202,7 +202,7 @@ function WorkspaceViewTagsPage({route}: WorkspaceViewTagsProps) { pressOnEnter isSplitButton={false} buttonSize={CONST.DROPDOWN_BUTTON_SIZE.MEDIUM} - customText={translate('workspace.common.selected', {selectedNumber: selectedTagsArray.length})} + customText={translate('workspace.common.selected', undefined, selectedTagsArray.length)} options={options} style={[isSmallScreenWidth && styles.flexGrow1, isSmallScreenWidth && styles.mb3]} /> diff --git a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx index edd2ef4e3a65..f40b2fc054b9 100644 --- a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx +++ b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx @@ -235,7 +235,7 @@ function WorkspaceTaxesPage({ onPress={() => {}} options={dropdownMenuOptions} buttonSize={CONST.DROPDOWN_BUTTON_SIZE.MEDIUM} - customText={translate('workspace.common.selected', {selectedNumber: selectedTaxesIDs.length})} + customText={translate('workspace.common.selected', undefined, selectedTaxesIDs.length)} shouldAlwaysShowDropdownMenu pressOnEnter isSplitButton={false} From e7df141dd5b4a843ddd128da78d06085a67c28be Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 22 Jul 2024 16:54:25 +0530 Subject: [PATCH 003/463] Fix lint --- src/components/AddressForm.tsx | 2 +- src/components/ArchivedReportFooter.tsx | 37 +++++++++++++++++++------ tests/unit/TranslateTest.ts | 11 ++------ 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/components/AddressForm.tsx b/src/components/AddressForm.tsx index 7ca4cc3273ca..d6ba5813a101 100644 --- a/src/components/AddressForm.tsx +++ b/src/components/AddressForm.tsx @@ -126,7 +126,7 @@ function AddressForm({ } } } else if (!CONST.GENERIC_ZIP_CODE_REGEX.test(values?.zipPostCode?.trim()?.toUpperCase() ?? '')) { - errors.zipPostCode = translate('privatePersonalDetails.error.incorrectZipFormat'); + errors.zipPostCode = translate('privatePersonalDetails.error.incorrectZipFormat', undefined); } return errors; diff --git a/src/components/ArchivedReportFooter.tsx b/src/components/ArchivedReportFooter.tsx index 35f5aeecb5a4..7e0121a3ae4f 100644 --- a/src/components/ArchivedReportFooter.tsx +++ b/src/components/ArchivedReportFooter.tsx @@ -53,14 +53,35 @@ function ArchivedReportFooter({report, reportClosedAction, personalDetails = {}} policyName = lodashEscape(policyName); } - const text = shouldRenderHTML - ? translate(`reportArchiveReasons.${archiveReason}`, { - displayName: `${displayName}`, - oldDisplayName: `${oldDisplayName}`, - policyName: `${policyName}`, - shouldUseYou: actorPersonalDetails?.accountID === getCurrentUserAccountID(), - }) - : translate(`reportArchiveReasons.${archiveReason}`); + let text; + switch (archiveReason) { + case CONST.REPORT.ARCHIVE_REASON.ACCOUNT_CLOSED: + text = translate(`reportArchiveReasons.${archiveReason}`, { + displayName: `${displayName}`, + }); + break; + case CONST.REPORT.ARCHIVE_REASON.ACCOUNT_MERGED: + text = translate(`reportArchiveReasons.${archiveReason}`, { + displayName: `${displayName}`, + oldDisplayName: `${oldDisplayName}`, + }); + break; + case CONST.REPORT.ARCHIVE_REASON.REMOVED_FROM_POLICY: + text = translate(`reportArchiveReasons.${archiveReason}`, { + displayName: `${displayName}`, + policyName: `${policyName}`, + shouldUseYou: actorPersonalDetails?.accountID === getCurrentUserAccountID(), + }); + break; + case CONST.REPORT.ARCHIVE_REASON.POLICY_DELETED: + text = translate(`reportArchiveReasons.${archiveReason}`, { + policyName: `${policyName}`, + }); + break; + default: + text = translate(`reportArchiveReasons.${archiveReason}`); + break; + } return ( { expect(Localize.translate(CONST.LOCALES.ES_ES, 'testKey4' as TranslationPaths)).toBe('testKey4'); asMutable(CONFIG).IS_IN_PRODUCTION = ORIGINAL_IS_IN_PRODUCTION; }); - - it('Test when translation value is a function', () => { - const expectedValue = 'With variable Test Variable'; - const testVariable = 'Test Variable'; - // @ts-expect-error - TranslationPaths doesn't include testKeyGroup.testFunction as a valid key - expect(Localize.translate(CONST.LOCALES.EN, 'testKeyGroup.testFunction' as TranslationPaths, {testVariable})).toBe(expectedValue); - }); }); describe('Translation Keys', () => { @@ -126,7 +119,7 @@ describe('flattenObject', () => { none: 'No description', }, content: func, - messages: ['Hello', 'Hi', 'Sup!'], + messages: 'Hello!', }, }, }; @@ -141,7 +134,7 @@ describe('flattenObject', () => { 'complex.report.title.task': 'Task', 'complex.report.description.none': 'No description', 'complex.report.content': func, - 'complex.report.messages': ['Hello', 'Hi', 'Sup!'], + 'complex.report.messages': 'Hello!', }); }); }); From dbc34e6ee66d91bd0c9835a8099315d41827ca18 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal <58412969+shubham1206agra@users.noreply.github.com> Date: Thu, 25 Jul 2024 15:10:43 +0530 Subject: [PATCH 004/463] Apply suggestions from code review Co-authored-by: Jayesh Mangwani <35371050+jayeshmangwani@users.noreply.github.com> --- src/languages/en.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 5e3b9241aae9..80e37460ac05 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -3302,16 +3302,16 @@ export default { addRate: 'Add rate', trackTax: 'Track tax', deleteRates: () => ({ - one: `Delete 1 rate`, - other: (count: number) => `Delete ${count} rates`, + one: 'Delete rate', + other: () => 'Delete rates', }), enableRates: () => ({ - one: `Enable 1 rate`, - other: (count: number) => `Enable ${count} rates`, + one: 'Enable rate', + other: () => 'Enable rates', }), disableRates: () => ({ - one: `Disable 1 rate`, - other: (count: number) => `Disable ${count} rates`, + one: 'Disable rate', + other: () => 'Disable rates', }), enableRate: 'Enable rate', status: 'Status', @@ -3321,8 +3321,8 @@ export default { defaultCategory: 'Default category', deleteDistanceRate: 'Delete distance rate', areYouSureDelete: () => ({ - one: `Are you sure you want to delete 1 rate?`, - other: (count: number) => `Are you sure you want to delete ${count} rates?`, + one: 'Are you sure you want to delete this rate?', + other: () => 'Are you sure you want to delete these rates?', }), }, editor: { From 7f91f9be8ce90c02b2980225267ed120f45cce7c Mon Sep 17 00:00:00 2001 From: Shubham Agrawal <58412969+shubham1206agra@users.noreply.github.com> Date: Thu, 25 Jul 2024 15:14:16 +0530 Subject: [PATCH 005/463] Apply suggestions from code review --- src/languages/es.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/languages/es.ts b/src/languages/es.ts index 1ce4ac35586b..0ae384b5b075 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -3345,16 +3345,16 @@ export default { addRate: 'Agregar tasa', trackTax: 'Impuesto de seguimiento', deleteRates: () => ({ - one: `Eliminar 1 tasa`, - other: (count: number) => `Eliminar ${count} tasas`, + one: 'Eliminar tasa', + other: () => 'Eliminar tasas', }), enableRates: () => ({ - one: `Activar 1 tasa`, - other: (count: number) => `Activar ${count} tasas`, + one: 'Activar 1 tasa', + other: () => 'Activar tasas', }), disableRates: () => ({ - one: `Desactivar 1 tasa`, - other: (count: number) => `Desactivar ${count} tasas`, + one: 'Desactivar tasa', + other: () => 'Desactivar tasas', }), enableRate: 'Activar tasa', status: 'Estado', @@ -3364,8 +3364,8 @@ export default { defaultCategory: 'Categoría predeterminada', deleteDistanceRate: 'Eliminar tasa de distancia', areYouSureDelete: () => ({ - one: `¿Estás seguro de que quieres eliminar 1 tasa?`, - other: (count: number) => `¿Estás seguro de que quieres eliminar ${count} tasas?`, + one: '¿Estás seguro de que quieres eliminar esta tasa?', + other: () => '¿Estás seguro de que quieres eliminar estas tasas?', }), }, editor: { From c8dd8d1e696031b4c438c7ac607776c62f3a19ad Mon Sep 17 00:00:00 2001 From: Shubham Agrawal <58412969+shubham1206agra@users.noreply.github.com> Date: Mon, 29 Jul 2024 08:19:44 +0530 Subject: [PATCH 006/463] Apply suggestions from code review --- .../home/report/ReportActionCompose/ReportActionCompose.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index 77e8f366d866..275fe000fe79 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -202,7 +202,7 @@ function ReportActionCompose({ return translate('reportActionCompose.blockedFromConcierge'); } - return translate('reportActionCompose.conciergePlaceholderOptions', isSmallScreenWidth); + return translate('reportActionCompose.conciergePlaceholderOptions', shouldUseNarrowLayout); } return translate('reportActionCompose.writeSomething'); From 3a15ab360099f7427680f2ca6327a84338eea4f2 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Tue, 30 Jul 2024 18:11:49 +0530 Subject: [PATCH 007/463] Fixed unused type --- src/languages/types.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/languages/types.ts b/src/languages/types.ts index 62c96beb323e..611deac1e854 100644 --- a/src/languages/types.ts +++ b/src/languages/types.ts @@ -300,11 +300,6 @@ type TranslationFlatObject = { [TKey in TranslationPaths]: TranslateType; }; -type PluralTranslationFlatObject = Pick< - TranslationFlatObject, - {[K in keyof TranslationFlatObject]: TranslationFlatObject[K] extends TranslationPluralPhaseValue ? K : never}[keyof TranslationFlatObject] ->; - type TermsParams = {amount: string}; type ElectronicFundsParams = {percentage: string; amount: string}; @@ -458,7 +453,6 @@ export type { TranslationBase, TranslationFlatObject, TranslationPaths, - PluralTranslationFlatObject, UntilTimeParams, UpdatedTheDistanceParams, UpdatedTheRequestParams, From fd0b5e7175b1be67111891cc67130ffd3e536419 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Tue, 30 Jul 2024 18:27:46 +0530 Subject: [PATCH 008/463] Fixed lint --- src/pages/Search/SearchFiltersDatePage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/Search/SearchFiltersDatePage.tsx b/src/pages/Search/SearchFiltersDatePage.tsx index 9ac9973c8ca2..ae11e972dc20 100644 --- a/src/pages/Search/SearchFiltersDatePage.tsx +++ b/src/pages/Search/SearchFiltersDatePage.tsx @@ -47,7 +47,7 @@ function SearchFiltersDatePage() { Date: Tue, 30 Jul 2024 19:19:32 +0530 Subject: [PATCH 009/463] Fixed lint --- src/languages/en.ts | 2 +- src/languages/es.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index e87a5bb71e3d..f1961dd7b449 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -35,8 +35,8 @@ import type { GoBackMessageParams, GoToRoomParams, InstantSummaryParams, - LastSyncDateTranslationParams, IssueVirtualCardParams, + LastSyncDateTranslationParams, LocalTimeParams, LoggedInAsParams, LogSizeParams, diff --git a/src/languages/es.ts b/src/languages/es.ts index 488cbbca626a..f44850067036 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -33,8 +33,8 @@ import type { GoBackMessageParams, GoToRoomParams, InstantSummaryParams, - LastSyncDateTranslationParams, IssueVirtualCardParams, + LastSyncDateTranslationParams, LocalTimeParams, LoggedInAsParams, LogSizeParams, From 5eed7b5482abfeef2dc723ec9797c04944ce688d Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Thu, 1 Aug 2024 18:00:10 +0530 Subject: [PATCH 010/463] Apply suggestions --- src/languages/en.ts | 1 - src/languages/es.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index bc91fa1ab428..ec03c97d8948 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -823,7 +823,6 @@ export default { confirmApprove: 'Confirm approval amount', confirmApprovalAmount: 'Approve only compliant expenses, or approve the entire report.', confirmApprovalAllHoldAmount: () => ({ - zero: `This expense is on hold. Do you want to approve anyway?`, one: `This expense is on hold. Do you want to approve anyway?`, other: () => `These expenses are on hold. Do you want to approve anyway?`, }), diff --git a/src/languages/es.ts b/src/languages/es.ts index 3133d6446db2..4a0b72ad237b 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -816,7 +816,6 @@ export default { confirmApprove: 'Confirmar importe a aprobar', confirmApprovalAmount: 'Aprueba sólo los gastos conformes, o aprueba todo el informe.', confirmApprovalAllHoldAmount: () => ({ - zero: `Ningún gasto está bloqueado. ¿Quieres aprobar todo el informe?`, one: `Este gasto está bloqueado. ¿Quieres aprobarlo de todos modos?`, other: () => `Estos gastos están bloqueados. ¿Quieres aprobarlos de todos modos?`, }), From 426d50e80e2809e4b6e0b42a643574bf0e51eb53 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Thu, 1 Aug 2024 18:01:53 +0530 Subject: [PATCH 011/463] Apply suggestions --- src/components/ArchivedReportFooter.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ArchivedReportFooter.tsx b/src/components/ArchivedReportFooter.tsx index 7e0121a3ae4f..eeee6c68b73f 100644 --- a/src/components/ArchivedReportFooter.tsx +++ b/src/components/ArchivedReportFooter.tsx @@ -53,7 +53,7 @@ function ArchivedReportFooter({report, reportClosedAction, personalDetails = {}} policyName = lodashEscape(policyName); } - let text; + let text: string; switch (archiveReason) { case CONST.REPORT.ARCHIVE_REASON.ACCOUNT_CLOSED: text = translate(`reportArchiveReasons.${archiveReason}`, { From 158b4c9bd0a56333bf6134d5772468447fd37fe0 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 5 Aug 2024 22:45:35 +0530 Subject: [PATCH 012/463] Polyfill plural rules for hermes --- src/languages/es.ts | 2 +- src/libs/IntlPolyfill/index.android.ts | 4 ++++ src/libs/IntlPolyfill/index.ios.ts | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/languages/es.ts b/src/languages/es.ts index 27d4b40380ed..a2d51f58cd89 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -3388,7 +3388,7 @@ export default { other: () => 'Eliminar tasas', }), enableRates: () => ({ - one: 'Activar 1 tasa', + one: 'Activar tasa', other: () => 'Activar tasas', }), disableRates: () => ({ diff --git a/src/libs/IntlPolyfill/index.android.ts b/src/libs/IntlPolyfill/index.android.ts index 7a21ae26bfa4..0f852457e3db 100644 --- a/src/libs/IntlPolyfill/index.android.ts +++ b/src/libs/IntlPolyfill/index.android.ts @@ -11,6 +11,10 @@ const intlPolyfill: IntlPolyfill = () => { require('@formatjs/intl-locale/polyfill'); + require('@formatjs/intl-pluralrules/polyfill'); + require('@formatjs/intl-pluralrules/locale-data/en'); + require('@formatjs/intl-pluralrules/locale-data/es'); + polyfillListFormat(); }; diff --git a/src/libs/IntlPolyfill/index.ios.ts b/src/libs/IntlPolyfill/index.ios.ts index 569b666eb434..0ee189b4d329 100644 --- a/src/libs/IntlPolyfill/index.ios.ts +++ b/src/libs/IntlPolyfill/index.ios.ts @@ -16,6 +16,8 @@ const intlPolyfill: IntlPolyfill = () => { // Required to polyfill NumberFormat on iOS // see: https://github.com/facebook/hermes/issues/1172#issuecomment-1776156538 require('@formatjs/intl-pluralrules/polyfill'); + require('@formatjs/intl-pluralrules/locale-data/en'); + require('@formatjs/intl-pluralrules/locale-data/es'); polyfillNumberFormat(); // Required to polyfill DateTimeFormat on iOS From 2c7a93778e27c7e6faa9b5357abbfc87801a8528 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 5 Aug 2024 22:51:47 +0530 Subject: [PATCH 013/463] Adjusting position of code --- src/libs/IntlPolyfill/index.ios.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libs/IntlPolyfill/index.ios.ts b/src/libs/IntlPolyfill/index.ios.ts index 0ee189b4d329..3a41790aa8b6 100644 --- a/src/libs/IntlPolyfill/index.ios.ts +++ b/src/libs/IntlPolyfill/index.ios.ts @@ -13,11 +13,12 @@ const intlPolyfill: IntlPolyfill = () => { require('@formatjs/intl-locale/polyfill'); - // Required to polyfill NumberFormat on iOS - // see: https://github.com/facebook/hermes/issues/1172#issuecomment-1776156538 require('@formatjs/intl-pluralrules/polyfill'); require('@formatjs/intl-pluralrules/locale-data/en'); require('@formatjs/intl-pluralrules/locale-data/es'); + + // Required to polyfill NumberFormat on iOS + // see: https://github.com/facebook/hermes/issues/1172#issuecomment-1776156538 polyfillNumberFormat(); // Required to polyfill DateTimeFormat on iOS From 2428dfac03e32a62f735c6d829072764e361d4e1 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Thu, 8 Aug 2024 16:54:27 +0530 Subject: [PATCH 014/463] Applying suggestion --- src/components/AddressForm.tsx | 2 +- src/libs/Localize/index.ts | 2 +- src/pages/Search/SearchFiltersDatePage.tsx | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/AddressForm.tsx b/src/components/AddressForm.tsx index d6ba5813a101..7ca4cc3273ca 100644 --- a/src/components/AddressForm.tsx +++ b/src/components/AddressForm.tsx @@ -126,7 +126,7 @@ function AddressForm({ } } } else if (!CONST.GENERIC_ZIP_CODE_REGEX.test(values?.zipPostCode?.trim()?.toUpperCase() ?? '')) { - errors.zipPostCode = translate('privatePersonalDetails.error.incorrectZipFormat', undefined); + errors.zipPostCode = translate('privatePersonalDetails.error.incorrectZipFormat'); } return errors; diff --git a/src/libs/Localize/index.ts b/src/libs/Localize/index.ts index f1b705398067..70db13c32851 100644 --- a/src/libs/Localize/index.ts +++ b/src/libs/Localize/index.ts @@ -45,7 +45,7 @@ function init() { }, {}); } -type PhraseParameters = T extends (arg: infer A) => string ? [A] : T extends (arg: infer A) => PluralFormPhase ? [A, number] : never[]; +type PhraseParameters = T extends (arg?: infer A) => string ? [A?] : T extends (arg: infer A) => string ? [A] : T extends (arg: infer A) => PluralFormPhase ? [A, number] : never[]; type Phrase = TranslationFlatObject[TKey]; /** diff --git a/src/pages/Search/SearchFiltersDatePage.tsx b/src/pages/Search/SearchFiltersDatePage.tsx index e2a465f6fa9e..4bc95aa21351 100644 --- a/src/pages/Search/SearchFiltersDatePage.tsx +++ b/src/pages/Search/SearchFiltersDatePage.tsx @@ -53,7 +53,7 @@ function SearchFiltersDatePage() { Date: Thu, 8 Aug 2024 21:12:35 +0530 Subject: [PATCH 015/463] Adjusting code --- src/languages/en.ts | 1 - src/languages/es.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 5bcdfdc1cb14..bccd8bdfba18 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -731,7 +731,6 @@ export default { invalidDomainError: 'You have entered an invalid domain. To continue, please enter a valid domain.', publicDomainError: 'You have entered a public domain. To continue, please enter a private domain.', expenseCount: ({scanningReceipts = 0, pendingReceipts = 0}: RequestCountParams) => ({ - zero: `0 expenses${scanningReceipts > 0 ? `, ${scanningReceipts} scanning` : ''}${pendingReceipts > 0 ? `, ${pendingReceipts} pending` : ''}`, one: `1 expense${scanningReceipts > 0 ? `, ${scanningReceipts} scanning` : ''}${pendingReceipts > 0 ? `, ${pendingReceipts} pending` : ''}`, other: (count: number) => `${count} expenses${scanningReceipts > 0 ? `, ${scanningReceipts} scanning` : ''}${pendingReceipts > 0 ? `, ${pendingReceipts} pending` : ''}`, }), diff --git a/src/languages/es.ts b/src/languages/es.ts index bfab43641f85..61cd8baba543 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -724,7 +724,6 @@ export default { invalidDomainError: 'Ha introducido un dominio no válido. Para continuar, introduzca un dominio válido.', publicDomainError: 'Ha introducido un dominio público. Para continuar, introduzca un dominio privado.', expenseCount: ({scanningReceipts = 0, pendingReceipts = 0}: RequestCountParams) => ({ - zero: `0 gasto${scanningReceipts > 0 ? `, ${scanningReceipts} escaneando` : ''}${pendingReceipts > 0 ? `, ${pendingReceipts} pendiente` : ''}`, one: `1 gasto${scanningReceipts > 0 ? `, ${scanningReceipts} escaneando` : ''}${pendingReceipts > 0 ? `, ${pendingReceipts} pendiente` : ''}`, other: (count: number) => `${count} gastos${scanningReceipts > 0 ? `, ${scanningReceipts} escaneando` : ''}${pendingReceipts > 0 ? `, ${pendingReceipts} pendiente` : ''}`, }), From b38931602767fe3bcb2d222957343aefb02886a6 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal <58412969+shubham1206agra@users.noreply.github.com> Date: Fri, 16 Aug 2024 15:10:34 +0530 Subject: [PATCH 016/463] Apply suggestions from code review --- src/libs/IntlPolyfill/index.android.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/IntlPolyfill/index.android.ts b/src/libs/IntlPolyfill/index.android.ts index 84761382b3fd..e6ab02d15c25 100644 --- a/src/libs/IntlPolyfill/index.android.ts +++ b/src/libs/IntlPolyfill/index.android.ts @@ -11,7 +11,7 @@ const intlPolyfill: IntlPolyfill = () => { require('@formatjs/intl-locale/polyfill-force'); - require('@formatjs/intl-pluralrules/polyfill'); + require('@formatjs/intl-pluralrules/polyfill-force'); require('@formatjs/intl-pluralrules/locale-data/en'); require('@formatjs/intl-pluralrules/locale-data/es'); From 6dfb0cd941be2203e0a1b6fc1ae6e04c6439b95b Mon Sep 17 00:00:00 2001 From: Shubham Agrawal <58412969+shubham1206agra@users.noreply.github.com> Date: Fri, 16 Aug 2024 15:16:54 +0530 Subject: [PATCH 017/463] Apply suggestions from code review --- src/languages/en.ts | 1 - src/languages/es.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 495bec63a5d7..71a26d93c623 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -866,7 +866,6 @@ export default { confirmPay: 'Confirm payment amount', confirmPayAmount: "Pay what's not on hold, or pay the entire report.", confirmPayAllHoldAmount: () => ({ - zero: `This expense is on hold. Do you want to pay anyway?`, one: `This expense is on hold. Do you want to pay anyway?`, other: () => `These expenses are on hold. Do you want to pay anyway?`, }), diff --git a/src/languages/es.ts b/src/languages/es.ts index e1187603afd8..92a23c0afb49 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -859,7 +859,6 @@ export default { confirmPay: 'Confirmar importe de pago', confirmPayAmount: 'Paga lo que no está bloqueado, o paga el informe completo.', confirmPayAllHoldAmount: () => ({ - zero: `Ningún gasto está bloqueado. ¿Quieres pagar todo el informe?`, one: `Este gasto está bloqueado. ¿Quieres pagarlo de todos modos?`, other: () => `Estos gastos están bloqueados. ¿Quieres pagarlos de todos modos?`, }), From aeccf49cffe1fc69276ff63c40474fca7e02740f Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Sun, 18 Aug 2024 19:42:00 +0100 Subject: [PATCH 018/463] Fix TS check --- src/libs/actions/Report.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index cb771db4aabf..3d663b0f4cb2 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -1336,7 +1336,8 @@ function handleReportChanged(report: OnyxEntry) { return; } - if (report?.reportID && report.preexistingReportID && ReportUtils.isMoneyRequestReport(report)) { + // Handle cleanup of stale optimistic IOU report and its report preview separately + if (report?.reportID && report.preexistingReportID && ReportUtils.isMoneyRequestReport(report) && report?.parentReportActionID) { Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`, { [report.parentReportActionID]: null, }); From 895108439ea8f158373287d987b978fa37e5a4ca Mon Sep 17 00:00:00 2001 From: Shubham Agrawal <58412969+shubham1206agra@users.noreply.github.com> Date: Fri, 23 Aug 2024 08:41:56 +0530 Subject: [PATCH 019/463] Apply suggestions from code review --- src/languages/en.ts | 2 +- src/languages/es.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 16571e7e35e8..4a6b86830587 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -754,7 +754,7 @@ export default { invalidDomainError: 'You have entered an invalid domain. To continue, please enter a valid domain.', publicDomainError: 'You have entered a public domain. To continue, please enter a private domain.', expenseCount: ({scanningReceipts = 0, pendingReceipts = 0}: RequestCountParams) => { - const statusText = []; + const statusText: string[] = []; if (scanningReceipts > 0) { statusText.push(`${scanningReceipts} scanning`); } diff --git a/src/languages/es.ts b/src/languages/es.ts index e670a003648a..5f753962ff34 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -745,7 +745,7 @@ export default { invalidDomainError: 'Ha introducido un dominio no válido. Para continuar, introduzca un dominio válido.', publicDomainError: 'Ha introducido un dominio público. Para continuar, introduzca un dominio privado.', expenseCount: ({scanningReceipts = 0, pendingReceipts = 0}: RequestCountParams) => { - const statusText = []; + const statusText: string[] = []; if (scanningReceipts > 0) { statusText.push(`${scanningReceipts} escaneando`); } From 29124ea861c38f311a46da8b8f79b19ecafefedd Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Fri, 23 Aug 2024 09:22:10 +0530 Subject: [PATCH 020/463] Post merge fixes --- src/languages/en.ts | 17 ++++++++++------- src/languages/es.ts | 17 ++++++++++------- src/languages/types.ts | 19 +++++++++++++++++++ src/libs/ReportActionsUtils.ts | 6 +++--- src/pages/Search/AdvancedSearchFilters.tsx | 5 ++++- .../report/ContextMenu/ContextMenuActions.tsx | 2 +- src/pages/home/report/ReportActionItem.tsx | 2 +- 7 files changed, 48 insertions(+), 20 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 4a6b86830587..6bd72a3790f7 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -69,12 +69,14 @@ import type { ReportArchiveReasonsPolicyDeletedParams, ReportArchiveReasonsRemovedFromPolicyParams, ReportIntegrationMessageTranslationParams, + ReportMemberRoleParams, RequestAmountParams, RequestCountParams, RequestedAmountMessageParams, ResolutionConstraintsParams, RoomNameReservedErrorParams, RoomRenamedToParams, + SearchFilterAmountBetweenParams, SetTheDistanceParams, SetTheRequestParams, SettledAfterAddedBankAccountParams, @@ -98,6 +100,7 @@ import type { UntilTimeParams, UpdatedTheDistanceParams, UpdatedTheRequestParams, + UpdateReportMemberRoleParams, UsePlusButtonParams, UserIsAlreadyMemberParams, UserSplitParams, @@ -763,8 +766,8 @@ export default { } return { one: statusText.length > 0 ? `1 expense (${statusText.join(', ')})` : `1 expense`, - other: (count: number) => statusText.length > 0 ? `${count} expenses (${statusText.join(', ')})` : `${count} expenses`, - } + other: (count: number) => (statusText.length > 0 ? `${count} expenses (${statusText.join(', ')})` : `${count} expenses`), + }; }, deleteExpense: () => ({ one: `Delete expense`, @@ -3786,7 +3789,7 @@ export default { amount: { lessThan: (amount?: string) => `Less than ${amount ?? ''}`, greaterThan: (amount?: string) => `Greater than ${amount ?? ''}`, - between: (greaterThan: string, lessThan: string) => `Between ${greaterThan} and ${lessThan}`, + between: ({greaterThan, lessThan}: SearchFilterAmountBetweenParams) => `Between ${greaterThan} and ${lessThan}`, }, }, expenseType: 'Expense type', @@ -3921,10 +3924,10 @@ export default { stripePaid: ({amount, currency}: StripePaidParams) => `paid ${currency}${amount}`, takeControl: `took control`, unapproved: ({amount, currency}: UnapprovedParams) => `unapproved ${currency}${amount}`, - integrationSyncFailed: (label: string, errorMessage: string) => `failed to sync with ${label} ("${errorMessage}")`, - addEmployee: (email: string, role: string) => `added ${email} as ${role === 'user' ? 'member' : 'admin'}`, - updateRole: (email: string, currentRole: string, newRole: string) => `updated the role of ${email} from ${currentRole} to ${newRole}`, - removeMember: (email: string, role: string) => `removed ${role} ${email}`, + integrationSyncFailed: ({label, errorMessage}: ReportIntegrationMessageTranslationParams) => `failed to sync with ${label} ("${errorMessage}")`, + addEmployee: ({email, role}: ReportMemberRoleParams) => `added ${email} as ${role === 'user' ? 'member' : 'admin'}`, + updateRole: ({email, currentRole, newRole}: UpdateReportMemberRoleParams) => `updated the role of ${email} from ${currentRole} to ${newRole}`, + removeMember: ({email, role}: ReportMemberRoleParams) => `removed ${role} ${email}`, }, }, }, diff --git a/src/languages/es.ts b/src/languages/es.ts index 5f753962ff34..a12fd53009c0 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -67,12 +67,14 @@ import type { ReportArchiveReasonsPolicyDeletedParams, ReportArchiveReasonsRemovedFromPolicyParams, ReportIntegrationMessageTranslationParams, + ReportMemberRoleParams, RequestAmountParams, RequestCountParams, RequestedAmountMessageParams, ResolutionConstraintsParams, RoomNameReservedErrorParams, RoomRenamedToParams, + SearchFilterAmountBetweenParams, SetTheDistanceParams, SetTheRequestParams, SettledAfterAddedBankAccountParams, @@ -95,6 +97,7 @@ import type { UntilTimeParams, UpdatedTheDistanceParams, UpdatedTheRequestParams, + UpdateReportMemberRoleParams, UsePlusButtonParams, UserIsAlreadyMemberParams, UserSplitParams, @@ -754,8 +757,8 @@ export default { } return { one: statusText.length > 0 ? `1 gasto (${statusText.join(', ')})` : `1 gasto`, - other: (count: number) => statusText.length > 0 ? `${count} gastos (${statusText.join(', ')})` : `${count} gastos`, - } + other: (count: number) => (statusText.length > 0 ? `${count} gastos (${statusText.join(', ')})` : `${count} gastos`), + }; }, deleteExpense: () => ({ one: `Eliminar gasto`, @@ -3826,7 +3829,7 @@ export default { amount: { lessThan: (amount?: string) => `Menos de ${amount ?? ''}`, greaterThan: (amount?: string) => `Más que ${amount ?? ''}`, - between: (greaterThan: string, lessThan: string) => `Entre ${greaterThan} y ${lessThan}`, + between: ({greaterThan, lessThan}: SearchFilterAmountBetweenParams) => `Entre ${greaterThan} y ${lessThan}`, }, }, expenseType: 'Tipo de gasto', @@ -3962,11 +3965,11 @@ export default { stripePaid: ({amount, currency}: StripePaidParams) => `pagado ${currency}${amount}`, takeControl: `tomó el control`, unapproved: ({amount, currency}: UnapprovedParams) => `no aprobado ${currency}${amount}`, - integrationSyncFailed: (label: string, errorMessage: string) => `no se pudo sincronizar con ${label} ("${errorMessage}")`, - addEmployee: (email: string, role: string) => `agregó a ${email} como ${role === 'user' ? 'miembro' : 'administrador'}`, - updateRole: (email: string, currentRole: string, newRole: string) => + integrationSyncFailed: ({label, errorMessage}: ReportIntegrationMessageTranslationParams) => `no se pudo sincronizar con ${label} ("${errorMessage}")`, + addEmployee: ({email, role}: ReportMemberRoleParams) => `agregó a ${email} como ${role === 'user' ? 'miembro' : 'administrador'}`, + updateRole: ({email, currentRole, newRole}: UpdateReportMemberRoleParams) => `actualicé el rol ${email} de ${currentRole === 'user' ? 'miembro' : 'administrador'} a ${newRole === 'user' ? 'miembro' : 'administrador'}`, - removeMember: (email: string, role: string) => `eliminado ${role === 'user' ? 'miembro' : 'administrador'} ${email}`, + removeMember: ({email, role}: ReportMemberRoleParams) => `eliminado ${role === 'user' ? 'miembro' : 'administrador'} ${email}`, }, }, }, diff --git a/src/languages/types.ts b/src/languages/types.ts index 444a97d26249..b95122979df8 100644 --- a/src/languages/types.ts +++ b/src/languages/types.ts @@ -386,6 +386,22 @@ type ApprovalWorkflowErrorParams = { name2: string; }; +type SearchFilterAmountBetweenParams = { + greaterThan: string; + lessThan: string; +}; + +type ReportMemberRoleParams = { + email: string; + role: string; +}; + +type UpdateReportMemberRoleParams = { + email: string; + currentRole: string; + newRole: string; +}; + export type { AddressLineParams, AdminCanceledRequestParams, @@ -512,4 +528,7 @@ export type { StatementPageTitleTranslationParams, ReportIntegrationMessageTranslationParams, ApprovalWorkflowErrorParams, + SearchFilterAmountBetweenParams, + ReportMemberRoleParams, + UpdateReportMemberRoleParams, }; diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 5fdfec3fd96b..008a5a4be225 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -1613,7 +1613,7 @@ function getPolicyChangeLogAddEmployeeMessage(reportAction: OnyxInputOrEntry): reportAction is ReportAction { @@ -1628,7 +1628,7 @@ function getPolicyChangeLogChangeRoleMessage(reportAction: OnyxInputOrEntry>) { diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 5143a2d70008..d0929e33db52 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -69,7 +69,10 @@ function getFilterDisplayTitle(filters: Partial, fiel if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.AMOUNT) { const {lessThan, greaterThan} = filters; if (lessThan && greaterThan) { - return translate('search.filters.amount.between', convertToDisplayStringWithoutCurrency(Number(greaterThan)), convertToDisplayStringWithoutCurrency(Number(lessThan))); + return translate('search.filters.amount.between', { + greaterThan: convertToDisplayStringWithoutCurrency(Number(greaterThan)), + lessThan: convertToDisplayStringWithoutCurrency(Number(lessThan)), + }); } if (lessThan) { return translate('search.filters.amount.lessThan', convertToDisplayStringWithoutCurrency(Number(lessThan))); diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx index db7e482a0457..4174557c2e05 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx @@ -472,7 +472,7 @@ const ContextMenuActions: ContextMenuAction[] = [ setClipboardMessage(ReportActionsUtils.getPolicyChangeLogDeleteMemberMessage(reportAction)); } else if (ReportActionsUtils.isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.INTEGRATION_SYNC_FAILED)) { const {label, errorMessage} = ReportActionsUtils.getOriginalMessage(reportAction) ?? {label: '', errorMessage: ''}; - setClipboardMessage(Localize.translateLocal('report.actions.type.integrationSyncFailed', label, errorMessage)); + setClipboardMessage(Localize.translateLocal('report.actions.type.integrationSyncFailed', {label, errorMessage})); } else if (content) { setClipboardMessage( content.replace(/()(.*?)(<\/mention-user>)/gi, (match, openTag: string, innerContent: string, closeTag: string): string => { diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index e4dab8518eb2..012fb84b5bc5 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -675,7 +675,7 @@ function ReportActionItem({ children = ; } else if (ReportActionsUtils.isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.INTEGRATION_SYNC_FAILED)) { const {label, errorMessage} = ReportActionsUtils.getOriginalMessage(action) ?? {label: '', errorMessage: ''}; - children = ; + children = ; } else { const hasBeenFlagged = ![CONST.MODERATION.MODERATOR_DECISION_APPROVED, CONST.MODERATION.MODERATOR_DECISION_PENDING].some((item) => item === moderationDecision) && From d1fd0869ad469a7f4eb71b28e8a407e5682bf9d8 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Mon, 26 Aug 2024 17:37:53 +0800 Subject: [PATCH 021/463] add backTo to many pages so it shows the correct screen below the RHP overlay --- src/ROUTES.ts | 38 ++++-- src/components/AvatarWithDisplayName.tsx | 11 +- src/components/MoneyReportHeader.tsx | 4 +- src/components/MoneyRequestHeader.tsx | 4 +- src/components/PromotedActionsBar.tsx | 8 +- .../ReportActionItem/MoneyReportView.tsx | 11 +- .../ReportActionItem/MoneyRequestView.tsx | 113 ++++++++++++++++-- src/libs/HeaderUtils.ts | 4 +- src/libs/Navigation/Navigation.ts | 9 ++ src/libs/Navigation/linkingConfig/config.ts | 12 +- src/libs/Navigation/types.ts | 43 +++++-- src/libs/ReportUtils.ts | 4 +- src/libs/actions/Task.ts | 11 +- src/pages/EditReportFieldPage.tsx | 33 +++-- src/pages/ReportDetailsPage.tsx | 19 +-- src/pages/ReportParticipantsPage.tsx | 10 +- src/pages/ShareCodePage.tsx | 9 +- .../home/report/ReportActionItemSingle.tsx | 2 +- .../report/ReportDetailsShareCodePage.tsx | 10 +- .../home/report/withReportOrNotFound.tsx | 14 ++- .../settings/Report/ReportSettingsPage.tsx | 4 +- src/pages/tasks/NewTaskDescriptionPage.tsx | 8 +- src/pages/tasks/NewTaskDetailsPage.tsx | 8 +- src/pages/tasks/NewTaskPage.tsx | 12 +- src/pages/tasks/NewTaskTitlePage.tsx | 8 +- src/pages/tasks/TaskAssigneeSelectorModal.tsx | 7 +- .../TaskShareDestinationSelectorModal.tsx | 4 +- 27 files changed, 304 insertions(+), 116 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 47a2ad76209e..2364e7a384f7 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -265,11 +265,11 @@ const ROUTES = { }, EDIT_REPORT_FIELD_REQUEST: { route: 'r/:reportID/edit/policyField/:policyID/:fieldID', - getRoute: (reportID: string, policyID: string, fieldID: string) => `r/${reportID}/edit/policyField/${policyID}/${fieldID}` as const, + getRoute: (reportID: string, policyID: string, fieldID: string, backTo?: string) => getUrlWithBackToParam(`r/${reportID}/edit/policyField/${policyID}/${fieldID}` as const, backTo), }, REPORT_WITH_ID_DETAILS_SHARE_CODE: { route: 'r/:reportID/details/shareCode', - getRoute: (reportID: string) => `r/${reportID}/details/shareCode` as const, + getRoute: (reportID: string, backTo?: string) => getUrlWithBackToParam(`r/${reportID}/details/shareCode` as const, backTo), }, ATTACHMENTS: { route: 'attachment', @@ -278,7 +278,7 @@ const ROUTES = { }, REPORT_PARTICIPANTS: { route: 'r/:reportID/participants', - getRoute: (reportID: string) => `r/${reportID}/participants` as const, + getRoute: (reportID: string, backTo?: string) => getUrlWithBackToParam(`r/${reportID}/participants` as const, backTo), }, REPORT_PARTICIPANTS_INVITE: { route: 'r/:reportID/participants/invite', @@ -302,7 +302,7 @@ const ROUTES = { }, REPORT_SETTINGS: { route: 'r/:reportID/settings', - getRoute: (reportID: string) => `r/${reportID}/settings` as const, + getRoute: (reportID: string, backTo?: string) => getUrlWithBackToParam(`r/${reportID}/settings` as const, backTo), }, REPORT_SETTINGS_NAME: { route: 'r/:reportID/settings/name', @@ -508,12 +508,27 @@ const ROUTES = { IOU_SEND_ADD_DEBIT_CARD: 'pay/new/add-debit-card', IOU_SEND_ENABLE_PAYMENTS: 'pay/new/enable-payments', - NEW_TASK: 'new/task', - NEW_TASK_ASSIGNEE: 'new/task/assignee', + NEW_TASK: { + route: 'new/task', + getRoute: (backTo?: string) => getUrlWithBackToParam('new/task', backTo), + }, + NEW_TASK_ASSIGNEE: { + route: 'new/task/assignee', + getRoute: (backTo?: string) => getUrlWithBackToParam('new/task/assignee', backTo), + }, NEW_TASK_SHARE_DESTINATION: 'new/task/share-destination', - NEW_TASK_DETAILS: 'new/task/details', - NEW_TASK_TITLE: 'new/task/title', - NEW_TASK_DESCRIPTION: 'new/task/description', + NEW_TASK_DETAILS: { + route: 'new/task/details', + getRoute: (backTo?: string) => getUrlWithBackToParam('new/task/details', backTo), + }, + NEW_TASK_TITLE: { + route: 'new/task/title', + getRoute: (backTo?: string) => getUrlWithBackToParam('new/task/title', backTo), + }, + NEW_TASK_DESCRIPTION: { + route: 'new/task/description', + getRoute: (backTo?: string) => getUrlWithBackToParam('new/task/description', backTo), + }, TEACHERS_UNITE: 'settings/teachersunite', I_KNOW_A_TEACHER: 'settings/teachersunite/i-know-a-teacher', @@ -969,7 +984,10 @@ const ROUTES = { route: 'referral/:contentType', getRoute: (contentType: string, backTo?: string) => getUrlWithBackToParam(`referral/${contentType}`, backTo), }, - PROCESS_MONEY_REQUEST_HOLD: 'hold-expense-educational', + PROCESS_MONEY_REQUEST_HOLD: { + route: 'hold-expense-educational', + getRoute: (backTo?: string) => getUrlWithBackToParam('hold-expense-educational', backTo), + }, TRAVEL_MY_TRIPS: 'travel', TRAVEL_TCS: 'travel/terms', TRACK_TRAINING_MODAL: 'track-training', diff --git a/src/components/AvatarWithDisplayName.tsx b/src/components/AvatarWithDisplayName.tsx index 2ccdd47c3205..adb3775cadd4 100644 --- a/src/components/AvatarWithDisplayName.tsx +++ b/src/components/AvatarWithDisplayName.tsx @@ -79,10 +79,15 @@ function AvatarWithDisplayName({ actorAccountID.current = parentReportAction?.actorAccountID ?? -1; }, [parentReportActions, report]); + const goToDetailsPage = useCallback(() => { + ReportUtils.navigateToDetailsPage(report, Navigation.getReportRHPActiveRoute()); + }, [report]); + const showActorDetails = useCallback(() => { // We should navigate to the details page if the report is a IOU/expense report if (shouldEnableDetailPageNavigation) { - return ReportUtils.navigateToDetailsPage(report); + goToDetailsPage(); + return; } if (ReportUtils.isExpenseReport(report) && report?.ownerAccountID) { @@ -107,7 +112,7 @@ function AvatarWithDisplayName({ // Report detail route is added as fallback but based on the current implementation this route won't be executed Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID)); } - }, [report, shouldEnableDetailPageNavigation]); + }, [report, shouldEnableDetailPageNavigation, goToDetailsPage]); const headerView = ( @@ -172,7 +177,7 @@ function AvatarWithDisplayName({ return ( ReportUtils.navigateToDetailsPage(report)} + onPress={goToDetailsPage} style={[styles.flexRow, styles.alignItemsCenter, styles.flex1]} accessibilityLabel={title} role={CONST.ROLE.BUTTON} diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index ee3929292cd3..b349dbe0fa81 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -249,11 +249,11 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea } if (isSmallScreenWidth) { - if (Navigation.getActiveRoute().slice(1) === ROUTES.PROCESS_MONEY_REQUEST_HOLD) { + if (Navigation.getActiveRoute().slice(1) === ROUTES.PROCESS_MONEY_REQUEST_HOLD.route) { Navigation.goBack(); } } else { - Navigation.navigate(ROUTES.PROCESS_MONEY_REQUEST_HOLD); + Navigation.navigate(ROUTES.PROCESS_MONEY_REQUEST_HOLD.getRoute(Navigation.getReportRHPActiveRoute())); } }, [isSmallScreenWidth, shouldShowHoldMenu]); diff --git a/src/components/MoneyRequestHeader.tsx b/src/components/MoneyRequestHeader.tsx index d7844a1f5e93..3d06deea9627 100644 --- a/src/components/MoneyRequestHeader.tsx +++ b/src/components/MoneyRequestHeader.tsx @@ -109,11 +109,11 @@ function MoneyRequestHeader({report, parentReportAction, policy, shouldUseNarrow } if (isSmallScreenWidth) { - if (Navigation.getActiveRoute().slice(1) === ROUTES.PROCESS_MONEY_REQUEST_HOLD) { + if (Navigation.getActiveRoute().slice(1) === ROUTES.PROCESS_MONEY_REQUEST_HOLD.route) { Navigation.goBack(); } } else { - Navigation.navigate(ROUTES.PROCESS_MONEY_REQUEST_HOLD); + Navigation.navigate(ROUTES.PROCESS_MONEY_REQUEST_HOLD.getRoute(Navigation.getReportRHPActiveRoute())); } }, [isSmallScreenWidth, shouldShowHoldMenu]); diff --git a/src/components/PromotedActionsBar.tsx b/src/components/PromotedActionsBar.tsx index b0309d702f9a..6bae83d170da 100644 --- a/src/components/PromotedActionsBar.tsx +++ b/src/components/PromotedActionsBar.tsx @@ -24,9 +24,11 @@ type PromotedAction = { key: string; } & ThreeDotsMenuItem; -type BasePromotedActions = typeof CONST.PROMOTED_ACTIONS.PIN | typeof CONST.PROMOTED_ACTIONS.SHARE | typeof CONST.PROMOTED_ACTIONS.JOIN; +type BasePromotedActions = typeof CONST.PROMOTED_ACTIONS.PIN | typeof CONST.PROMOTED_ACTIONS.JOIN; type PromotedActionsType = Record PromotedAction> & { + share: (report: OnyxReport, backTo?: string) => PromotedAction; +} & { message: (params: {reportID?: string; accountID?: number; login?: string}) => PromotedAction; } & { hold: (params: {isTextHold: boolean; reportAction: ReportAction | undefined; reportID?: string}) => PromotedAction; @@ -37,9 +39,9 @@ const PromotedActions = { key: CONST.PROMOTED_ACTIONS.PIN, ...HeaderUtils.getPinMenuItem(report), }), - share: (report) => ({ + share: (report, backTo) => ({ key: CONST.PROMOTED_ACTIONS.SHARE, - ...HeaderUtils.getShareMenuItem(report), + ...HeaderUtils.getShareMenuItem(report, backTo), }), join: (report) => ({ key: CONST.PROMOTED_ACTIONS.JOIN, diff --git a/src/components/ReportActionItem/MoneyReportView.tsx b/src/components/ReportActionItem/MoneyReportView.tsx index fbf03821fa16..26e7fd8a5d52 100644 --- a/src/components/ReportActionItem/MoneyReportView.tsx +++ b/src/components/ReportActionItem/MoneyReportView.tsx @@ -108,7 +108,16 @@ function MoneyReportView({report, policy, isCombinedReport = false, shouldShowTo Navigation.navigate(ROUTES.EDIT_REPORT_FIELD_REQUEST.getRoute(report.reportID, report.policyID ?? '-1', reportField.fieldID))} + onPress={() => + Navigation.navigate( + ROUTES.EDIT_REPORT_FIELD_REQUEST.getRoute( + report.reportID, + report.policyID ?? '-1', + reportField.fieldID, + Navigation.getReportRHPActiveRoute(), + ), + ) + } shouldShowRightIcon disabled={isFieldDisabled} wrapperStyle={[styles.pv2, styles.taskDescriptionMenuItem]} diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 4a76f33de346..ebc78ffe84bc 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -348,7 +348,15 @@ function MoneyRequestView({ shouldShowRightIcon={canEditDistance} titleStyle={styles.flex1} onPress={() => - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute(CONST.IOU.ACTION.EDIT, iouType, transaction?.transactionID ?? '-1', report?.reportID ?? '-1')) + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute( + CONST.IOU.ACTION.EDIT, + iouType, + transaction?.transactionID ?? '-1', + report?.reportID ?? '-1', + Navigation.getReportRHPActiveRoute(), + ), + ) } /> @@ -360,7 +368,15 @@ function MoneyRequestView({ shouldShowRightIcon={canEditDistanceRate} titleStyle={styles.flex1} onPress={() => - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DISTANCE_RATE.getRoute(CONST.IOU.ACTION.EDIT, iouType, transaction?.transactionID ?? '-1', report?.reportID ?? '-1')) + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_DISTANCE_RATE.getRoute( + CONST.IOU.ACTION.EDIT, + iouType, + transaction?.transactionID ?? '-1', + report?.reportID ?? '-1', + Navigation.getReportRHPActiveRoute(), + ), + ) } /> @@ -373,7 +389,17 @@ function MoneyRequestView({ interactive={canEditDistance} shouldShowRightIcon={canEditDistance} titleStyle={styles.flex1} - onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute(CONST.IOU.ACTION.EDIT, iouType, transaction?.transactionID ?? '-1', report?.reportID ?? '-1'))} + onPress={() => + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute( + CONST.IOU.ACTION.EDIT, + iouType, + transaction?.transactionID ?? '-1', + report?.reportID ?? '-1', + Navigation.getReportRHPActiveRoute(), + ), + ) + } /> ); @@ -432,7 +458,16 @@ function MoneyRequestView({ shouldShowRightIcon={canEdit} titleStyle={styles.flex1} onPress={() => - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_TAG.getRoute(CONST.IOU.ACTION.EDIT, iouType, orderWeight, transaction?.transactionID ?? '', report?.reportID ?? '-1')) + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_TAG.getRoute( + CONST.IOU.ACTION.EDIT, + iouType, + orderWeight, + transaction?.transactionID ?? '', + report?.reportID ?? '-1', + Navigation.getReportRHPActiveRoute(), + ), + ) } brickRoadIndicator={tagError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} errorText={tagError} @@ -509,7 +544,7 @@ function MoneyRequestView({ iouType, transaction?.transactionID ?? '-1', report?.reportID ?? '-1', - Navigation.getActiveRouteWithoutParams(), + Navigation.getReportRHPActiveRoute(), ), ) } @@ -527,7 +562,15 @@ function MoneyRequestView({ interactive={canEditAmount} shouldShowRightIcon={canEditAmount} onPress={() => - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute(CONST.IOU.ACTION.EDIT, iouType, transaction?.transactionID ?? '-1', report?.reportID ?? '-1')) + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute( + CONST.IOU.ACTION.EDIT, + iouType, + transaction?.transactionID ?? '-1', + report?.reportID ?? '-1', + Navigation.getReportRHPActiveRoute(), + ), + ) } brickRoadIndicator={getErrorForField('amount') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} errorText={getErrorForField('amount')} @@ -542,7 +585,15 @@ function MoneyRequestView({ shouldShowRightIcon={canEdit} titleStyle={styles.flex1} onPress={() => - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DESCRIPTION.getRoute(CONST.IOU.ACTION.EDIT, iouType, transaction?.transactionID ?? '-1', report?.reportID ?? '-1')) + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_DESCRIPTION.getRoute( + CONST.IOU.ACTION.EDIT, + iouType, + transaction?.transactionID ?? '-1', + report?.reportID ?? '-1', + Navigation.getReportRHPActiveRoute(), + ), + ) } wrapperStyle={[styles.pv2, styles.taskDescriptionMenuItem]} brickRoadIndicator={getErrorForField('comment') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} @@ -561,7 +612,15 @@ function MoneyRequestView({ shouldShowRightIcon={canEditMerchant} titleStyle={styles.flex1} onPress={() => - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_MERCHANT.getRoute(CONST.IOU.ACTION.EDIT, iouType, transaction?.transactionID ?? '-1', report?.reportID ?? '-1')) + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_MERCHANT.getRoute( + CONST.IOU.ACTION.EDIT, + iouType, + transaction?.transactionID ?? '-1', + report?.reportID ?? '-1', + Navigation.getReportRHPActiveRoute(), + ), + ) } wrapperStyle={[styles.taskDescriptionMenuItem]} brickRoadIndicator={getErrorForField('merchant') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} @@ -578,7 +637,15 @@ function MoneyRequestView({ shouldShowRightIcon={canEditDate} titleStyle={styles.flex1} onPress={() => - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DATE.getRoute(CONST.IOU.ACTION.EDIT, iouType, transaction?.transactionID ?? '-1', report?.reportID ?? '-1' ?? '-1')) + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_DATE.getRoute( + CONST.IOU.ACTION.EDIT, + iouType, + transaction?.transactionID ?? '-1', + report?.reportID ?? '-1' ?? '-1', + Navigation.getReportRHPActiveRoute(), + ), + ) } brickRoadIndicator={getErrorForField('date') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} errorText={getErrorForField('date')} @@ -593,7 +660,15 @@ function MoneyRequestView({ shouldShowRightIcon={canEdit} titleStyle={styles.flex1} onPress={() => - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute(CONST.IOU.ACTION.EDIT, iouType, transaction?.transactionID ?? '-1', report?.reportID ?? '-1')) + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute( + CONST.IOU.ACTION.EDIT, + iouType, + transaction?.transactionID ?? '-1', + report?.reportID ?? '-1', + Navigation.getReportRHPActiveRoute(), + ), + ) } brickRoadIndicator={getErrorForField('category') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} errorText={getErrorForField('category')} @@ -620,7 +695,15 @@ function MoneyRequestView({ shouldShowRightIcon={canEditTaxFields} titleStyle={styles.flex1} onPress={() => - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_TAX_RATE.getRoute(CONST.IOU.ACTION.EDIT, iouType, transaction?.transactionID ?? '-1', report?.reportID ?? '-1')) + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_TAX_RATE.getRoute( + CONST.IOU.ACTION.EDIT, + iouType, + transaction?.transactionID ?? '-1', + report?.reportID ?? '-1', + Navigation.getReportRHPActiveRoute(), + ), + ) } brickRoadIndicator={getErrorForField('tax') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} errorText={getErrorForField('tax')} @@ -637,7 +720,13 @@ function MoneyRequestView({ titleStyle={styles.flex1} onPress={() => Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_TAX_AMOUNT.getRoute(CONST.IOU.ACTION.EDIT, iouType, transaction?.transactionID ?? '-1', report?.reportID ?? '-1'), + ROUTES.MONEY_REQUEST_STEP_TAX_AMOUNT.getRoute( + CONST.IOU.ACTION.EDIT, + iouType, + transaction?.transactionID ?? '-1', + report?.reportID ?? '-1', + Navigation.getReportRHPActiveRoute(), + ), ) } /> diff --git a/src/libs/HeaderUtils.ts b/src/libs/HeaderUtils.ts index 03c582d6b16b..b31d59804c51 100644 --- a/src/libs/HeaderUtils.ts +++ b/src/libs/HeaderUtils.ts @@ -17,11 +17,11 @@ function getPinMenuItem(report: OnyxReport): ThreeDotsMenuItem { }; } -function getShareMenuItem(report: OnyxReport): ThreeDotsMenuItem { +function getShareMenuItem(report: OnyxReport, backTo?: string): ThreeDotsMenuItem { return { icon: Expensicons.QrCode, text: Localize.translateLocal('common.share'), - onSelected: () => Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS_SHARE_CODE.getRoute(report?.reportID ?? '')), + onSelected: () => Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS_SHARE_CODE.getRoute(report?.reportID ?? '', backTo)), }; } diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 4bd86503fd2b..72de445dbe42 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -20,6 +20,7 @@ import getTopmostBottomTabRoute from './getTopmostBottomTabRoute'; import getTopmostCentralPaneRoute from './getTopmostCentralPaneRoute'; import originalGetTopmostReportActionId from './getTopmostReportActionID'; import originalGetTopmostReportId from './getTopmostReportId'; +import isReportOpenInRHP from './isReportOpenInRHP'; import linkingConfig from './linkingConfig'; import getMatchingBottomTabRouteForState from './linkingConfig/getMatchingBottomTabRouteForState'; import linkTo from './linkTo'; @@ -153,6 +154,13 @@ function getActiveRoute(): string { return ''; } +function getReportRHPActiveRoute(): string { + if (isReportOpenInRHP(navigationRef.getRootState())) { + return getActiveRoute(); + } + return ''; +} + /** * Check whether the passed route is currently Active or not. * @@ -415,6 +423,7 @@ export default { isActiveRoute, getActiveRoute, getActiveRouteWithoutParams, + getReportRHPActiveRoute, closeAndNavigate, goBack, isNavigationReady, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 4d3f19984b8f..f4528b4ed9a6 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -833,12 +833,12 @@ const config: LinkingOptions['config'] = { }, [SCREENS.RIGHT_MODAL.NEW_TASK]: { screens: { - [SCREENS.NEW_TASK.ROOT]: ROUTES.NEW_TASK, - [SCREENS.NEW_TASK.TASK_ASSIGNEE_SELECTOR]: ROUTES.NEW_TASK_ASSIGNEE, + [SCREENS.NEW_TASK.ROOT]: ROUTES.NEW_TASK.route, + [SCREENS.NEW_TASK.TASK_ASSIGNEE_SELECTOR]: ROUTES.NEW_TASK_ASSIGNEE.route, [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.NEW_TASK.DETAILS]: ROUTES.NEW_TASK_DETAILS.route, + [SCREENS.NEW_TASK.TITLE]: ROUTES.NEW_TASK_TITLE.route, + [SCREENS.NEW_TASK.DESCRIPTION]: ROUTES.NEW_TASK_DESCRIPTION.route, }, }, [SCREENS.RIGHT_MODAL.TEACHERS_UNITE]: { @@ -1006,7 +1006,7 @@ const config: LinkingOptions['config'] = { }, [SCREENS.RIGHT_MODAL.PROCESS_MONEY_REQUEST_HOLD]: { screens: { - [SCREENS.PROCESS_MONEY_REQUEST_HOLD_ROOT]: ROUTES.PROCESS_MONEY_REQUEST_HOLD, + [SCREENS.PROCESS_MONEY_REQUEST_HOLD_ROOT]: ROUTES.PROCESS_MONEY_REQUEST_HOLD.route, }, }, [SCREENS.RIGHT_MODAL.TRAVEL]: { diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index ceb62f1dac1c..8ed751ac9245 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -728,9 +728,13 @@ type ProfileNavigatorParamList = { }; type ReportDetailsNavigatorParamList = { - [SCREENS.REPORT_DETAILS.ROOT]: undefined; + [SCREENS.REPORT_DETAILS.ROOT]: { + reportID: string; + backTo?: Routes; + }; [SCREENS.REPORT_DETAILS.SHARE_CODE]: { reportID: string; + backTo?: Routes; }; [SCREENS.REPORT_DETAILS.EXPORT]: { reportID: string; @@ -740,7 +744,10 @@ type ReportDetailsNavigatorParamList = { }; type ReportSettingsNavigatorParamList = { - [SCREENS.REPORT_SETTINGS.ROOT]: {reportID: string}; + [SCREENS.REPORT_SETTINGS.ROOT]: { + reportID: string; + backTo?: Routes; + }; [SCREENS.REPORT_SETTINGS.NAME]: {reportID: string}; [SCREENS.REPORT_SETTINGS.NOTIFICATION_PREFERENCES]: {reportID: string}; [SCREENS.REPORT_SETTINGS.WRITE_CAPABILITY]: {reportID: string}; @@ -754,7 +761,10 @@ type ReportDescriptionNavigatorParamList = { }; type ParticipantsNavigatorParamList = { - [SCREENS.REPORT_PARTICIPANTS.ROOT]: {reportID: string}; + [SCREENS.REPORT_PARTICIPANTS.ROOT]: { + reportID: string; + backTo?: Routes; + }; [SCREENS.REPORT_PARTICIPANTS.INVITE]: {reportID: string}; [SCREENS.REPORT_PARTICIPANTS.DETAILS]: { reportID: string; @@ -938,12 +948,22 @@ type MoneyRequestNavigatorParamList = { }; type NewTaskNavigatorParamList = { - [SCREENS.NEW_TASK.ROOT]: undefined; - [SCREENS.NEW_TASK.TASK_ASSIGNEE_SELECTOR]: undefined; + [SCREENS.NEW_TASK.ROOT]: { + backTo?: Routes; + }; + [SCREENS.NEW_TASK.TASK_ASSIGNEE_SELECTOR]: { + backTo?: Routes; + }; [SCREENS.NEW_TASK.TASK_SHARE_DESTINATION_SELECTOR]: undefined; - [SCREENS.NEW_TASK.DETAILS]: undefined; - [SCREENS.NEW_TASK.TITLE]: undefined; - [SCREENS.NEW_TASK.DESCRIPTION]: undefined; + [SCREENS.NEW_TASK.DETAILS]: { + backTo?: Routes; + }; + [SCREENS.NEW_TASK.TITLE]: { + backTo?: Routes; + }; + [SCREENS.NEW_TASK.DESCRIPTION]: { + backTo?: Routes; + }; }; type TeachersUniteNavigatorParamList = { @@ -1005,7 +1025,12 @@ type FlagCommentNavigatorParamList = { }; type EditRequestNavigatorParamList = { - [SCREENS.EDIT_REQUEST.REPORT_FIELD]: undefined; + [SCREENS.EDIT_REQUEST.REPORT_FIELD]: { + fieldID: string; + reportID: string; + policyID: string; + backTo?: Routes; + }; }; type SignInNavigatorParamList = { diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 38b73ffc2057..034f00d4abc7 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3872,7 +3872,7 @@ function getParentNavigationSubtitle(report: OnyxEntry, invoiceReceiverP /** * Navigate to the details page of a given report */ -function navigateToDetailsPage(report: OnyxEntry) { +function navigateToDetailsPage(report: OnyxEntry, backTo?: string) { const isSelfDMReport = isSelfDM(report); const isOneOnOneChatReport = isOneOnOneChat(report); const participantAccountID = getParticipantsAccountIDsForDisplay(report); @@ -3883,7 +3883,7 @@ function navigateToDetailsPage(report: OnyxEntry) { } if (report?.reportID) { - Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report?.reportID)); + Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report?.reportID, backTo)); } } diff --git a/src/libs/actions/Task.ts b/src/libs/actions/Task.ts index 001245717e12..f92267ee3eef 100644 --- a/src/libs/actions/Task.ts +++ b/src/libs/actions/Task.ts @@ -18,6 +18,7 @@ import playSound, {SOUNDS} from '@libs/Sound'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type {Route} from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type {Icon} from '@src/types/onyx/OnyxCommon'; import type {ReportActions} from '@src/types/onyx/ReportAction'; @@ -836,7 +837,7 @@ function clearOutTaskInfoAndNavigate(reportID?: string, chatReport?: OnyxEntry) { /** * Closes the current open task modal and clears out the task info from the store. */ -function dismissModalAndClearOutTaskInfo() { - Navigation.closeRHPFlow(); +function dismissModalAndClearOutTaskInfo(backTo?: Route) { + if (backTo) { + Navigation.goBack(backTo); + } else { + Navigation.closeRHPFlow(); + } clearOutTaskInfo(); } diff --git a/src/pages/EditReportFieldPage.tsx b/src/pages/EditReportFieldPage.tsx index 9922eeb2a430..206756a2a07f 100644 --- a/src/pages/EditReportFieldPage.tsx +++ b/src/pages/EditReportFieldPage.tsx @@ -1,3 +1,4 @@ +import type {StackScreenProps} from '@react-navigation/stack'; import {Str} from 'expensify-common'; import React, {useState} from 'react'; import {withOnyx} from 'react-native-onyx'; @@ -14,9 +15,12 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import isSearchTopmostCentralPane from '@libs/Navigation/isSearchTopmostCentralPane'; import Navigation from '@libs/Navigation/Navigation'; +import type {EditRequestNavigatorParamList} from '@libs/Navigation/types'; import * as ReportUtils from '@libs/ReportUtils'; import * as ReportActions from '@src/libs/actions/Report'; 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 EditReportFieldDate from './EditReportFieldDate'; import EditReportFieldDropdown from './EditReportFieldDropdown'; @@ -30,26 +34,12 @@ type EditReportFieldPageOnyxProps = { policy: OnyxEntry; }; -type EditReportFieldPageProps = EditReportFieldPageOnyxProps & { - /** Route from navigation */ - route: { - /** Params from the route */ - params: { - /** Which field we are editing */ - fieldID: string; - - /** reportID for the expense report */ - reportID: string; - - /** policyID for the expense report */ - policyID: string; - }; - }; -}; +type EditReportFieldPageProps = EditReportFieldPageOnyxProps & StackScreenProps; function EditReportFieldPage({route, policy, report}: EditReportFieldPageProps) { const {windowWidth} = useWindowDimensions(); const styles = useThemeStyles(); + const backTo = route.params.backTo; const fieldKey = ReportUtils.getReportFieldKey(route.params.fieldID); const reportField = report?.fieldList?.[fieldKey] ?? policy?.fieldList?.[fieldKey]; const isDisabled = ReportUtils.isReportFieldDisabled(report, reportField, policy); @@ -74,11 +64,19 @@ function EditReportFieldPage({route, policy, report}: EditReportFieldPageProps) ); } + const goBack = () => { + if (isReportFieldTitle) { + Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID, backTo)); + return; + } + Navigation.goBack(backTo); + }; + const handleReportFieldChange = (form: FormOnyxValues) => { const value = form[fieldKey]; if (isReportFieldTitle) { ReportActions.updateReportName(report.reportID, value, report.reportName ?? ''); - Navigation.goBack(); + goBack(); } else { ReportActions.updateReportField(report.reportID, {...reportField, value: value === '' ? null : value}, reportField); Navigation.dismissModal(isSearchTopmostCentralPane() ? undefined : report?.reportID); @@ -114,6 +112,7 @@ function EditReportFieldPage({route, policy, report}: EditReportFieldPageProps) threeDotsMenuItems={menuItems} shouldShowThreeDotsButton={!!menuItems?.length} threeDotsAnchorPosition={styles.threeDotsPopoverOffsetNoCloseButton(windowWidth)} + onBackButtonPress={goBack} /> ; -function ReportDetailsPage({policies, report, session, personalDetails}: ReportDetailsPageProps) { +function ReportDetailsPage({policies, report, session, personalDetails, route}: ReportDetailsPageProps) { const {translate} = useLocalize(); const {isOffline} = useNetwork(); const styles = useThemeStyles(); + const backTo = route.params.backTo; // The app would crash due to subscribing to the entire report collection if parentReportID is an empty string. So we should have a fallback ID here. /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */ @@ -316,7 +317,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD if (shouldOpenRoomMembersPage) { Navigation.navigate(ROUTES.ROOM_MEMBERS.getRoute(report?.reportID ?? '-1')); } else { - Navigation.navigate(ROUTES.REPORT_PARTICIPANTS.getRoute(report?.reportID ?? '-1')); + Navigation.navigate(ROUTES.REPORT_PARTICIPANTS.getRoute(report?.reportID ?? '-1', backTo)); } }, }); @@ -341,7 +342,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD isAnonymousAction: false, shouldShowRightIcon: true, action: () => { - Navigation.navigate(ROUTES.REPORT_SETTINGS.getRoute(report?.reportID ?? '-1')); + Navigation.navigate(ROUTES.REPORT_SETTINGS.getRoute(report?.reportID ?? '-1', backTo)); }, }); } @@ -456,6 +457,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD canUnapproveRequest, unapproveExpenseReportOrShowModal, isExpenseReport, + backTo, ]); const displayNamesWithTooltips = useMemo(() => { @@ -561,10 +563,10 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD result.push(PromotedActions.pin(report)); } - result.push(PromotedActions.share(report)); + result.push(PromotedActions.share(report, backTo)); return result; - }, [report, moneyRequestAction, canJoin, isExpenseReport, shouldShowHoldAction, canHoldUnholdReportAction.canHoldRequest, transactionThreadReportID]); + }, [report, moneyRequestAction, canJoin, isExpenseReport, shouldShowHoldAction, canHoldUnholdReportAction.canHoldRequest, transactionThreadReportID, backTo]); const nameSectionExpenseIOU = ( @@ -671,7 +673,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD titleStyle={styles.newKansasLarge} shouldCheckActionAllowedOnPress={false} description={Str.UCFirst(titleField.name)} - onPress={() => Navigation.navigate(ROUTES.EDIT_REPORT_FIELD_REQUEST.getRoute(report.reportID, report.policyID ?? '-1', titleField.fieldID ?? '-1'))} + onPress={() => Navigation.navigate(ROUTES.EDIT_REPORT_FIELD_REQUEST.getRoute(report.reportID, report.policyID ?? '-1', titleField.fieldID ?? '-1', backTo))} furtherDetailsComponent={nameSectionFurtherDetailsContent} /> @@ -706,7 +708,10 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD return ( - + Navigation.goBack(backTo)} + /> {renderedAvatar} diff --git a/src/pages/ReportParticipantsPage.tsx b/src/pages/ReportParticipantsPage.tsx index 9815177da615..e35f6763325c 100755 --- a/src/pages/ReportParticipantsPage.tsx +++ b/src/pages/ReportParticipantsPage.tsx @@ -1,4 +1,5 @@ import {useIsFocused} from '@react-navigation/native'; +import type {StackScreenProps} from '@react-navigation/stack'; import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {InteractionManager, View} from 'react-native'; import type {TextInput} from 'react-native'; @@ -24,17 +25,20 @@ import useThemeStyles from '@hooks/useThemeStyles'; import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; import * as Report from '@libs/actions/Report'; import Navigation from '@libs/Navigation/Navigation'; +import type {ParticipantsNavigatorParamList} from '@libs/Navigation/types'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type SCREENS from '@src/SCREENS'; import type {WithReportOrNotFoundProps} from './home/report/withReportOrNotFound'; import withReportOrNotFound from './home/report/withReportOrNotFound'; type MemberOption = Omit & {accountID: number}; -function ReportParticipantsPage({report}: WithReportOrNotFoundProps) { +type ReportParticipantsPageProps = WithReportOrNotFoundProps & StackScreenProps; +function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { const [selectedMembers, setSelectedMembers] = useState([]); const [removeMembersConfirmModalVisible, setRemoveMembersConfirmModalVisible] = useState(false); const {translate, formatPhoneNumber} = useLocalize(); @@ -287,7 +291,7 @@ function ReportParticipantsPage({report}: WithReportOrNotFoundProps) { Navigation.navigate(ROUTES.REPORT_PARTICIPANTS_DETAILS.getRoute(report.reportID, item.accountID)); return; } - Navigation.navigate(ROUTES.PROFILE.getRoute(item.accountID)); + Navigation.navigate(ROUTES.PROFILE.getRoute(item.accountID, Navigation.getActiveRoute())); }, [report, isCurrentUserAdmin, isGroupChat], ); @@ -324,7 +328,7 @@ function ReportParticipantsPage({report}: WithReportOrNotFoundProps) { } if (report) { - Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID)); + Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID, route.params.backTo)); } }} guidesCallTaskID={CONST.GUIDES_CALL_TASK_IDS.WORKSPACE_MEMBERS} diff --git a/src/pages/ShareCodePage.tsx b/src/pages/ShareCodePage.tsx index e11e99a6e852..18f6c5960b5e 100644 --- a/src/pages/ShareCodePage.tsx +++ b/src/pages/ShareCodePage.tsx @@ -19,6 +19,7 @@ import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import Clipboard from '@libs/Clipboard'; import Navigation from '@libs/Navigation/Navigation'; +import type {BackToParams} from '@libs/Navigation/types'; import * as ReportUtils from '@libs/ReportUtils'; import * as Url from '@libs/Url'; import * as UserUtils from '@libs/UserUtils'; @@ -34,7 +35,7 @@ type ShareCodePageOnyxProps = { policy?: OnyxEntry; }; -type ShareCodePageProps = ShareCodePageOnyxProps; +type ShareCodePageProps = ShareCodePageOnyxProps & BackToParams; /** * When sharing a policy (workspace) only return user avatar that is user defined. Default ws avatars have separate logic. @@ -53,7 +54,7 @@ function getLogoForWorkspace(report: OnyxEntry, policy?: OnyxEntry Navigation.goBack(isReport ? ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report?.reportID) : undefined)} + onBackButtonPress={() => Navigation.goBack(isReport ? ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report?.reportID, backTo) : undefined)} shouldShowBackButton /> @@ -146,7 +147,7 @@ function ShareCodePage({report, policy}: ShareCodePageProps) { Navigation.navigate(ROUTES.REFERRAL_DETAILS_MODAL.getRoute(CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SHARE_CODE, Navigation.getActiveRouteWithoutParams()))} + onPress={() => Navigation.navigate(ROUTES.REFERRAL_DETAILS_MODAL.getRoute(CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SHARE_CODE, Navigation.getActiveRoute()))} shouldShowRightIcon /> diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index 95a7332f0606..49fc6f6dba43 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -58,7 +58,7 @@ type ReportActionItemSingleProps = Partial & { }; const showUserDetails = (accountID: string) => { - Navigation.navigate(ROUTES.PROFILE.getRoute(accountID)); + Navigation.navigate(ROUTES.PROFILE.getRoute(accountID, Navigation.getReportRHPActiveRoute())); }; const showWorkspaceDetails = (reportID: string) => { diff --git a/src/pages/home/report/ReportDetailsShareCodePage.tsx b/src/pages/home/report/ReportDetailsShareCodePage.tsx index efee188d0beb..4caa29209fa9 100644 --- a/src/pages/home/report/ReportDetailsShareCodePage.tsx +++ b/src/pages/home/report/ReportDetailsShareCodePage.tsx @@ -1,10 +1,13 @@ +import type {StackScreenProps} from '@react-navigation/stack'; import React from 'react'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; +import type {ReportDetailsNavigatorParamList} from '@libs/Navigation/types'; import * as ReportUtils from '@libs/ReportUtils'; import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; import ShareCodePage from '@pages/ShareCodePage'; import ONYXKEYS from '@src/ONYXKEYS'; +import type SCREENS from '@src/SCREENS'; import type {Policy} from '@src/types/onyx'; import type {WithReportOrNotFoundProps} from './withReportOrNotFound'; import withReportOrNotFound from './withReportOrNotFound'; @@ -13,14 +16,17 @@ type ReportDetailsShareCodePageOnyxProps = { policy: OnyxEntry; }; -type ReportDetailsShareCodePageProps = ReportDetailsShareCodePageOnyxProps & WithReportOrNotFoundProps; +type ReportDetailsShareCodePageProps = ReportDetailsShareCodePageOnyxProps & + WithReportOrNotFoundProps & + StackScreenProps; -function ReportDetailsShareCodePage({report, policy}: ReportDetailsShareCodePageProps) { +function ReportDetailsShareCodePage({report, policy, route}: ReportDetailsShareCodePageProps) { if (ReportUtils.isSelfDM(report)) { return ; } return ( diff --git a/src/pages/home/report/withReportOrNotFound.tsx b/src/pages/home/report/withReportOrNotFound.tsx index 7f6165a031ee..58381e4f0764 100644 --- a/src/pages/home/report/withReportOrNotFound.tsx +++ b/src/pages/home/report/withReportOrNotFound.tsx @@ -7,7 +7,13 @@ import {withOnyx} from 'react-native-onyx'; import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import getComponentDisplayName from '@libs/getComponentDisplayName'; import * as ReportUtils from '@libs/ReportUtils'; -import type {ParticipantsNavigatorParamList, PrivateNotesNavigatorParamList, ReportDescriptionNavigatorParamList} from '@navigation/types'; +import type { + ParticipantsNavigatorParamList, + PrivateNotesNavigatorParamList, + ReportDescriptionNavigatorParamList, + ReportDetailsNavigatorParamList, + ReportSettingsNavigatorParamList, +} from '@navigation/types'; import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; import * as Report from '@userActions/Report'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -36,8 +42,12 @@ type WithReportOrNotFoundProps = WithReportOrNotFoundOnyxProps & { route: | RouteProp | RouteProp + | RouteProp | RouteProp - | RouteProp; + | RouteProp + | RouteProp + | RouteProp + | RouteProp; /** The report currently being looked at */ report: OnyxTypes.Report; diff --git a/src/pages/settings/Report/ReportSettingsPage.tsx b/src/pages/settings/Report/ReportSettingsPage.tsx index 6e1ab9a61737..c541bee377a3 100644 --- a/src/pages/settings/Report/ReportSettingsPage.tsx +++ b/src/pages/settings/Report/ReportSettingsPage.tsx @@ -23,7 +23,7 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject'; type ReportSettingsPageProps = WithReportOrNotFoundProps & StackScreenProps; -function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { +function ReportSettingsPage({report, policies, route}: ReportSettingsPageProps) { const reportID = report?.reportID ?? '-1'; const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -52,7 +52,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, route.params.backTo))} /> {shouldShowNotificationPref && ( diff --git a/src/pages/tasks/NewTaskDescriptionPage.tsx b/src/pages/tasks/NewTaskDescriptionPage.tsx index f18829e8c803..6689524cd11e 100644 --- a/src/pages/tasks/NewTaskDescriptionPage.tsx +++ b/src/pages/tasks/NewTaskDescriptionPage.tsx @@ -34,14 +34,15 @@ type NewTaskDescriptionPageOnyxProps = { type NewTaskDescriptionPageProps = NewTaskDescriptionPageOnyxProps & StackScreenProps; -function NewTaskDescriptionPage({task}: NewTaskDescriptionPageProps) { +function NewTaskDescriptionPage({task, route}: NewTaskDescriptionPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const {inputCallbackRef, inputRef} = useAutoFocusInput(); + const goBack = () => Navigation.goBack(ROUTES.NEW_TASK.getRoute(route.params.backTo)); const onSubmit = (values: FormOnyxValues) => { TaskActions.setDescriptionValue(values.taskDescription); - Navigation.goBack(ROUTES.NEW_TASK); + goBack(); }; const validate = (values: FormOnyxValues): FormInputErrors => { @@ -63,8 +64,7 @@ function NewTaskDescriptionPage({task}: NewTaskDescriptionPageProps) { <> TaskActions.dismissModalAndClearOutTaskInfo()} - onBackButtonPress={() => Navigation.goBack(ROUTES.NEW_TASK)} + onBackButtonPress={goBack} /> ; -function NewTaskDetailsPage({task}: NewTaskDetailsPageProps) { +function NewTaskDetailsPage({task, route}: NewTaskDetailsPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const [taskTitle, setTaskTitle] = useState(task?.title ?? ''); @@ -42,6 +42,7 @@ function NewTaskDetailsPage({task}: NewTaskDetailsPageProps) { const {inputCallbackRef} = useAutoFocusInput(); + const backTo = route.params.backTo; const skipConfirmation = task?.skipConfirmation && task?.assigneeAccountID && task?.parentReportID; const buttonText = skipConfirmation ? translate('newTaskPage.assignTask') : translate('common.next'); @@ -84,7 +85,7 @@ function NewTaskDetailsPage({task}: NewTaskDetailsPageProps) { task.assigneeChatReport, ); } else { - Navigation.navigate(ROUTES.NEW_TASK); + Navigation.navigate(ROUTES.NEW_TASK.getRoute(backTo)); } }; @@ -96,9 +97,8 @@ function NewTaskDetailsPage({task}: NewTaskDetailsPageProps) { > TaskActions.dismissModalAndClearOutTaskInfo()} shouldShowBackButton - onBackButtonPress={() => TaskActions.dismissModalAndClearOutTaskInfo()} + onBackButtonPress={() => TaskActions.dismissModalAndClearOutTaskInfo(backTo)} /> ; -function NewTaskPage({task, reports, personalDetails}: NewTaskPageProps) { +function NewTaskPage({task, reports, personalDetails, route}: NewTaskPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const [assignee, setAssignee] = useState(); @@ -62,6 +62,7 @@ function NewTaskPage({task, reports, personalDetails}: NewTaskPageProps) { const {paddingBottom} = useStyledSafeAreaInsets(); + const backTo = route.params.backTo; const confirmButtonRef = useRef(null); const focusTimeoutRef = useRef(null); useFocusEffect( @@ -153,10 +154,9 @@ function NewTaskPage({task, reports, personalDetails}: NewTaskPageProps) { > TaskActions.dismissModalAndClearOutTaskInfo()} shouldShowBackButton onBackButtonPress={() => { - Navigation.goBack(ROUTES.NEW_TASK_DETAILS); + Navigation.goBack(ROUTES.NEW_TASK_DETAILS.getRoute(backTo)); }} /> {hasDestinationError && ( @@ -180,14 +180,14 @@ function NewTaskPage({task, reports, personalDetails}: NewTaskPageProps) { Navigation.navigate(ROUTES.NEW_TASK_TITLE)} + onPress={() => Navigation.navigate(ROUTES.NEW_TASK_TITLE.getRoute(backTo))} shouldShowRightIcon rightLabel={translate('common.required')} /> Navigation.navigate(ROUTES.NEW_TASK_DESCRIPTION)} + onPress={() => Navigation.navigate(ROUTES.NEW_TASK_DESCRIPTION.getRoute(backTo))} shouldShowRightIcon shouldParseTitle numberOfLinesTitle={2} @@ -198,7 +198,7 @@ function NewTaskPage({task, reports, personalDetails}: NewTaskPageProps) { title={assignee?.displayName ?? ''} description={assignee?.displayName ? LocalePhoneNumber.formatPhoneNumber(assignee?.subtitle) : translate('task.assignee')} icon={assignee?.icons} - onPress={() => Navigation.navigate(ROUTES.NEW_TASK_ASSIGNEE)} + onPress={() => Navigation.navigate(ROUTES.NEW_TASK_ASSIGNEE.getRoute(backTo))} shouldShowRightIcon titleWithTooltips={assigneeTooltipDetails} /> diff --git a/src/pages/tasks/NewTaskTitlePage.tsx b/src/pages/tasks/NewTaskTitlePage.tsx index cdc9fc27596a..3b45418db87d 100644 --- a/src/pages/tasks/NewTaskTitlePage.tsx +++ b/src/pages/tasks/NewTaskTitlePage.tsx @@ -29,12 +29,13 @@ type NewTaskTitlePageOnyxProps = { }; type NewTaskTitlePageProps = NewTaskTitlePageOnyxProps & StackScreenProps; -function NewTaskTitlePage({task}: NewTaskTitlePageProps) { +function NewTaskTitlePage({task, route}: NewTaskTitlePageProps) { const styles = useThemeStyles(); const {inputCallbackRef} = useAutoFocusInput(); const {translate} = useLocalize(); + const goBack = () => Navigation.goBack(ROUTES.NEW_TASK.getRoute(route.params.backTo)); const validate = (values: FormOnyxValues): FormInputErrors => { const errors = {}; @@ -52,7 +53,7 @@ function NewTaskTitlePage({task}: NewTaskTitlePageProps) { // the response const onSubmit = (values: FormOnyxValues) => { TaskActions.setTitleValue(values.taskTitle); - Navigation.goBack(ROUTES.NEW_TASK); + goBack(); }; return ( @@ -63,9 +64,8 @@ function NewTaskTitlePage({task}: NewTaskTitlePageProps) { > TaskActions.dismissModalAndClearOutTaskInfo()} shouldShowBackButton - onBackButtonPress={() => Navigation.goBack(ROUTES.NEW_TASK)} + onBackButtonPress={goBack} /> >(); const {translate} = useLocalize(); const session = useSession(); + const backTo = 'backTo' in route.params ? (route.params.backTo as string) : ''; const [isSearchingForReports] = useOnyx(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, {initWithStoredValues: false}); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const {userToInvite, recentReports, personalDetails, currentUserOption, searchValue, debouncedSearchValue, setSearchValue, headerMessage, areOptionsInitialized} = useOptions(); @@ -210,14 +211,14 @@ function TaskAssigneeSelectorModal({reports, task}: TaskAssigneeSelectorModalPro OptionsListUtils.isCurrentUser({...option, accountID: option?.accountID ?? -1, login: option?.login ?? undefined}), ); InteractionManager.runAfterInteractions(() => { - Navigation.goBack(ROUTES.NEW_TASK); + Navigation.goBack(ROUTES.NEW_TASK.getRoute(backTo)); }); } }, - [session?.accountID, task?.shareDestination, report], + [session?.accountID, task?.shareDestination, report, backTo], ); - const handleBackButtonPress = useCallback(() => (route.params?.reportID ? Navigation.dismissModal() : Navigation.goBack(ROUTES.NEW_TASK)), [route.params]); + const handleBackButtonPress = useCallback(() => (route.params?.reportID ? Navigation.dismissModal() : Navigation.goBack(ROUTES.NEW_TASK.getRoute(backTo))), [route.params, backTo]); const isOpen = ReportUtils.isOpenTaskReport(report); const canModifyTask = TaskActions.canModifyTask(report, currentUserPersonalDetails.accountID); diff --git a/src/pages/tasks/TaskShareDestinationSelectorModal.tsx b/src/pages/tasks/TaskShareDestinationSelectorModal.tsx index 1754c512bd6b..8cd38a54f7f9 100644 --- a/src/pages/tasks/TaskShareDestinationSelectorModal.tsx +++ b/src/pages/tasks/TaskShareDestinationSelectorModal.tsx @@ -31,7 +31,7 @@ const selectReportHandler = (option: unknown) => { } Task.setShareDestinationValue(optionItem?.reportID); - Navigation.goBack(ROUTES.NEW_TASK); + Navigation.goBack(ROUTES.NEW_TASK.getRoute()); }; const reportFilter = (reportOptions: Array>) => @@ -130,7 +130,7 @@ function TaskShareDestinationSelectorModal() { <> Navigation.goBack(ROUTES.NEW_TASK)} + onBackButtonPress={() => Navigation.goBack(ROUTES.NEW_TASK.getRoute())} /> Date: Mon, 26 Aug 2024 18:31:19 +0800 Subject: [PATCH 022/463] add more backTo to currency page --- src/ROUTES.ts | 6 +++--- .../MoneyRequestConfirmationListFooter.tsx | 2 +- src/components/ReportActionItem/MoneyRequestView.tsx | 1 + src/libs/Navigation/types.ts | 2 ++ src/pages/iou/request/step/IOURequestStepAmount.tsx | 6 ++---- .../iou/request/step/IOURequestStepCurrency.tsx | 12 ++++-------- 6 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 2364e7a384f7..36ce107d8cea 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -377,9 +377,9 @@ const ROUTES = { `${action as string}/${iouType as string}/confirmation/${transactionID}/${reportID}${participantsAutoAssigned ? '?participantsAutoAssigned=true' : ''}` as const, }, MONEY_REQUEST_STEP_AMOUNT: { - route: ':action/:iouType/amount/:transactionID/:reportID', - getRoute: (action: IOUAction, iouType: IOUType, transactionID: string, reportID: string, backTo = '') => - getUrlWithBackToParam(`${action as string}/${iouType as string}/amount/${transactionID}/${reportID}`, backTo), + route: ':action/:iouType/amount/:transactionID/:reportID/:pageIndex?', + getRoute: (action: IOUAction, iouType: IOUType, transactionID: string, reportID: string, pageIndex: string, backTo = '') => + getUrlWithBackToParam(`${action as string}/${iouType as string}/amount/${transactionID}/${reportID}/${pageIndex}`, backTo), }, MONEY_REQUEST_STEP_TAX_RATE: { route: ':action/:iouType/taxRate/:transactionID/:reportID?', diff --git a/src/components/MoneyRequestConfirmationListFooter.tsx b/src/components/MoneyRequestConfirmationListFooter.tsx index 623348a4c7a4..b3c30e7fc4ee 100644 --- a/src/components/MoneyRequestConfirmationListFooter.tsx +++ b/src/components/MoneyRequestConfirmationListFooter.tsx @@ -282,7 +282,7 @@ function MoneyRequestConfirmationListFooter({ return; } - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute(action, iouType, transactionID, reportID, Navigation.getActiveRouteWithoutParams())); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute(action, iouType, transactionID, reportID, 'confirm', Navigation.getActiveRouteWithoutParams())); }} style={[styles.moneyRequestMenuItem, styles.mt2]} titleStyle={styles.moneyRequestConfirmationAmount} diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index ebc78ffe84bc..b956a012eb2a 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -568,6 +568,7 @@ function MoneyRequestView({ iouType, transaction?.transactionID ?? '-1', report?.reportID ?? '-1', + '', Navigation.getReportRHPActiveRoute(), ), ) diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 8ed751ac9245..b071650fe677 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -897,6 +897,7 @@ type MoneyRequestNavigatorParamList = { backTo: never; action: never; currency: never; + pageIndex?: string; }; [SCREENS.MONEY_REQUEST.START]: { iouType: IOUType; @@ -910,6 +911,7 @@ type MoneyRequestNavigatorParamList = { transactionID: string; backTo: Routes; action: IOUAction; + pageIndex?: string; currency?: string; }; [SCREENS.MONEY_REQUEST.STEP_DISTANCE_RATE]: { diff --git a/src/pages/iou/request/step/IOURequestStepAmount.tsx b/src/pages/iou/request/step/IOURequestStepAmount.tsx index 069f86ce0899..829c42aac132 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.tsx +++ b/src/pages/iou/request/step/IOURequestStepAmount.tsx @@ -62,7 +62,7 @@ type IOURequestStepAmountProps = IOURequestStepAmountOnyxProps & function IOURequestStepAmount({ report, route: { - params: {iouType, reportID, transactionID, backTo, action, currency: selectedCurrency = ''}, + params: {iouType, reportID, transactionID, backTo, pageIndex, action, currency: selectedCurrency = ''}, }, transaction, policy, @@ -133,9 +133,7 @@ function IOURequestStepAmount({ }; const navigateToCurrencySelectionPage = () => { - Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_CURRENCY.getRoute(action, iouType, transactionID, reportID, backTo ? 'confirm' : '', currency, Navigation.getActiveRouteWithoutParams()), - ); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CURRENCY.getRoute(action, iouType, transactionID, reportID, pageIndex, currency, Navigation.getActiveRoute())); }; const navigateToParticipantPage = () => { diff --git a/src/pages/iou/request/step/IOURequestStepCurrency.tsx b/src/pages/iou/request/step/IOURequestStepCurrency.tsx index 74600a5f3650..fd999fecac48 100644 --- a/src/pages/iou/request/step/IOURequestStepCurrency.tsx +++ b/src/pages/iou/request/step/IOURequestStepCurrency.tsx @@ -8,10 +8,10 @@ import useLocalize from '@hooks/useLocalize'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; +import {appendParam} from '@libs/Url'; import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES, {getUrlWithBackToParam} from '@src/ROUTES'; import type {Route} from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type {Transaction} from '@src/types/onyx'; @@ -28,7 +28,7 @@ type IOURequestStepCurrencyProps = IOURequestStepCurrencyOnyxProps & WithFullTra function IOURequestStepCurrency({ route: { - params: {backTo, iouType, pageIndex, reportID, transactionID, action, currency: selectedCurrency = ''}, + params: {backTo, pageIndex, transactionID, action, currency: selectedCurrency = ''}, }, draftTransaction, }: IOURequestStepCurrencyProps) { @@ -42,14 +42,10 @@ function IOURequestStepCurrency({ // 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 as string, - `/${ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID)}`, - ); if (selectedCurrencyValue) { - Navigation.navigate(`${routeToAmountPageWithConfirmationAsBackTo}¤cy=${selectedCurrencyValue}` as Route); + Navigation.navigate(appendParam(backTo as string, 'currency', selectedCurrencyValue)); } else { - Navigation.goBack(routeToAmountPageWithConfirmationAsBackTo as Route); + Navigation.goBack(backTo as Route); } return; } From 61177b567cc6de030c43b58f7bed1eceda3e5a62 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Mon, 26 Aug 2024 19:00:10 +0800 Subject: [PATCH 023/463] lint --- src/pages/iou/request/step/IOURequestStepCurrency.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/request/step/IOURequestStepCurrency.tsx b/src/pages/iou/request/step/IOURequestStepCurrency.tsx index fd999fecac48..7bef6e8cad48 100644 --- a/src/pages/iou/request/step/IOURequestStepCurrency.tsx +++ b/src/pages/iou/request/step/IOURequestStepCurrency.tsx @@ -45,7 +45,7 @@ function IOURequestStepCurrency({ if (selectedCurrencyValue) { Navigation.navigate(appendParam(backTo as string, 'currency', selectedCurrencyValue)); } else { - Navigation.goBack(backTo as Route); + Navigation.goBack(backTo); } return; } From caea4ae939a1998dff3cdee7973e2db8dd3df423 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Mon, 26 Aug 2024 19:11:40 +0800 Subject: [PATCH 024/463] remove unused import --- src/pages/iou/request/step/IOURequestStepCurrency.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/iou/request/step/IOURequestStepCurrency.tsx b/src/pages/iou/request/step/IOURequestStepCurrency.tsx index 7bef6e8cad48..8f8cdc731fb1 100644 --- a/src/pages/iou/request/step/IOURequestStepCurrency.tsx +++ b/src/pages/iou/request/step/IOURequestStepCurrency.tsx @@ -12,7 +12,6 @@ import {appendParam} from '@libs/Url'; import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Route} from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type {Transaction} from '@src/types/onyx'; import StepScreenWrapper from './StepScreenWrapper'; From 5530ac78625080d68756f1267fc95cb1e330ceb2 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Tue, 27 Aug 2024 12:07:43 +0800 Subject: [PATCH 025/463] use const --- src/CONST.ts | 3 +++ src/components/MoneyRequestConfirmationListFooter.tsx | 2 +- src/pages/iou/request/step/IOURequestStepCurrency.tsx | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 175aa8cd3c16..23bd27d01858 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1976,6 +1976,9 @@ const CONST = { ACCESS_VARIANTS: { CREATE: 'create', }, + PAGE_INDEX: { + CONFIRM: 'confirm', + }, }, GROWL: { diff --git a/src/components/MoneyRequestConfirmationListFooter.tsx b/src/components/MoneyRequestConfirmationListFooter.tsx index 2dce23c84e8d..b5975090bc19 100644 --- a/src/components/MoneyRequestConfirmationListFooter.tsx +++ b/src/components/MoneyRequestConfirmationListFooter.tsx @@ -285,7 +285,7 @@ function MoneyRequestConfirmationListFooter({ return; } - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute(action, iouType, transactionID, reportID, 'confirm', Navigation.getActiveRouteWithoutParams())); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute(action, iouType, transactionID, reportID, CONST.IOU.PAGE_INDEX.CONFIRM, Navigation.getActiveRouteWithoutParams())); }} style={[styles.moneyRequestMenuItem, styles.mt2]} titleStyle={styles.moneyRequestConfirmationAmount} diff --git a/src/pages/iou/request/step/IOURequestStepCurrency.tsx b/src/pages/iou/request/step/IOURequestStepCurrency.tsx index 8f8cdc731fb1..548b4d075d78 100644 --- a/src/pages/iou/request/step/IOURequestStepCurrency.tsx +++ b/src/pages/iou/request/step/IOURequestStepCurrency.tsx @@ -40,7 +40,7 @@ function IOURequestStepCurrency({ // 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') { + if (pageIndex === CONST.IOU.PAGE_INDEX.CONFIRM) { if (selectedCurrencyValue) { Navigation.navigate(appendParam(backTo as string, 'currency', selectedCurrencyValue)); } else { @@ -53,7 +53,7 @@ function IOURequestStepCurrency({ const confirmCurrencySelection = (option: CurrencyListItem) => { Keyboard.dismiss(); - if (pageIndex !== 'confirm') { + if (pageIndex !== CONST.IOU.PAGE_INDEX.CONFIRM) { IOU.setMoneyRequestCurrency(transactionID, option.currencyCode, action === CONST.IOU.ACTION.EDIT); } From 74e4de7e4be4b66cef1ebe946d08fc422d1cc450 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Tue, 27 Aug 2024 12:18:27 +0800 Subject: [PATCH 026/463] prettier --- src/components/MoneyRequestConfirmationListFooter.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/MoneyRequestConfirmationListFooter.tsx b/src/components/MoneyRequestConfirmationListFooter.tsx index b5975090bc19..e7d2c597966d 100644 --- a/src/components/MoneyRequestConfirmationListFooter.tsx +++ b/src/components/MoneyRequestConfirmationListFooter.tsx @@ -285,7 +285,9 @@ function MoneyRequestConfirmationListFooter({ return; } - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute(action, iouType, transactionID, reportID, CONST.IOU.PAGE_INDEX.CONFIRM, Navigation.getActiveRouteWithoutParams())); + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute(action, iouType, transactionID, reportID, CONST.IOU.PAGE_INDEX.CONFIRM, Navigation.getActiveRouteWithoutParams()), + ); }} style={[styles.moneyRequestMenuItem, styles.mt2]} titleStyle={styles.moneyRequestConfirmationAmount} From 8be3d6fda4233aa8ab9eb4bec90dca586db81229 Mon Sep 17 00:00:00 2001 From: daledah Date: Tue, 27 Aug 2024 16:04:54 +0700 Subject: [PATCH 027/463] feat: update trips empty state view --- src/components/EmptyStateComponent/index.tsx | 6 +- src/components/EmptyStateComponent/types.ts | 4 +- src/languages/en.ts | 2 +- src/languages/es.ts | 2 +- src/pages/Search/EmptySearchView.tsx | 71 ++++++++++++++++++-- 5 files changed, 76 insertions(+), 9 deletions(-) diff --git a/src/components/EmptyStateComponent/index.tsx b/src/components/EmptyStateComponent/index.tsx index 6fcee2290d2b..f2be42c3a583 100644 --- a/src/components/EmptyStateComponent/index.tsx +++ b/src/components/EmptyStateComponent/index.tsx @@ -1,4 +1,5 @@ import type {VideoReadyForDisplayEvent} from 'expo-av'; +import {isString} from 'lodash'; import React, {useMemo, useState} from 'react'; import {View} from 'react-native'; import Button from '@components/Button'; @@ -20,6 +21,7 @@ function EmptyStateComponent({ buttonText, buttonAction, title, + titleStyles, subtitle, headerStyles, headerContentStyles, @@ -88,8 +90,8 @@ function EmptyStateComponent({ {HeaderComponent} - {title} - {subtitle} + {title} + {isString(subtitle) ? {subtitle} : subtitle} {!!buttonText && !!buttonAction && (